1 //===-- CommandObjectFrame.cpp --------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 #include "CommandObjectFrame.h"
9 #include "lldb/Core/Debugger.h"
10 #include "lldb/Core/ValueObject.h"
11 #include "lldb/DataFormatters/DataVisualization.h"
12 #include "lldb/DataFormatters/ValueObjectPrinter.h"
13 #include "lldb/Host/Config.h"
14 #include "lldb/Host/OptionParser.h"
15 #include "lldb/Interpreter/CommandInterpreter.h"
16 #include "lldb/Interpreter/CommandReturnObject.h"
17 #include "lldb/Interpreter/OptionGroupFormat.h"
18 #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
19 #include "lldb/Interpreter/OptionGroupVariable.h"
20 #include "lldb/Interpreter/Options.h"
21 #include "lldb/Symbol/Function.h"
22 #include "lldb/Symbol/SymbolContext.h"
23 #include "lldb/Symbol/Variable.h"
24 #include "lldb/Symbol/VariableList.h"
25 #include "lldb/Target/StackFrame.h"
26 #include "lldb/Target/StackFrameRecognizer.h"
27 #include "lldb/Target/StopInfo.h"
28 #include "lldb/Target/Target.h"
29 #include "lldb/Target/Thread.h"
30 #include "lldb/Utility/Args.h"
31 
32 #include <memory>
33 #include <string>
34 
35 using namespace lldb;
36 using namespace lldb_private;
37 
38 #pragma mark CommandObjectFrameDiagnose
39 
40 // CommandObjectFrameInfo
41 
42 // CommandObjectFrameDiagnose
43 
44 #define LLDB_OPTIONS_frame_diag
45 #include "CommandOptions.inc"
46 
47 class CommandObjectFrameDiagnose : public CommandObjectParsed {
48 public:
49   class CommandOptions : public Options {
50   public:
CommandOptions()51     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
52 
53     ~CommandOptions() override = default;
54 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)55     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
56                           ExecutionContext *execution_context) override {
57       Status error;
58       const int short_option = m_getopt_table[option_idx].val;
59       switch (short_option) {
60       case 'r':
61         reg = ConstString(option_arg);
62         break;
63 
64       case 'a': {
65         address.emplace();
66         if (option_arg.getAsInteger(0, *address)) {
67           address.reset();
68           error.SetErrorStringWithFormat("invalid address argument '%s'",
69                                          option_arg.str().c_str());
70         }
71       } break;
72 
73       case 'o': {
74         offset.emplace();
75         if (option_arg.getAsInteger(0, *offset)) {
76           offset.reset();
77           error.SetErrorStringWithFormat("invalid offset argument '%s'",
78                                          option_arg.str().c_str());
79         }
80       } break;
81 
82       default:
83         llvm_unreachable("Unimplemented option");
84       }
85 
86       return error;
87     }
88 
OptionParsingStarting(ExecutionContext * execution_context)89     void OptionParsingStarting(ExecutionContext *execution_context) override {
90       address.reset();
91       reg.reset();
92       offset.reset();
93     }
94 
GetDefinitions()95     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
96       return llvm::makeArrayRef(g_frame_diag_options);
97     }
98 
99     // Options.
100     llvm::Optional<lldb::addr_t> address;
101     llvm::Optional<ConstString> reg;
102     llvm::Optional<int64_t> offset;
103   };
104 
CommandObjectFrameDiagnose(CommandInterpreter & interpreter)105   CommandObjectFrameDiagnose(CommandInterpreter &interpreter)
106       : CommandObjectParsed(interpreter, "frame diagnose",
107                             "Try to determine what path path the current stop "
108                             "location used to get to a register or address",
109                             nullptr,
110                             eCommandRequiresThread | eCommandTryTargetAPILock |
111                                 eCommandProcessMustBeLaunched |
112                                 eCommandProcessMustBePaused),
113         m_options() {
114     CommandArgumentEntry arg;
115     CommandArgumentData index_arg;
116 
117     // Define the first (and only) variant of this arg.
118     index_arg.arg_type = eArgTypeFrameIndex;
119     index_arg.arg_repetition = eArgRepeatOptional;
120 
121     // There is only one variant this argument could be; put it into the
122     // argument entry.
123     arg.push_back(index_arg);
124 
125     // Push the data for the first argument into the m_arguments vector.
126     m_arguments.push_back(arg);
127   }
128 
129   ~CommandObjectFrameDiagnose() override = default;
130 
GetOptions()131   Options *GetOptions() override { return &m_options; }
132 
133 protected:
DoExecute(Args & command,CommandReturnObject & result)134   bool DoExecute(Args &command, CommandReturnObject &result) override {
135     Thread *thread = m_exe_ctx.GetThreadPtr();
136     StackFrameSP frame_sp = thread->GetSelectedFrame();
137 
138     ValueObjectSP valobj_sp;
139 
140     if (m_options.address.hasValue()) {
141       if (m_options.reg.hasValue() || m_options.offset.hasValue()) {
142         result.AppendError(
143             "`frame diagnose --address` is incompatible with other arguments.");
144         result.SetStatus(eReturnStatusFailed);
145         return false;
146       }
147       valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue());
148     } else if (m_options.reg.hasValue()) {
149       valobj_sp = frame_sp->GuessValueForRegisterAndOffset(
150           m_options.reg.getValue(), m_options.offset.getValueOr(0));
151     } else {
152       StopInfoSP stop_info_sp = thread->GetStopInfo();
153       if (!stop_info_sp) {
154         result.AppendError("No arguments provided, and no stop info.");
155         result.SetStatus(eReturnStatusFailed);
156         return false;
157       }
158 
159       valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
160     }
161 
162     if (!valobj_sp) {
163       result.AppendError("No diagnosis available.");
164       result.SetStatus(eReturnStatusFailed);
165       return false;
166     }
167 
168     DumpValueObjectOptions::DeclPrintingHelper helper =
169         [&valobj_sp](ConstString type, ConstString var,
170                      const DumpValueObjectOptions &opts,
171                      Stream &stream) -> bool {
172       const ValueObject::GetExpressionPathFormat format = ValueObject::
173           GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
174       valobj_sp->GetExpressionPath(stream, format);
175       stream.PutCString(" =");
176       return true;
177     };
178 
179     DumpValueObjectOptions options;
180     options.SetDeclPrintingHelper(helper);
181     ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(),
182                                options);
183     printer.PrintValueObject();
184 
185     return true;
186   }
187 
188   CommandOptions m_options;
189 };
190 
191 #pragma mark CommandObjectFrameInfo
192 
193 // CommandObjectFrameInfo
194 
195 class CommandObjectFrameInfo : public CommandObjectParsed {
196 public:
CommandObjectFrameInfo(CommandInterpreter & interpreter)197   CommandObjectFrameInfo(CommandInterpreter &interpreter)
198       : CommandObjectParsed(interpreter, "frame info",
199                             "List information about the current "
200                             "stack frame in the current thread.",
201                             "frame info",
202                             eCommandRequiresFrame | eCommandTryTargetAPILock |
203                                 eCommandProcessMustBeLaunched |
204                                 eCommandProcessMustBePaused) {}
205 
206   ~CommandObjectFrameInfo() override = default;
207 
208 protected:
DoExecute(Args & command,CommandReturnObject & result)209   bool DoExecute(Args &command, CommandReturnObject &result) override {
210     m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream());
211     result.SetStatus(eReturnStatusSuccessFinishResult);
212     return result.Succeeded();
213   }
214 };
215 
216 #pragma mark CommandObjectFrameSelect
217 
218 // CommandObjectFrameSelect
219 
220 #define LLDB_OPTIONS_frame_select
221 #include "CommandOptions.inc"
222 
223 class CommandObjectFrameSelect : public CommandObjectParsed {
224 public:
225   class CommandOptions : public Options {
226   public:
CommandOptions()227     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
228 
229     ~CommandOptions() override = default;
230 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)231     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
232                           ExecutionContext *execution_context) override {
233       Status error;
234       const int short_option = m_getopt_table[option_idx].val;
235       switch (short_option) {
236       case 'r': {
237         int32_t offset = 0;
238         if (option_arg.getAsInteger(0, offset) || offset == INT32_MIN) {
239           error.SetErrorStringWithFormat("invalid frame offset argument '%s'",
240                                          option_arg.str().c_str());
241         } else
242           relative_frame_offset = offset;
243         break;
244       }
245 
246       default:
247         llvm_unreachable("Unimplemented option");
248       }
249 
250       return error;
251     }
252 
OptionParsingStarting(ExecutionContext * execution_context)253     void OptionParsingStarting(ExecutionContext *execution_context) override {
254       relative_frame_offset.reset();
255     }
256 
GetDefinitions()257     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
258       return llvm::makeArrayRef(g_frame_select_options);
259     }
260 
261     llvm::Optional<int32_t> relative_frame_offset;
262   };
263 
CommandObjectFrameSelect(CommandInterpreter & interpreter)264   CommandObjectFrameSelect(CommandInterpreter &interpreter)
265       : CommandObjectParsed(interpreter, "frame select",
266                             "Select the current stack frame by "
267                             "index from within the current thread "
268                             "(see 'thread backtrace'.)",
269                             nullptr,
270                             eCommandRequiresThread | eCommandTryTargetAPILock |
271                                 eCommandProcessMustBeLaunched |
272                                 eCommandProcessMustBePaused),
273         m_options() {
274     CommandArgumentEntry arg;
275     CommandArgumentData index_arg;
276 
277     // Define the first (and only) variant of this arg.
278     index_arg.arg_type = eArgTypeFrameIndex;
279     index_arg.arg_repetition = eArgRepeatOptional;
280 
281     // There is only one variant this argument could be; put it into the
282     // argument entry.
283     arg.push_back(index_arg);
284 
285     // Push the data for the first argument into the m_arguments vector.
286     m_arguments.push_back(arg);
287   }
288 
289   ~CommandObjectFrameSelect() override = default;
290 
291   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)292   HandleArgumentCompletion(CompletionRequest &request,
293                            OptionElementVector &opt_element_vector) override {
294     if (request.GetCursorIndex() != 0)
295       return;
296 
297     CommandCompletions::InvokeCommonCompletionCallbacks(
298         GetCommandInterpreter(), CommandCompletions::eFrameIndexCompletion,
299         request, nullptr);
300   }
301 
GetOptions()302   Options *GetOptions() override { return &m_options; }
303 
304 protected:
DoExecute(Args & command,CommandReturnObject & result)305   bool DoExecute(Args &command, CommandReturnObject &result) override {
306     // No need to check "thread" for validity as eCommandRequiresThread ensures
307     // it is valid
308     Thread *thread = m_exe_ctx.GetThreadPtr();
309 
310     uint32_t frame_idx = UINT32_MAX;
311     if (m_options.relative_frame_offset.hasValue()) {
312       // The one and only argument is a signed relative frame index
313       frame_idx = thread->GetSelectedFrameIndex();
314       if (frame_idx == UINT32_MAX)
315         frame_idx = 0;
316 
317       if (*m_options.relative_frame_offset < 0) {
318         if (static_cast<int32_t>(frame_idx) >=
319             -*m_options.relative_frame_offset)
320           frame_idx += *m_options.relative_frame_offset;
321         else {
322           if (frame_idx == 0) {
323             // If you are already at the bottom of the stack, then just warn
324             // and don't reset the frame.
325             result.AppendError("Already at the bottom of the stack.");
326             result.SetStatus(eReturnStatusFailed);
327             return false;
328           } else
329             frame_idx = 0;
330         }
331       } else if (*m_options.relative_frame_offset > 0) {
332         // I don't want "up 20" where "20" takes you past the top of the stack
333         // to produce
334         // an error, but rather to just go to the top.  So I have to count the
335         // stack here...
336         const uint32_t num_frames = thread->GetStackFrameCount();
337         if (static_cast<int32_t>(num_frames - frame_idx) >
338             *m_options.relative_frame_offset)
339           frame_idx += *m_options.relative_frame_offset;
340         else {
341           if (frame_idx == num_frames - 1) {
342             // If we are already at the top of the stack, just warn and don't
343             // reset the frame.
344             result.AppendError("Already at the top of the stack.");
345             result.SetStatus(eReturnStatusFailed);
346             return false;
347           } else
348             frame_idx = num_frames - 1;
349         }
350       }
351     } else {
352       if (command.GetArgumentCount() > 1) {
353         result.AppendErrorWithFormat(
354             "too many arguments; expected frame-index, saw '%s'.\n",
355             command[0].c_str());
356         m_options.GenerateOptionUsage(
357             result.GetErrorStream(), this,
358             GetCommandInterpreter().GetDebugger().GetTerminalWidth());
359         return false;
360       }
361 
362       if (command.GetArgumentCount() == 1) {
363         if (command[0].ref().getAsInteger(0, frame_idx)) {
364           result.AppendErrorWithFormat("invalid frame index argument '%s'.",
365                                        command[0].c_str());
366           result.SetStatus(eReturnStatusFailed);
367           return false;
368         }
369       } else if (command.GetArgumentCount() == 0) {
370         frame_idx = thread->GetSelectedFrameIndex();
371         if (frame_idx == UINT32_MAX) {
372           frame_idx = 0;
373         }
374       }
375     }
376 
377     bool success = thread->SetSelectedFrameByIndexNoisily(
378         frame_idx, result.GetOutputStream());
379     if (success) {
380       m_exe_ctx.SetFrameSP(thread->GetSelectedFrame());
381       result.SetStatus(eReturnStatusSuccessFinishResult);
382     } else {
383       result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
384                                    frame_idx);
385       result.SetStatus(eReturnStatusFailed);
386     }
387 
388     return result.Succeeded();
389   }
390 
391   CommandOptions m_options;
392 };
393 
394 #pragma mark CommandObjectFrameVariable
395 // List images with associated information
396 class CommandObjectFrameVariable : public CommandObjectParsed {
397 public:
CommandObjectFrameVariable(CommandInterpreter & interpreter)398   CommandObjectFrameVariable(CommandInterpreter &interpreter)
399       : CommandObjectParsed(
400             interpreter, "frame variable",
401             "Show variables for the current stack frame. Defaults to all "
402             "arguments and local variables in scope. Names of argument, "
403             "local, file static and file global variables can be specified. "
404             "Children of aggregate variables can be specified such as "
405             "'var->child.x'.  The -> and [] operators in 'frame variable' do "
406             "not invoke operator overloads if they exist, but directly access "
407             "the specified element.  If you want to trigger operator overloads "
408             "use the expression command to print the variable instead."
409             "\nIt is worth noting that except for overloaded "
410             "operators, when printing local variables 'expr local_var' and "
411             "'frame var local_var' produce the same "
412             "results.  However, 'frame variable' is more efficient, since it "
413             "uses debug information and memory reads directly, rather than "
414             "parsing and evaluating an expression, which may even involve "
415             "JITing and running code in the target program.",
416             nullptr,
417             eCommandRequiresFrame | eCommandTryTargetAPILock |
418                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
419                 eCommandRequiresProcess),
420         m_option_group(),
421         m_option_variable(
422             true), // Include the frame specific options by passing "true"
423         m_option_format(eFormatDefault), m_varobj_options() {
424     CommandArgumentEntry arg;
425     CommandArgumentData var_name_arg;
426 
427     // Define the first (and only) variant of this arg.
428     var_name_arg.arg_type = eArgTypeVarName;
429     var_name_arg.arg_repetition = eArgRepeatStar;
430 
431     // There is only one variant this argument could be; put it into the
432     // argument entry.
433     arg.push_back(var_name_arg);
434 
435     // Push the data for the first argument into the m_arguments vector.
436     m_arguments.push_back(arg);
437 
438     m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
439     m_option_group.Append(&m_option_format,
440                           OptionGroupFormat::OPTION_GROUP_FORMAT |
441                               OptionGroupFormat::OPTION_GROUP_GDB_FMT,
442                           LLDB_OPT_SET_1);
443     m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
444     m_option_group.Finalize();
445   }
446 
447   ~CommandObjectFrameVariable() override = default;
448 
GetOptions()449   Options *GetOptions() override { return &m_option_group; }
450 
451   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)452   HandleArgumentCompletion(CompletionRequest &request,
453                            OptionElementVector &opt_element_vector) override {
454     // Arguments are the standard source file completer.
455     CommandCompletions::InvokeCommonCompletionCallbacks(
456         GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion,
457         request, nullptr);
458   }
459 
460 protected:
GetScopeString(VariableSP var_sp)461   llvm::StringRef GetScopeString(VariableSP var_sp) {
462     if (!var_sp)
463       return llvm::StringRef::withNullAsEmpty(nullptr);
464 
465     switch (var_sp->GetScope()) {
466     case eValueTypeVariableGlobal:
467       return "GLOBAL: ";
468     case eValueTypeVariableStatic:
469       return "STATIC: ";
470     case eValueTypeVariableArgument:
471       return "ARG: ";
472     case eValueTypeVariableLocal:
473       return "LOCAL: ";
474     case eValueTypeVariableThreadLocal:
475       return "THREAD: ";
476     default:
477       break;
478     }
479 
480     return llvm::StringRef::withNullAsEmpty(nullptr);
481   }
482 
DoExecute(Args & command,CommandReturnObject & result)483   bool DoExecute(Args &command, CommandReturnObject &result) override {
484     // No need to check "frame" for validity as eCommandRequiresFrame ensures
485     // it is valid
486     StackFrame *frame = m_exe_ctx.GetFramePtr();
487 
488     Stream &s = result.GetOutputStream();
489 
490     // Be careful about the stack frame, if any summary formatter runs code, it
491     // might clear the StackFrameList for the thread.  So hold onto a shared
492     // pointer to the frame so it stays alive.
493 
494     VariableList *variable_list =
495         frame->GetVariableList(m_option_variable.show_globals);
496 
497     VariableSP var_sp;
498     ValueObjectSP valobj_sp;
499 
500     TypeSummaryImplSP summary_format_sp;
501     if (!m_option_variable.summary.IsCurrentValueEmpty())
502       DataVisualization::NamedSummaryFormats::GetSummaryFormat(
503           ConstString(m_option_variable.summary.GetCurrentValue()),
504           summary_format_sp);
505     else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
506       summary_format_sp = std::make_shared<StringSummaryFormat>(
507           TypeSummaryImpl::Flags(),
508           m_option_variable.summary_string.GetCurrentValue());
509 
510     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
511         eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault,
512         summary_format_sp));
513 
514     const SymbolContext &sym_ctx =
515         frame->GetSymbolContext(eSymbolContextFunction);
516     if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
517       m_option_variable.show_globals = true;
518 
519     if (variable_list) {
520       const Format format = m_option_format.GetFormat();
521       options.SetFormat(format);
522 
523       if (!command.empty()) {
524         VariableList regex_var_list;
525 
526         // If we have any args to the variable command, we will make variable
527         // objects from them...
528         for (auto &entry : command) {
529           if (m_option_variable.use_regex) {
530             const size_t regex_start_index = regex_var_list.GetSize();
531             llvm::StringRef name_str = entry.ref();
532             RegularExpression regex(name_str);
533             if (regex.IsValid()) {
534               size_t num_matches = 0;
535               const size_t num_new_regex_vars =
536                   variable_list->AppendVariablesIfUnique(regex, regex_var_list,
537                                                          num_matches);
538               if (num_new_regex_vars > 0) {
539                 for (size_t regex_idx = regex_start_index,
540                             end_index = regex_var_list.GetSize();
541                      regex_idx < end_index; ++regex_idx) {
542                   var_sp = regex_var_list.GetVariableAtIndex(regex_idx);
543                   if (var_sp) {
544                     valobj_sp = frame->GetValueObjectForFrameVariable(
545                         var_sp, m_varobj_options.use_dynamic);
546                     if (valobj_sp) {
547                       std::string scope_string;
548                       if (m_option_variable.show_scope)
549                         scope_string = GetScopeString(var_sp).str();
550 
551                       if (!scope_string.empty())
552                         s.PutCString(scope_string);
553 
554                       if (m_option_variable.show_decl &&
555                           var_sp->GetDeclaration().GetFile()) {
556                         bool show_fullpaths = false;
557                         bool show_module = true;
558                         if (var_sp->DumpDeclaration(&s, show_fullpaths,
559                                                     show_module))
560                           s.PutCString(": ");
561                       }
562                       valobj_sp->Dump(result.GetOutputStream(), options);
563                     }
564                   }
565                 }
566               } else if (num_matches == 0) {
567                 result.GetErrorStream().Printf("error: no variables matched "
568                                                "the regular expression '%s'.\n",
569                                                entry.c_str());
570               }
571             } else {
572               if (llvm::Error err = regex.GetError())
573                 result.GetErrorStream().Printf(
574                     "error: %s\n", llvm::toString(std::move(err)).c_str());
575               else
576                 result.GetErrorStream().Printf(
577                     "error: unknown regex error when compiling '%s'\n",
578                     entry.c_str());
579             }
580           } else // No regex, either exact variable names or variable
581                  // expressions.
582           {
583             Status error;
584             uint32_t expr_path_options =
585                 StackFrame::eExpressionPathOptionCheckPtrVsMember |
586                 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
587                 StackFrame::eExpressionPathOptionsInspectAnonymousUnions;
588             lldb::VariableSP var_sp;
589             valobj_sp = frame->GetValueForVariableExpressionPath(
590                 entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
591                 var_sp, error);
592             if (valobj_sp) {
593               std::string scope_string;
594               if (m_option_variable.show_scope)
595                 scope_string = GetScopeString(var_sp).str();
596 
597               if (!scope_string.empty())
598                 s.PutCString(scope_string);
599               if (m_option_variable.show_decl && var_sp &&
600                   var_sp->GetDeclaration().GetFile()) {
601                 var_sp->GetDeclaration().DumpStopContext(&s, false);
602                 s.PutCString(": ");
603               }
604 
605               options.SetFormat(format);
606               options.SetVariableFormatDisplayLanguage(
607                   valobj_sp->GetPreferredDisplayLanguage());
608 
609               Stream &output_stream = result.GetOutputStream();
610               options.SetRootValueObjectName(
611                   valobj_sp->GetParent() ? entry.c_str() : nullptr);
612               valobj_sp->Dump(output_stream, options);
613             } else {
614               const char *error_cstr = error.AsCString(nullptr);
615               if (error_cstr)
616                 result.GetErrorStream().Printf("error: %s\n", error_cstr);
617               else
618                 result.GetErrorStream().Printf("error: unable to find any "
619                                                "variable expression path that "
620                                                "matches '%s'.\n",
621                                                entry.c_str());
622             }
623           }
624         }
625       } else // No command arg specified.  Use variable_list, instead.
626       {
627         const size_t num_variables = variable_list->GetSize();
628         if (num_variables > 0) {
629           for (size_t i = 0; i < num_variables; i++) {
630             var_sp = variable_list->GetVariableAtIndex(i);
631             switch (var_sp->GetScope()) {
632             case eValueTypeVariableGlobal:
633               if (!m_option_variable.show_globals)
634                 continue;
635               break;
636             case eValueTypeVariableStatic:
637               if (!m_option_variable.show_globals)
638                 continue;
639               break;
640             case eValueTypeVariableArgument:
641               if (!m_option_variable.show_args)
642                 continue;
643               break;
644             case eValueTypeVariableLocal:
645               if (!m_option_variable.show_locals)
646                 continue;
647               break;
648             default:
649               continue;
650               break;
651             }
652             std::string scope_string;
653             if (m_option_variable.show_scope)
654               scope_string = GetScopeString(var_sp).str();
655 
656             // Use the variable object code to make sure we are using the same
657             // APIs as the public API will be using...
658             valobj_sp = frame->GetValueObjectForFrameVariable(
659                 var_sp, m_varobj_options.use_dynamic);
660             if (valobj_sp) {
661               // When dumping all variables, don't print any variables that are
662               // not in scope to avoid extra unneeded output
663               if (valobj_sp->IsInScope()) {
664                 if (!valobj_sp->GetTargetSP()
665                          ->GetDisplayRuntimeSupportValues() &&
666                     valobj_sp->IsRuntimeSupportValue())
667                   continue;
668 
669                 if (!scope_string.empty())
670                   s.PutCString(scope_string);
671 
672                 if (m_option_variable.show_decl &&
673                     var_sp->GetDeclaration().GetFile()) {
674                   var_sp->GetDeclaration().DumpStopContext(&s, false);
675                   s.PutCString(": ");
676                 }
677 
678                 options.SetFormat(format);
679                 options.SetVariableFormatDisplayLanguage(
680                     valobj_sp->GetPreferredDisplayLanguage());
681                 options.SetRootValueObjectName(
682                     var_sp ? var_sp->GetName().AsCString() : nullptr);
683                 valobj_sp->Dump(result.GetOutputStream(), options);
684               }
685             }
686           }
687         }
688       }
689       result.SetStatus(eReturnStatusSuccessFinishResult);
690     }
691 
692     if (m_option_variable.show_recognized_args) {
693       auto recognized_frame = frame->GetRecognizedFrame();
694       if (recognized_frame) {
695         ValueObjectListSP recognized_arg_list =
696             recognized_frame->GetRecognizedArguments();
697         if (recognized_arg_list) {
698           for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
699             options.SetFormat(m_option_format.GetFormat());
700             options.SetVariableFormatDisplayLanguage(
701                 rec_value_sp->GetPreferredDisplayLanguage());
702             options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
703             rec_value_sp->Dump(result.GetOutputStream(), options);
704           }
705         }
706       }
707     }
708 
709     if (m_interpreter.TruncationWarningNecessary()) {
710       result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
711                                       m_cmd_name.c_str());
712       m_interpreter.TruncationWarningGiven();
713     }
714 
715     // Increment statistics.
716     bool res = result.Succeeded();
717     Target &target = GetSelectedOrDummyTarget();
718     if (res)
719       target.IncrementStats(StatisticKind::FrameVarSuccess);
720     else
721       target.IncrementStats(StatisticKind::FrameVarFailure);
722     return res;
723   }
724 
725   OptionGroupOptions m_option_group;
726   OptionGroupVariable m_option_variable;
727   OptionGroupFormat m_option_format;
728   OptionGroupValueObjectDisplay m_varobj_options;
729 };
730 
731 #pragma mark CommandObjectFrameRecognizer
732 
733 #define LLDB_OPTIONS_frame_recognizer_add
734 #include "CommandOptions.inc"
735 
736 class CommandObjectFrameRecognizerAdd : public CommandObjectParsed {
737 private:
738   class CommandOptions : public Options {
739   public:
CommandOptions()740     CommandOptions() : Options() {}
741     ~CommandOptions() override = default;
742 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)743     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
744                           ExecutionContext *execution_context) override {
745       Status error;
746       const int short_option = m_getopt_table[option_idx].val;
747 
748       switch (short_option) {
749       case 'l':
750         m_class_name = std::string(option_arg);
751         break;
752       case 's':
753         m_module = std::string(option_arg);
754         break;
755       case 'n':
756         m_symbols.push_back(std::string(option_arg));
757         break;
758       case 'x':
759         m_regex = true;
760         break;
761       default:
762         llvm_unreachable("Unimplemented option");
763       }
764 
765       return error;
766     }
767 
OptionParsingStarting(ExecutionContext * execution_context)768     void OptionParsingStarting(ExecutionContext *execution_context) override {
769       m_module = "";
770       m_symbols.clear();
771       m_class_name = "";
772       m_regex = false;
773     }
774 
GetDefinitions()775     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
776       return llvm::makeArrayRef(g_frame_recognizer_add_options);
777     }
778 
779     // Instance variables to hold the values for command options.
780     std::string m_class_name;
781     std::string m_module;
782     std::vector<std::string> m_symbols;
783     bool m_regex;
784   };
785 
786   CommandOptions m_options;
787 
GetOptions()788   Options *GetOptions() override { return &m_options; }
789 
790 protected:
791   bool DoExecute(Args &command, CommandReturnObject &result) override;
792 
793 public:
CommandObjectFrameRecognizerAdd(CommandInterpreter & interpreter)794   CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)
795       : CommandObjectParsed(interpreter, "frame recognizer add",
796                             "Add a new frame recognizer.", nullptr),
797         m_options() {
798     SetHelpLong(R"(
799 Frame recognizers allow for retrieving information about special frames based on
800 ABI, arguments or other special properties of that frame, even without source
801 code or debug info. Currently, one use case is to extract function arguments
802 that would otherwise be unaccesible, or augment existing arguments.
803 
804 Adding a custom frame recognizer is possible by implementing a Python class
805 and using the 'frame recognizer add' command. The Python class should have a
806 'get_recognized_arguments' method and it will receive an argument of type
807 lldb.SBFrame representing the current frame that we are trying to recognize.
808 The method should return a (possibly empty) list of lldb.SBValue objects that
809 represent the recognized arguments.
810 
811 An example of a recognizer that retrieves the file descriptor values from libc
812 functions 'read', 'write' and 'close' follows:
813 
814   class LibcFdRecognizer(object):
815     def get_recognized_arguments(self, frame):
816       if frame.name in ["read", "write", "close"]:
817         fd = frame.EvaluateExpression("$arg1").unsigned
818         value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd)
819         return [value]
820       return []
821 
822 The file containing this implementation can be imported via 'command script
823 import' and then we can register this recognizer with 'frame recognizer add'.
824 It's important to restrict the recognizer to the libc library (which is
825 libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
826 in other modules:
827 
828 (lldb) command script import .../fd_recognizer.py
829 (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
830 
831 When the program is stopped at the beginning of the 'read' function in libc, we
832 can view the recognizer arguments in 'frame variable':
833 
834 (lldb) b read
835 (lldb) r
836 Process 1234 stopped
837 * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
838     frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
839 (lldb) frame variable
840 (int) fd = 3
841 
842     )");
843   }
844   ~CommandObjectFrameRecognizerAdd() override = default;
845 };
846 
DoExecute(Args & command,CommandReturnObject & result)847 bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command,
848                                                 CommandReturnObject &result) {
849 #if LLDB_ENABLE_PYTHON
850   if (m_options.m_class_name.empty()) {
851     result.AppendErrorWithFormat(
852         "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
853     result.SetStatus(eReturnStatusFailed);
854     return false;
855   }
856 
857   if (m_options.m_module.empty()) {
858     result.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
859                                  m_cmd_name.c_str());
860     result.SetStatus(eReturnStatusFailed);
861     return false;
862   }
863 
864   if (m_options.m_symbols.empty()) {
865     result.AppendErrorWithFormat(
866         "%s needs at least one symbol name (-n argument).\n",
867         m_cmd_name.c_str());
868     result.SetStatus(eReturnStatusFailed);
869     return false;
870   }
871 
872   if (m_options.m_regex && m_options.m_symbols.size() > 1) {
873     result.AppendErrorWithFormat(
874         "%s needs only one symbol regular expression (-n argument).\n",
875         m_cmd_name.c_str());
876     result.SetStatus(eReturnStatusFailed);
877     return false;
878   }
879 
880   ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
881 
882   if (interpreter &&
883       !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
884     result.AppendWarning("The provided class does not exist - please define it "
885                          "before attempting to use this frame recognizer");
886   }
887 
888   StackFrameRecognizerSP recognizer_sp =
889       StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(
890           interpreter, m_options.m_class_name.c_str()));
891   if (m_options.m_regex) {
892     auto module =
893         RegularExpressionSP(new RegularExpression(m_options.m_module));
894     auto func =
895         RegularExpressionSP(new RegularExpression(m_options.m_symbols.front()));
896     GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer(
897         recognizer_sp, module, func);
898   } else {
899     auto module = ConstString(m_options.m_module);
900     std::vector<ConstString> symbols(m_options.m_symbols.begin(),
901                                      m_options.m_symbols.end());
902     GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer(
903         recognizer_sp, module, symbols);
904   }
905 #endif
906 
907   result.SetStatus(eReturnStatusSuccessFinishNoResult);
908   return result.Succeeded();
909 }
910 
911 class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
912 public:
CommandObjectFrameRecognizerClear(CommandInterpreter & interpreter)913   CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
914       : CommandObjectParsed(interpreter, "frame recognizer clear",
915                             "Delete all frame recognizers.", nullptr) {}
916 
917   ~CommandObjectFrameRecognizerClear() override = default;
918 
919 protected:
DoExecute(Args & command,CommandReturnObject & result)920   bool DoExecute(Args &command, CommandReturnObject &result) override {
921     GetSelectedOrDummyTarget()
922         .GetFrameRecognizerManager()
923         .RemoveAllRecognizers();
924     result.SetStatus(eReturnStatusSuccessFinishResult);
925     return result.Succeeded();
926   }
927 };
928 
929 class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
930 public:
CommandObjectFrameRecognizerDelete(CommandInterpreter & interpreter)931   CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
932       : CommandObjectParsed(interpreter, "frame recognizer delete",
933                             "Delete an existing frame recognizer.", nullptr) {}
934 
935   ~CommandObjectFrameRecognizerDelete() override = default;
936 
937   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)938   HandleArgumentCompletion(CompletionRequest &request,
939                            OptionElementVector &opt_element_vector) override {
940     if (request.GetCursorIndex() != 0)
941       return;
942 
943     GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach(
944         [&request](uint32_t rid, std::string rname, std::string module,
945                    llvm::ArrayRef<lldb_private::ConstString> symbols,
946                    bool regexp) {
947           StreamString strm;
948           if (rname.empty())
949             rname = "(internal)";
950 
951           strm << rname;
952           if (!module.empty())
953             strm << ", module " << module;
954           if (!symbols.empty())
955             for (auto &symbol : symbols)
956               strm << ", symbol " << symbol;
957           if (regexp)
958             strm << " (regexp)";
959 
960           request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString());
961         });
962   }
963 
964 protected:
DoExecute(Args & command,CommandReturnObject & result)965   bool DoExecute(Args &command, CommandReturnObject &result) override {
966     if (command.GetArgumentCount() == 0) {
967       if (!m_interpreter.Confirm(
968               "About to delete all frame recognizers, do you want to do that?",
969               true)) {
970         result.AppendMessage("Operation cancelled...");
971         result.SetStatus(eReturnStatusFailed);
972         return false;
973       }
974 
975       GetSelectedOrDummyTarget()
976           .GetFrameRecognizerManager()
977           .RemoveAllRecognizers();
978       result.SetStatus(eReturnStatusSuccessFinishResult);
979       return result.Succeeded();
980     }
981 
982     if (command.GetArgumentCount() != 1) {
983       result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
984                                    m_cmd_name.c_str());
985       result.SetStatus(eReturnStatusFailed);
986       return false;
987     }
988 
989     uint32_t recognizer_id;
990     if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) {
991       result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
992                                    command.GetArgumentAtIndex(0));
993       result.SetStatus(eReturnStatusFailed);
994       return false;
995     }
996 
997     if (!GetSelectedOrDummyTarget()
998              .GetFrameRecognizerManager()
999              .RemoveRecognizerWithID(recognizer_id)) {
1000       result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
1001                                    command.GetArgumentAtIndex(0));
1002       result.SetStatus(eReturnStatusFailed);
1003       return false;
1004     }
1005     result.SetStatus(eReturnStatusSuccessFinishResult);
1006     return result.Succeeded();
1007   }
1008 };
1009 
1010 class CommandObjectFrameRecognizerList : public CommandObjectParsed {
1011 public:
CommandObjectFrameRecognizerList(CommandInterpreter & interpreter)1012   CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
1013       : CommandObjectParsed(interpreter, "frame recognizer list",
1014                             "Show a list of active frame recognizers.",
1015                             nullptr) {}
1016 
1017   ~CommandObjectFrameRecognizerList() override = default;
1018 
1019 protected:
DoExecute(Args & command,CommandReturnObject & result)1020   bool DoExecute(Args &command, CommandReturnObject &result) override {
1021     bool any_printed = false;
1022     GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach(
1023         [&result, &any_printed](
1024             uint32_t recognizer_id, std::string name, std::string module,
1025             llvm::ArrayRef<ConstString> symbols, bool regexp) {
1026           Stream &stream = result.GetOutputStream();
1027 
1028           if (name.empty())
1029             name = "(internal)";
1030 
1031           stream << std::to_string(recognizer_id) << ": " << name;
1032           if (!module.empty())
1033             stream << ", module " << module;
1034           if (!symbols.empty())
1035             for (auto &symbol : symbols)
1036               stream << ", symbol " << symbol;
1037           if (regexp)
1038             stream << " (regexp)";
1039 
1040           stream.EOL();
1041           stream.Flush();
1042 
1043           any_printed = true;
1044         });
1045 
1046     if (any_printed)
1047       result.SetStatus(eReturnStatusSuccessFinishResult);
1048     else {
1049       result.GetOutputStream().PutCString("no matching results found.\n");
1050       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1051     }
1052     return result.Succeeded();
1053   }
1054 };
1055 
1056 class CommandObjectFrameRecognizerInfo : public CommandObjectParsed {
1057 public:
CommandObjectFrameRecognizerInfo(CommandInterpreter & interpreter)1058   CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
1059       : CommandObjectParsed(
1060             interpreter, "frame recognizer info",
1061             "Show which frame recognizer is applied a stack frame (if any).",
1062             nullptr) {
1063     CommandArgumentEntry arg;
1064     CommandArgumentData index_arg;
1065 
1066     // Define the first (and only) variant of this arg.
1067     index_arg.arg_type = eArgTypeFrameIndex;
1068     index_arg.arg_repetition = eArgRepeatPlain;
1069 
1070     // There is only one variant this argument could be; put it into the
1071     // argument entry.
1072     arg.push_back(index_arg);
1073 
1074     // Push the data for the first argument into the m_arguments vector.
1075     m_arguments.push_back(arg);
1076   }
1077 
1078   ~CommandObjectFrameRecognizerInfo() override = default;
1079 
1080 protected:
DoExecute(Args & command,CommandReturnObject & result)1081   bool DoExecute(Args &command, CommandReturnObject &result) override {
1082     const char *frame_index_str = command.GetArgumentAtIndex(0);
1083     uint32_t frame_index;
1084     if (!llvm::to_integer(frame_index_str, frame_index)) {
1085       result.AppendErrorWithFormat("'%s' is not a valid frame index.",
1086                                    frame_index_str);
1087       result.SetStatus(eReturnStatusFailed);
1088       return false;
1089     }
1090 
1091     Process *process = m_exe_ctx.GetProcessPtr();
1092     if (process == nullptr) {
1093       result.AppendError("no process");
1094       result.SetStatus(eReturnStatusFailed);
1095       return false;
1096     }
1097     Thread *thread = m_exe_ctx.GetThreadPtr();
1098     if (thread == nullptr) {
1099       result.AppendError("no thread");
1100       result.SetStatus(eReturnStatusFailed);
1101       return false;
1102     }
1103     if (command.GetArgumentCount() != 1) {
1104       result.AppendErrorWithFormat(
1105           "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
1106       result.SetStatus(eReturnStatusFailed);
1107       return false;
1108     }
1109 
1110     StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
1111     if (!frame_sp) {
1112       result.AppendErrorWithFormat("no frame with index %u", frame_index);
1113       result.SetStatus(eReturnStatusFailed);
1114       return false;
1115     }
1116 
1117     auto recognizer = GetSelectedOrDummyTarget()
1118                           .GetFrameRecognizerManager()
1119                           .GetRecognizerForFrame(frame_sp);
1120 
1121     Stream &output_stream = result.GetOutputStream();
1122     output_stream.Printf("frame %d ", frame_index);
1123     if (recognizer) {
1124       output_stream << "is recognized by ";
1125       output_stream << recognizer->GetName();
1126     } else {
1127       output_stream << "not recognized by any recognizer";
1128     }
1129     output_stream.EOL();
1130     result.SetStatus(eReturnStatusSuccessFinishResult);
1131     return result.Succeeded();
1132   }
1133 };
1134 
1135 class CommandObjectFrameRecognizer : public CommandObjectMultiword {
1136 public:
CommandObjectFrameRecognizer(CommandInterpreter & interpreter)1137   CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
1138       : CommandObjectMultiword(
1139             interpreter, "frame recognizer",
1140             "Commands for editing and viewing frame recognizers.",
1141             "frame recognizer [<sub-command-options>] ") {
1142     LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd(
1143                               interpreter)));
1144     LoadSubCommand(
1145         "clear",
1146         CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter)));
1147     LoadSubCommand(
1148         "delete",
1149         CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter)));
1150     LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList(
1151                                interpreter)));
1152     LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo(
1153                                interpreter)));
1154   }
1155 
1156   ~CommandObjectFrameRecognizer() override = default;
1157 };
1158 
1159 #pragma mark CommandObjectMultiwordFrame
1160 
1161 // CommandObjectMultiwordFrame
1162 
CommandObjectMultiwordFrame(CommandInterpreter & interpreter)1163 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
1164     CommandInterpreter &interpreter)
1165     : CommandObjectMultiword(interpreter, "frame",
1166                              "Commands for selecting and "
1167                              "examing the current "
1168                              "thread's stack frames.",
1169                              "frame <subcommand> [<subcommand-options>]") {
1170   LoadSubCommand("diagnose",
1171                  CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
1172   LoadSubCommand("info",
1173                  CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1174   LoadSubCommand("select",
1175                  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1176   LoadSubCommand("variable",
1177                  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
1178 #if LLDB_ENABLE_PYTHON
1179   LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer(
1180                                    interpreter)));
1181 #endif
1182 }
1183 
1184 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
1185