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