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