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