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