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