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