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         error.SetErrorStringWithFormat("invalid short option character '%c'",
96                                        short_option);
97         break;
98       }
99 
100       return error;
101     }
102 
103     void OptionParsingStarting(ExecutionContext *execution_context) override {
104       address.reset();
105       reg.reset();
106       offset.reset();
107     }
108 
109     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
110       return llvm::makeArrayRef(g_frame_diag_options);
111     }
112 
113     // Options.
114     llvm::Optional<lldb::addr_t> address;
115     llvm::Optional<ConstString> reg;
116     llvm::Optional<int64_t> offset;
117   };
118 
119   CommandObjectFrameDiagnose(CommandInterpreter &interpreter)
120       : CommandObjectParsed(interpreter, "frame diagnose",
121                             "Try to determine what path path the current stop "
122                             "location used to get to a register or address",
123                             nullptr,
124                             eCommandRequiresThread | eCommandTryTargetAPILock |
125                                 eCommandProcessMustBeLaunched |
126                                 eCommandProcessMustBePaused),
127         m_options() {
128     CommandArgumentEntry arg;
129     CommandArgumentData index_arg;
130 
131     // Define the first (and only) variant of this arg.
132     index_arg.arg_type = eArgTypeFrameIndex;
133     index_arg.arg_repetition = eArgRepeatOptional;
134 
135     // There is only one variant this argument could be; put it into the
136     // argument entry.
137     arg.push_back(index_arg);
138 
139     // Push the data for the first argument into the m_arguments vector.
140     m_arguments.push_back(arg);
141   }
142 
143   ~CommandObjectFrameDiagnose() override = default;
144 
145   Options *GetOptions() override { return &m_options; }
146 
147 protected:
148   bool DoExecute(Args &command, CommandReturnObject &result) override {
149     Thread *thread = m_exe_ctx.GetThreadPtr();
150     StackFrameSP frame_sp = thread->GetSelectedFrame();
151 
152     ValueObjectSP valobj_sp;
153 
154     if (m_options.address.hasValue()) {
155       if (m_options.reg.hasValue() || m_options.offset.hasValue()) {
156         result.AppendError(
157             "`frame diagnose --address` is incompatible with other arguments.");
158         result.SetStatus(eReturnStatusFailed);
159         return false;
160       }
161       valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue());
162     } else if (m_options.reg.hasValue()) {
163       valobj_sp = frame_sp->GuessValueForRegisterAndOffset(
164           m_options.reg.getValue(), m_options.offset.getValueOr(0));
165     } else {
166       StopInfoSP stop_info_sp = thread->GetStopInfo();
167       if (!stop_info_sp) {
168         result.AppendError("No arguments provided, and no stop info.");
169         result.SetStatus(eReturnStatusFailed);
170         return false;
171       }
172 
173       valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
174     }
175 
176     if (!valobj_sp) {
177       result.AppendError("No diagnosis available.");
178       result.SetStatus(eReturnStatusFailed);
179       return false;
180     }
181 
182 
183     DumpValueObjectOptions::DeclPrintingHelper helper = [&valobj_sp](
184         ConstString type, ConstString var, const DumpValueObjectOptions &opts,
185         Stream &stream) -> bool {
186       const ValueObject::GetExpressionPathFormat format = ValueObject::
187           GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
188       const bool qualify_cxx_base_classes = false;
189       valobj_sp->GetExpressionPath(stream, qualify_cxx_base_classes, format);
190       stream.PutCString(" =");
191       return true;
192     };
193 
194     DumpValueObjectOptions options;
195     options.SetDeclPrintingHelper(helper);
196     ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(),
197                                options);
198     printer.PrintValueObject();
199 
200     return true;
201   }
202 
203 protected:
204   CommandOptions m_options;
205 };
206 
207 #pragma mark CommandObjectFrameInfo
208 
209 // CommandObjectFrameInfo
210 
211 class CommandObjectFrameInfo : public CommandObjectParsed {
212 public:
213   CommandObjectFrameInfo(CommandInterpreter &interpreter)
214       : CommandObjectParsed(
215             interpreter, "frame info", "List information about the current "
216                                        "stack frame in the current thread.",
217             "frame info",
218             eCommandRequiresFrame | eCommandTryTargetAPILock |
219                 eCommandProcessMustBeLaunched | 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         if (option_arg.getAsInteger(0, relative_frame_offset)) {
253           relative_frame_offset = INT32_MIN;
254           error.SetErrorStringWithFormat("invalid frame offset argument '%s'",
255                                          option_arg.str().c_str());
256         }
257         break;
258 
259       default:
260         error.SetErrorStringWithFormat("invalid short option character '%c'",
261                                        short_option);
262         break;
263       }
264 
265       return error;
266     }
267 
268     void OptionParsingStarting(ExecutionContext *execution_context) override {
269       relative_frame_offset = INT32_MIN;
270     }
271 
272     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
273       return llvm::makeArrayRef(g_frame_select_options);
274     }
275 
276     int32_t relative_frame_offset;
277   };
278 
279   CommandObjectFrameSelect(CommandInterpreter &interpreter)
280       : CommandObjectParsed(
281             interpreter, "frame select", "Select the current stack frame by "
282                                          "index from within the current thread "
283                                          "(see 'thread backtrace'.)",
284             nullptr,
285             eCommandRequiresThread | eCommandTryTargetAPILock |
286                 eCommandProcessMustBeLaunched | 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 != INT32_MIN) {
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) >= -m_options.relative_frame_offset)
322           frame_idx += m_options.relative_frame_offset;
323         else {
324           if (frame_idx == 0) {
325             // If you are already at the bottom of the stack, then just warn
326             // and don't reset the frame.
327             result.AppendError("Already at the bottom of the stack.");
328             result.SetStatus(eReturnStatusFailed);
329             return false;
330           } else
331             frame_idx = 0;
332         }
333       } else if (m_options.relative_frame_offset > 0) {
334         // I don't want "up 20" where "20" takes you past the top of the stack
335         // to produce
336         // an error, but rather to just go to the top.  So I have to count the
337         // stack here...
338         const uint32_t num_frames = thread->GetStackFrameCount();
339         if (static_cast<int32_t>(num_frames - frame_idx) >
340             m_options.relative_frame_offset)
341           frame_idx += m_options.relative_frame_offset;
342         else {
343           if (frame_idx == num_frames - 1) {
344             // If we are already at the top of the stack, just warn and don't
345             // reset the frame.
346             result.AppendError("Already at the top of the stack.");
347             result.SetStatus(eReturnStatusFailed);
348             return false;
349           } else
350             frame_idx = num_frames - 1;
351         }
352       }
353     } else {
354       if (command.GetArgumentCount() > 1) {
355         result.AppendErrorWithFormat(
356             "too many arguments; expected frame-index, saw '%s'.\n",
357             command[0].c_str());
358         m_options.GenerateOptionUsage(
359             result.GetErrorStream(), this,
360             GetCommandInterpreter().GetDebugger().GetTerminalWidth());
361         return false;
362       }
363 
364       if (command.GetArgumentCount() == 1) {
365         if (command[0].ref.getAsInteger(0, frame_idx)) {
366           result.AppendErrorWithFormat("invalid frame index argument '%s'.",
367                                        command[0].c_str());
368           result.SetStatus(eReturnStatusFailed);
369           return false;
370         }
371       } else if (command.GetArgumentCount() == 0) {
372         frame_idx = thread->GetSelectedFrameIndex();
373         if (frame_idx == UINT32_MAX) {
374           frame_idx = 0;
375         }
376       }
377     }
378 
379     bool success = thread->SetSelectedFrameByIndexNoisily(
380         frame_idx, result.GetOutputStream());
381     if (success) {
382       m_exe_ctx.SetFrameSP(thread->GetSelectedFrame());
383       result.SetStatus(eReturnStatusSuccessFinishResult);
384     } else {
385       result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
386                                    frame_idx);
387       result.SetStatus(eReturnStatusFailed);
388     }
389 
390     return result.Succeeded();
391   }
392 
393 protected:
394   CommandOptions m_options;
395 };
396 
397 #pragma mark CommandObjectFrameVariable
398 // List images with associated information
399 class CommandObjectFrameVariable : public CommandObjectParsed {
400 public:
401   CommandObjectFrameVariable(CommandInterpreter &interpreter)
402       : CommandObjectParsed(
403             interpreter, "frame variable",
404             "Show variables for the current stack frame. Defaults to all "
405             "arguments and local variables in scope. Names of argument, "
406             "local, file static and file global variables can be specified. "
407             "Children of aggregate variables can be specified such as "
408             "'var->child.x'.  The -> and [] operators in 'frame variable' do "
409             "not invoke operator overloads if they exist, but directly access "
410             "the specified element.  If you want to trigger operator overloads "
411             "use the expression command to print the variable instead."
412             "\nIt is worth noting that except for overloaded "
413             "operators, when printing local variables 'expr local_var' and "
414             "'frame var local_var' produce the same "
415             "results.  However, 'frame variable' is more efficient, since it "
416             "uses debug information and memory reads directly, rather than "
417             "parsing and evaluating an expression, which may even involve "
418             "JITing and running code in the target program.",
419             nullptr, eCommandRequiresFrame | eCommandTryTargetAPILock |
420                          eCommandProcessMustBeLaunched |
421                          eCommandProcessMustBePaused | eCommandRequiresProcess),
422         m_option_group(),
423         m_option_variable(
424             true), // Include the frame specific options by passing "true"
425         m_option_format(eFormatDefault),
426         m_varobj_options() {
427     CommandArgumentEntry arg;
428     CommandArgumentData var_name_arg;
429 
430     // Define the first (and only) variant of this arg.
431     var_name_arg.arg_type = eArgTypeVarName;
432     var_name_arg.arg_repetition = eArgRepeatStar;
433 
434     // There is only one variant this argument could be; put it into the
435     // argument entry.
436     arg.push_back(var_name_arg);
437 
438     // Push the data for the first argument into the m_arguments vector.
439     m_arguments.push_back(arg);
440 
441     m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
442     m_option_group.Append(&m_option_format,
443                           OptionGroupFormat::OPTION_GROUP_FORMAT |
444                               OptionGroupFormat::OPTION_GROUP_GDB_FMT,
445                           LLDB_OPT_SET_1);
446     m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
447     m_option_group.Finalize();
448   }
449 
450   ~CommandObjectFrameVariable() override = default;
451 
452   Options *GetOptions() override { return &m_option_group; }
453 
454   void
455   HandleArgumentCompletion(CompletionRequest &request,
456                            OptionElementVector &opt_element_vector) override {
457     // Arguments are the standard source file completer.
458     CommandCompletions::InvokeCommonCompletionCallbacks(
459         GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion,
460         request, nullptr);
461   }
462 
463 protected:
464   llvm::StringRef GetScopeString(VariableSP var_sp) {
465     if (!var_sp)
466       return llvm::StringRef::withNullAsEmpty(nullptr);
467 
468     switch (var_sp->GetScope()) {
469     case eValueTypeVariableGlobal:
470       return "GLOBAL: ";
471     case eValueTypeVariableStatic:
472       return "STATIC: ";
473     case eValueTypeVariableArgument:
474       return "ARG: ";
475     case eValueTypeVariableLocal:
476       return "LOCAL: ";
477     case eValueTypeVariableThreadLocal:
478       return "THREAD: ";
479     default:
480       break;
481     }
482 
483     return llvm::StringRef::withNullAsEmpty(nullptr);
484   }
485 
486   bool DoExecute(Args &command, CommandReturnObject &result) override {
487     // No need to check "frame" for validity as eCommandRequiresFrame ensures
488     // it is valid
489     StackFrame *frame = m_exe_ctx.GetFramePtr();
490 
491     Stream &s = result.GetOutputStream();
492 
493     // Be careful about the stack frame, if any summary formatter runs code, it
494     // might clear the StackFrameList for the thread.  So hold onto a shared
495     // pointer to the frame so it stays alive.
496 
497     VariableList *variable_list =
498         frame->GetVariableList(m_option_variable.show_globals);
499 
500     VariableSP var_sp;
501     ValueObjectSP valobj_sp;
502 
503     TypeSummaryImplSP summary_format_sp;
504     if (!m_option_variable.summary.IsCurrentValueEmpty())
505       DataVisualization::NamedSummaryFormats::GetSummaryFormat(
506           ConstString(m_option_variable.summary.GetCurrentValue()),
507           summary_format_sp);
508     else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
509       summary_format_sp = std::make_shared<StringSummaryFormat>(
510           TypeSummaryImpl::Flags(),
511           m_option_variable.summary_string.GetCurrentValue());
512 
513     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
514         eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault,
515         summary_format_sp));
516 
517     const SymbolContext &sym_ctx =
518         frame->GetSymbolContext(eSymbolContextFunction);
519     if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
520       m_option_variable.show_globals = true;
521 
522     if (variable_list) {
523       const Format format = m_option_format.GetFormat();
524       options.SetFormat(format);
525 
526       if (!command.empty()) {
527         VariableList regex_var_list;
528 
529         // If we have any args to the variable command, we will make variable
530         // objects from them...
531         for (auto &entry : command) {
532           if (m_option_variable.use_regex) {
533             const size_t regex_start_index = regex_var_list.GetSize();
534             llvm::StringRef name_str = entry.ref;
535             RegularExpression regex(name_str);
536             if (regex.IsValid()) {
537               size_t num_matches = 0;
538               const size_t num_new_regex_vars =
539                   variable_list->AppendVariablesIfUnique(regex, regex_var_list,
540                                                          num_matches);
541               if (num_new_regex_vars > 0) {
542                 for (size_t regex_idx = regex_start_index,
543                             end_index = regex_var_list.GetSize();
544                      regex_idx < end_index; ++regex_idx) {
545                   var_sp = regex_var_list.GetVariableAtIndex(regex_idx);
546                   if (var_sp) {
547                     valobj_sp = frame->GetValueObjectForFrameVariable(
548                         var_sp, m_varobj_options.use_dynamic);
549                     if (valobj_sp) {
550                       std::string scope_string;
551                       if (m_option_variable.show_scope)
552                         scope_string = GetScopeString(var_sp).str();
553 
554                       if (!scope_string.empty())
555                         s.PutCString(scope_string);
556 
557                       if (m_option_variable.show_decl &&
558                           var_sp->GetDeclaration().GetFile()) {
559                         bool show_fullpaths = false;
560                         bool show_module = true;
561                         if (var_sp->DumpDeclaration(&s, show_fullpaths,
562                                                     show_module))
563                           s.PutCString(": ");
564                       }
565                       valobj_sp->Dump(result.GetOutputStream(), options);
566                     }
567                   }
568                 }
569               } else if (num_matches == 0) {
570                 result.GetErrorStream().Printf("error: no variables matched "
571                                                "the regular expression '%s'.\n",
572                                                entry.c_str());
573               }
574             } else {
575               if (llvm::Error err = regex.GetError())
576                 result.GetErrorStream().Printf(
577                     "error: %s\n", llvm::toString(std::move(err)).c_str());
578               else
579                 result.GetErrorStream().Printf(
580                     "error: unknown regex error when compiling '%s'\n",
581                     entry.c_str());
582             }
583           } else // No regex, either exact variable names or variable
584                  // expressions.
585           {
586             Status error;
587             uint32_t expr_path_options =
588                 StackFrame::eExpressionPathOptionCheckPtrVsMember |
589                 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
590                 StackFrame::eExpressionPathOptionsInspectAnonymousUnions;
591             lldb::VariableSP var_sp;
592             valobj_sp = frame->GetValueForVariableExpressionPath(
593                 entry.ref, m_varobj_options.use_dynamic, expr_path_options,
594                 var_sp, error);
595             if (valobj_sp) {
596               std::string scope_string;
597               if (m_option_variable.show_scope)
598                 scope_string = GetScopeString(var_sp).str();
599 
600               if (!scope_string.empty())
601                 s.PutCString(scope_string);
602               if (m_option_variable.show_decl && var_sp &&
603                   var_sp->GetDeclaration().GetFile()) {
604                 var_sp->GetDeclaration().DumpStopContext(&s, false);
605                 s.PutCString(": ");
606               }
607 
608               options.SetFormat(format);
609               options.SetVariableFormatDisplayLanguage(
610                   valobj_sp->GetPreferredDisplayLanguage());
611 
612               Stream &output_stream = result.GetOutputStream();
613               options.SetRootValueObjectName(
614                   valobj_sp->GetParent() ? entry.c_str() : nullptr);
615               valobj_sp->Dump(output_stream, options);
616             } else {
617               const char *error_cstr = error.AsCString(nullptr);
618               if (error_cstr)
619                 result.GetErrorStream().Printf("error: %s\n", error_cstr);
620               else
621                 result.GetErrorStream().Printf("error: unable to find any "
622                                                "variable expression path that "
623                                                "matches '%s'.\n",
624                                                entry.c_str());
625             }
626           }
627         }
628       } else // No command arg specified.  Use variable_list, instead.
629       {
630         const size_t num_variables = variable_list->GetSize();
631         if (num_variables > 0) {
632           for (size_t i = 0; i < num_variables; i++) {
633             var_sp = variable_list->GetVariableAtIndex(i);
634             switch (var_sp->GetScope()) {
635             case eValueTypeVariableGlobal:
636               if (!m_option_variable.show_globals)
637                 continue;
638               break;
639             case eValueTypeVariableStatic:
640               if (!m_option_variable.show_globals)
641                 continue;
642               break;
643             case eValueTypeVariableArgument:
644               if (!m_option_variable.show_args)
645                 continue;
646               break;
647             case eValueTypeVariableLocal:
648               if (!m_option_variable.show_locals)
649                 continue;
650               break;
651             default:
652               continue;
653               break;
654             }
655             std::string scope_string;
656             if (m_option_variable.show_scope)
657               scope_string = GetScopeString(var_sp).str();
658 
659             // Use the variable object code to make sure we are using the same
660             // APIs as the public API will be using...
661             valobj_sp = frame->GetValueObjectForFrameVariable(
662                 var_sp, m_varobj_options.use_dynamic);
663             if (valobj_sp) {
664               // When dumping all variables, don't print any variables that are
665               // not in scope to avoid extra unneeded output
666               if (valobj_sp->IsInScope()) {
667                 if (!valobj_sp->GetTargetSP()
668                          ->GetDisplayRuntimeSupportValues() &&
669                     valobj_sp->IsRuntimeSupportValue())
670                   continue;
671 
672                 if (!scope_string.empty())
673                   s.PutCString(scope_string);
674 
675                 if (m_option_variable.show_decl &&
676                     var_sp->GetDeclaration().GetFile()) {
677                   var_sp->GetDeclaration().DumpStopContext(&s, false);
678                   s.PutCString(": ");
679                 }
680 
681                 options.SetFormat(format);
682                 options.SetVariableFormatDisplayLanguage(
683                     valobj_sp->GetPreferredDisplayLanguage());
684                 options.SetRootValueObjectName(
685                     var_sp ? var_sp->GetName().AsCString() : nullptr);
686                 valobj_sp->Dump(result.GetOutputStream(), options);
687               }
688             }
689           }
690         }
691       }
692       result.SetStatus(eReturnStatusSuccessFinishResult);
693     }
694 
695     if (m_option_variable.show_recognized_args) {
696       auto recognized_frame = frame->GetRecognizedFrame();
697       if (recognized_frame) {
698         ValueObjectListSP recognized_arg_list =
699             recognized_frame->GetRecognizedArguments();
700         if (recognized_arg_list) {
701           for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
702             options.SetFormat(m_option_format.GetFormat());
703             options.SetVariableFormatDisplayLanguage(
704                 rec_value_sp->GetPreferredDisplayLanguage());
705             options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
706             rec_value_sp->Dump(result.GetOutputStream(), options);
707           }
708         }
709       }
710     }
711 
712     if (m_interpreter.TruncationWarningNecessary()) {
713       result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
714                                       m_cmd_name.c_str());
715       m_interpreter.TruncationWarningGiven();
716     }
717 
718     // Increment statistics.
719     bool res = result.Succeeded();
720     Target *target = GetSelectedOrDummyTarget();
721     if (res)
722       target->IncrementStats(StatisticKind::FrameVarSuccess);
723     else
724       target->IncrementStats(StatisticKind::FrameVarFailure);
725     return res;
726   }
727 
728 protected:
729   OptionGroupOptions m_option_group;
730   OptionGroupVariable m_option_variable;
731   OptionGroupFormat m_option_format;
732   OptionGroupValueObjectDisplay m_varobj_options;
733 };
734 
735 #pragma mark CommandObjectFrameRecognizer
736 
737 #define LLDB_OPTIONS_frame_recognizer_add
738 #include "CommandOptions.inc"
739 
740 class CommandObjectFrameRecognizerAdd : public CommandObjectParsed {
741 private:
742   class CommandOptions : public Options {
743   public:
744     CommandOptions() : Options() {}
745     ~CommandOptions() override = default;
746 
747     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
748                           ExecutionContext *execution_context) override {
749       Status error;
750       const int short_option = m_getopt_table[option_idx].val;
751 
752       switch (short_option) {
753       case 'l':
754         m_class_name = std::string(option_arg);
755         break;
756       case 's':
757         m_module = std::string(option_arg);
758         break;
759       case 'n':
760         m_function = std::string(option_arg);
761         break;
762       case 'x':
763         m_regex = true;
764         break;
765       default:
766         error.SetErrorStringWithFormat("unrecognized option '%c'",
767                                        short_option);
768         break;
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(
882         "The provided class does not exist - please define it "
883         "before attempting to use this frame recognizer");
884   }
885 
886   StackFrameRecognizerSP recognizer_sp =
887       StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(
888           interpreter, m_options.m_class_name.c_str()));
889   if (m_options.m_regex) {
890     auto module =
891         RegularExpressionSP(new RegularExpression(m_options.m_module));
892     auto func =
893         RegularExpressionSP(new RegularExpression(m_options.m_function));
894     StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
895   } else {
896     auto module = ConstString(m_options.m_module);
897     auto func = ConstString(m_options.m_function);
898     StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
899   }
900 #endif
901 
902   result.SetStatus(eReturnStatusSuccessFinishNoResult);
903   return result.Succeeded();
904 }
905 
906 class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
907 public:
908   CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
909       : CommandObjectParsed(interpreter, "frame recognizer clear",
910                            "Delete all frame recognizers.", nullptr) {}
911 
912   ~CommandObjectFrameRecognizerClear() override = default;
913 
914 protected:
915   bool DoExecute(Args &command, CommandReturnObject &result) override {
916     StackFrameRecognizerManager::RemoveAllRecognizers();
917     result.SetStatus(eReturnStatusSuccessFinishResult);
918     return result.Succeeded();
919   }
920 };
921 
922 class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
923  public:
924   CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
925       : CommandObjectParsed(interpreter, "frame recognizer delete",
926                             "Delete an existing frame recognizer.", nullptr) {}
927 
928   ~CommandObjectFrameRecognizerDelete() override = default;
929 
930  protected:
931   bool DoExecute(Args &command, CommandReturnObject &result) override {
932     if (command.GetArgumentCount() == 0) {
933       if (!m_interpreter.Confirm(
934               "About to delete all frame recognizers, do you want to do that?",
935               true)) {
936         result.AppendMessage("Operation cancelled...");
937         result.SetStatus(eReturnStatusFailed);
938         return false;
939       }
940 
941       StackFrameRecognizerManager::RemoveAllRecognizers();
942       result.SetStatus(eReturnStatusSuccessFinishResult);
943       return result.Succeeded();
944     }
945 
946     if (command.GetArgumentCount() != 1) {
947       result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
948                                    m_cmd_name.c_str());
949       result.SetStatus(eReturnStatusFailed);
950       return false;
951     }
952 
953     uint32_t recognizer_id =
954         StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0);
955 
956     StackFrameRecognizerManager::RemoveRecognizerWithID(recognizer_id);
957     result.SetStatus(eReturnStatusSuccessFinishResult);
958     return result.Succeeded();
959   }
960 };
961 
962 class CommandObjectFrameRecognizerList : public CommandObjectParsed {
963  public:
964   CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
965       : CommandObjectParsed(interpreter, "frame recognizer list",
966                             "Show a list of active frame recognizers.",
967                             nullptr) {}
968 
969   ~CommandObjectFrameRecognizerList() override = default;
970 
971  protected:
972   bool DoExecute(Args &command, CommandReturnObject &result) override {
973     bool any_printed = false;
974     StackFrameRecognizerManager::ForEach(
975         [&result, &any_printed](uint32_t recognizer_id, std::string name,
976                                 std::string function, std::string symbol,
977                                 bool regexp) {
978           if (name == "") 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(
1074         "add",
1075         CommandObjectSP(new CommandObjectFrameRecognizerAdd(interpreter)));
1076     LoadSubCommand(
1077         "clear",
1078         CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter)));
1079     LoadSubCommand(
1080         "delete",
1081         CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter)));
1082     LoadSubCommand(
1083         "list",
1084         CommandObjectSP(new CommandObjectFrameRecognizerList(interpreter)));
1085     LoadSubCommand(
1086         "info",
1087         CommandObjectSP(new CommandObjectFrameRecognizerInfo(interpreter)));
1088   }
1089 
1090   ~CommandObjectFrameRecognizer() override = default;
1091 };
1092 
1093 #pragma mark CommandObjectMultiwordFrame
1094 
1095 // CommandObjectMultiwordFrame
1096 
1097 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
1098     CommandInterpreter &interpreter)
1099     : CommandObjectMultiword(interpreter, "frame", "Commands for selecting and "
1100                                                    "examing the current "
1101                                                    "thread's stack frames.",
1102                              "frame <subcommand> [<subcommand-options>]") {
1103   LoadSubCommand("diagnose",
1104                  CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
1105   LoadSubCommand("info",
1106                  CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1107   LoadSubCommand("select",
1108                  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1109   LoadSubCommand("variable",
1110                  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
1111 #ifndef LLDB_DISABLE_PYTHON
1112   LoadSubCommand(
1113       "recognizer",
1114       CommandObjectSP(new CommandObjectFrameRecognizer(interpreter)));
1115 #endif
1116 }
1117 
1118 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
1119