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