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