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