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