xref: /llvm-project/lldb/source/Commands/CommandObjectFrame.cpp (revision 8bc97a3ee4f411e583a13e0966239848080d753d)
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   bool 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 false;
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 false;
157       }
158 
159       valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
160     }
161 
162     if (!valobj_sp) {
163       result.AppendError("No diagnosis available.");
164       return false;
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     ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(),
181                                options);
182     printer.PrintValueObject();
183 
184     return true;
185   }
186 
187   CommandOptions m_options;
188 };
189 
190 #pragma mark CommandObjectFrameInfo
191 
192 // CommandObjectFrameInfo
193 
194 class CommandObjectFrameInfo : public CommandObjectParsed {
195 public:
196   CommandObjectFrameInfo(CommandInterpreter &interpreter)
197       : CommandObjectParsed(interpreter, "frame info",
198                             "List information about the current "
199                             "stack frame in the current thread.",
200                             "frame info",
201                             eCommandRequiresFrame | eCommandTryTargetAPILock |
202                                 eCommandProcessMustBeLaunched |
203                                 eCommandProcessMustBePaused) {}
204 
205   ~CommandObjectFrameInfo() override = default;
206 
207 protected:
208   bool DoExecute(Args &command, CommandReturnObject &result) override {
209     m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream());
210     result.SetStatus(eReturnStatusSuccessFinishResult);
211     return result.Succeeded();
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   void
290   HandleArgumentCompletion(CompletionRequest &request,
291                            OptionElementVector &opt_element_vector) override {
292     if (request.GetCursorIndex() != 0)
293       return;
294 
295     lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
296         GetCommandInterpreter(), lldb::eFrameIndexCompletion, request, nullptr);
297   }
298 
299   Options *GetOptions() override { return &m_options; }
300 
301 protected:
302   bool DoExecute(Args &command, CommandReturnObject &result) override {
303     // No need to check "thread" for validity as eCommandRequiresThread ensures
304     // it is valid
305     Thread *thread = m_exe_ctx.GetThreadPtr();
306 
307     uint32_t frame_idx = UINT32_MAX;
308     if (m_options.relative_frame_offset) {
309       // The one and only argument is a signed relative frame index
310       frame_idx = thread->GetSelectedFrameIndex(SelectMostRelevantFrame);
311       if (frame_idx == UINT32_MAX)
312         frame_idx = 0;
313 
314       if (*m_options.relative_frame_offset < 0) {
315         if (static_cast<int32_t>(frame_idx) >=
316             -*m_options.relative_frame_offset)
317           frame_idx += *m_options.relative_frame_offset;
318         else {
319           if (frame_idx == 0) {
320             // If you are already at the bottom of the stack, then just warn
321             // and don't reset the frame.
322             result.AppendError("Already at the bottom of the stack.");
323             return false;
324           } else
325             frame_idx = 0;
326         }
327       } else if (*m_options.relative_frame_offset > 0) {
328         // I don't want "up 20" where "20" takes you past the top of the stack
329         // to produce an error, but rather to just go to the top.  OTOH, start
330         // by seeing if the requested frame exists, in which case we can avoid
331         // counting the stack here...
332         const uint32_t frame_requested = frame_idx
333             + *m_options.relative_frame_offset;
334         StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_requested);
335         if (frame_sp)
336           frame_idx = frame_requested;
337         else {
338           // The request went past the stack, so handle that case:
339           const uint32_t num_frames = thread->GetStackFrameCount();
340           if (static_cast<int32_t>(num_frames - frame_idx) >
341               *m_options.relative_frame_offset)
342           frame_idx += *m_options.relative_frame_offset;
343           else {
344             if (frame_idx == num_frames - 1) {
345               // If we are already at the top of the stack, just warn and don't
346               // reset the frame.
347               result.AppendError("Already at the top of the stack.");
348               return false;
349             } else
350               frame_idx = num_frames - 1;
351           }
352         }
353       }
354     } else {
355       if (command.GetArgumentCount() > 1) {
356         result.AppendErrorWithFormat(
357             "too many arguments; expected frame-index, saw '%s'.\n",
358             command[0].c_str());
359         m_options.GenerateOptionUsage(
360             result.GetErrorStream(), *this,
361             GetCommandInterpreter().GetDebugger().GetTerminalWidth());
362         return false;
363       }
364 
365       if (command.GetArgumentCount() == 1) {
366         if (command[0].ref().getAsInteger(0, frame_idx)) {
367           result.AppendErrorWithFormat("invalid frame index argument '%s'.",
368                                        command[0].c_str());
369           return false;
370         }
371       } else if (command.GetArgumentCount() == 0) {
372         frame_idx = thread->GetSelectedFrameIndex(SelectMostRelevantFrame);
373         if (frame_idx == UINT32_MAX) {
374           frame_idx = 0;
375         }
376       }
377     }
378 
379     bool success = thread->SetSelectedFrameByIndexNoisily(
380         frame_idx, result.GetOutputStream());
381     if (success) {
382       m_exe_ctx.SetFrameSP(thread->GetSelectedFrame(SelectMostRelevantFrame));
383       result.SetStatus(eReturnStatusSuccessFinishResult);
384     } else {
385       result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
386                                    frame_idx);
387     }
388 
389     return result.Succeeded();
390   }
391 
392   CommandOptions m_options;
393 };
394 
395 #pragma mark CommandObjectFrameVariable
396 // List images with associated information
397 class CommandObjectFrameVariable : public CommandObjectParsed {
398 public:
399   CommandObjectFrameVariable(CommandInterpreter &interpreter)
400       : CommandObjectParsed(
401             interpreter, "frame variable",
402             "Show variables for the current stack frame. Defaults to all "
403             "arguments and local variables in scope. Names of argument, "
404             "local, file static and file global variables can be specified.",
405             nullptr,
406             eCommandRequiresFrame | eCommandTryTargetAPILock |
407                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
408                 eCommandRequiresProcess),
409         m_option_variable(
410             true), // Include the frame specific options by passing "true"
411         m_option_format(eFormatDefault) {
412     SetHelpLong(R"(
413 Children of aggregate variables can be specified such as 'var->child.x'.  In
414 'frame variable', the operators -> and [] do not invoke operator overloads if
415 they exist, but directly access the specified element.  If you want to trigger
416 operator overloads use the expression command to print the variable instead.
417 
418 It is worth noting that except for overloaded operators, when printing local
419 variables 'expr local_var' and 'frame var local_var' produce the same results.
420 However, 'frame variable' is more efficient, since it uses debug information and
421 memory reads directly, rather than parsing and evaluating an expression, which
422 may even involve JITing and running code in the target program.)");
423 
424     CommandArgumentEntry arg;
425     CommandArgumentData var_name_arg;
426 
427     // Define the first (and only) variant of this arg.
428     var_name_arg.arg_type = eArgTypeVarName;
429     var_name_arg.arg_repetition = eArgRepeatStar;
430 
431     // There is only one variant this argument could be; put it into the
432     // argument entry.
433     arg.push_back(var_name_arg);
434 
435     // Push the data for the first argument into the m_arguments vector.
436     m_arguments.push_back(arg);
437 
438     m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
439     m_option_group.Append(&m_option_format,
440                           OptionGroupFormat::OPTION_GROUP_FORMAT |
441                               OptionGroupFormat::OPTION_GROUP_GDB_FMT,
442                           LLDB_OPT_SET_1);
443     m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
444     m_option_group.Finalize();
445   }
446 
447   ~CommandObjectFrameVariable() override = default;
448 
449   Options *GetOptions() override { return &m_option_group; }
450 
451   void
452   HandleArgumentCompletion(CompletionRequest &request,
453                            OptionElementVector &opt_element_vector) override {
454     // Arguments are the standard source file completer.
455     lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
456         GetCommandInterpreter(), lldb::eVariablePathCompletion, request,
457         nullptr);
458   }
459 
460 protected:
461   llvm::StringRef GetScopeString(VariableSP var_sp) {
462     if (!var_sp)
463       return llvm::StringRef();
464 
465     switch (var_sp->GetScope()) {
466     case eValueTypeVariableGlobal:
467       return "GLOBAL: ";
468     case eValueTypeVariableStatic:
469       return "STATIC: ";
470     case eValueTypeVariableArgument:
471       return "ARG: ";
472     case eValueTypeVariableLocal:
473       return "LOCAL: ";
474     case eValueTypeVariableThreadLocal:
475       return "THREAD: ";
476     default:
477       break;
478     }
479 
480     return llvm::StringRef();
481   }
482 
483   /// Returns true if `scope` matches any of the options in `m_option_variable`.
484   bool ScopeRequested(lldb::ValueType scope) {
485     switch (scope) {
486     case eValueTypeVariableGlobal:
487     case eValueTypeVariableStatic:
488       return m_option_variable.show_globals;
489     case eValueTypeVariableArgument:
490       return m_option_variable.show_args;
491     case eValueTypeVariableLocal:
492       return m_option_variable.show_locals;
493     case eValueTypeInvalid:
494     case eValueTypeRegister:
495     case eValueTypeRegisterSet:
496     case eValueTypeConstResult:
497     case eValueTypeVariableThreadLocal:
498       return false;
499     }
500   }
501 
502   bool DoExecute(Args &command, CommandReturnObject &result) override {
503     // No need to check "frame" for validity as eCommandRequiresFrame ensures
504     // it is valid
505     StackFrame *frame = m_exe_ctx.GetFramePtr();
506 
507     Stream &s = result.GetOutputStream();
508 
509     // Be careful about the stack frame, if any summary formatter runs code, it
510     // might clear the StackFrameList for the thread.  So hold onto a shared
511     // pointer to the frame so it stays alive.
512 
513     Status error;
514     VariableList *variable_list =
515         frame->GetVariableList(m_option_variable.show_globals, &error);
516 
517     if (error.Fail() && (!variable_list || variable_list->GetSize() == 0)) {
518       result.AppendError(error.AsCString());
519 
520     }
521     VariableSP var_sp;
522     ValueObjectSP valobj_sp;
523 
524     TypeSummaryImplSP summary_format_sp;
525     if (!m_option_variable.summary.IsCurrentValueEmpty())
526       DataVisualization::NamedSummaryFormats::GetSummaryFormat(
527           ConstString(m_option_variable.summary.GetCurrentValue()),
528           summary_format_sp);
529     else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
530       summary_format_sp = std::make_shared<StringSummaryFormat>(
531           TypeSummaryImpl::Flags(),
532           m_option_variable.summary_string.GetCurrentValue());
533 
534     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
535         eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault,
536         summary_format_sp));
537 
538     const SymbolContext &sym_ctx =
539         frame->GetSymbolContext(eSymbolContextFunction);
540     if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
541       m_option_variable.show_globals = true;
542 
543     if (variable_list) {
544       const Format format = m_option_format.GetFormat();
545       options.SetFormat(format);
546 
547       if (!command.empty()) {
548         VariableList regex_var_list;
549 
550         // If we have any args to the variable command, we will make variable
551         // objects from them...
552         for (auto &entry : command) {
553           if (m_option_variable.use_regex) {
554             const size_t regex_start_index = regex_var_list.GetSize();
555             llvm::StringRef name_str = entry.ref();
556             RegularExpression regex(name_str);
557             if (regex.IsValid()) {
558               size_t num_matches = 0;
559               const size_t num_new_regex_vars =
560                   variable_list->AppendVariablesIfUnique(regex, regex_var_list,
561                                                          num_matches);
562               if (num_new_regex_vars > 0) {
563                 for (size_t regex_idx = regex_start_index,
564                             end_index = regex_var_list.GetSize();
565                      regex_idx < end_index; ++regex_idx) {
566                   var_sp = regex_var_list.GetVariableAtIndex(regex_idx);
567                   if (var_sp) {
568                     valobj_sp = frame->GetValueObjectForFrameVariable(
569                         var_sp, m_varobj_options.use_dynamic);
570                     if (valobj_sp) {
571                       std::string scope_string;
572                       if (m_option_variable.show_scope)
573                         scope_string = GetScopeString(var_sp).str();
574 
575                       if (!scope_string.empty())
576                         s.PutCString(scope_string);
577 
578                       if (m_option_variable.show_decl &&
579                           var_sp->GetDeclaration().GetFile()) {
580                         bool show_fullpaths = false;
581                         bool show_module = true;
582                         if (var_sp->DumpDeclaration(&s, show_fullpaths,
583                                                     show_module))
584                           s.PutCString(": ");
585                       }
586                       valobj_sp->Dump(result.GetOutputStream(), options);
587                     }
588                   }
589                 }
590               } else if (num_matches == 0) {
591                 result.AppendErrorWithFormat(
592                     "no variables matched the regular expression '%s'.",
593                     entry.c_str());
594               }
595             } else {
596               if (llvm::Error err = regex.GetError())
597                 result.AppendError(llvm::toString(std::move(err)));
598               else
599                 result.AppendErrorWithFormat(
600                     "unknown regex error when compiling '%s'", entry.c_str());
601             }
602           } else // No regex, either exact variable names or variable
603                  // expressions.
604           {
605             Status error;
606             uint32_t expr_path_options =
607                 StackFrame::eExpressionPathOptionCheckPtrVsMember |
608                 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
609                 StackFrame::eExpressionPathOptionsInspectAnonymousUnions;
610             lldb::VariableSP var_sp;
611             valobj_sp = frame->GetValueForVariableExpressionPath(
612                 entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
613                 var_sp, error);
614             if (valobj_sp) {
615               std::string scope_string;
616               if (m_option_variable.show_scope)
617                 scope_string = GetScopeString(var_sp).str();
618 
619               if (!scope_string.empty())
620                 s.PutCString(scope_string);
621               if (m_option_variable.show_decl && var_sp &&
622                   var_sp->GetDeclaration().GetFile()) {
623                 var_sp->GetDeclaration().DumpStopContext(&s, false);
624                 s.PutCString(": ");
625               }
626 
627               options.SetFormat(format);
628               options.SetVariableFormatDisplayLanguage(
629                   valobj_sp->GetPreferredDisplayLanguage());
630 
631               Stream &output_stream = result.GetOutputStream();
632               options.SetRootValueObjectName(
633                   valobj_sp->GetParent() ? entry.c_str() : nullptr);
634               valobj_sp->Dump(output_stream, options);
635             } else {
636               if (auto error_cstr = error.AsCString(nullptr))
637                 result.AppendError(error_cstr);
638               else
639                 result.AppendErrorWithFormat(
640                     "unable to find any variable expression path that matches "
641                     "'%s'.",
642                     entry.c_str());
643             }
644           }
645         }
646       } else // No command arg specified.  Use variable_list, instead.
647       {
648         const size_t num_variables = variable_list->GetSize();
649         if (num_variables > 0) {
650           for (size_t i = 0; i < num_variables; i++) {
651             var_sp = variable_list->GetVariableAtIndex(i);
652             if (!ScopeRequested(var_sp->GetScope()))
653                 continue;
654             std::string scope_string;
655             if (m_option_variable.show_scope)
656               scope_string = GetScopeString(var_sp).str();
657 
658             // Use the variable object code to make sure we are using the same
659             // APIs as the public API will be using...
660             valobj_sp = frame->GetValueObjectForFrameVariable(
661                 var_sp, m_varobj_options.use_dynamic);
662             if (valobj_sp) {
663               // When dumping all variables, don't print any variables that are
664               // not in scope to avoid extra unneeded output
665               if (valobj_sp->IsInScope()) {
666                 if (!valobj_sp->GetTargetSP()
667                          ->GetDisplayRuntimeSupportValues() &&
668                     valobj_sp->IsRuntimeSupportValue())
669                   continue;
670 
671                 if (!scope_string.empty())
672                   s.PutCString(scope_string);
673 
674                 if (m_option_variable.show_decl &&
675                     var_sp->GetDeclaration().GetFile()) {
676                   var_sp->GetDeclaration().DumpStopContext(&s, false);
677                   s.PutCString(": ");
678                 }
679 
680                 options.SetFormat(format);
681                 options.SetVariableFormatDisplayLanguage(
682                     valobj_sp->GetPreferredDisplayLanguage());
683                 options.SetRootValueObjectName(
684                     var_sp ? var_sp->GetName().AsCString() : nullptr);
685                 valobj_sp->Dump(result.GetOutputStream(), options);
686               }
687             }
688           }
689         }
690       }
691       if (result.GetStatus() != eReturnStatusFailed)
692         result.SetStatus(eReturnStatusSuccessFinishResult);
693     }
694 
695     if (m_option_variable.show_recognized_args) {
696       auto recognized_frame = frame->GetRecognizedFrame();
697       if (recognized_frame) {
698         ValueObjectListSP recognized_arg_list =
699             recognized_frame->GetRecognizedArguments();
700         if (recognized_arg_list) {
701           for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
702             options.SetFormat(m_option_format.GetFormat());
703             options.SetVariableFormatDisplayLanguage(
704                 rec_value_sp->GetPreferredDisplayLanguage());
705             options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
706             rec_value_sp->Dump(result.GetOutputStream(), options);
707           }
708         }
709       }
710     }
711 
712     m_interpreter.PrintWarningsIfNecessary(result.GetOutputStream(),
713                                            m_cmd_name);
714 
715     // Increment statistics.
716     bool res = result.Succeeded();
717     TargetStats &target_stats = GetSelectedOrDummyTarget().GetStatistics();
718     if (res)
719       target_stats.GetFrameVariableStats().NotifySuccess();
720     else
721       target_stats.GetFrameVariableStats().NotifyFailure();
722     return res;
723   }
724 
725   OptionGroupOptions m_option_group;
726   OptionGroupVariable m_option_variable;
727   OptionGroupFormat m_option_format;
728   OptionGroupValueObjectDisplay m_varobj_options;
729 };
730 
731 #pragma mark CommandObjectFrameRecognizer
732 
733 #define LLDB_OPTIONS_frame_recognizer_add
734 #include "CommandOptions.inc"
735 
736 class CommandObjectFrameRecognizerAdd : public CommandObjectParsed {
737 private:
738   class CommandOptions : public Options {
739   public:
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   bool DoExecute(Args &command, CommandReturnObject &result) override;
805 
806 public:
807   CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)
808       : CommandObjectParsed(interpreter, "frame recognizer add",
809                             "Add a new frame recognizer.", nullptr) {
810     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 bool 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 false;
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 false;
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 false;
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 false;
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   return result.Succeeded();
918 }
919 
920 class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
921 public:
922   CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
923       : CommandObjectParsed(interpreter, "frame recognizer clear",
924                             "Delete all frame recognizers.", nullptr) {}
925 
926   ~CommandObjectFrameRecognizerClear() override = default;
927 
928 protected:
929   bool DoExecute(Args &command, CommandReturnObject &result) override {
930     GetSelectedOrDummyTarget()
931         .GetFrameRecognizerManager()
932         .RemoveAllRecognizers();
933     result.SetStatus(eReturnStatusSuccessFinishResult);
934     return result.Succeeded();
935   }
936 };
937 
938 class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
939 public:
940   CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
941       : CommandObjectParsed(interpreter, "frame recognizer delete",
942                             "Delete an existing frame recognizer by id.",
943                             nullptr) {
944     CommandArgumentData thread_arg{eArgTypeRecognizerID, eArgRepeatPlain};
945     m_arguments.push_back({thread_arg});
946   }
947 
948   ~CommandObjectFrameRecognizerDelete() override = default;
949 
950   void
951   HandleArgumentCompletion(CompletionRequest &request,
952                            OptionElementVector &opt_element_vector) override {
953     if (request.GetCursorIndex() != 0)
954       return;
955 
956     GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach(
957         [&request](uint32_t rid, std::string rname, std::string module,
958                    llvm::ArrayRef<lldb_private::ConstString> symbols,
959                    bool regexp) {
960           StreamString strm;
961           if (rname.empty())
962             rname = "(internal)";
963 
964           strm << rname;
965           if (!module.empty())
966             strm << ", module " << module;
967           if (!symbols.empty())
968             for (auto &symbol : symbols)
969               strm << ", symbol " << symbol;
970           if (regexp)
971             strm << " (regexp)";
972 
973           request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString());
974         });
975   }
976 
977 protected:
978   bool DoExecute(Args &command, CommandReturnObject &result) override {
979     if (command.GetArgumentCount() == 0) {
980       if (!m_interpreter.Confirm(
981               "About to delete all frame recognizers, do you want to do that?",
982               true)) {
983         result.AppendMessage("Operation cancelled...");
984         return false;
985       }
986 
987       GetSelectedOrDummyTarget()
988           .GetFrameRecognizerManager()
989           .RemoveAllRecognizers();
990       result.SetStatus(eReturnStatusSuccessFinishResult);
991       return result.Succeeded();
992     }
993 
994     if (command.GetArgumentCount() != 1) {
995       result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
996                                    m_cmd_name.c_str());
997       return false;
998     }
999 
1000     uint32_t recognizer_id;
1001     if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) {
1002       result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
1003                                    command.GetArgumentAtIndex(0));
1004       return false;
1005     }
1006 
1007     if (!GetSelectedOrDummyTarget()
1008              .GetFrameRecognizerManager()
1009              .RemoveRecognizerWithID(recognizer_id)) {
1010       result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
1011                                    command.GetArgumentAtIndex(0));
1012       return false;
1013     }
1014     result.SetStatus(eReturnStatusSuccessFinishResult);
1015     return result.Succeeded();
1016   }
1017 };
1018 
1019 class CommandObjectFrameRecognizerList : public CommandObjectParsed {
1020 public:
1021   CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
1022       : CommandObjectParsed(interpreter, "frame recognizer list",
1023                             "Show a list of active frame recognizers.",
1024                             nullptr) {}
1025 
1026   ~CommandObjectFrameRecognizerList() override = default;
1027 
1028 protected:
1029   bool DoExecute(Args &command, CommandReturnObject &result) override {
1030     bool any_printed = false;
1031     GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach(
1032         [&result, &any_printed](
1033             uint32_t recognizer_id, std::string name, std::string module,
1034             llvm::ArrayRef<ConstString> symbols, bool regexp) {
1035           Stream &stream = result.GetOutputStream();
1036 
1037           if (name.empty())
1038             name = "(internal)";
1039 
1040           stream << std::to_string(recognizer_id) << ": " << name;
1041           if (!module.empty())
1042             stream << ", module " << module;
1043           if (!symbols.empty())
1044             for (auto &symbol : symbols)
1045               stream << ", symbol " << symbol;
1046           if (regexp)
1047             stream << " (regexp)";
1048 
1049           stream.EOL();
1050           stream.Flush();
1051 
1052           any_printed = true;
1053         });
1054 
1055     if (any_printed)
1056       result.SetStatus(eReturnStatusSuccessFinishResult);
1057     else {
1058       result.GetOutputStream().PutCString("no matching results found.\n");
1059       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1060     }
1061     return result.Succeeded();
1062   }
1063 };
1064 
1065 class CommandObjectFrameRecognizerInfo : public CommandObjectParsed {
1066 public:
1067   CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
1068       : CommandObjectParsed(
1069             interpreter, "frame recognizer info",
1070             "Show which frame recognizer is applied a stack frame (if any).",
1071             nullptr) {
1072     CommandArgumentEntry arg;
1073     CommandArgumentData index_arg;
1074 
1075     // Define the first (and only) variant of this arg.
1076     index_arg.arg_type = eArgTypeFrameIndex;
1077     index_arg.arg_repetition = eArgRepeatPlain;
1078 
1079     // There is only one variant this argument could be; put it into the
1080     // argument entry.
1081     arg.push_back(index_arg);
1082 
1083     // Push the data for the first argument into the m_arguments vector.
1084     m_arguments.push_back(arg);
1085   }
1086 
1087   ~CommandObjectFrameRecognizerInfo() override = default;
1088 
1089 protected:
1090   bool DoExecute(Args &command, CommandReturnObject &result) override {
1091     const char *frame_index_str = command.GetArgumentAtIndex(0);
1092     uint32_t frame_index;
1093     if (!llvm::to_integer(frame_index_str, frame_index)) {
1094       result.AppendErrorWithFormat("'%s' is not a valid frame index.",
1095                                    frame_index_str);
1096       return false;
1097     }
1098 
1099     Process *process = m_exe_ctx.GetProcessPtr();
1100     if (process == nullptr) {
1101       result.AppendError("no process");
1102       return false;
1103     }
1104     Thread *thread = m_exe_ctx.GetThreadPtr();
1105     if (thread == nullptr) {
1106       result.AppendError("no thread");
1107       return false;
1108     }
1109     if (command.GetArgumentCount() != 1) {
1110       result.AppendErrorWithFormat(
1111           "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
1112       return false;
1113     }
1114 
1115     StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
1116     if (!frame_sp) {
1117       result.AppendErrorWithFormat("no frame with index %u", frame_index);
1118       return false;
1119     }
1120 
1121     auto recognizer = GetSelectedOrDummyTarget()
1122                           .GetFrameRecognizerManager()
1123                           .GetRecognizerForFrame(frame_sp);
1124 
1125     Stream &output_stream = result.GetOutputStream();
1126     output_stream.Printf("frame %d ", frame_index);
1127     if (recognizer) {
1128       output_stream << "is recognized by ";
1129       output_stream << recognizer->GetName();
1130     } else {
1131       output_stream << "not recognized by any recognizer";
1132     }
1133     output_stream.EOL();
1134     result.SetStatus(eReturnStatusSuccessFinishResult);
1135     return result.Succeeded();
1136   }
1137 };
1138 
1139 class CommandObjectFrameRecognizer : public CommandObjectMultiword {
1140 public:
1141   CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
1142       : CommandObjectMultiword(
1143             interpreter, "frame recognizer",
1144             "Commands for editing and viewing frame recognizers.",
1145             "frame recognizer [<sub-command-options>] ") {
1146     LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd(
1147                               interpreter)));
1148     LoadSubCommand(
1149         "clear",
1150         CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter)));
1151     LoadSubCommand(
1152         "delete",
1153         CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter)));
1154     LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList(
1155                                interpreter)));
1156     LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo(
1157                                interpreter)));
1158   }
1159 
1160   ~CommandObjectFrameRecognizer() override = default;
1161 };
1162 
1163 #pragma mark CommandObjectMultiwordFrame
1164 
1165 // CommandObjectMultiwordFrame
1166 
1167 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
1168     CommandInterpreter &interpreter)
1169     : CommandObjectMultiword(interpreter, "frame",
1170                              "Commands for selecting and "
1171                              "examing the current "
1172                              "thread's stack frames.",
1173                              "frame <subcommand> [<subcommand-options>]") {
1174   LoadSubCommand("diagnose",
1175                  CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
1176   LoadSubCommand("info",
1177                  CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1178   LoadSubCommand("select",
1179                  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1180   LoadSubCommand("variable",
1181                  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
1182 #if LLDB_ENABLE_PYTHON
1183   LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer(
1184                                    interpreter)));
1185 #endif
1186 }
1187 
1188 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
1189