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