xref: /openbsd-src/gnu/llvm/lldb/source/Commands/CommandObjectFrame.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- CommandObjectFrame.cpp --------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick #include "CommandObjectFrame.h"
9061da546Spatrick #include "lldb/Core/Debugger.h"
10061da546Spatrick #include "lldb/Core/ValueObject.h"
11061da546Spatrick #include "lldb/DataFormatters/DataVisualization.h"
12061da546Spatrick #include "lldb/DataFormatters/ValueObjectPrinter.h"
13061da546Spatrick #include "lldb/Host/Config.h"
14061da546Spatrick #include "lldb/Host/OptionParser.h"
15061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h"
16*f6aab3d8Srobert #include "lldb/Interpreter/CommandOptionArgumentTable.h"
17061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h"
18*f6aab3d8Srobert #include "lldb/Interpreter/OptionArgParser.h"
19061da546Spatrick #include "lldb/Interpreter/OptionGroupFormat.h"
20061da546Spatrick #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
21061da546Spatrick #include "lldb/Interpreter/OptionGroupVariable.h"
22061da546Spatrick #include "lldb/Interpreter/Options.h"
23061da546Spatrick #include "lldb/Symbol/Function.h"
24061da546Spatrick #include "lldb/Symbol/SymbolContext.h"
25061da546Spatrick #include "lldb/Symbol/Variable.h"
26061da546Spatrick #include "lldb/Symbol/VariableList.h"
27061da546Spatrick #include "lldb/Target/StackFrame.h"
28061da546Spatrick #include "lldb/Target/StackFrameRecognizer.h"
29061da546Spatrick #include "lldb/Target/StopInfo.h"
30061da546Spatrick #include "lldb/Target/Target.h"
31061da546Spatrick #include "lldb/Target/Thread.h"
32061da546Spatrick #include "lldb/Utility/Args.h"
33061da546Spatrick 
34061da546Spatrick #include <memory>
35*f6aab3d8Srobert #include <optional>
36061da546Spatrick #include <string>
37061da546Spatrick 
38061da546Spatrick using namespace lldb;
39061da546Spatrick using namespace lldb_private;
40061da546Spatrick 
41061da546Spatrick #pragma mark CommandObjectFrameDiagnose
42061da546Spatrick 
43061da546Spatrick // CommandObjectFrameInfo
44061da546Spatrick 
45061da546Spatrick // CommandObjectFrameDiagnose
46061da546Spatrick 
47061da546Spatrick #define LLDB_OPTIONS_frame_diag
48061da546Spatrick #include "CommandOptions.inc"
49061da546Spatrick 
50061da546Spatrick class CommandObjectFrameDiagnose : public CommandObjectParsed {
51061da546Spatrick public:
52061da546Spatrick   class CommandOptions : public Options {
53061da546Spatrick   public:
CommandOptions()54*f6aab3d8Srobert     CommandOptions() { OptionParsingStarting(nullptr); }
55061da546Spatrick 
56061da546Spatrick     ~CommandOptions() override = default;
57061da546Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)58061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
59061da546Spatrick                           ExecutionContext *execution_context) override {
60061da546Spatrick       Status error;
61061da546Spatrick       const int short_option = m_getopt_table[option_idx].val;
62061da546Spatrick       switch (short_option) {
63061da546Spatrick       case 'r':
64061da546Spatrick         reg = ConstString(option_arg);
65061da546Spatrick         break;
66061da546Spatrick 
67061da546Spatrick       case 'a': {
68061da546Spatrick         address.emplace();
69061da546Spatrick         if (option_arg.getAsInteger(0, *address)) {
70061da546Spatrick           address.reset();
71061da546Spatrick           error.SetErrorStringWithFormat("invalid address argument '%s'",
72061da546Spatrick                                          option_arg.str().c_str());
73061da546Spatrick         }
74061da546Spatrick       } break;
75061da546Spatrick 
76061da546Spatrick       case 'o': {
77061da546Spatrick         offset.emplace();
78061da546Spatrick         if (option_arg.getAsInteger(0, *offset)) {
79061da546Spatrick           offset.reset();
80061da546Spatrick           error.SetErrorStringWithFormat("invalid offset argument '%s'",
81061da546Spatrick                                          option_arg.str().c_str());
82061da546Spatrick         }
83061da546Spatrick       } break;
84061da546Spatrick 
85061da546Spatrick       default:
86061da546Spatrick         llvm_unreachable("Unimplemented option");
87061da546Spatrick       }
88061da546Spatrick 
89061da546Spatrick       return error;
90061da546Spatrick     }
91061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)92061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
93061da546Spatrick       address.reset();
94061da546Spatrick       reg.reset();
95061da546Spatrick       offset.reset();
96061da546Spatrick     }
97061da546Spatrick 
GetDefinitions()98061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
99*f6aab3d8Srobert       return llvm::ArrayRef(g_frame_diag_options);
100061da546Spatrick     }
101061da546Spatrick 
102061da546Spatrick     // Options.
103*f6aab3d8Srobert     std::optional<lldb::addr_t> address;
104*f6aab3d8Srobert     std::optional<ConstString> reg;
105*f6aab3d8Srobert     std::optional<int64_t> offset;
106061da546Spatrick   };
107061da546Spatrick 
CommandObjectFrameDiagnose(CommandInterpreter & interpreter)108061da546Spatrick   CommandObjectFrameDiagnose(CommandInterpreter &interpreter)
109061da546Spatrick       : CommandObjectParsed(interpreter, "frame diagnose",
110*f6aab3d8Srobert                             "Try to determine what path the current stop "
111061da546Spatrick                             "location used to get to a register or address",
112061da546Spatrick                             nullptr,
113061da546Spatrick                             eCommandRequiresThread | eCommandTryTargetAPILock |
114061da546Spatrick                                 eCommandProcessMustBeLaunched |
115*f6aab3d8Srobert                                 eCommandProcessMustBePaused) {
116061da546Spatrick     CommandArgumentEntry arg;
117061da546Spatrick     CommandArgumentData index_arg;
118061da546Spatrick 
119061da546Spatrick     // Define the first (and only) variant of this arg.
120061da546Spatrick     index_arg.arg_type = eArgTypeFrameIndex;
121061da546Spatrick     index_arg.arg_repetition = eArgRepeatOptional;
122061da546Spatrick 
123061da546Spatrick     // There is only one variant this argument could be; put it into the
124061da546Spatrick     // argument entry.
125061da546Spatrick     arg.push_back(index_arg);
126061da546Spatrick 
127061da546Spatrick     // Push the data for the first argument into the m_arguments vector.
128061da546Spatrick     m_arguments.push_back(arg);
129061da546Spatrick   }
130061da546Spatrick 
131061da546Spatrick   ~CommandObjectFrameDiagnose() override = default;
132061da546Spatrick 
GetOptions()133061da546Spatrick   Options *GetOptions() override { return &m_options; }
134061da546Spatrick 
135061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)136061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
137061da546Spatrick     Thread *thread = m_exe_ctx.GetThreadPtr();
138061da546Spatrick     StackFrameSP frame_sp = thread->GetSelectedFrame();
139061da546Spatrick 
140061da546Spatrick     ValueObjectSP valobj_sp;
141061da546Spatrick 
142*f6aab3d8Srobert     if (m_options.address) {
143*f6aab3d8Srobert       if (m_options.reg || m_options.offset) {
144061da546Spatrick         result.AppendError(
145061da546Spatrick             "`frame diagnose --address` is incompatible with other arguments.");
146061da546Spatrick         return false;
147061da546Spatrick       }
148*f6aab3d8Srobert       valobj_sp = frame_sp->GuessValueForAddress(*m_options.address);
149*f6aab3d8Srobert     } else if (m_options.reg) {
150061da546Spatrick       valobj_sp = frame_sp->GuessValueForRegisterAndOffset(
151*f6aab3d8Srobert           *m_options.reg, m_options.offset.value_or(0));
152061da546Spatrick     } else {
153061da546Spatrick       StopInfoSP stop_info_sp = thread->GetStopInfo();
154061da546Spatrick       if (!stop_info_sp) {
155061da546Spatrick         result.AppendError("No arguments provided, and no stop info.");
156061da546Spatrick         return false;
157061da546Spatrick       }
158061da546Spatrick 
159061da546Spatrick       valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
160061da546Spatrick     }
161061da546Spatrick 
162061da546Spatrick     if (!valobj_sp) {
163061da546Spatrick       result.AppendError("No diagnosis available.");
164061da546Spatrick       return false;
165061da546Spatrick     }
166061da546Spatrick 
167061da546Spatrick     DumpValueObjectOptions::DeclPrintingHelper helper =
168061da546Spatrick         [&valobj_sp](ConstString type, ConstString var,
169061da546Spatrick                      const DumpValueObjectOptions &opts,
170061da546Spatrick                      Stream &stream) -> bool {
171061da546Spatrick       const ValueObject::GetExpressionPathFormat format = ValueObject::
172061da546Spatrick           GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
173dda28197Spatrick       valobj_sp->GetExpressionPath(stream, format);
174061da546Spatrick       stream.PutCString(" =");
175061da546Spatrick       return true;
176061da546Spatrick     };
177061da546Spatrick 
178061da546Spatrick     DumpValueObjectOptions options;
179061da546Spatrick     options.SetDeclPrintingHelper(helper);
180061da546Spatrick     ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(),
181061da546Spatrick                                options);
182061da546Spatrick     printer.PrintValueObject();
183061da546Spatrick 
184061da546Spatrick     return true;
185061da546Spatrick   }
186061da546Spatrick 
187061da546Spatrick   CommandOptions m_options;
188061da546Spatrick };
189061da546Spatrick 
190061da546Spatrick #pragma mark CommandObjectFrameInfo
191061da546Spatrick 
192061da546Spatrick // CommandObjectFrameInfo
193061da546Spatrick 
194061da546Spatrick class CommandObjectFrameInfo : public CommandObjectParsed {
195061da546Spatrick public:
CommandObjectFrameInfo(CommandInterpreter & interpreter)196061da546Spatrick   CommandObjectFrameInfo(CommandInterpreter &interpreter)
197061da546Spatrick       : CommandObjectParsed(interpreter, "frame info",
198061da546Spatrick                             "List information about the current "
199061da546Spatrick                             "stack frame in the current thread.",
200061da546Spatrick                             "frame info",
201061da546Spatrick                             eCommandRequiresFrame | eCommandTryTargetAPILock |
202061da546Spatrick                                 eCommandProcessMustBeLaunched |
203061da546Spatrick                                 eCommandProcessMustBePaused) {}
204061da546Spatrick 
205061da546Spatrick   ~CommandObjectFrameInfo() override = default;
206061da546Spatrick 
207061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)208061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
209061da546Spatrick     m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream());
210061da546Spatrick     result.SetStatus(eReturnStatusSuccessFinishResult);
211061da546Spatrick     return result.Succeeded();
212061da546Spatrick   }
213061da546Spatrick };
214061da546Spatrick 
215061da546Spatrick #pragma mark CommandObjectFrameSelect
216061da546Spatrick 
217061da546Spatrick // CommandObjectFrameSelect
218061da546Spatrick 
219061da546Spatrick #define LLDB_OPTIONS_frame_select
220061da546Spatrick #include "CommandOptions.inc"
221061da546Spatrick 
222061da546Spatrick class CommandObjectFrameSelect : public CommandObjectParsed {
223061da546Spatrick public:
224061da546Spatrick   class CommandOptions : public Options {
225061da546Spatrick   public:
CommandOptions()226*f6aab3d8Srobert     CommandOptions() { OptionParsingStarting(nullptr); }
227061da546Spatrick 
228061da546Spatrick     ~CommandOptions() override = default;
229061da546Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)230061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
231061da546Spatrick                           ExecutionContext *execution_context) override {
232061da546Spatrick       Status error;
233061da546Spatrick       const int short_option = m_getopt_table[option_idx].val;
234061da546Spatrick       switch (short_option) {
235061da546Spatrick       case 'r': {
236061da546Spatrick         int32_t offset = 0;
237061da546Spatrick         if (option_arg.getAsInteger(0, offset) || offset == INT32_MIN) {
238061da546Spatrick           error.SetErrorStringWithFormat("invalid frame offset argument '%s'",
239061da546Spatrick                                          option_arg.str().c_str());
240061da546Spatrick         } else
241061da546Spatrick           relative_frame_offset = offset;
242061da546Spatrick         break;
243061da546Spatrick       }
244061da546Spatrick 
245061da546Spatrick       default:
246061da546Spatrick         llvm_unreachable("Unimplemented option");
247061da546Spatrick       }
248061da546Spatrick 
249061da546Spatrick       return error;
250061da546Spatrick     }
251061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)252061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
253061da546Spatrick       relative_frame_offset.reset();
254061da546Spatrick     }
255061da546Spatrick 
GetDefinitions()256061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
257*f6aab3d8Srobert       return llvm::ArrayRef(g_frame_select_options);
258061da546Spatrick     }
259061da546Spatrick 
260*f6aab3d8Srobert     std::optional<int32_t> relative_frame_offset;
261061da546Spatrick   };
262061da546Spatrick 
CommandObjectFrameSelect(CommandInterpreter & interpreter)263061da546Spatrick   CommandObjectFrameSelect(CommandInterpreter &interpreter)
264061da546Spatrick       : CommandObjectParsed(interpreter, "frame select",
265061da546Spatrick                             "Select the current stack frame by "
266061da546Spatrick                             "index from within the current thread "
267061da546Spatrick                             "(see 'thread backtrace'.)",
268061da546Spatrick                             nullptr,
269061da546Spatrick                             eCommandRequiresThread | eCommandTryTargetAPILock |
270061da546Spatrick                                 eCommandProcessMustBeLaunched |
271*f6aab3d8Srobert                                 eCommandProcessMustBePaused) {
272061da546Spatrick     CommandArgumentEntry arg;
273061da546Spatrick     CommandArgumentData index_arg;
274061da546Spatrick 
275061da546Spatrick     // Define the first (and only) variant of this arg.
276061da546Spatrick     index_arg.arg_type = eArgTypeFrameIndex;
277061da546Spatrick     index_arg.arg_repetition = eArgRepeatOptional;
278061da546Spatrick 
279061da546Spatrick     // There is only one variant this argument could be; put it into the
280061da546Spatrick     // argument entry.
281061da546Spatrick     arg.push_back(index_arg);
282061da546Spatrick 
283061da546Spatrick     // Push the data for the first argument into the m_arguments vector.
284061da546Spatrick     m_arguments.push_back(arg);
285061da546Spatrick   }
286061da546Spatrick 
287061da546Spatrick   ~CommandObjectFrameSelect() override = default;
288061da546Spatrick 
289dda28197Spatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)290dda28197Spatrick   HandleArgumentCompletion(CompletionRequest &request,
291dda28197Spatrick                            OptionElementVector &opt_element_vector) override {
292be691f3bSpatrick     if (request.GetCursorIndex() != 0)
293dda28197Spatrick       return;
294dda28197Spatrick 
295be691f3bSpatrick     CommandCompletions::InvokeCommonCompletionCallbacks(
296be691f3bSpatrick         GetCommandInterpreter(), CommandCompletions::eFrameIndexCompletion,
297be691f3bSpatrick         request, nullptr);
298dda28197Spatrick   }
299dda28197Spatrick 
GetOptions()300061da546Spatrick   Options *GetOptions() override { return &m_options; }
301061da546Spatrick 
302061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)303061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
304061da546Spatrick     // No need to check "thread" for validity as eCommandRequiresThread ensures
305061da546Spatrick     // it is valid
306061da546Spatrick     Thread *thread = m_exe_ctx.GetThreadPtr();
307061da546Spatrick 
308061da546Spatrick     uint32_t frame_idx = UINT32_MAX;
309*f6aab3d8Srobert     if (m_options.relative_frame_offset) {
310061da546Spatrick       // The one and only argument is a signed relative frame index
311061da546Spatrick       frame_idx = thread->GetSelectedFrameIndex();
312061da546Spatrick       if (frame_idx == UINT32_MAX)
313061da546Spatrick         frame_idx = 0;
314061da546Spatrick 
315061da546Spatrick       if (*m_options.relative_frame_offset < 0) {
316061da546Spatrick         if (static_cast<int32_t>(frame_idx) >=
317061da546Spatrick             -*m_options.relative_frame_offset)
318061da546Spatrick           frame_idx += *m_options.relative_frame_offset;
319061da546Spatrick         else {
320061da546Spatrick           if (frame_idx == 0) {
321061da546Spatrick             // If you are already at the bottom of the stack, then just warn
322061da546Spatrick             // and don't reset the frame.
323061da546Spatrick             result.AppendError("Already at the bottom of the stack.");
324061da546Spatrick             return false;
325061da546Spatrick           } else
326061da546Spatrick             frame_idx = 0;
327061da546Spatrick         }
328061da546Spatrick       } else if (*m_options.relative_frame_offset > 0) {
329061da546Spatrick         // I don't want "up 20" where "20" takes you past the top of the stack
330061da546Spatrick         // to produce
331061da546Spatrick         // an error, but rather to just go to the top.  So I have to count the
332061da546Spatrick         // stack here...
333061da546Spatrick         const uint32_t num_frames = thread->GetStackFrameCount();
334061da546Spatrick         if (static_cast<int32_t>(num_frames - frame_idx) >
335061da546Spatrick             *m_options.relative_frame_offset)
336061da546Spatrick           frame_idx += *m_options.relative_frame_offset;
337061da546Spatrick         else {
338061da546Spatrick           if (frame_idx == num_frames - 1) {
339061da546Spatrick             // If we are already at the top of the stack, just warn and don't
340061da546Spatrick             // reset the frame.
341061da546Spatrick             result.AppendError("Already at the top of the stack.");
342061da546Spatrick             return false;
343061da546Spatrick           } else
344061da546Spatrick             frame_idx = num_frames - 1;
345061da546Spatrick         }
346061da546Spatrick       }
347061da546Spatrick     } else {
348061da546Spatrick       if (command.GetArgumentCount() > 1) {
349061da546Spatrick         result.AppendErrorWithFormat(
350061da546Spatrick             "too many arguments; expected frame-index, saw '%s'.\n",
351061da546Spatrick             command[0].c_str());
352061da546Spatrick         m_options.GenerateOptionUsage(
353*f6aab3d8Srobert             result.GetErrorStream(), *this,
354061da546Spatrick             GetCommandInterpreter().GetDebugger().GetTerminalWidth());
355061da546Spatrick         return false;
356061da546Spatrick       }
357061da546Spatrick 
358061da546Spatrick       if (command.GetArgumentCount() == 1) {
359061da546Spatrick         if (command[0].ref().getAsInteger(0, frame_idx)) {
360061da546Spatrick           result.AppendErrorWithFormat("invalid frame index argument '%s'.",
361061da546Spatrick                                        command[0].c_str());
362061da546Spatrick           return false;
363061da546Spatrick         }
364061da546Spatrick       } else if (command.GetArgumentCount() == 0) {
365061da546Spatrick         frame_idx = thread->GetSelectedFrameIndex();
366061da546Spatrick         if (frame_idx == UINT32_MAX) {
367061da546Spatrick           frame_idx = 0;
368061da546Spatrick         }
369061da546Spatrick       }
370061da546Spatrick     }
371061da546Spatrick 
372061da546Spatrick     bool success = thread->SetSelectedFrameByIndexNoisily(
373061da546Spatrick         frame_idx, result.GetOutputStream());
374061da546Spatrick     if (success) {
375061da546Spatrick       m_exe_ctx.SetFrameSP(thread->GetSelectedFrame());
376061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishResult);
377061da546Spatrick     } else {
378061da546Spatrick       result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
379061da546Spatrick                                    frame_idx);
380061da546Spatrick     }
381061da546Spatrick 
382061da546Spatrick     return result.Succeeded();
383061da546Spatrick   }
384061da546Spatrick 
385061da546Spatrick   CommandOptions m_options;
386061da546Spatrick };
387061da546Spatrick 
388061da546Spatrick #pragma mark CommandObjectFrameVariable
389061da546Spatrick // List images with associated information
390061da546Spatrick class CommandObjectFrameVariable : public CommandObjectParsed {
391061da546Spatrick public:
CommandObjectFrameVariable(CommandInterpreter & interpreter)392061da546Spatrick   CommandObjectFrameVariable(CommandInterpreter &interpreter)
393061da546Spatrick       : CommandObjectParsed(
394061da546Spatrick             interpreter, "frame variable",
395061da546Spatrick             "Show variables for the current stack frame. Defaults to all "
396061da546Spatrick             "arguments and local variables in scope. Names of argument, "
397*f6aab3d8Srobert             "local, file static and file global variables can be specified.",
398061da546Spatrick             nullptr,
399061da546Spatrick             eCommandRequiresFrame | eCommandTryTargetAPILock |
400061da546Spatrick                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
401061da546Spatrick                 eCommandRequiresProcess),
402061da546Spatrick         m_option_variable(
403061da546Spatrick             true), // Include the frame specific options by passing "true"
404*f6aab3d8Srobert         m_option_format(eFormatDefault) {
405*f6aab3d8Srobert     SetHelpLong(R"(
406*f6aab3d8Srobert Children of aggregate variables can be specified such as 'var->child.x'.  In
407*f6aab3d8Srobert 'frame variable', the operators -> and [] do not invoke operator overloads if
408*f6aab3d8Srobert they exist, but directly access the specified element.  If you want to trigger
409*f6aab3d8Srobert operator overloads use the expression command to print the variable instead.
410*f6aab3d8Srobert 
411*f6aab3d8Srobert It is worth noting that except for overloaded operators, when printing local
412*f6aab3d8Srobert variables 'expr local_var' and 'frame var local_var' produce the same results.
413*f6aab3d8Srobert However, 'frame variable' is more efficient, since it uses debug information and
414*f6aab3d8Srobert memory reads directly, rather than parsing and evaluating an expression, which
415*f6aab3d8Srobert may even involve JITing and running code in the target program.)");
416*f6aab3d8Srobert 
417061da546Spatrick     CommandArgumentEntry arg;
418061da546Spatrick     CommandArgumentData var_name_arg;
419061da546Spatrick 
420061da546Spatrick     // Define the first (and only) variant of this arg.
421061da546Spatrick     var_name_arg.arg_type = eArgTypeVarName;
422061da546Spatrick     var_name_arg.arg_repetition = eArgRepeatStar;
423061da546Spatrick 
424061da546Spatrick     // There is only one variant this argument could be; put it into the
425061da546Spatrick     // argument entry.
426061da546Spatrick     arg.push_back(var_name_arg);
427061da546Spatrick 
428061da546Spatrick     // Push the data for the first argument into the m_arguments vector.
429061da546Spatrick     m_arguments.push_back(arg);
430061da546Spatrick 
431061da546Spatrick     m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
432061da546Spatrick     m_option_group.Append(&m_option_format,
433061da546Spatrick                           OptionGroupFormat::OPTION_GROUP_FORMAT |
434061da546Spatrick                               OptionGroupFormat::OPTION_GROUP_GDB_FMT,
435061da546Spatrick                           LLDB_OPT_SET_1);
436061da546Spatrick     m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
437061da546Spatrick     m_option_group.Finalize();
438061da546Spatrick   }
439061da546Spatrick 
440061da546Spatrick   ~CommandObjectFrameVariable() override = default;
441061da546Spatrick 
GetOptions()442061da546Spatrick   Options *GetOptions() override { return &m_option_group; }
443061da546Spatrick 
444061da546Spatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)445061da546Spatrick   HandleArgumentCompletion(CompletionRequest &request,
446061da546Spatrick                            OptionElementVector &opt_element_vector) override {
447061da546Spatrick     // Arguments are the standard source file completer.
448061da546Spatrick     CommandCompletions::InvokeCommonCompletionCallbacks(
449061da546Spatrick         GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion,
450061da546Spatrick         request, nullptr);
451061da546Spatrick   }
452061da546Spatrick 
453061da546Spatrick protected:
GetScopeString(VariableSP var_sp)454061da546Spatrick   llvm::StringRef GetScopeString(VariableSP var_sp) {
455061da546Spatrick     if (!var_sp)
456be691f3bSpatrick       return llvm::StringRef();
457061da546Spatrick 
458061da546Spatrick     switch (var_sp->GetScope()) {
459061da546Spatrick     case eValueTypeVariableGlobal:
460061da546Spatrick       return "GLOBAL: ";
461061da546Spatrick     case eValueTypeVariableStatic:
462061da546Spatrick       return "STATIC: ";
463061da546Spatrick     case eValueTypeVariableArgument:
464061da546Spatrick       return "ARG: ";
465061da546Spatrick     case eValueTypeVariableLocal:
466061da546Spatrick       return "LOCAL: ";
467061da546Spatrick     case eValueTypeVariableThreadLocal:
468061da546Spatrick       return "THREAD: ";
469061da546Spatrick     default:
470061da546Spatrick       break;
471061da546Spatrick     }
472061da546Spatrick 
473be691f3bSpatrick     return llvm::StringRef();
474061da546Spatrick   }
475061da546Spatrick 
DoExecute(Args & command,CommandReturnObject & result)476061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
477061da546Spatrick     // No need to check "frame" for validity as eCommandRequiresFrame ensures
478061da546Spatrick     // it is valid
479061da546Spatrick     StackFrame *frame = m_exe_ctx.GetFramePtr();
480061da546Spatrick 
481061da546Spatrick     Stream &s = result.GetOutputStream();
482061da546Spatrick 
483061da546Spatrick     // Be careful about the stack frame, if any summary formatter runs code, it
484061da546Spatrick     // might clear the StackFrameList for the thread.  So hold onto a shared
485061da546Spatrick     // pointer to the frame so it stays alive.
486061da546Spatrick 
487*f6aab3d8Srobert     Status error;
488061da546Spatrick     VariableList *variable_list =
489*f6aab3d8Srobert         frame->GetVariableList(m_option_variable.show_globals, &error);
490061da546Spatrick 
491*f6aab3d8Srobert     if (error.Fail() && (!variable_list || variable_list->GetSize() == 0)) {
492*f6aab3d8Srobert       result.AppendError(error.AsCString());
493*f6aab3d8Srobert 
494*f6aab3d8Srobert     }
495061da546Spatrick     VariableSP var_sp;
496061da546Spatrick     ValueObjectSP valobj_sp;
497061da546Spatrick 
498061da546Spatrick     TypeSummaryImplSP summary_format_sp;
499061da546Spatrick     if (!m_option_variable.summary.IsCurrentValueEmpty())
500061da546Spatrick       DataVisualization::NamedSummaryFormats::GetSummaryFormat(
501061da546Spatrick           ConstString(m_option_variable.summary.GetCurrentValue()),
502061da546Spatrick           summary_format_sp);
503061da546Spatrick     else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
504061da546Spatrick       summary_format_sp = std::make_shared<StringSummaryFormat>(
505061da546Spatrick           TypeSummaryImpl::Flags(),
506061da546Spatrick           m_option_variable.summary_string.GetCurrentValue());
507061da546Spatrick 
508061da546Spatrick     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
509061da546Spatrick         eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault,
510061da546Spatrick         summary_format_sp));
511061da546Spatrick 
512061da546Spatrick     const SymbolContext &sym_ctx =
513061da546Spatrick         frame->GetSymbolContext(eSymbolContextFunction);
514061da546Spatrick     if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
515061da546Spatrick       m_option_variable.show_globals = true;
516061da546Spatrick 
517061da546Spatrick     if (variable_list) {
518061da546Spatrick       const Format format = m_option_format.GetFormat();
519061da546Spatrick       options.SetFormat(format);
520061da546Spatrick 
521061da546Spatrick       if (!command.empty()) {
522061da546Spatrick         VariableList regex_var_list;
523061da546Spatrick 
524061da546Spatrick         // If we have any args to the variable command, we will make variable
525061da546Spatrick         // objects from them...
526061da546Spatrick         for (auto &entry : command) {
527061da546Spatrick           if (m_option_variable.use_regex) {
528061da546Spatrick             const size_t regex_start_index = regex_var_list.GetSize();
529061da546Spatrick             llvm::StringRef name_str = entry.ref();
530061da546Spatrick             RegularExpression regex(name_str);
531061da546Spatrick             if (regex.IsValid()) {
532061da546Spatrick               size_t num_matches = 0;
533061da546Spatrick               const size_t num_new_regex_vars =
534061da546Spatrick                   variable_list->AppendVariablesIfUnique(regex, regex_var_list,
535061da546Spatrick                                                          num_matches);
536061da546Spatrick               if (num_new_regex_vars > 0) {
537061da546Spatrick                 for (size_t regex_idx = regex_start_index,
538061da546Spatrick                             end_index = regex_var_list.GetSize();
539061da546Spatrick                      regex_idx < end_index; ++regex_idx) {
540061da546Spatrick                   var_sp = regex_var_list.GetVariableAtIndex(regex_idx);
541061da546Spatrick                   if (var_sp) {
542061da546Spatrick                     valobj_sp = frame->GetValueObjectForFrameVariable(
543061da546Spatrick                         var_sp, m_varobj_options.use_dynamic);
544061da546Spatrick                     if (valobj_sp) {
545061da546Spatrick                       std::string scope_string;
546061da546Spatrick                       if (m_option_variable.show_scope)
547061da546Spatrick                         scope_string = GetScopeString(var_sp).str();
548061da546Spatrick 
549061da546Spatrick                       if (!scope_string.empty())
550061da546Spatrick                         s.PutCString(scope_string);
551061da546Spatrick 
552061da546Spatrick                       if (m_option_variable.show_decl &&
553061da546Spatrick                           var_sp->GetDeclaration().GetFile()) {
554061da546Spatrick                         bool show_fullpaths = false;
555061da546Spatrick                         bool show_module = true;
556061da546Spatrick                         if (var_sp->DumpDeclaration(&s, show_fullpaths,
557061da546Spatrick                                                     show_module))
558061da546Spatrick                           s.PutCString(": ");
559061da546Spatrick                       }
560061da546Spatrick                       valobj_sp->Dump(result.GetOutputStream(), options);
561061da546Spatrick                     }
562061da546Spatrick                   }
563061da546Spatrick                 }
564061da546Spatrick               } else if (num_matches == 0) {
565*f6aab3d8Srobert                 result.AppendErrorWithFormat(
566*f6aab3d8Srobert                     "no variables matched the regular expression '%s'.",
567061da546Spatrick                     entry.c_str());
568061da546Spatrick               }
569061da546Spatrick             } else {
570061da546Spatrick               if (llvm::Error err = regex.GetError())
571*f6aab3d8Srobert                 result.AppendError(llvm::toString(std::move(err)));
572061da546Spatrick               else
573*f6aab3d8Srobert                 result.AppendErrorWithFormat(
574*f6aab3d8Srobert                     "unknown regex error when compiling '%s'", entry.c_str());
575061da546Spatrick             }
576061da546Spatrick           } else // No regex, either exact variable names or variable
577061da546Spatrick                  // expressions.
578061da546Spatrick           {
579061da546Spatrick             Status error;
580061da546Spatrick             uint32_t expr_path_options =
581061da546Spatrick                 StackFrame::eExpressionPathOptionCheckPtrVsMember |
582061da546Spatrick                 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
583061da546Spatrick                 StackFrame::eExpressionPathOptionsInspectAnonymousUnions;
584061da546Spatrick             lldb::VariableSP var_sp;
585061da546Spatrick             valobj_sp = frame->GetValueForVariableExpressionPath(
586061da546Spatrick                 entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
587061da546Spatrick                 var_sp, error);
588061da546Spatrick             if (valobj_sp) {
589061da546Spatrick               std::string scope_string;
590061da546Spatrick               if (m_option_variable.show_scope)
591061da546Spatrick                 scope_string = GetScopeString(var_sp).str();
592061da546Spatrick 
593061da546Spatrick               if (!scope_string.empty())
594061da546Spatrick                 s.PutCString(scope_string);
595061da546Spatrick               if (m_option_variable.show_decl && var_sp &&
596061da546Spatrick                   var_sp->GetDeclaration().GetFile()) {
597061da546Spatrick                 var_sp->GetDeclaration().DumpStopContext(&s, false);
598061da546Spatrick                 s.PutCString(": ");
599061da546Spatrick               }
600061da546Spatrick 
601061da546Spatrick               options.SetFormat(format);
602061da546Spatrick               options.SetVariableFormatDisplayLanguage(
603061da546Spatrick                   valobj_sp->GetPreferredDisplayLanguage());
604061da546Spatrick 
605061da546Spatrick               Stream &output_stream = result.GetOutputStream();
606061da546Spatrick               options.SetRootValueObjectName(
607061da546Spatrick                   valobj_sp->GetParent() ? entry.c_str() : nullptr);
608061da546Spatrick               valobj_sp->Dump(output_stream, options);
609061da546Spatrick             } else {
610*f6aab3d8Srobert               if (auto error_cstr = error.AsCString(nullptr))
611*f6aab3d8Srobert                 result.AppendError(error_cstr);
612061da546Spatrick               else
613*f6aab3d8Srobert                 result.AppendErrorWithFormat(
614*f6aab3d8Srobert                     "unable to find any variable expression path that matches "
615*f6aab3d8Srobert                     "'%s'.",
616061da546Spatrick                     entry.c_str());
617061da546Spatrick             }
618061da546Spatrick           }
619061da546Spatrick         }
620061da546Spatrick       } else // No command arg specified.  Use variable_list, instead.
621061da546Spatrick       {
622061da546Spatrick         const size_t num_variables = variable_list->GetSize();
623061da546Spatrick         if (num_variables > 0) {
624061da546Spatrick           for (size_t i = 0; i < num_variables; i++) {
625061da546Spatrick             var_sp = variable_list->GetVariableAtIndex(i);
626061da546Spatrick             switch (var_sp->GetScope()) {
627061da546Spatrick             case eValueTypeVariableGlobal:
628061da546Spatrick               if (!m_option_variable.show_globals)
629061da546Spatrick                 continue;
630061da546Spatrick               break;
631061da546Spatrick             case eValueTypeVariableStatic:
632061da546Spatrick               if (!m_option_variable.show_globals)
633061da546Spatrick                 continue;
634061da546Spatrick               break;
635061da546Spatrick             case eValueTypeVariableArgument:
636061da546Spatrick               if (!m_option_variable.show_args)
637061da546Spatrick                 continue;
638061da546Spatrick               break;
639061da546Spatrick             case eValueTypeVariableLocal:
640061da546Spatrick               if (!m_option_variable.show_locals)
641061da546Spatrick                 continue;
642061da546Spatrick               break;
643061da546Spatrick             default:
644061da546Spatrick               continue;
645061da546Spatrick               break;
646061da546Spatrick             }
647061da546Spatrick             std::string scope_string;
648061da546Spatrick             if (m_option_variable.show_scope)
649061da546Spatrick               scope_string = GetScopeString(var_sp).str();
650061da546Spatrick 
651061da546Spatrick             // Use the variable object code to make sure we are using the same
652061da546Spatrick             // APIs as the public API will be using...
653061da546Spatrick             valobj_sp = frame->GetValueObjectForFrameVariable(
654061da546Spatrick                 var_sp, m_varobj_options.use_dynamic);
655061da546Spatrick             if (valobj_sp) {
656061da546Spatrick               // When dumping all variables, don't print any variables that are
657061da546Spatrick               // not in scope to avoid extra unneeded output
658061da546Spatrick               if (valobj_sp->IsInScope()) {
659061da546Spatrick                 if (!valobj_sp->GetTargetSP()
660061da546Spatrick                          ->GetDisplayRuntimeSupportValues() &&
661061da546Spatrick                     valobj_sp->IsRuntimeSupportValue())
662061da546Spatrick                   continue;
663061da546Spatrick 
664061da546Spatrick                 if (!scope_string.empty())
665061da546Spatrick                   s.PutCString(scope_string);
666061da546Spatrick 
667061da546Spatrick                 if (m_option_variable.show_decl &&
668061da546Spatrick                     var_sp->GetDeclaration().GetFile()) {
669061da546Spatrick                   var_sp->GetDeclaration().DumpStopContext(&s, false);
670061da546Spatrick                   s.PutCString(": ");
671061da546Spatrick                 }
672061da546Spatrick 
673061da546Spatrick                 options.SetFormat(format);
674061da546Spatrick                 options.SetVariableFormatDisplayLanguage(
675061da546Spatrick                     valobj_sp->GetPreferredDisplayLanguage());
676061da546Spatrick                 options.SetRootValueObjectName(
677061da546Spatrick                     var_sp ? var_sp->GetName().AsCString() : nullptr);
678061da546Spatrick                 valobj_sp->Dump(result.GetOutputStream(), options);
679061da546Spatrick               }
680061da546Spatrick             }
681061da546Spatrick           }
682061da546Spatrick         }
683061da546Spatrick       }
684*f6aab3d8Srobert       if (result.GetStatus() != eReturnStatusFailed)
685061da546Spatrick         result.SetStatus(eReturnStatusSuccessFinishResult);
686061da546Spatrick     }
687061da546Spatrick 
688061da546Spatrick     if (m_option_variable.show_recognized_args) {
689061da546Spatrick       auto recognized_frame = frame->GetRecognizedFrame();
690061da546Spatrick       if (recognized_frame) {
691061da546Spatrick         ValueObjectListSP recognized_arg_list =
692061da546Spatrick             recognized_frame->GetRecognizedArguments();
693061da546Spatrick         if (recognized_arg_list) {
694061da546Spatrick           for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
695061da546Spatrick             options.SetFormat(m_option_format.GetFormat());
696061da546Spatrick             options.SetVariableFormatDisplayLanguage(
697061da546Spatrick                 rec_value_sp->GetPreferredDisplayLanguage());
698061da546Spatrick             options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
699061da546Spatrick             rec_value_sp->Dump(result.GetOutputStream(), options);
700061da546Spatrick           }
701061da546Spatrick         }
702061da546Spatrick       }
703061da546Spatrick     }
704061da546Spatrick 
705*f6aab3d8Srobert     m_interpreter.PrintWarningsIfNecessary(result.GetOutputStream(),
706*f6aab3d8Srobert                                            m_cmd_name);
707061da546Spatrick 
708061da546Spatrick     // Increment statistics.
709061da546Spatrick     bool res = result.Succeeded();
710*f6aab3d8Srobert     TargetStats &target_stats = GetSelectedOrDummyTarget().GetStatistics();
711061da546Spatrick     if (res)
712*f6aab3d8Srobert       target_stats.GetFrameVariableStats().NotifySuccess();
713061da546Spatrick     else
714*f6aab3d8Srobert       target_stats.GetFrameVariableStats().NotifyFailure();
715061da546Spatrick     return res;
716061da546Spatrick   }
717061da546Spatrick 
718061da546Spatrick   OptionGroupOptions m_option_group;
719061da546Spatrick   OptionGroupVariable m_option_variable;
720061da546Spatrick   OptionGroupFormat m_option_format;
721061da546Spatrick   OptionGroupValueObjectDisplay m_varobj_options;
722061da546Spatrick };
723061da546Spatrick 
724061da546Spatrick #pragma mark CommandObjectFrameRecognizer
725061da546Spatrick 
726061da546Spatrick #define LLDB_OPTIONS_frame_recognizer_add
727061da546Spatrick #include "CommandOptions.inc"
728061da546Spatrick 
729061da546Spatrick class CommandObjectFrameRecognizerAdd : public CommandObjectParsed {
730061da546Spatrick private:
731061da546Spatrick   class CommandOptions : public Options {
732061da546Spatrick   public:
733*f6aab3d8Srobert     CommandOptions() = default;
734061da546Spatrick     ~CommandOptions() override = default;
735061da546Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)736061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
737061da546Spatrick                           ExecutionContext *execution_context) override {
738061da546Spatrick       Status error;
739061da546Spatrick       const int short_option = m_getopt_table[option_idx].val;
740061da546Spatrick 
741061da546Spatrick       switch (short_option) {
742*f6aab3d8Srobert       case 'f': {
743*f6aab3d8Srobert         bool value, success;
744*f6aab3d8Srobert         value = OptionArgParser::ToBoolean(option_arg, true, &success);
745*f6aab3d8Srobert         if (success) {
746*f6aab3d8Srobert           m_first_instruction_only = value;
747*f6aab3d8Srobert         } else {
748*f6aab3d8Srobert           error.SetErrorStringWithFormat(
749*f6aab3d8Srobert               "invalid boolean value '%s' passed for -f option",
750*f6aab3d8Srobert               option_arg.str().c_str());
751*f6aab3d8Srobert         }
752*f6aab3d8Srobert       } break;
753061da546Spatrick       case 'l':
754061da546Spatrick         m_class_name = std::string(option_arg);
755061da546Spatrick         break;
756061da546Spatrick       case 's':
757061da546Spatrick         m_module = std::string(option_arg);
758061da546Spatrick         break;
759061da546Spatrick       case 'n':
760dda28197Spatrick         m_symbols.push_back(std::string(option_arg));
761061da546Spatrick         break;
762061da546Spatrick       case 'x':
763061da546Spatrick         m_regex = true;
764061da546Spatrick         break;
765061da546Spatrick       default:
766061da546Spatrick         llvm_unreachable("Unimplemented option");
767061da546Spatrick       }
768061da546Spatrick 
769061da546Spatrick       return error;
770061da546Spatrick     }
771061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)772061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
773061da546Spatrick       m_module = "";
774dda28197Spatrick       m_symbols.clear();
775061da546Spatrick       m_class_name = "";
776061da546Spatrick       m_regex = false;
777*f6aab3d8Srobert       m_first_instruction_only = true;
778061da546Spatrick     }
779061da546Spatrick 
GetDefinitions()780061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
781*f6aab3d8Srobert       return llvm::ArrayRef(g_frame_recognizer_add_options);
782061da546Spatrick     }
783061da546Spatrick 
784061da546Spatrick     // Instance variables to hold the values for command options.
785061da546Spatrick     std::string m_class_name;
786061da546Spatrick     std::string m_module;
787dda28197Spatrick     std::vector<std::string> m_symbols;
788061da546Spatrick     bool m_regex;
789*f6aab3d8Srobert     bool m_first_instruction_only;
790061da546Spatrick   };
791061da546Spatrick 
792061da546Spatrick   CommandOptions m_options;
793061da546Spatrick 
GetOptions()794061da546Spatrick   Options *GetOptions() override { return &m_options; }
795061da546Spatrick 
796061da546Spatrick protected:
797061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override;
798061da546Spatrick 
799061da546Spatrick public:
CommandObjectFrameRecognizerAdd(CommandInterpreter & interpreter)800061da546Spatrick   CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)
801061da546Spatrick       : CommandObjectParsed(interpreter, "frame recognizer add",
802*f6aab3d8Srobert                             "Add a new frame recognizer.", nullptr) {
803061da546Spatrick     SetHelpLong(R"(
804061da546Spatrick Frame recognizers allow for retrieving information about special frames based on
805061da546Spatrick ABI, arguments or other special properties of that frame, even without source
806061da546Spatrick code or debug info. Currently, one use case is to extract function arguments
807061da546Spatrick that would otherwise be unaccesible, or augment existing arguments.
808061da546Spatrick 
809061da546Spatrick Adding a custom frame recognizer is possible by implementing a Python class
810061da546Spatrick and using the 'frame recognizer add' command. The Python class should have a
811061da546Spatrick 'get_recognized_arguments' method and it will receive an argument of type
812061da546Spatrick lldb.SBFrame representing the current frame that we are trying to recognize.
813061da546Spatrick The method should return a (possibly empty) list of lldb.SBValue objects that
814061da546Spatrick represent the recognized arguments.
815061da546Spatrick 
816061da546Spatrick An example of a recognizer that retrieves the file descriptor values from libc
817061da546Spatrick functions 'read', 'write' and 'close' follows:
818061da546Spatrick 
819061da546Spatrick   class LibcFdRecognizer(object):
820061da546Spatrick     def get_recognized_arguments(self, frame):
821061da546Spatrick       if frame.name in ["read", "write", "close"]:
822061da546Spatrick         fd = frame.EvaluateExpression("$arg1").unsigned
823*f6aab3d8Srobert         target = frame.thread.process.target
824*f6aab3d8Srobert         value = target.CreateValueFromExpression("fd", "(int)%d" % fd)
825061da546Spatrick         return [value]
826061da546Spatrick       return []
827061da546Spatrick 
828061da546Spatrick The file containing this implementation can be imported via 'command script
829061da546Spatrick import' and then we can register this recognizer with 'frame recognizer add'.
830061da546Spatrick It's important to restrict the recognizer to the libc library (which is
831061da546Spatrick libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
832061da546Spatrick in other modules:
833061da546Spatrick 
834061da546Spatrick (lldb) command script import .../fd_recognizer.py
835061da546Spatrick (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
836061da546Spatrick 
837061da546Spatrick When the program is stopped at the beginning of the 'read' function in libc, we
838061da546Spatrick can view the recognizer arguments in 'frame variable':
839061da546Spatrick 
840061da546Spatrick (lldb) b read
841061da546Spatrick (lldb) r
842061da546Spatrick Process 1234 stopped
843061da546Spatrick * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
844061da546Spatrick     frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
845061da546Spatrick (lldb) frame variable
846061da546Spatrick (int) fd = 3
847061da546Spatrick 
848061da546Spatrick     )");
849061da546Spatrick   }
850061da546Spatrick   ~CommandObjectFrameRecognizerAdd() override = default;
851061da546Spatrick };
852061da546Spatrick 
DoExecute(Args & command,CommandReturnObject & result)853061da546Spatrick bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command,
854061da546Spatrick                                                 CommandReturnObject &result) {
855061da546Spatrick #if LLDB_ENABLE_PYTHON
856061da546Spatrick   if (m_options.m_class_name.empty()) {
857061da546Spatrick     result.AppendErrorWithFormat(
858061da546Spatrick         "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
859061da546Spatrick     return false;
860061da546Spatrick   }
861061da546Spatrick 
862061da546Spatrick   if (m_options.m_module.empty()) {
863061da546Spatrick     result.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
864061da546Spatrick                                  m_cmd_name.c_str());
865061da546Spatrick     return false;
866061da546Spatrick   }
867061da546Spatrick 
868dda28197Spatrick   if (m_options.m_symbols.empty()) {
869dda28197Spatrick     result.AppendErrorWithFormat(
870dda28197Spatrick         "%s needs at least one symbol name (-n argument).\n",
871dda28197Spatrick         m_cmd_name.c_str());
872dda28197Spatrick     return false;
873dda28197Spatrick   }
874dda28197Spatrick 
875dda28197Spatrick   if (m_options.m_regex && m_options.m_symbols.size() > 1) {
876dda28197Spatrick     result.AppendErrorWithFormat(
877dda28197Spatrick         "%s needs only one symbol regular expression (-n argument).\n",
878061da546Spatrick         m_cmd_name.c_str());
879061da546Spatrick     return false;
880061da546Spatrick   }
881061da546Spatrick 
882061da546Spatrick   ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
883061da546Spatrick 
884061da546Spatrick   if (interpreter &&
885061da546Spatrick       !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
886061da546Spatrick     result.AppendWarning("The provided class does not exist - please define it "
887061da546Spatrick                          "before attempting to use this frame recognizer");
888061da546Spatrick   }
889061da546Spatrick 
890061da546Spatrick   StackFrameRecognizerSP recognizer_sp =
891061da546Spatrick       StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(
892061da546Spatrick           interpreter, m_options.m_class_name.c_str()));
893061da546Spatrick   if (m_options.m_regex) {
894061da546Spatrick     auto module =
895061da546Spatrick         RegularExpressionSP(new RegularExpression(m_options.m_module));
896061da546Spatrick     auto func =
897dda28197Spatrick         RegularExpressionSP(new RegularExpression(m_options.m_symbols.front()));
898be691f3bSpatrick     GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer(
899*f6aab3d8Srobert         recognizer_sp, module, func, m_options.m_first_instruction_only);
900061da546Spatrick   } else {
901061da546Spatrick     auto module = ConstString(m_options.m_module);
902dda28197Spatrick     std::vector<ConstString> symbols(m_options.m_symbols.begin(),
903dda28197Spatrick                                      m_options.m_symbols.end());
904be691f3bSpatrick     GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer(
905*f6aab3d8Srobert         recognizer_sp, module, symbols, m_options.m_first_instruction_only);
906061da546Spatrick   }
907061da546Spatrick #endif
908061da546Spatrick 
909061da546Spatrick   result.SetStatus(eReturnStatusSuccessFinishNoResult);
910061da546Spatrick   return result.Succeeded();
911061da546Spatrick }
912061da546Spatrick 
913061da546Spatrick class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
914061da546Spatrick public:
CommandObjectFrameRecognizerClear(CommandInterpreter & interpreter)915061da546Spatrick   CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
916061da546Spatrick       : CommandObjectParsed(interpreter, "frame recognizer clear",
917061da546Spatrick                             "Delete all frame recognizers.", nullptr) {}
918061da546Spatrick 
919061da546Spatrick   ~CommandObjectFrameRecognizerClear() override = default;
920061da546Spatrick 
921061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)922061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
923be691f3bSpatrick     GetSelectedOrDummyTarget()
924be691f3bSpatrick         .GetFrameRecognizerManager()
925be691f3bSpatrick         .RemoveAllRecognizers();
926061da546Spatrick     result.SetStatus(eReturnStatusSuccessFinishResult);
927061da546Spatrick     return result.Succeeded();
928061da546Spatrick   }
929061da546Spatrick };
930061da546Spatrick 
931061da546Spatrick class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
932061da546Spatrick public:
CommandObjectFrameRecognizerDelete(CommandInterpreter & interpreter)933061da546Spatrick   CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
934061da546Spatrick       : CommandObjectParsed(interpreter, "frame recognizer delete",
935*f6aab3d8Srobert                             "Delete an existing frame recognizer by id.",
936*f6aab3d8Srobert                             nullptr) {
937*f6aab3d8Srobert     CommandArgumentData thread_arg{eArgTypeRecognizerID, eArgRepeatPlain};
938*f6aab3d8Srobert     m_arguments.push_back({thread_arg});
939*f6aab3d8Srobert   }
940061da546Spatrick 
941061da546Spatrick   ~CommandObjectFrameRecognizerDelete() override = default;
942061da546Spatrick 
943dda28197Spatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)944dda28197Spatrick   HandleArgumentCompletion(CompletionRequest &request,
945dda28197Spatrick                            OptionElementVector &opt_element_vector) override {
946dda28197Spatrick     if (request.GetCursorIndex() != 0)
947dda28197Spatrick       return;
948dda28197Spatrick 
949be691f3bSpatrick     GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach(
950dda28197Spatrick         [&request](uint32_t rid, std::string rname, std::string module,
951dda28197Spatrick                    llvm::ArrayRef<lldb_private::ConstString> symbols,
952dda28197Spatrick                    bool regexp) {
953dda28197Spatrick           StreamString strm;
954dda28197Spatrick           if (rname.empty())
955dda28197Spatrick             rname = "(internal)";
956dda28197Spatrick 
957dda28197Spatrick           strm << rname;
958dda28197Spatrick           if (!module.empty())
959dda28197Spatrick             strm << ", module " << module;
960dda28197Spatrick           if (!symbols.empty())
961dda28197Spatrick             for (auto &symbol : symbols)
962dda28197Spatrick               strm << ", symbol " << symbol;
963dda28197Spatrick           if (regexp)
964dda28197Spatrick             strm << " (regexp)";
965dda28197Spatrick 
966dda28197Spatrick           request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString());
967dda28197Spatrick         });
968dda28197Spatrick   }
969dda28197Spatrick 
970061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)971061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
972061da546Spatrick     if (command.GetArgumentCount() == 0) {
973061da546Spatrick       if (!m_interpreter.Confirm(
974061da546Spatrick               "About to delete all frame recognizers, do you want to do that?",
975061da546Spatrick               true)) {
976061da546Spatrick         result.AppendMessage("Operation cancelled...");
977061da546Spatrick         return false;
978061da546Spatrick       }
979061da546Spatrick 
980be691f3bSpatrick       GetSelectedOrDummyTarget()
981be691f3bSpatrick           .GetFrameRecognizerManager()
982be691f3bSpatrick           .RemoveAllRecognizers();
983061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishResult);
984061da546Spatrick       return result.Succeeded();
985061da546Spatrick     }
986061da546Spatrick 
987061da546Spatrick     if (command.GetArgumentCount() != 1) {
988061da546Spatrick       result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
989061da546Spatrick                                    m_cmd_name.c_str());
990061da546Spatrick       return false;
991061da546Spatrick     }
992061da546Spatrick 
993dda28197Spatrick     uint32_t recognizer_id;
994dda28197Spatrick     if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) {
995dda28197Spatrick       result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
996dda28197Spatrick                                    command.GetArgumentAtIndex(0));
997dda28197Spatrick       return false;
998dda28197Spatrick     }
999061da546Spatrick 
1000be691f3bSpatrick     if (!GetSelectedOrDummyTarget()
1001be691f3bSpatrick              .GetFrameRecognizerManager()
1002be691f3bSpatrick              .RemoveRecognizerWithID(recognizer_id)) {
1003be691f3bSpatrick       result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
1004be691f3bSpatrick                                    command.GetArgumentAtIndex(0));
1005be691f3bSpatrick       return false;
1006be691f3bSpatrick     }
1007061da546Spatrick     result.SetStatus(eReturnStatusSuccessFinishResult);
1008061da546Spatrick     return result.Succeeded();
1009061da546Spatrick   }
1010061da546Spatrick };
1011061da546Spatrick 
1012061da546Spatrick class CommandObjectFrameRecognizerList : public CommandObjectParsed {
1013061da546Spatrick public:
CommandObjectFrameRecognizerList(CommandInterpreter & interpreter)1014061da546Spatrick   CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
1015061da546Spatrick       : CommandObjectParsed(interpreter, "frame recognizer list",
1016061da546Spatrick                             "Show a list of active frame recognizers.",
1017061da546Spatrick                             nullptr) {}
1018061da546Spatrick 
1019061da546Spatrick   ~CommandObjectFrameRecognizerList() override = default;
1020061da546Spatrick 
1021061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1022061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
1023061da546Spatrick     bool any_printed = false;
1024be691f3bSpatrick     GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach(
1025dda28197Spatrick         [&result, &any_printed](
1026dda28197Spatrick             uint32_t recognizer_id, std::string name, std::string module,
1027dda28197Spatrick             llvm::ArrayRef<ConstString> symbols, bool regexp) {
1028dda28197Spatrick           Stream &stream = result.GetOutputStream();
1029dda28197Spatrick 
1030dda28197Spatrick           if (name.empty())
1031061da546Spatrick             name = "(internal)";
1032dda28197Spatrick 
1033dda28197Spatrick           stream << std::to_string(recognizer_id) << ": " << name;
1034dda28197Spatrick           if (!module.empty())
1035dda28197Spatrick             stream << ", module " << module;
1036dda28197Spatrick           if (!symbols.empty())
1037dda28197Spatrick             for (auto &symbol : symbols)
1038dda28197Spatrick               stream << ", symbol " << symbol;
1039dda28197Spatrick           if (regexp)
1040dda28197Spatrick             stream << " (regexp)";
1041dda28197Spatrick 
1042dda28197Spatrick           stream.EOL();
1043dda28197Spatrick           stream.Flush();
1044dda28197Spatrick 
1045061da546Spatrick           any_printed = true;
1046061da546Spatrick         });
1047061da546Spatrick 
1048061da546Spatrick     if (any_printed)
1049061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishResult);
1050061da546Spatrick     else {
1051061da546Spatrick       result.GetOutputStream().PutCString("no matching results found.\n");
1052061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1053061da546Spatrick     }
1054061da546Spatrick     return result.Succeeded();
1055061da546Spatrick   }
1056061da546Spatrick };
1057061da546Spatrick 
1058061da546Spatrick class CommandObjectFrameRecognizerInfo : public CommandObjectParsed {
1059061da546Spatrick public:
CommandObjectFrameRecognizerInfo(CommandInterpreter & interpreter)1060061da546Spatrick   CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
1061061da546Spatrick       : CommandObjectParsed(
1062061da546Spatrick             interpreter, "frame recognizer info",
1063061da546Spatrick             "Show which frame recognizer is applied a stack frame (if any).",
1064061da546Spatrick             nullptr) {
1065061da546Spatrick     CommandArgumentEntry arg;
1066061da546Spatrick     CommandArgumentData index_arg;
1067061da546Spatrick 
1068061da546Spatrick     // Define the first (and only) variant of this arg.
1069061da546Spatrick     index_arg.arg_type = eArgTypeFrameIndex;
1070061da546Spatrick     index_arg.arg_repetition = eArgRepeatPlain;
1071061da546Spatrick 
1072061da546Spatrick     // There is only one variant this argument could be; put it into the
1073061da546Spatrick     // argument entry.
1074061da546Spatrick     arg.push_back(index_arg);
1075061da546Spatrick 
1076061da546Spatrick     // Push the data for the first argument into the m_arguments vector.
1077061da546Spatrick     m_arguments.push_back(arg);
1078061da546Spatrick   }
1079061da546Spatrick 
1080061da546Spatrick   ~CommandObjectFrameRecognizerInfo() override = default;
1081061da546Spatrick 
1082061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1083061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
1084dda28197Spatrick     const char *frame_index_str = command.GetArgumentAtIndex(0);
1085dda28197Spatrick     uint32_t frame_index;
1086dda28197Spatrick     if (!llvm::to_integer(frame_index_str, frame_index)) {
1087dda28197Spatrick       result.AppendErrorWithFormat("'%s' is not a valid frame index.",
1088dda28197Spatrick                                    frame_index_str);
1089dda28197Spatrick       return false;
1090dda28197Spatrick     }
1091dda28197Spatrick 
1092061da546Spatrick     Process *process = m_exe_ctx.GetProcessPtr();
1093061da546Spatrick     if (process == nullptr) {
1094061da546Spatrick       result.AppendError("no process");
1095061da546Spatrick       return false;
1096061da546Spatrick     }
1097061da546Spatrick     Thread *thread = m_exe_ctx.GetThreadPtr();
1098061da546Spatrick     if (thread == nullptr) {
1099061da546Spatrick       result.AppendError("no thread");
1100061da546Spatrick       return false;
1101061da546Spatrick     }
1102061da546Spatrick     if (command.GetArgumentCount() != 1) {
1103061da546Spatrick       result.AppendErrorWithFormat(
1104061da546Spatrick           "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
1105061da546Spatrick       return false;
1106061da546Spatrick     }
1107061da546Spatrick 
1108061da546Spatrick     StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
1109061da546Spatrick     if (!frame_sp) {
1110061da546Spatrick       result.AppendErrorWithFormat("no frame with index %u", frame_index);
1111061da546Spatrick       return false;
1112061da546Spatrick     }
1113061da546Spatrick 
1114be691f3bSpatrick     auto recognizer = GetSelectedOrDummyTarget()
1115be691f3bSpatrick                           .GetFrameRecognizerManager()
1116be691f3bSpatrick                           .GetRecognizerForFrame(frame_sp);
1117061da546Spatrick 
1118061da546Spatrick     Stream &output_stream = result.GetOutputStream();
1119061da546Spatrick     output_stream.Printf("frame %d ", frame_index);
1120061da546Spatrick     if (recognizer) {
1121061da546Spatrick       output_stream << "is recognized by ";
1122061da546Spatrick       output_stream << recognizer->GetName();
1123061da546Spatrick     } else {
1124061da546Spatrick       output_stream << "not recognized by any recognizer";
1125061da546Spatrick     }
1126061da546Spatrick     output_stream.EOL();
1127061da546Spatrick     result.SetStatus(eReturnStatusSuccessFinishResult);
1128061da546Spatrick     return result.Succeeded();
1129061da546Spatrick   }
1130061da546Spatrick };
1131061da546Spatrick 
1132061da546Spatrick class CommandObjectFrameRecognizer : public CommandObjectMultiword {
1133061da546Spatrick public:
CommandObjectFrameRecognizer(CommandInterpreter & interpreter)1134061da546Spatrick   CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
1135061da546Spatrick       : CommandObjectMultiword(
1136061da546Spatrick             interpreter, "frame recognizer",
1137061da546Spatrick             "Commands for editing and viewing frame recognizers.",
1138061da546Spatrick             "frame recognizer [<sub-command-options>] ") {
1139061da546Spatrick     LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd(
1140061da546Spatrick                               interpreter)));
1141061da546Spatrick     LoadSubCommand(
1142061da546Spatrick         "clear",
1143061da546Spatrick         CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter)));
1144061da546Spatrick     LoadSubCommand(
1145061da546Spatrick         "delete",
1146061da546Spatrick         CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter)));
1147061da546Spatrick     LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList(
1148061da546Spatrick                                interpreter)));
1149061da546Spatrick     LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo(
1150061da546Spatrick                                interpreter)));
1151061da546Spatrick   }
1152061da546Spatrick 
1153061da546Spatrick   ~CommandObjectFrameRecognizer() override = default;
1154061da546Spatrick };
1155061da546Spatrick 
1156061da546Spatrick #pragma mark CommandObjectMultiwordFrame
1157061da546Spatrick 
1158061da546Spatrick // CommandObjectMultiwordFrame
1159061da546Spatrick 
CommandObjectMultiwordFrame(CommandInterpreter & interpreter)1160061da546Spatrick CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
1161061da546Spatrick     CommandInterpreter &interpreter)
1162061da546Spatrick     : CommandObjectMultiword(interpreter, "frame",
1163061da546Spatrick                              "Commands for selecting and "
1164061da546Spatrick                              "examing the current "
1165061da546Spatrick                              "thread's stack frames.",
1166061da546Spatrick                              "frame <subcommand> [<subcommand-options>]") {
1167061da546Spatrick   LoadSubCommand("diagnose",
1168061da546Spatrick                  CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
1169061da546Spatrick   LoadSubCommand("info",
1170061da546Spatrick                  CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1171061da546Spatrick   LoadSubCommand("select",
1172061da546Spatrick                  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1173061da546Spatrick   LoadSubCommand("variable",
1174061da546Spatrick                  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
1175061da546Spatrick #if LLDB_ENABLE_PYTHON
1176061da546Spatrick   LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer(
1177061da546Spatrick                                    interpreter)));
1178061da546Spatrick #endif
1179061da546Spatrick }
1180061da546Spatrick 
1181061da546Spatrick CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
1182