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