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