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