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