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