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