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