xref: /freebsd-src/contrib/llvm-project/lldb/source/Commands/CommandObjectFrame.cpp (revision 5e801ac66d24704442eba426ed13c3effb8a34e7)
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             "Children of aggregate variables can be specified such as "
399             "'var->child.x'.  The -> and [] operators in 'frame variable' do "
400             "not invoke operator overloads if they exist, but directly access "
401             "the specified element.  If you want to trigger operator overloads "
402             "use the expression command to print the variable instead."
403             "\nIt is worth noting that except for overloaded "
404             "operators, when printing local variables 'expr local_var' and "
405             "'frame var local_var' produce the same "
406             "results.  However, 'frame variable' is more efficient, since it "
407             "uses debug information and memory reads directly, rather than "
408             "parsing and evaluating an expression, which may even involve "
409             "JITing and running code in the target program.",
410             nullptr,
411             eCommandRequiresFrame | eCommandTryTargetAPILock |
412                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
413                 eCommandRequiresProcess),
414         m_option_group(),
415         m_option_variable(
416             true), // Include the frame specific options by passing "true"
417         m_option_format(eFormatDefault), m_varobj_options() {
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.GetErrorStream().Printf("error: no variables matched "
562                                                "the regular expression '%s'.\n",
563                                                entry.c_str());
564               }
565             } else {
566               if (llvm::Error err = regex.GetError())
567                 result.GetErrorStream().Printf(
568                     "error: %s\n", llvm::toString(std::move(err)).c_str());
569               else
570                 result.GetErrorStream().Printf(
571                     "error: unknown regex error when compiling '%s'\n",
572                     entry.c_str());
573             }
574           } else // No regex, either exact variable names or variable
575                  // expressions.
576           {
577             Status error;
578             uint32_t expr_path_options =
579                 StackFrame::eExpressionPathOptionCheckPtrVsMember |
580                 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
581                 StackFrame::eExpressionPathOptionsInspectAnonymousUnions;
582             lldb::VariableSP var_sp;
583             valobj_sp = frame->GetValueForVariableExpressionPath(
584                 entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
585                 var_sp, error);
586             if (valobj_sp) {
587               std::string scope_string;
588               if (m_option_variable.show_scope)
589                 scope_string = GetScopeString(var_sp).str();
590 
591               if (!scope_string.empty())
592                 s.PutCString(scope_string);
593               if (m_option_variable.show_decl && var_sp &&
594                   var_sp->GetDeclaration().GetFile()) {
595                 var_sp->GetDeclaration().DumpStopContext(&s, false);
596                 s.PutCString(": ");
597               }
598 
599               options.SetFormat(format);
600               options.SetVariableFormatDisplayLanguage(
601                   valobj_sp->GetPreferredDisplayLanguage());
602 
603               Stream &output_stream = result.GetOutputStream();
604               options.SetRootValueObjectName(
605                   valobj_sp->GetParent() ? entry.c_str() : nullptr);
606               valobj_sp->Dump(output_stream, options);
607             } else {
608               const char *error_cstr = error.AsCString(nullptr);
609               if (error_cstr)
610                 result.GetErrorStream().Printf("error: %s\n", error_cstr);
611               else
612                 result.GetErrorStream().Printf("error: unable to find any "
613                                                "variable expression path that "
614                                                "matches '%s'.\n",
615                                                entry.c_str());
616             }
617           }
618         }
619       } else // No command arg specified.  Use variable_list, instead.
620       {
621         const size_t num_variables = variable_list->GetSize();
622         if (num_variables > 0) {
623           for (size_t i = 0; i < num_variables; i++) {
624             var_sp = variable_list->GetVariableAtIndex(i);
625             switch (var_sp->GetScope()) {
626             case eValueTypeVariableGlobal:
627               if (!m_option_variable.show_globals)
628                 continue;
629               break;
630             case eValueTypeVariableStatic:
631               if (!m_option_variable.show_globals)
632                 continue;
633               break;
634             case eValueTypeVariableArgument:
635               if (!m_option_variable.show_args)
636                 continue;
637               break;
638             case eValueTypeVariableLocal:
639               if (!m_option_variable.show_locals)
640                 continue;
641               break;
642             default:
643               continue;
644               break;
645             }
646             std::string scope_string;
647             if (m_option_variable.show_scope)
648               scope_string = GetScopeString(var_sp).str();
649 
650             // Use the variable object code to make sure we are using the same
651             // APIs as the public API will be using...
652             valobj_sp = frame->GetValueObjectForFrameVariable(
653                 var_sp, m_varobj_options.use_dynamic);
654             if (valobj_sp) {
655               // When dumping all variables, don't print any variables that are
656               // not in scope to avoid extra unneeded output
657               if (valobj_sp->IsInScope()) {
658                 if (!valobj_sp->GetTargetSP()
659                          ->GetDisplayRuntimeSupportValues() &&
660                     valobj_sp->IsRuntimeSupportValue())
661                   continue;
662 
663                 if (!scope_string.empty())
664                   s.PutCString(scope_string);
665 
666                 if (m_option_variable.show_decl &&
667                     var_sp->GetDeclaration().GetFile()) {
668                   var_sp->GetDeclaration().DumpStopContext(&s, false);
669                   s.PutCString(": ");
670                 }
671 
672                 options.SetFormat(format);
673                 options.SetVariableFormatDisplayLanguage(
674                     valobj_sp->GetPreferredDisplayLanguage());
675                 options.SetRootValueObjectName(
676                     var_sp ? var_sp->GetName().AsCString() : nullptr);
677                 valobj_sp->Dump(result.GetOutputStream(), options);
678               }
679             }
680           }
681         }
682       }
683       result.SetStatus(eReturnStatusSuccessFinishResult);
684     }
685 
686     if (m_option_variable.show_recognized_args) {
687       auto recognized_frame = frame->GetRecognizedFrame();
688       if (recognized_frame) {
689         ValueObjectListSP recognized_arg_list =
690             recognized_frame->GetRecognizedArguments();
691         if (recognized_arg_list) {
692           for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
693             options.SetFormat(m_option_format.GetFormat());
694             options.SetVariableFormatDisplayLanguage(
695                 rec_value_sp->GetPreferredDisplayLanguage());
696             options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
697             rec_value_sp->Dump(result.GetOutputStream(), options);
698           }
699         }
700       }
701     }
702 
703     if (m_interpreter.TruncationWarningNecessary()) {
704       result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
705                                       m_cmd_name.c_str());
706       m_interpreter.TruncationWarningGiven();
707     }
708 
709     // Increment statistics.
710     bool res = result.Succeeded();
711     TargetStats &target_stats = GetSelectedOrDummyTarget().GetStatistics();
712     if (res)
713       target_stats.GetFrameVariableStats().NotifySuccess();
714     else
715       target_stats.GetFrameVariableStats().NotifyFailure();
716     return res;
717   }
718 
719   OptionGroupOptions m_option_group;
720   OptionGroupVariable m_option_variable;
721   OptionGroupFormat m_option_format;
722   OptionGroupValueObjectDisplay m_varobj_options;
723 };
724 
725 #pragma mark CommandObjectFrameRecognizer
726 
727 #define LLDB_OPTIONS_frame_recognizer_add
728 #include "CommandOptions.inc"
729 
730 class CommandObjectFrameRecognizerAdd : public CommandObjectParsed {
731 private:
732   class CommandOptions : public Options {
733   public:
734     CommandOptions() : Options() {}
735     ~CommandOptions() override = default;
736 
737     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
738                           ExecutionContext *execution_context) override {
739       Status error;
740       const int short_option = m_getopt_table[option_idx].val;
741 
742       switch (short_option) {
743       case 'f': {
744         bool value, success;
745         value = OptionArgParser::ToBoolean(option_arg, true, &success);
746         if (success) {
747           m_first_instruction_only = value;
748         } else {
749           error.SetErrorStringWithFormat(
750               "invalid boolean value '%s' passed for -f option",
751               option_arg.str().c_str());
752         }
753       } break;
754       case 'l':
755         m_class_name = std::string(option_arg);
756         break;
757       case 's':
758         m_module = std::string(option_arg);
759         break;
760       case 'n':
761         m_symbols.push_back(std::string(option_arg));
762         break;
763       case 'x':
764         m_regex = true;
765         break;
766       default:
767         llvm_unreachable("Unimplemented option");
768       }
769 
770       return error;
771     }
772 
773     void OptionParsingStarting(ExecutionContext *execution_context) override {
774       m_module = "";
775       m_symbols.clear();
776       m_class_name = "";
777       m_regex = false;
778       m_first_instruction_only = true;
779     }
780 
781     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
782       return llvm::makeArrayRef(g_frame_recognizer_add_options);
783     }
784 
785     // Instance variables to hold the values for command options.
786     std::string m_class_name;
787     std::string m_module;
788     std::vector<std::string> m_symbols;
789     bool m_regex;
790     bool m_first_instruction_only;
791   };
792 
793   CommandOptions m_options;
794 
795   Options *GetOptions() override { return &m_options; }
796 
797 protected:
798   bool DoExecute(Args &command, CommandReturnObject &result) override;
799 
800 public:
801   CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)
802       : CommandObjectParsed(interpreter, "frame recognizer add",
803                             "Add a new frame recognizer.", nullptr),
804         m_options() {
805     SetHelpLong(R"(
806 Frame recognizers allow for retrieving information about special frames based on
807 ABI, arguments or other special properties of that frame, even without source
808 code or debug info. Currently, one use case is to extract function arguments
809 that would otherwise be unaccesible, or augment existing arguments.
810 
811 Adding a custom frame recognizer is possible by implementing a Python class
812 and using the 'frame recognizer add' command. The Python class should have a
813 'get_recognized_arguments' method and it will receive an argument of type
814 lldb.SBFrame representing the current frame that we are trying to recognize.
815 The method should return a (possibly empty) list of lldb.SBValue objects that
816 represent the recognized arguments.
817 
818 An example of a recognizer that retrieves the file descriptor values from libc
819 functions 'read', 'write' and 'close' follows:
820 
821   class LibcFdRecognizer(object):
822     def get_recognized_arguments(self, frame):
823       if frame.name in ["read", "write", "close"]:
824         fd = frame.EvaluateExpression("$arg1").unsigned
825         value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd)
826         return [value]
827       return []
828 
829 The file containing this implementation can be imported via 'command script
830 import' and then we can register this recognizer with 'frame recognizer add'.
831 It's important to restrict the recognizer to the libc library (which is
832 libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
833 in other modules:
834 
835 (lldb) command script import .../fd_recognizer.py
836 (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
837 
838 When the program is stopped at the beginning of the 'read' function in libc, we
839 can view the recognizer arguments in 'frame variable':
840 
841 (lldb) b read
842 (lldb) r
843 Process 1234 stopped
844 * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
845     frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
846 (lldb) frame variable
847 (int) fd = 3
848 
849     )");
850   }
851   ~CommandObjectFrameRecognizerAdd() override = default;
852 };
853 
854 bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command,
855                                                 CommandReturnObject &result) {
856 #if LLDB_ENABLE_PYTHON
857   if (m_options.m_class_name.empty()) {
858     result.AppendErrorWithFormat(
859         "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
860     return false;
861   }
862 
863   if (m_options.m_module.empty()) {
864     result.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
865                                  m_cmd_name.c_str());
866     return false;
867   }
868 
869   if (m_options.m_symbols.empty()) {
870     result.AppendErrorWithFormat(
871         "%s needs at least one symbol name (-n argument).\n",
872         m_cmd_name.c_str());
873     return false;
874   }
875 
876   if (m_options.m_regex && m_options.m_symbols.size() > 1) {
877     result.AppendErrorWithFormat(
878         "%s needs only one symbol regular expression (-n argument).\n",
879         m_cmd_name.c_str());
880     return false;
881   }
882 
883   ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
884 
885   if (interpreter &&
886       !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
887     result.AppendWarning("The provided class does not exist - please define it "
888                          "before attempting to use this frame recognizer");
889   }
890 
891   StackFrameRecognizerSP recognizer_sp =
892       StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(
893           interpreter, m_options.m_class_name.c_str()));
894   if (m_options.m_regex) {
895     auto module =
896         RegularExpressionSP(new RegularExpression(m_options.m_module));
897     auto func =
898         RegularExpressionSP(new RegularExpression(m_options.m_symbols.front()));
899     GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer(
900         recognizer_sp, module, func, m_options.m_first_instruction_only);
901   } else {
902     auto module = ConstString(m_options.m_module);
903     std::vector<ConstString> symbols(m_options.m_symbols.begin(),
904                                      m_options.m_symbols.end());
905     GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer(
906         recognizer_sp, module, symbols, m_options.m_first_instruction_only);
907   }
908 #endif
909 
910   result.SetStatus(eReturnStatusSuccessFinishNoResult);
911   return result.Succeeded();
912 }
913 
914 class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
915 public:
916   CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
917       : CommandObjectParsed(interpreter, "frame recognizer clear",
918                             "Delete all frame recognizers.", nullptr) {}
919 
920   ~CommandObjectFrameRecognizerClear() override = default;
921 
922 protected:
923   bool DoExecute(Args &command, CommandReturnObject &result) override {
924     GetSelectedOrDummyTarget()
925         .GetFrameRecognizerManager()
926         .RemoveAllRecognizers();
927     result.SetStatus(eReturnStatusSuccessFinishResult);
928     return result.Succeeded();
929   }
930 };
931 
932 class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
933 public:
934   CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
935       : CommandObjectParsed(interpreter, "frame recognizer delete",
936                             "Delete an existing frame recognizer.", nullptr) {}
937 
938   ~CommandObjectFrameRecognizerDelete() override = default;
939 
940   void
941   HandleArgumentCompletion(CompletionRequest &request,
942                            OptionElementVector &opt_element_vector) override {
943     if (request.GetCursorIndex() != 0)
944       return;
945 
946     GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach(
947         [&request](uint32_t rid, std::string rname, std::string module,
948                    llvm::ArrayRef<lldb_private::ConstString> symbols,
949                    bool regexp) {
950           StreamString strm;
951           if (rname.empty())
952             rname = "(internal)";
953 
954           strm << rname;
955           if (!module.empty())
956             strm << ", module " << module;
957           if (!symbols.empty())
958             for (auto &symbol : symbols)
959               strm << ", symbol " << symbol;
960           if (regexp)
961             strm << " (regexp)";
962 
963           request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString());
964         });
965   }
966 
967 protected:
968   bool DoExecute(Args &command, CommandReturnObject &result) override {
969     if (command.GetArgumentCount() == 0) {
970       if (!m_interpreter.Confirm(
971               "About to delete all frame recognizers, do you want to do that?",
972               true)) {
973         result.AppendMessage("Operation cancelled...");
974         return false;
975       }
976 
977       GetSelectedOrDummyTarget()
978           .GetFrameRecognizerManager()
979           .RemoveAllRecognizers();
980       result.SetStatus(eReturnStatusSuccessFinishResult);
981       return result.Succeeded();
982     }
983 
984     if (command.GetArgumentCount() != 1) {
985       result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
986                                    m_cmd_name.c_str());
987       return false;
988     }
989 
990     uint32_t recognizer_id;
991     if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) {
992       result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
993                                    command.GetArgumentAtIndex(0));
994       return false;
995     }
996 
997     if (!GetSelectedOrDummyTarget()
998              .GetFrameRecognizerManager()
999              .RemoveRecognizerWithID(recognizer_id)) {
1000       result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
1001                                    command.GetArgumentAtIndex(0));
1002       return false;
1003     }
1004     result.SetStatus(eReturnStatusSuccessFinishResult);
1005     return result.Succeeded();
1006   }
1007 };
1008 
1009 class CommandObjectFrameRecognizerList : public CommandObjectParsed {
1010 public:
1011   CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
1012       : CommandObjectParsed(interpreter, "frame recognizer list",
1013                             "Show a list of active frame recognizers.",
1014                             nullptr) {}
1015 
1016   ~CommandObjectFrameRecognizerList() override = default;
1017 
1018 protected:
1019   bool DoExecute(Args &command, CommandReturnObject &result) override {
1020     bool any_printed = false;
1021     GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach(
1022         [&result, &any_printed](
1023             uint32_t recognizer_id, std::string name, std::string module,
1024             llvm::ArrayRef<ConstString> symbols, bool regexp) {
1025           Stream &stream = result.GetOutputStream();
1026 
1027           if (name.empty())
1028             name = "(internal)";
1029 
1030           stream << std::to_string(recognizer_id) << ": " << name;
1031           if (!module.empty())
1032             stream << ", module " << module;
1033           if (!symbols.empty())
1034             for (auto &symbol : symbols)
1035               stream << ", symbol " << symbol;
1036           if (regexp)
1037             stream << " (regexp)";
1038 
1039           stream.EOL();
1040           stream.Flush();
1041 
1042           any_printed = true;
1043         });
1044 
1045     if (any_printed)
1046       result.SetStatus(eReturnStatusSuccessFinishResult);
1047     else {
1048       result.GetOutputStream().PutCString("no matching results found.\n");
1049       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1050     }
1051     return result.Succeeded();
1052   }
1053 };
1054 
1055 class CommandObjectFrameRecognizerInfo : public CommandObjectParsed {
1056 public:
1057   CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
1058       : CommandObjectParsed(
1059             interpreter, "frame recognizer info",
1060             "Show which frame recognizer is applied a stack frame (if any).",
1061             nullptr) {
1062     CommandArgumentEntry arg;
1063     CommandArgumentData index_arg;
1064 
1065     // Define the first (and only) variant of this arg.
1066     index_arg.arg_type = eArgTypeFrameIndex;
1067     index_arg.arg_repetition = eArgRepeatPlain;
1068 
1069     // There is only one variant this argument could be; put it into the
1070     // argument entry.
1071     arg.push_back(index_arg);
1072 
1073     // Push the data for the first argument into the m_arguments vector.
1074     m_arguments.push_back(arg);
1075   }
1076 
1077   ~CommandObjectFrameRecognizerInfo() override = default;
1078 
1079 protected:
1080   bool DoExecute(Args &command, CommandReturnObject &result) override {
1081     const char *frame_index_str = command.GetArgumentAtIndex(0);
1082     uint32_t frame_index;
1083     if (!llvm::to_integer(frame_index_str, frame_index)) {
1084       result.AppendErrorWithFormat("'%s' is not a valid frame index.",
1085                                    frame_index_str);
1086       return false;
1087     }
1088 
1089     Process *process = m_exe_ctx.GetProcessPtr();
1090     if (process == nullptr) {
1091       result.AppendError("no process");
1092       return false;
1093     }
1094     Thread *thread = m_exe_ctx.GetThreadPtr();
1095     if (thread == nullptr) {
1096       result.AppendError("no thread");
1097       return false;
1098     }
1099     if (command.GetArgumentCount() != 1) {
1100       result.AppendErrorWithFormat(
1101           "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
1102       return false;
1103     }
1104 
1105     StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
1106     if (!frame_sp) {
1107       result.AppendErrorWithFormat("no frame with index %u", frame_index);
1108       return false;
1109     }
1110 
1111     auto recognizer = GetSelectedOrDummyTarget()
1112                           .GetFrameRecognizerManager()
1113                           .GetRecognizerForFrame(frame_sp);
1114 
1115     Stream &output_stream = result.GetOutputStream();
1116     output_stream.Printf("frame %d ", frame_index);
1117     if (recognizer) {
1118       output_stream << "is recognized by ";
1119       output_stream << recognizer->GetName();
1120     } else {
1121       output_stream << "not recognized by any recognizer";
1122     }
1123     output_stream.EOL();
1124     result.SetStatus(eReturnStatusSuccessFinishResult);
1125     return result.Succeeded();
1126   }
1127 };
1128 
1129 class CommandObjectFrameRecognizer : public CommandObjectMultiword {
1130 public:
1131   CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
1132       : CommandObjectMultiword(
1133             interpreter, "frame recognizer",
1134             "Commands for editing and viewing frame recognizers.",
1135             "frame recognizer [<sub-command-options>] ") {
1136     LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd(
1137                               interpreter)));
1138     LoadSubCommand(
1139         "clear",
1140         CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter)));
1141     LoadSubCommand(
1142         "delete",
1143         CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter)));
1144     LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList(
1145                                interpreter)));
1146     LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo(
1147                                interpreter)));
1148   }
1149 
1150   ~CommandObjectFrameRecognizer() override = default;
1151 };
1152 
1153 #pragma mark CommandObjectMultiwordFrame
1154 
1155 // CommandObjectMultiwordFrame
1156 
1157 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
1158     CommandInterpreter &interpreter)
1159     : CommandObjectMultiword(interpreter, "frame",
1160                              "Commands for selecting and "
1161                              "examing the current "
1162                              "thread's stack frames.",
1163                              "frame <subcommand> [<subcommand-options>]") {
1164   LoadSubCommand("diagnose",
1165                  CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
1166   LoadSubCommand("info",
1167                  CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1168   LoadSubCommand("select",
1169                  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1170   LoadSubCommand("variable",
1171                  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
1172 #if LLDB_ENABLE_PYTHON
1173   LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer(
1174                                    interpreter)));
1175 #endif
1176 }
1177 
1178 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
1179