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