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_function = 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_function = "";
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::string m_function;
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_function.empty()) {
858     result.AppendErrorWithFormat("%s needs a function name (-n argument).\n",
859                                  m_cmd_name.c_str());
860     result.SetStatus(eReturnStatusFailed);
861     return false;
862   }
863 
864   ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
865 
866   if (interpreter &&
867       !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
868     result.AppendWarning("The provided class does not exist - please define it "
869                          "before attempting to use this frame recognizer");
870   }
871 
872   StackFrameRecognizerSP recognizer_sp =
873       StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(
874           interpreter, m_options.m_class_name.c_str()));
875   if (m_options.m_regex) {
876     auto module =
877         RegularExpressionSP(new RegularExpression(m_options.m_module));
878     auto func =
879         RegularExpressionSP(new RegularExpression(m_options.m_function));
880     StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
881   } else {
882     auto module = ConstString(m_options.m_module);
883     auto func = ConstString(m_options.m_function);
884     StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func, {});
885   }
886 #endif
887 
888   result.SetStatus(eReturnStatusSuccessFinishNoResult);
889   return result.Succeeded();
890 }
891 
892 class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
893 public:
894   CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
895       : CommandObjectParsed(interpreter, "frame recognizer clear",
896                             "Delete all frame recognizers.", nullptr) {}
897 
898   ~CommandObjectFrameRecognizerClear() override = default;
899 
900 protected:
901   bool DoExecute(Args &command, CommandReturnObject &result) override {
902     StackFrameRecognizerManager::RemoveAllRecognizers();
903     result.SetStatus(eReturnStatusSuccessFinishResult);
904     return result.Succeeded();
905   }
906 };
907 
908 class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
909 public:
910   CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
911       : CommandObjectParsed(interpreter, "frame recognizer delete",
912                             "Delete an existing frame recognizer.", nullptr) {}
913 
914   ~CommandObjectFrameRecognizerDelete() override = default;
915 
916 protected:
917   bool DoExecute(Args &command, CommandReturnObject &result) override {
918     if (command.GetArgumentCount() == 0) {
919       if (!m_interpreter.Confirm(
920               "About to delete all frame recognizers, do you want to do that?",
921               true)) {
922         result.AppendMessage("Operation cancelled...");
923         result.SetStatus(eReturnStatusFailed);
924         return false;
925       }
926 
927       StackFrameRecognizerManager::RemoveAllRecognizers();
928       result.SetStatus(eReturnStatusSuccessFinishResult);
929       return result.Succeeded();
930     }
931 
932     if (command.GetArgumentCount() != 1) {
933       result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
934                                    m_cmd_name.c_str());
935       result.SetStatus(eReturnStatusFailed);
936       return false;
937     }
938 
939     uint32_t recognizer_id =
940         StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0);
941 
942     StackFrameRecognizerManager::RemoveRecognizerWithID(recognizer_id);
943     result.SetStatus(eReturnStatusSuccessFinishResult);
944     return result.Succeeded();
945   }
946 };
947 
948 class CommandObjectFrameRecognizerList : public CommandObjectParsed {
949 public:
950   CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
951       : CommandObjectParsed(interpreter, "frame recognizer list",
952                             "Show a list of active frame recognizers.",
953                             nullptr) {}
954 
955   ~CommandObjectFrameRecognizerList() override = default;
956 
957 protected:
958   bool DoExecute(Args &command, CommandReturnObject &result) override {
959     bool any_printed = false;
960     StackFrameRecognizerManager::ForEach(
961         [&result, &any_printed](uint32_t recognizer_id, std::string name,
962                                 std::string module, std::string symbol,
963                                 std::string alternate_symbol, bool regexp) {
964           Stream &stream = result.GetOutputStream();
965 
966           if (name.empty())
967             name = "(internal)";
968 
969           stream << std::to_string(recognizer_id) << ": " << name;
970           if (!module.empty())
971             stream << ", module " << module;
972           if (!symbol.empty())
973             stream << ", function " << symbol;
974           if (!alternate_symbol.empty())
975             stream << ", symbol " << alternate_symbol;
976           if (regexp)
977             stream << " (regexp)";
978 
979           stream.EOL();
980           stream.Flush();
981 
982           any_printed = true;
983         });
984 
985     if (any_printed)
986       result.SetStatus(eReturnStatusSuccessFinishResult);
987     else {
988       result.GetOutputStream().PutCString("no matching results found.\n");
989       result.SetStatus(eReturnStatusSuccessFinishNoResult);
990     }
991     return result.Succeeded();
992   }
993 };
994 
995 class CommandObjectFrameRecognizerInfo : public CommandObjectParsed {
996 public:
997   CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
998       : CommandObjectParsed(
999             interpreter, "frame recognizer info",
1000             "Show which frame recognizer is applied a stack frame (if any).",
1001             nullptr) {
1002     CommandArgumentEntry arg;
1003     CommandArgumentData index_arg;
1004 
1005     // Define the first (and only) variant of this arg.
1006     index_arg.arg_type = eArgTypeFrameIndex;
1007     index_arg.arg_repetition = eArgRepeatPlain;
1008 
1009     // There is only one variant this argument could be; put it into the
1010     // argument entry.
1011     arg.push_back(index_arg);
1012 
1013     // Push the data for the first argument into the m_arguments vector.
1014     m_arguments.push_back(arg);
1015   }
1016 
1017   ~CommandObjectFrameRecognizerInfo() override = default;
1018 
1019 protected:
1020   bool DoExecute(Args &command, CommandReturnObject &result) override {
1021     Process *process = m_exe_ctx.GetProcessPtr();
1022     if (process == nullptr) {
1023       result.AppendError("no process");
1024       result.SetStatus(eReturnStatusFailed);
1025       return false;
1026     }
1027     Thread *thread = m_exe_ctx.GetThreadPtr();
1028     if (thread == nullptr) {
1029       result.AppendError("no thread");
1030       result.SetStatus(eReturnStatusFailed);
1031       return false;
1032     }
1033     if (command.GetArgumentCount() != 1) {
1034       result.AppendErrorWithFormat(
1035           "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
1036       result.SetStatus(eReturnStatusFailed);
1037       return false;
1038     }
1039 
1040     uint32_t frame_index =
1041         StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0);
1042     StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
1043     if (!frame_sp) {
1044       result.AppendErrorWithFormat("no frame with index %u", frame_index);
1045       result.SetStatus(eReturnStatusFailed);
1046       return false;
1047     }
1048 
1049     auto recognizer =
1050         StackFrameRecognizerManager::GetRecognizerForFrame(frame_sp);
1051 
1052     Stream &output_stream = result.GetOutputStream();
1053     output_stream.Printf("frame %d ", frame_index);
1054     if (recognizer) {
1055       output_stream << "is recognized by ";
1056       output_stream << recognizer->GetName();
1057     } else {
1058       output_stream << "not recognized by any recognizer";
1059     }
1060     output_stream.EOL();
1061     result.SetStatus(eReturnStatusSuccessFinishResult);
1062     return result.Succeeded();
1063   }
1064 };
1065 
1066 class CommandObjectFrameRecognizer : public CommandObjectMultiword {
1067 public:
1068   CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
1069       : CommandObjectMultiword(
1070             interpreter, "frame recognizer",
1071             "Commands for editing and viewing frame recognizers.",
1072             "frame recognizer [<sub-command-options>] ") {
1073     LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd(
1074                               interpreter)));
1075     LoadSubCommand(
1076         "clear",
1077         CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter)));
1078     LoadSubCommand(
1079         "delete",
1080         CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter)));
1081     LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList(
1082                                interpreter)));
1083     LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo(
1084                                interpreter)));
1085   }
1086 
1087   ~CommandObjectFrameRecognizer() override = default;
1088 };
1089 
1090 #pragma mark CommandObjectMultiwordFrame
1091 
1092 // CommandObjectMultiwordFrame
1093 
1094 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
1095     CommandInterpreter &interpreter)
1096     : CommandObjectMultiword(interpreter, "frame",
1097                              "Commands for selecting and "
1098                              "examing the current "
1099                              "thread's stack frames.",
1100                              "frame <subcommand> [<subcommand-options>]") {
1101   LoadSubCommand("diagnose",
1102                  CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
1103   LoadSubCommand("info",
1104                  CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1105   LoadSubCommand("select",
1106                  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1107   LoadSubCommand("variable",
1108                  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
1109 #if LLDB_ENABLE_PYTHON
1110   LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer(
1111                                    interpreter)));
1112 #endif
1113 }
1114 
1115 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
1116