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