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