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