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