xref: /openbsd-src/gnu/llvm/lldb/source/Commands/CommandObjectFrame.cpp (revision dda2819751e49c83612958492e38917049128b41)
1*dda28197Spatrick //===-- 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"
16061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h"
17061da546Spatrick #include "lldb/Interpreter/OptionGroupFormat.h"
18061da546Spatrick #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
19061da546Spatrick #include "lldb/Interpreter/OptionGroupVariable.h"
20061da546Spatrick #include "lldb/Interpreter/Options.h"
21061da546Spatrick #include "lldb/Symbol/Function.h"
22061da546Spatrick #include "lldb/Symbol/SymbolContext.h"
23061da546Spatrick #include "lldb/Symbol/Variable.h"
24061da546Spatrick #include "lldb/Symbol/VariableList.h"
25061da546Spatrick #include "lldb/Target/StackFrame.h"
26061da546Spatrick #include "lldb/Target/StackFrameRecognizer.h"
27061da546Spatrick #include "lldb/Target/StopInfo.h"
28061da546Spatrick #include "lldb/Target/Target.h"
29061da546Spatrick #include "lldb/Target/Thread.h"
30061da546Spatrick #include "lldb/Utility/Args.h"
31061da546Spatrick 
32061da546Spatrick #include <memory>
33061da546Spatrick #include <string>
34061da546Spatrick 
35061da546Spatrick using namespace lldb;
36061da546Spatrick using namespace lldb_private;
37061da546Spatrick 
38061da546Spatrick #pragma mark CommandObjectFrameDiagnose
39061da546Spatrick 
40061da546Spatrick // CommandObjectFrameInfo
41061da546Spatrick 
42061da546Spatrick // CommandObjectFrameDiagnose
43061da546Spatrick 
44061da546Spatrick #define LLDB_OPTIONS_frame_diag
45061da546Spatrick #include "CommandOptions.inc"
46061da546Spatrick 
47061da546Spatrick class CommandObjectFrameDiagnose : public CommandObjectParsed {
48061da546Spatrick public:
49061da546Spatrick   class CommandOptions : public Options {
50061da546Spatrick   public:
51061da546Spatrick     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
52061da546Spatrick 
53061da546Spatrick     ~CommandOptions() override = default;
54061da546Spatrick 
55061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
56061da546Spatrick                           ExecutionContext *execution_context) override {
57061da546Spatrick       Status error;
58061da546Spatrick       const int short_option = m_getopt_table[option_idx].val;
59061da546Spatrick       switch (short_option) {
60061da546Spatrick       case 'r':
61061da546Spatrick         reg = ConstString(option_arg);
62061da546Spatrick         break;
63061da546Spatrick 
64061da546Spatrick       case 'a': {
65061da546Spatrick         address.emplace();
66061da546Spatrick         if (option_arg.getAsInteger(0, *address)) {
67061da546Spatrick           address.reset();
68061da546Spatrick           error.SetErrorStringWithFormat("invalid address argument '%s'",
69061da546Spatrick                                          option_arg.str().c_str());
70061da546Spatrick         }
71061da546Spatrick       } break;
72061da546Spatrick 
73061da546Spatrick       case 'o': {
74061da546Spatrick         offset.emplace();
75061da546Spatrick         if (option_arg.getAsInteger(0, *offset)) {
76061da546Spatrick           offset.reset();
77061da546Spatrick           error.SetErrorStringWithFormat("invalid offset argument '%s'",
78061da546Spatrick                                          option_arg.str().c_str());
79061da546Spatrick         }
80061da546Spatrick       } break;
81061da546Spatrick 
82061da546Spatrick       default:
83061da546Spatrick         llvm_unreachable("Unimplemented option");
84061da546Spatrick       }
85061da546Spatrick 
86061da546Spatrick       return error;
87061da546Spatrick     }
88061da546Spatrick 
89061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
90061da546Spatrick       address.reset();
91061da546Spatrick       reg.reset();
92061da546Spatrick       offset.reset();
93061da546Spatrick     }
94061da546Spatrick 
95061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
96061da546Spatrick       return llvm::makeArrayRef(g_frame_diag_options);
97061da546Spatrick     }
98061da546Spatrick 
99061da546Spatrick     // Options.
100061da546Spatrick     llvm::Optional<lldb::addr_t> address;
101061da546Spatrick     llvm::Optional<ConstString> reg;
102061da546Spatrick     llvm::Optional<int64_t> offset;
103061da546Spatrick   };
104061da546Spatrick 
105061da546Spatrick   CommandObjectFrameDiagnose(CommandInterpreter &interpreter)
106061da546Spatrick       : CommandObjectParsed(interpreter, "frame diagnose",
107061da546Spatrick                             "Try to determine what path path the current stop "
108061da546Spatrick                             "location used to get to a register or address",
109061da546Spatrick                             nullptr,
110061da546Spatrick                             eCommandRequiresThread | eCommandTryTargetAPILock |
111061da546Spatrick                                 eCommandProcessMustBeLaunched |
112061da546Spatrick                                 eCommandProcessMustBePaused),
113061da546Spatrick         m_options() {
114061da546Spatrick     CommandArgumentEntry arg;
115061da546Spatrick     CommandArgumentData index_arg;
116061da546Spatrick 
117061da546Spatrick     // Define the first (and only) variant of this arg.
118061da546Spatrick     index_arg.arg_type = eArgTypeFrameIndex;
119061da546Spatrick     index_arg.arg_repetition = eArgRepeatOptional;
120061da546Spatrick 
121061da546Spatrick     // There is only one variant this argument could be; put it into the
122061da546Spatrick     // argument entry.
123061da546Spatrick     arg.push_back(index_arg);
124061da546Spatrick 
125061da546Spatrick     // Push the data for the first argument into the m_arguments vector.
126061da546Spatrick     m_arguments.push_back(arg);
127061da546Spatrick   }
128061da546Spatrick 
129061da546Spatrick   ~CommandObjectFrameDiagnose() override = default;
130061da546Spatrick 
131061da546Spatrick   Options *GetOptions() override { return &m_options; }
132061da546Spatrick 
133061da546Spatrick protected:
134061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
135061da546Spatrick     Thread *thread = m_exe_ctx.GetThreadPtr();
136061da546Spatrick     StackFrameSP frame_sp = thread->GetSelectedFrame();
137061da546Spatrick 
138061da546Spatrick     ValueObjectSP valobj_sp;
139061da546Spatrick 
140061da546Spatrick     if (m_options.address.hasValue()) {
141061da546Spatrick       if (m_options.reg.hasValue() || m_options.offset.hasValue()) {
142061da546Spatrick         result.AppendError(
143061da546Spatrick             "`frame diagnose --address` is incompatible with other arguments.");
144061da546Spatrick         result.SetStatus(eReturnStatusFailed);
145061da546Spatrick         return false;
146061da546Spatrick       }
147061da546Spatrick       valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue());
148061da546Spatrick     } else if (m_options.reg.hasValue()) {
149061da546Spatrick       valobj_sp = frame_sp->GuessValueForRegisterAndOffset(
150061da546Spatrick           m_options.reg.getValue(), m_options.offset.getValueOr(0));
151061da546Spatrick     } else {
152061da546Spatrick       StopInfoSP stop_info_sp = thread->GetStopInfo();
153061da546Spatrick       if (!stop_info_sp) {
154061da546Spatrick         result.AppendError("No arguments provided, and no stop info.");
155061da546Spatrick         result.SetStatus(eReturnStatusFailed);
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       result.SetStatus(eReturnStatusFailed);
165061da546Spatrick       return false;
166061da546Spatrick     }
167061da546Spatrick 
168061da546Spatrick     DumpValueObjectOptions::DeclPrintingHelper helper =
169061da546Spatrick         [&valobj_sp](ConstString type, ConstString var,
170061da546Spatrick                      const DumpValueObjectOptions &opts,
171061da546Spatrick                      Stream &stream) -> bool {
172061da546Spatrick       const ValueObject::GetExpressionPathFormat format = ValueObject::
173061da546Spatrick           GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
174*dda28197Spatrick       valobj_sp->GetExpressionPath(stream, format);
175061da546Spatrick       stream.PutCString(" =");
176061da546Spatrick       return true;
177061da546Spatrick     };
178061da546Spatrick 
179061da546Spatrick     DumpValueObjectOptions options;
180061da546Spatrick     options.SetDeclPrintingHelper(helper);
181061da546Spatrick     ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(),
182061da546Spatrick                                options);
183061da546Spatrick     printer.PrintValueObject();
184061da546Spatrick 
185061da546Spatrick     return true;
186061da546Spatrick   }
187061da546Spatrick 
188061da546Spatrick   CommandOptions m_options;
189061da546Spatrick };
190061da546Spatrick 
191061da546Spatrick #pragma mark CommandObjectFrameInfo
192061da546Spatrick 
193061da546Spatrick // CommandObjectFrameInfo
194061da546Spatrick 
195061da546Spatrick class CommandObjectFrameInfo : public CommandObjectParsed {
196061da546Spatrick public:
197061da546Spatrick   CommandObjectFrameInfo(CommandInterpreter &interpreter)
198061da546Spatrick       : CommandObjectParsed(interpreter, "frame info",
199061da546Spatrick                             "List information about the current "
200061da546Spatrick                             "stack frame in the current thread.",
201061da546Spatrick                             "frame info",
202061da546Spatrick                             eCommandRequiresFrame | eCommandTryTargetAPILock |
203061da546Spatrick                                 eCommandProcessMustBeLaunched |
204061da546Spatrick                                 eCommandProcessMustBePaused) {}
205061da546Spatrick 
206061da546Spatrick   ~CommandObjectFrameInfo() override = default;
207061da546Spatrick 
208061da546Spatrick protected:
209061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
210061da546Spatrick     m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream());
211061da546Spatrick     result.SetStatus(eReturnStatusSuccessFinishResult);
212061da546Spatrick     return result.Succeeded();
213061da546Spatrick   }
214061da546Spatrick };
215061da546Spatrick 
216061da546Spatrick #pragma mark CommandObjectFrameSelect
217061da546Spatrick 
218061da546Spatrick // CommandObjectFrameSelect
219061da546Spatrick 
220061da546Spatrick #define LLDB_OPTIONS_frame_select
221061da546Spatrick #include "CommandOptions.inc"
222061da546Spatrick 
223061da546Spatrick class CommandObjectFrameSelect : public CommandObjectParsed {
224061da546Spatrick public:
225061da546Spatrick   class CommandOptions : public Options {
226061da546Spatrick   public:
227061da546Spatrick     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
228061da546Spatrick 
229061da546Spatrick     ~CommandOptions() override = default;
230061da546Spatrick 
231061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
232061da546Spatrick                           ExecutionContext *execution_context) override {
233061da546Spatrick       Status error;
234061da546Spatrick       const int short_option = m_getopt_table[option_idx].val;
235061da546Spatrick       switch (short_option) {
236061da546Spatrick       case 'r': {
237061da546Spatrick         int32_t offset = 0;
238061da546Spatrick         if (option_arg.getAsInteger(0, offset) || offset == INT32_MIN) {
239061da546Spatrick           error.SetErrorStringWithFormat("invalid frame offset argument '%s'",
240061da546Spatrick                                          option_arg.str().c_str());
241061da546Spatrick         } else
242061da546Spatrick           relative_frame_offset = offset;
243061da546Spatrick         break;
244061da546Spatrick       }
245061da546Spatrick 
246061da546Spatrick       default:
247061da546Spatrick         llvm_unreachable("Unimplemented option");
248061da546Spatrick       }
249061da546Spatrick 
250061da546Spatrick       return error;
251061da546Spatrick     }
252061da546Spatrick 
253061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
254061da546Spatrick       relative_frame_offset.reset();
255061da546Spatrick     }
256061da546Spatrick 
257061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
258061da546Spatrick       return llvm::makeArrayRef(g_frame_select_options);
259061da546Spatrick     }
260061da546Spatrick 
261061da546Spatrick     llvm::Optional<int32_t> relative_frame_offset;
262061da546Spatrick   };
263061da546Spatrick 
264061da546Spatrick   CommandObjectFrameSelect(CommandInterpreter &interpreter)
265061da546Spatrick       : CommandObjectParsed(interpreter, "frame select",
266061da546Spatrick                             "Select the current stack frame by "
267061da546Spatrick                             "index from within the current thread "
268061da546Spatrick                             "(see 'thread backtrace'.)",
269061da546Spatrick                             nullptr,
270061da546Spatrick                             eCommandRequiresThread | eCommandTryTargetAPILock |
271061da546Spatrick                                 eCommandProcessMustBeLaunched |
272061da546Spatrick                                 eCommandProcessMustBePaused),
273061da546Spatrick         m_options() {
274061da546Spatrick     CommandArgumentEntry arg;
275061da546Spatrick     CommandArgumentData index_arg;
276061da546Spatrick 
277061da546Spatrick     // Define the first (and only) variant of this arg.
278061da546Spatrick     index_arg.arg_type = eArgTypeFrameIndex;
279061da546Spatrick     index_arg.arg_repetition = eArgRepeatOptional;
280061da546Spatrick 
281061da546Spatrick     // There is only one variant this argument could be; put it into the
282061da546Spatrick     // argument entry.
283061da546Spatrick     arg.push_back(index_arg);
284061da546Spatrick 
285061da546Spatrick     // Push the data for the first argument into the m_arguments vector.
286061da546Spatrick     m_arguments.push_back(arg);
287061da546Spatrick   }
288061da546Spatrick 
289061da546Spatrick   ~CommandObjectFrameSelect() override = default;
290061da546Spatrick 
291*dda28197Spatrick   void
292*dda28197Spatrick   HandleArgumentCompletion(CompletionRequest &request,
293*dda28197Spatrick                            OptionElementVector &opt_element_vector) override {
294*dda28197Spatrick     if (!m_exe_ctx.HasProcessScope() || request.GetCursorIndex() != 0)
295*dda28197Spatrick       return;
296*dda28197Spatrick 
297*dda28197Spatrick     lldb::ThreadSP thread_sp = m_exe_ctx.GetThreadSP();
298*dda28197Spatrick     const uint32_t frame_num = thread_sp->GetStackFrameCount();
299*dda28197Spatrick     for (uint32_t i = 0; i < frame_num; ++i) {
300*dda28197Spatrick       lldb::StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(i);
301*dda28197Spatrick       StreamString strm;
302*dda28197Spatrick       frame_sp->Dump(&strm, false, true);
303*dda28197Spatrick       request.TryCompleteCurrentArg(std::to_string(i), strm.GetString());
304*dda28197Spatrick     }
305*dda28197Spatrick   }
306*dda28197Spatrick 
307061da546Spatrick   Options *GetOptions() override { return &m_options; }
308061da546Spatrick 
309061da546Spatrick protected:
310061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
311061da546Spatrick     // No need to check "thread" for validity as eCommandRequiresThread ensures
312061da546Spatrick     // it is valid
313061da546Spatrick     Thread *thread = m_exe_ctx.GetThreadPtr();
314061da546Spatrick 
315061da546Spatrick     uint32_t frame_idx = UINT32_MAX;
316061da546Spatrick     if (m_options.relative_frame_offset.hasValue()) {
317061da546Spatrick       // The one and only argument is a signed relative frame index
318061da546Spatrick       frame_idx = thread->GetSelectedFrameIndex();
319061da546Spatrick       if (frame_idx == UINT32_MAX)
320061da546Spatrick         frame_idx = 0;
321061da546Spatrick 
322061da546Spatrick       if (*m_options.relative_frame_offset < 0) {
323061da546Spatrick         if (static_cast<int32_t>(frame_idx) >=
324061da546Spatrick             -*m_options.relative_frame_offset)
325061da546Spatrick           frame_idx += *m_options.relative_frame_offset;
326061da546Spatrick         else {
327061da546Spatrick           if (frame_idx == 0) {
328061da546Spatrick             // If you are already at the bottom of the stack, then just warn
329061da546Spatrick             // and don't reset the frame.
330061da546Spatrick             result.AppendError("Already at the bottom of the stack.");
331061da546Spatrick             result.SetStatus(eReturnStatusFailed);
332061da546Spatrick             return false;
333061da546Spatrick           } else
334061da546Spatrick             frame_idx = 0;
335061da546Spatrick         }
336061da546Spatrick       } else if (*m_options.relative_frame_offset > 0) {
337061da546Spatrick         // I don't want "up 20" where "20" takes you past the top of the stack
338061da546Spatrick         // to produce
339061da546Spatrick         // an error, but rather to just go to the top.  So I have to count the
340061da546Spatrick         // stack here...
341061da546Spatrick         const uint32_t num_frames = thread->GetStackFrameCount();
342061da546Spatrick         if (static_cast<int32_t>(num_frames - frame_idx) >
343061da546Spatrick             *m_options.relative_frame_offset)
344061da546Spatrick           frame_idx += *m_options.relative_frame_offset;
345061da546Spatrick         else {
346061da546Spatrick           if (frame_idx == num_frames - 1) {
347061da546Spatrick             // If we are already at the top of the stack, just warn and don't
348061da546Spatrick             // reset the frame.
349061da546Spatrick             result.AppendError("Already at the top of the stack.");
350061da546Spatrick             result.SetStatus(eReturnStatusFailed);
351061da546Spatrick             return false;
352061da546Spatrick           } else
353061da546Spatrick             frame_idx = num_frames - 1;
354061da546Spatrick         }
355061da546Spatrick       }
356061da546Spatrick     } else {
357061da546Spatrick       if (command.GetArgumentCount() > 1) {
358061da546Spatrick         result.AppendErrorWithFormat(
359061da546Spatrick             "too many arguments; expected frame-index, saw '%s'.\n",
360061da546Spatrick             command[0].c_str());
361061da546Spatrick         m_options.GenerateOptionUsage(
362061da546Spatrick             result.GetErrorStream(), this,
363061da546Spatrick             GetCommandInterpreter().GetDebugger().GetTerminalWidth());
364061da546Spatrick         return false;
365061da546Spatrick       }
366061da546Spatrick 
367061da546Spatrick       if (command.GetArgumentCount() == 1) {
368061da546Spatrick         if (command[0].ref().getAsInteger(0, frame_idx)) {
369061da546Spatrick           result.AppendErrorWithFormat("invalid frame index argument '%s'.",
370061da546Spatrick                                        command[0].c_str());
371061da546Spatrick           result.SetStatus(eReturnStatusFailed);
372061da546Spatrick           return false;
373061da546Spatrick         }
374061da546Spatrick       } else if (command.GetArgumentCount() == 0) {
375061da546Spatrick         frame_idx = thread->GetSelectedFrameIndex();
376061da546Spatrick         if (frame_idx == UINT32_MAX) {
377061da546Spatrick           frame_idx = 0;
378061da546Spatrick         }
379061da546Spatrick       }
380061da546Spatrick     }
381061da546Spatrick 
382061da546Spatrick     bool success = thread->SetSelectedFrameByIndexNoisily(
383061da546Spatrick         frame_idx, result.GetOutputStream());
384061da546Spatrick     if (success) {
385061da546Spatrick       m_exe_ctx.SetFrameSP(thread->GetSelectedFrame());
386061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishResult);
387061da546Spatrick     } else {
388061da546Spatrick       result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
389061da546Spatrick                                    frame_idx);
390061da546Spatrick       result.SetStatus(eReturnStatusFailed);
391061da546Spatrick     }
392061da546Spatrick 
393061da546Spatrick     return result.Succeeded();
394061da546Spatrick   }
395061da546Spatrick 
396061da546Spatrick   CommandOptions m_options;
397061da546Spatrick };
398061da546Spatrick 
399061da546Spatrick #pragma mark CommandObjectFrameVariable
400061da546Spatrick // List images with associated information
401061da546Spatrick class CommandObjectFrameVariable : public CommandObjectParsed {
402061da546Spatrick public:
403061da546Spatrick   CommandObjectFrameVariable(CommandInterpreter &interpreter)
404061da546Spatrick       : CommandObjectParsed(
405061da546Spatrick             interpreter, "frame variable",
406061da546Spatrick             "Show variables for the current stack frame. Defaults to all "
407061da546Spatrick             "arguments and local variables in scope. Names of argument, "
408061da546Spatrick             "local, file static and file global variables can be specified. "
409061da546Spatrick             "Children of aggregate variables can be specified such as "
410061da546Spatrick             "'var->child.x'.  The -> and [] operators in 'frame variable' do "
411061da546Spatrick             "not invoke operator overloads if they exist, but directly access "
412061da546Spatrick             "the specified element.  If you want to trigger operator overloads "
413061da546Spatrick             "use the expression command to print the variable instead."
414061da546Spatrick             "\nIt is worth noting that except for overloaded "
415061da546Spatrick             "operators, when printing local variables 'expr local_var' and "
416061da546Spatrick             "'frame var local_var' produce the same "
417061da546Spatrick             "results.  However, 'frame variable' is more efficient, since it "
418061da546Spatrick             "uses debug information and memory reads directly, rather than "
419061da546Spatrick             "parsing and evaluating an expression, which may even involve "
420061da546Spatrick             "JITing and running code in the target program.",
421061da546Spatrick             nullptr,
422061da546Spatrick             eCommandRequiresFrame | eCommandTryTargetAPILock |
423061da546Spatrick                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
424061da546Spatrick                 eCommandRequiresProcess),
425061da546Spatrick         m_option_group(),
426061da546Spatrick         m_option_variable(
427061da546Spatrick             true), // Include the frame specific options by passing "true"
428061da546Spatrick         m_option_format(eFormatDefault), m_varobj_options() {
429061da546Spatrick     CommandArgumentEntry arg;
430061da546Spatrick     CommandArgumentData var_name_arg;
431061da546Spatrick 
432061da546Spatrick     // Define the first (and only) variant of this arg.
433061da546Spatrick     var_name_arg.arg_type = eArgTypeVarName;
434061da546Spatrick     var_name_arg.arg_repetition = eArgRepeatStar;
435061da546Spatrick 
436061da546Spatrick     // There is only one variant this argument could be; put it into the
437061da546Spatrick     // argument entry.
438061da546Spatrick     arg.push_back(var_name_arg);
439061da546Spatrick 
440061da546Spatrick     // Push the data for the first argument into the m_arguments vector.
441061da546Spatrick     m_arguments.push_back(arg);
442061da546Spatrick 
443061da546Spatrick     m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
444061da546Spatrick     m_option_group.Append(&m_option_format,
445061da546Spatrick                           OptionGroupFormat::OPTION_GROUP_FORMAT |
446061da546Spatrick                               OptionGroupFormat::OPTION_GROUP_GDB_FMT,
447061da546Spatrick                           LLDB_OPT_SET_1);
448061da546Spatrick     m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
449061da546Spatrick     m_option_group.Finalize();
450061da546Spatrick   }
451061da546Spatrick 
452061da546Spatrick   ~CommandObjectFrameVariable() override = default;
453061da546Spatrick 
454061da546Spatrick   Options *GetOptions() override { return &m_option_group; }
455061da546Spatrick 
456061da546Spatrick   void
457061da546Spatrick   HandleArgumentCompletion(CompletionRequest &request,
458061da546Spatrick                            OptionElementVector &opt_element_vector) override {
459061da546Spatrick     // Arguments are the standard source file completer.
460061da546Spatrick     CommandCompletions::InvokeCommonCompletionCallbacks(
461061da546Spatrick         GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion,
462061da546Spatrick         request, nullptr);
463061da546Spatrick   }
464061da546Spatrick 
465061da546Spatrick protected:
466061da546Spatrick   llvm::StringRef GetScopeString(VariableSP var_sp) {
467061da546Spatrick     if (!var_sp)
468061da546Spatrick       return llvm::StringRef::withNullAsEmpty(nullptr);
469061da546Spatrick 
470061da546Spatrick     switch (var_sp->GetScope()) {
471061da546Spatrick     case eValueTypeVariableGlobal:
472061da546Spatrick       return "GLOBAL: ";
473061da546Spatrick     case eValueTypeVariableStatic:
474061da546Spatrick       return "STATIC: ";
475061da546Spatrick     case eValueTypeVariableArgument:
476061da546Spatrick       return "ARG: ";
477061da546Spatrick     case eValueTypeVariableLocal:
478061da546Spatrick       return "LOCAL: ";
479061da546Spatrick     case eValueTypeVariableThreadLocal:
480061da546Spatrick       return "THREAD: ";
481061da546Spatrick     default:
482061da546Spatrick       break;
483061da546Spatrick     }
484061da546Spatrick 
485061da546Spatrick     return llvm::StringRef::withNullAsEmpty(nullptr);
486061da546Spatrick   }
487061da546Spatrick 
488061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
489061da546Spatrick     // No need to check "frame" for validity as eCommandRequiresFrame ensures
490061da546Spatrick     // it is valid
491061da546Spatrick     StackFrame *frame = m_exe_ctx.GetFramePtr();
492061da546Spatrick 
493061da546Spatrick     Stream &s = result.GetOutputStream();
494061da546Spatrick 
495061da546Spatrick     // Be careful about the stack frame, if any summary formatter runs code, it
496061da546Spatrick     // might clear the StackFrameList for the thread.  So hold onto a shared
497061da546Spatrick     // pointer to the frame so it stays alive.
498061da546Spatrick 
499061da546Spatrick     VariableList *variable_list =
500061da546Spatrick         frame->GetVariableList(m_option_variable.show_globals);
501061da546Spatrick 
502061da546Spatrick     VariableSP var_sp;
503061da546Spatrick     ValueObjectSP valobj_sp;
504061da546Spatrick 
505061da546Spatrick     TypeSummaryImplSP summary_format_sp;
506061da546Spatrick     if (!m_option_variable.summary.IsCurrentValueEmpty())
507061da546Spatrick       DataVisualization::NamedSummaryFormats::GetSummaryFormat(
508061da546Spatrick           ConstString(m_option_variable.summary.GetCurrentValue()),
509061da546Spatrick           summary_format_sp);
510061da546Spatrick     else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
511061da546Spatrick       summary_format_sp = std::make_shared<StringSummaryFormat>(
512061da546Spatrick           TypeSummaryImpl::Flags(),
513061da546Spatrick           m_option_variable.summary_string.GetCurrentValue());
514061da546Spatrick 
515061da546Spatrick     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
516061da546Spatrick         eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault,
517061da546Spatrick         summary_format_sp));
518061da546Spatrick 
519061da546Spatrick     const SymbolContext &sym_ctx =
520061da546Spatrick         frame->GetSymbolContext(eSymbolContextFunction);
521061da546Spatrick     if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
522061da546Spatrick       m_option_variable.show_globals = true;
523061da546Spatrick 
524061da546Spatrick     if (variable_list) {
525061da546Spatrick       const Format format = m_option_format.GetFormat();
526061da546Spatrick       options.SetFormat(format);
527061da546Spatrick 
528061da546Spatrick       if (!command.empty()) {
529061da546Spatrick         VariableList regex_var_list;
530061da546Spatrick 
531061da546Spatrick         // If we have any args to the variable command, we will make variable
532061da546Spatrick         // objects from them...
533061da546Spatrick         for (auto &entry : command) {
534061da546Spatrick           if (m_option_variable.use_regex) {
535061da546Spatrick             const size_t regex_start_index = regex_var_list.GetSize();
536061da546Spatrick             llvm::StringRef name_str = entry.ref();
537061da546Spatrick             RegularExpression regex(name_str);
538061da546Spatrick             if (regex.IsValid()) {
539061da546Spatrick               size_t num_matches = 0;
540061da546Spatrick               const size_t num_new_regex_vars =
541061da546Spatrick                   variable_list->AppendVariablesIfUnique(regex, regex_var_list,
542061da546Spatrick                                                          num_matches);
543061da546Spatrick               if (num_new_regex_vars > 0) {
544061da546Spatrick                 for (size_t regex_idx = regex_start_index,
545061da546Spatrick                             end_index = regex_var_list.GetSize();
546061da546Spatrick                      regex_idx < end_index; ++regex_idx) {
547061da546Spatrick                   var_sp = regex_var_list.GetVariableAtIndex(regex_idx);
548061da546Spatrick                   if (var_sp) {
549061da546Spatrick                     valobj_sp = frame->GetValueObjectForFrameVariable(
550061da546Spatrick                         var_sp, m_varobj_options.use_dynamic);
551061da546Spatrick                     if (valobj_sp) {
552061da546Spatrick                       std::string scope_string;
553061da546Spatrick                       if (m_option_variable.show_scope)
554061da546Spatrick                         scope_string = GetScopeString(var_sp).str();
555061da546Spatrick 
556061da546Spatrick                       if (!scope_string.empty())
557061da546Spatrick                         s.PutCString(scope_string);
558061da546Spatrick 
559061da546Spatrick                       if (m_option_variable.show_decl &&
560061da546Spatrick                           var_sp->GetDeclaration().GetFile()) {
561061da546Spatrick                         bool show_fullpaths = false;
562061da546Spatrick                         bool show_module = true;
563061da546Spatrick                         if (var_sp->DumpDeclaration(&s, show_fullpaths,
564061da546Spatrick                                                     show_module))
565061da546Spatrick                           s.PutCString(": ");
566061da546Spatrick                       }
567061da546Spatrick                       valobj_sp->Dump(result.GetOutputStream(), options);
568061da546Spatrick                     }
569061da546Spatrick                   }
570061da546Spatrick                 }
571061da546Spatrick               } else if (num_matches == 0) {
572061da546Spatrick                 result.GetErrorStream().Printf("error: no variables matched "
573061da546Spatrick                                                "the regular expression '%s'.\n",
574061da546Spatrick                                                entry.c_str());
575061da546Spatrick               }
576061da546Spatrick             } else {
577061da546Spatrick               if (llvm::Error err = regex.GetError())
578061da546Spatrick                 result.GetErrorStream().Printf(
579061da546Spatrick                     "error: %s\n", llvm::toString(std::move(err)).c_str());
580061da546Spatrick               else
581061da546Spatrick                 result.GetErrorStream().Printf(
582061da546Spatrick                     "error: unknown regex error when compiling '%s'\n",
583061da546Spatrick                     entry.c_str());
584061da546Spatrick             }
585061da546Spatrick           } else // No regex, either exact variable names or variable
586061da546Spatrick                  // expressions.
587061da546Spatrick           {
588061da546Spatrick             Status error;
589061da546Spatrick             uint32_t expr_path_options =
590061da546Spatrick                 StackFrame::eExpressionPathOptionCheckPtrVsMember |
591061da546Spatrick                 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
592061da546Spatrick                 StackFrame::eExpressionPathOptionsInspectAnonymousUnions;
593061da546Spatrick             lldb::VariableSP var_sp;
594061da546Spatrick             valobj_sp = frame->GetValueForVariableExpressionPath(
595061da546Spatrick                 entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
596061da546Spatrick                 var_sp, error);
597061da546Spatrick             if (valobj_sp) {
598061da546Spatrick               std::string scope_string;
599061da546Spatrick               if (m_option_variable.show_scope)
600061da546Spatrick                 scope_string = GetScopeString(var_sp).str();
601061da546Spatrick 
602061da546Spatrick               if (!scope_string.empty())
603061da546Spatrick                 s.PutCString(scope_string);
604061da546Spatrick               if (m_option_variable.show_decl && var_sp &&
605061da546Spatrick                   var_sp->GetDeclaration().GetFile()) {
606061da546Spatrick                 var_sp->GetDeclaration().DumpStopContext(&s, false);
607061da546Spatrick                 s.PutCString(": ");
608061da546Spatrick               }
609061da546Spatrick 
610061da546Spatrick               options.SetFormat(format);
611061da546Spatrick               options.SetVariableFormatDisplayLanguage(
612061da546Spatrick                   valobj_sp->GetPreferredDisplayLanguage());
613061da546Spatrick 
614061da546Spatrick               Stream &output_stream = result.GetOutputStream();
615061da546Spatrick               options.SetRootValueObjectName(
616061da546Spatrick                   valobj_sp->GetParent() ? entry.c_str() : nullptr);
617061da546Spatrick               valobj_sp->Dump(output_stream, options);
618061da546Spatrick             } else {
619061da546Spatrick               const char *error_cstr = error.AsCString(nullptr);
620061da546Spatrick               if (error_cstr)
621061da546Spatrick                 result.GetErrorStream().Printf("error: %s\n", error_cstr);
622061da546Spatrick               else
623061da546Spatrick                 result.GetErrorStream().Printf("error: unable to find any "
624061da546Spatrick                                                "variable expression path that "
625061da546Spatrick                                                "matches '%s'.\n",
626061da546Spatrick                                                entry.c_str());
627061da546Spatrick             }
628061da546Spatrick           }
629061da546Spatrick         }
630061da546Spatrick       } else // No command arg specified.  Use variable_list, instead.
631061da546Spatrick       {
632061da546Spatrick         const size_t num_variables = variable_list->GetSize();
633061da546Spatrick         if (num_variables > 0) {
634061da546Spatrick           for (size_t i = 0; i < num_variables; i++) {
635061da546Spatrick             var_sp = variable_list->GetVariableAtIndex(i);
636061da546Spatrick             switch (var_sp->GetScope()) {
637061da546Spatrick             case eValueTypeVariableGlobal:
638061da546Spatrick               if (!m_option_variable.show_globals)
639061da546Spatrick                 continue;
640061da546Spatrick               break;
641061da546Spatrick             case eValueTypeVariableStatic:
642061da546Spatrick               if (!m_option_variable.show_globals)
643061da546Spatrick                 continue;
644061da546Spatrick               break;
645061da546Spatrick             case eValueTypeVariableArgument:
646061da546Spatrick               if (!m_option_variable.show_args)
647061da546Spatrick                 continue;
648061da546Spatrick               break;
649061da546Spatrick             case eValueTypeVariableLocal:
650061da546Spatrick               if (!m_option_variable.show_locals)
651061da546Spatrick                 continue;
652061da546Spatrick               break;
653061da546Spatrick             default:
654061da546Spatrick               continue;
655061da546Spatrick               break;
656061da546Spatrick             }
657061da546Spatrick             std::string scope_string;
658061da546Spatrick             if (m_option_variable.show_scope)
659061da546Spatrick               scope_string = GetScopeString(var_sp).str();
660061da546Spatrick 
661061da546Spatrick             // Use the variable object code to make sure we are using the same
662061da546Spatrick             // APIs as the public API will be using...
663061da546Spatrick             valobj_sp = frame->GetValueObjectForFrameVariable(
664061da546Spatrick                 var_sp, m_varobj_options.use_dynamic);
665061da546Spatrick             if (valobj_sp) {
666061da546Spatrick               // When dumping all variables, don't print any variables that are
667061da546Spatrick               // not in scope to avoid extra unneeded output
668061da546Spatrick               if (valobj_sp->IsInScope()) {
669061da546Spatrick                 if (!valobj_sp->GetTargetSP()
670061da546Spatrick                          ->GetDisplayRuntimeSupportValues() &&
671061da546Spatrick                     valobj_sp->IsRuntimeSupportValue())
672061da546Spatrick                   continue;
673061da546Spatrick 
674061da546Spatrick                 if (!scope_string.empty())
675061da546Spatrick                   s.PutCString(scope_string);
676061da546Spatrick 
677061da546Spatrick                 if (m_option_variable.show_decl &&
678061da546Spatrick                     var_sp->GetDeclaration().GetFile()) {
679061da546Spatrick                   var_sp->GetDeclaration().DumpStopContext(&s, false);
680061da546Spatrick                   s.PutCString(": ");
681061da546Spatrick                 }
682061da546Spatrick 
683061da546Spatrick                 options.SetFormat(format);
684061da546Spatrick                 options.SetVariableFormatDisplayLanguage(
685061da546Spatrick                     valobj_sp->GetPreferredDisplayLanguage());
686061da546Spatrick                 options.SetRootValueObjectName(
687061da546Spatrick                     var_sp ? var_sp->GetName().AsCString() : nullptr);
688061da546Spatrick                 valobj_sp->Dump(result.GetOutputStream(), options);
689061da546Spatrick               }
690061da546Spatrick             }
691061da546Spatrick           }
692061da546Spatrick         }
693061da546Spatrick       }
694061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishResult);
695061da546Spatrick     }
696061da546Spatrick 
697061da546Spatrick     if (m_option_variable.show_recognized_args) {
698061da546Spatrick       auto recognized_frame = frame->GetRecognizedFrame();
699061da546Spatrick       if (recognized_frame) {
700061da546Spatrick         ValueObjectListSP recognized_arg_list =
701061da546Spatrick             recognized_frame->GetRecognizedArguments();
702061da546Spatrick         if (recognized_arg_list) {
703061da546Spatrick           for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
704061da546Spatrick             options.SetFormat(m_option_format.GetFormat());
705061da546Spatrick             options.SetVariableFormatDisplayLanguage(
706061da546Spatrick                 rec_value_sp->GetPreferredDisplayLanguage());
707061da546Spatrick             options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
708061da546Spatrick             rec_value_sp->Dump(result.GetOutputStream(), options);
709061da546Spatrick           }
710061da546Spatrick         }
711061da546Spatrick       }
712061da546Spatrick     }
713061da546Spatrick 
714061da546Spatrick     if (m_interpreter.TruncationWarningNecessary()) {
715061da546Spatrick       result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
716061da546Spatrick                                       m_cmd_name.c_str());
717061da546Spatrick       m_interpreter.TruncationWarningGiven();
718061da546Spatrick     }
719061da546Spatrick 
720061da546Spatrick     // Increment statistics.
721061da546Spatrick     bool res = result.Succeeded();
722061da546Spatrick     Target &target = GetSelectedOrDummyTarget();
723061da546Spatrick     if (res)
724061da546Spatrick       target.IncrementStats(StatisticKind::FrameVarSuccess);
725061da546Spatrick     else
726061da546Spatrick       target.IncrementStats(StatisticKind::FrameVarFailure);
727061da546Spatrick     return res;
728061da546Spatrick   }
729061da546Spatrick 
730061da546Spatrick   OptionGroupOptions m_option_group;
731061da546Spatrick   OptionGroupVariable m_option_variable;
732061da546Spatrick   OptionGroupFormat m_option_format;
733061da546Spatrick   OptionGroupValueObjectDisplay m_varobj_options;
734061da546Spatrick };
735061da546Spatrick 
736061da546Spatrick #pragma mark CommandObjectFrameRecognizer
737061da546Spatrick 
738061da546Spatrick #define LLDB_OPTIONS_frame_recognizer_add
739061da546Spatrick #include "CommandOptions.inc"
740061da546Spatrick 
741061da546Spatrick class CommandObjectFrameRecognizerAdd : public CommandObjectParsed {
742061da546Spatrick private:
743061da546Spatrick   class CommandOptions : public Options {
744061da546Spatrick   public:
745061da546Spatrick     CommandOptions() : Options() {}
746061da546Spatrick     ~CommandOptions() override = default;
747061da546Spatrick 
748061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
749061da546Spatrick                           ExecutionContext *execution_context) override {
750061da546Spatrick       Status error;
751061da546Spatrick       const int short_option = m_getopt_table[option_idx].val;
752061da546Spatrick 
753061da546Spatrick       switch (short_option) {
754061da546Spatrick       case 'l':
755061da546Spatrick         m_class_name = std::string(option_arg);
756061da546Spatrick         break;
757061da546Spatrick       case 's':
758061da546Spatrick         m_module = std::string(option_arg);
759061da546Spatrick         break;
760061da546Spatrick       case 'n':
761*dda28197Spatrick         m_symbols.push_back(std::string(option_arg));
762061da546Spatrick         break;
763061da546Spatrick       case 'x':
764061da546Spatrick         m_regex = true;
765061da546Spatrick         break;
766061da546Spatrick       default:
767061da546Spatrick         llvm_unreachable("Unimplemented option");
768061da546Spatrick       }
769061da546Spatrick 
770061da546Spatrick       return error;
771061da546Spatrick     }
772061da546Spatrick 
773061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
774061da546Spatrick       m_module = "";
775*dda28197Spatrick       m_symbols.clear();
776061da546Spatrick       m_class_name = "";
777061da546Spatrick       m_regex = false;
778061da546Spatrick     }
779061da546Spatrick 
780061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
781061da546Spatrick       return llvm::makeArrayRef(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;
787*dda28197Spatrick     std::vector<std::string> m_symbols;
788061da546Spatrick     bool m_regex;
789061da546Spatrick   };
790061da546Spatrick 
791061da546Spatrick   CommandOptions m_options;
792061da546Spatrick 
793061da546Spatrick   Options *GetOptions() override { return &m_options; }
794061da546Spatrick 
795061da546Spatrick protected:
796061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override;
797061da546Spatrick 
798061da546Spatrick public:
799061da546Spatrick   CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)
800061da546Spatrick       : CommandObjectParsed(interpreter, "frame recognizer add",
801061da546Spatrick                             "Add a new frame recognizer.", nullptr),
802061da546Spatrick         m_options() {
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
823061da546Spatrick         value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd)
824061da546Spatrick         return [value]
825061da546Spatrick       return []
826061da546Spatrick 
827061da546Spatrick The file containing this implementation can be imported via 'command script
828061da546Spatrick import' and then we can register this recognizer with 'frame recognizer add'.
829061da546Spatrick It's important to restrict the recognizer to the libc library (which is
830061da546Spatrick libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
831061da546Spatrick in other modules:
832061da546Spatrick 
833061da546Spatrick (lldb) command script import .../fd_recognizer.py
834061da546Spatrick (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
835061da546Spatrick 
836061da546Spatrick When the program is stopped at the beginning of the 'read' function in libc, we
837061da546Spatrick can view the recognizer arguments in 'frame variable':
838061da546Spatrick 
839061da546Spatrick (lldb) b read
840061da546Spatrick (lldb) r
841061da546Spatrick Process 1234 stopped
842061da546Spatrick * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
843061da546Spatrick     frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
844061da546Spatrick (lldb) frame variable
845061da546Spatrick (int) fd = 3
846061da546Spatrick 
847061da546Spatrick     )");
848061da546Spatrick   }
849061da546Spatrick   ~CommandObjectFrameRecognizerAdd() override = default;
850061da546Spatrick };
851061da546Spatrick 
852061da546Spatrick bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command,
853061da546Spatrick                                                 CommandReturnObject &result) {
854061da546Spatrick #if LLDB_ENABLE_PYTHON
855061da546Spatrick   if (m_options.m_class_name.empty()) {
856061da546Spatrick     result.AppendErrorWithFormat(
857061da546Spatrick         "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
858061da546Spatrick     result.SetStatus(eReturnStatusFailed);
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     result.SetStatus(eReturnStatusFailed);
866061da546Spatrick     return false;
867061da546Spatrick   }
868061da546Spatrick 
869*dda28197Spatrick   if (m_options.m_symbols.empty()) {
870*dda28197Spatrick     result.AppendErrorWithFormat(
871*dda28197Spatrick         "%s needs at least one symbol name (-n argument).\n",
872*dda28197Spatrick         m_cmd_name.c_str());
873*dda28197Spatrick     result.SetStatus(eReturnStatusFailed);
874*dda28197Spatrick     return false;
875*dda28197Spatrick   }
876*dda28197Spatrick 
877*dda28197Spatrick   if (m_options.m_regex && m_options.m_symbols.size() > 1) {
878*dda28197Spatrick     result.AppendErrorWithFormat(
879*dda28197Spatrick         "%s needs only one symbol regular expression (-n argument).\n",
880061da546Spatrick         m_cmd_name.c_str());
881061da546Spatrick     result.SetStatus(eReturnStatusFailed);
882061da546Spatrick     return false;
883061da546Spatrick   }
884061da546Spatrick 
885061da546Spatrick   ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
886061da546Spatrick 
887061da546Spatrick   if (interpreter &&
888061da546Spatrick       !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
889061da546Spatrick     result.AppendWarning("The provided class does not exist - please define it "
890061da546Spatrick                          "before attempting to use this frame recognizer");
891061da546Spatrick   }
892061da546Spatrick 
893061da546Spatrick   StackFrameRecognizerSP recognizer_sp =
894061da546Spatrick       StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(
895061da546Spatrick           interpreter, m_options.m_class_name.c_str()));
896061da546Spatrick   if (m_options.m_regex) {
897061da546Spatrick     auto module =
898061da546Spatrick         RegularExpressionSP(new RegularExpression(m_options.m_module));
899061da546Spatrick     auto func =
900*dda28197Spatrick         RegularExpressionSP(new RegularExpression(m_options.m_symbols.front()));
901061da546Spatrick     StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
902061da546Spatrick   } else {
903061da546Spatrick     auto module = ConstString(m_options.m_module);
904*dda28197Spatrick     std::vector<ConstString> symbols(m_options.m_symbols.begin(),
905*dda28197Spatrick                                      m_options.m_symbols.end());
906*dda28197Spatrick     StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, symbols);
907061da546Spatrick   }
908061da546Spatrick #endif
909061da546Spatrick 
910061da546Spatrick   result.SetStatus(eReturnStatusSuccessFinishNoResult);
911061da546Spatrick   return result.Succeeded();
912061da546Spatrick }
913061da546Spatrick 
914061da546Spatrick class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
915061da546Spatrick public:
916061da546Spatrick   CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
917061da546Spatrick       : CommandObjectParsed(interpreter, "frame recognizer clear",
918061da546Spatrick                             "Delete all frame recognizers.", nullptr) {}
919061da546Spatrick 
920061da546Spatrick   ~CommandObjectFrameRecognizerClear() override = default;
921061da546Spatrick 
922061da546Spatrick protected:
923061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
924061da546Spatrick     StackFrameRecognizerManager::RemoveAllRecognizers();
925061da546Spatrick     result.SetStatus(eReturnStatusSuccessFinishResult);
926061da546Spatrick     return result.Succeeded();
927061da546Spatrick   }
928061da546Spatrick };
929061da546Spatrick 
930061da546Spatrick class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
931061da546Spatrick public:
932061da546Spatrick   CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
933061da546Spatrick       : CommandObjectParsed(interpreter, "frame recognizer delete",
934061da546Spatrick                             "Delete an existing frame recognizer.", nullptr) {}
935061da546Spatrick 
936061da546Spatrick   ~CommandObjectFrameRecognizerDelete() override = default;
937061da546Spatrick 
938*dda28197Spatrick   void
939*dda28197Spatrick   HandleArgumentCompletion(CompletionRequest &request,
940*dda28197Spatrick                            OptionElementVector &opt_element_vector) override {
941*dda28197Spatrick     if (request.GetCursorIndex() != 0)
942*dda28197Spatrick       return;
943*dda28197Spatrick 
944*dda28197Spatrick     StackFrameRecognizerManager::ForEach(
945*dda28197Spatrick         [&request](uint32_t rid, std::string rname, std::string module,
946*dda28197Spatrick                    llvm::ArrayRef<lldb_private::ConstString> symbols,
947*dda28197Spatrick                    bool regexp) {
948*dda28197Spatrick           StreamString strm;
949*dda28197Spatrick           if (rname.empty())
950*dda28197Spatrick             rname = "(internal)";
951*dda28197Spatrick 
952*dda28197Spatrick           strm << rname;
953*dda28197Spatrick           if (!module.empty())
954*dda28197Spatrick             strm << ", module " << module;
955*dda28197Spatrick           if (!symbols.empty())
956*dda28197Spatrick             for (auto &symbol : symbols)
957*dda28197Spatrick               strm << ", symbol " << symbol;
958*dda28197Spatrick           if (regexp)
959*dda28197Spatrick             strm << " (regexp)";
960*dda28197Spatrick 
961*dda28197Spatrick           request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString());
962*dda28197Spatrick         });
963*dda28197Spatrick   }
964*dda28197Spatrick 
965061da546Spatrick protected:
966061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
967061da546Spatrick     if (command.GetArgumentCount() == 0) {
968061da546Spatrick       if (!m_interpreter.Confirm(
969061da546Spatrick               "About to delete all frame recognizers, do you want to do that?",
970061da546Spatrick               true)) {
971061da546Spatrick         result.AppendMessage("Operation cancelled...");
972061da546Spatrick         result.SetStatus(eReturnStatusFailed);
973061da546Spatrick         return false;
974061da546Spatrick       }
975061da546Spatrick 
976061da546Spatrick       StackFrameRecognizerManager::RemoveAllRecognizers();
977061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishResult);
978061da546Spatrick       return result.Succeeded();
979061da546Spatrick     }
980061da546Spatrick 
981061da546Spatrick     if (command.GetArgumentCount() != 1) {
982061da546Spatrick       result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
983061da546Spatrick                                    m_cmd_name.c_str());
984061da546Spatrick       result.SetStatus(eReturnStatusFailed);
985061da546Spatrick       return false;
986061da546Spatrick     }
987061da546Spatrick 
988*dda28197Spatrick     uint32_t recognizer_id;
989*dda28197Spatrick     if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) {
990*dda28197Spatrick       result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
991*dda28197Spatrick                                    command.GetArgumentAtIndex(0));
992*dda28197Spatrick       result.SetStatus(eReturnStatusFailed);
993*dda28197Spatrick       return false;
994*dda28197Spatrick     }
995061da546Spatrick 
996061da546Spatrick     StackFrameRecognizerManager::RemoveRecognizerWithID(recognizer_id);
997061da546Spatrick     result.SetStatus(eReturnStatusSuccessFinishResult);
998061da546Spatrick     return result.Succeeded();
999061da546Spatrick   }
1000061da546Spatrick };
1001061da546Spatrick 
1002061da546Spatrick class CommandObjectFrameRecognizerList : public CommandObjectParsed {
1003061da546Spatrick public:
1004061da546Spatrick   CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
1005061da546Spatrick       : CommandObjectParsed(interpreter, "frame recognizer list",
1006061da546Spatrick                             "Show a list of active frame recognizers.",
1007061da546Spatrick                             nullptr) {}
1008061da546Spatrick 
1009061da546Spatrick   ~CommandObjectFrameRecognizerList() override = default;
1010061da546Spatrick 
1011061da546Spatrick protected:
1012061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
1013061da546Spatrick     bool any_printed = false;
1014061da546Spatrick     StackFrameRecognizerManager::ForEach(
1015*dda28197Spatrick         [&result, &any_printed](
1016*dda28197Spatrick             uint32_t recognizer_id, std::string name, std::string module,
1017*dda28197Spatrick             llvm::ArrayRef<ConstString> symbols, bool regexp) {
1018*dda28197Spatrick           Stream &stream = result.GetOutputStream();
1019*dda28197Spatrick 
1020*dda28197Spatrick           if (name.empty())
1021061da546Spatrick             name = "(internal)";
1022*dda28197Spatrick 
1023*dda28197Spatrick           stream << std::to_string(recognizer_id) << ": " << name;
1024*dda28197Spatrick           if (!module.empty())
1025*dda28197Spatrick             stream << ", module " << module;
1026*dda28197Spatrick           if (!symbols.empty())
1027*dda28197Spatrick             for (auto &symbol : symbols)
1028*dda28197Spatrick               stream << ", symbol " << symbol;
1029*dda28197Spatrick           if (regexp)
1030*dda28197Spatrick             stream << " (regexp)";
1031*dda28197Spatrick 
1032*dda28197Spatrick           stream.EOL();
1033*dda28197Spatrick           stream.Flush();
1034*dda28197Spatrick 
1035061da546Spatrick           any_printed = true;
1036061da546Spatrick         });
1037061da546Spatrick 
1038061da546Spatrick     if (any_printed)
1039061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishResult);
1040061da546Spatrick     else {
1041061da546Spatrick       result.GetOutputStream().PutCString("no matching results found.\n");
1042061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1043061da546Spatrick     }
1044061da546Spatrick     return result.Succeeded();
1045061da546Spatrick   }
1046061da546Spatrick };
1047061da546Spatrick 
1048061da546Spatrick class CommandObjectFrameRecognizerInfo : public CommandObjectParsed {
1049061da546Spatrick public:
1050061da546Spatrick   CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
1051061da546Spatrick       : CommandObjectParsed(
1052061da546Spatrick             interpreter, "frame recognizer info",
1053061da546Spatrick             "Show which frame recognizer is applied a stack frame (if any).",
1054061da546Spatrick             nullptr) {
1055061da546Spatrick     CommandArgumentEntry arg;
1056061da546Spatrick     CommandArgumentData index_arg;
1057061da546Spatrick 
1058061da546Spatrick     // Define the first (and only) variant of this arg.
1059061da546Spatrick     index_arg.arg_type = eArgTypeFrameIndex;
1060061da546Spatrick     index_arg.arg_repetition = eArgRepeatPlain;
1061061da546Spatrick 
1062061da546Spatrick     // There is only one variant this argument could be; put it into the
1063061da546Spatrick     // argument entry.
1064061da546Spatrick     arg.push_back(index_arg);
1065061da546Spatrick 
1066061da546Spatrick     // Push the data for the first argument into the m_arguments vector.
1067061da546Spatrick     m_arguments.push_back(arg);
1068061da546Spatrick   }
1069061da546Spatrick 
1070061da546Spatrick   ~CommandObjectFrameRecognizerInfo() override = default;
1071061da546Spatrick 
1072061da546Spatrick protected:
1073061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
1074*dda28197Spatrick     const char *frame_index_str = command.GetArgumentAtIndex(0);
1075*dda28197Spatrick     uint32_t frame_index;
1076*dda28197Spatrick     if (!llvm::to_integer(frame_index_str, frame_index)) {
1077*dda28197Spatrick       result.AppendErrorWithFormat("'%s' is not a valid frame index.",
1078*dda28197Spatrick                                    frame_index_str);
1079*dda28197Spatrick       result.SetStatus(eReturnStatusFailed);
1080*dda28197Spatrick       return false;
1081*dda28197Spatrick     }
1082*dda28197Spatrick 
1083061da546Spatrick     Process *process = m_exe_ctx.GetProcessPtr();
1084061da546Spatrick     if (process == nullptr) {
1085061da546Spatrick       result.AppendError("no process");
1086061da546Spatrick       result.SetStatus(eReturnStatusFailed);
1087061da546Spatrick       return false;
1088061da546Spatrick     }
1089061da546Spatrick     Thread *thread = m_exe_ctx.GetThreadPtr();
1090061da546Spatrick     if (thread == nullptr) {
1091061da546Spatrick       result.AppendError("no thread");
1092061da546Spatrick       result.SetStatus(eReturnStatusFailed);
1093061da546Spatrick       return false;
1094061da546Spatrick     }
1095061da546Spatrick     if (command.GetArgumentCount() != 1) {
1096061da546Spatrick       result.AppendErrorWithFormat(
1097061da546Spatrick           "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
1098061da546Spatrick       result.SetStatus(eReturnStatusFailed);
1099061da546Spatrick       return false;
1100061da546Spatrick     }
1101061da546Spatrick 
1102061da546Spatrick     StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
1103061da546Spatrick     if (!frame_sp) {
1104061da546Spatrick       result.AppendErrorWithFormat("no frame with index %u", frame_index);
1105061da546Spatrick       result.SetStatus(eReturnStatusFailed);
1106061da546Spatrick       return false;
1107061da546Spatrick     }
1108061da546Spatrick 
1109061da546Spatrick     auto recognizer =
1110061da546Spatrick         StackFrameRecognizerManager::GetRecognizerForFrame(frame_sp);
1111061da546Spatrick 
1112061da546Spatrick     Stream &output_stream = result.GetOutputStream();
1113061da546Spatrick     output_stream.Printf("frame %d ", frame_index);
1114061da546Spatrick     if (recognizer) {
1115061da546Spatrick       output_stream << "is recognized by ";
1116061da546Spatrick       output_stream << recognizer->GetName();
1117061da546Spatrick     } else {
1118061da546Spatrick       output_stream << "not recognized by any recognizer";
1119061da546Spatrick     }
1120061da546Spatrick     output_stream.EOL();
1121061da546Spatrick     result.SetStatus(eReturnStatusSuccessFinishResult);
1122061da546Spatrick     return result.Succeeded();
1123061da546Spatrick   }
1124061da546Spatrick };
1125061da546Spatrick 
1126061da546Spatrick class CommandObjectFrameRecognizer : public CommandObjectMultiword {
1127061da546Spatrick public:
1128061da546Spatrick   CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
1129061da546Spatrick       : CommandObjectMultiword(
1130061da546Spatrick             interpreter, "frame recognizer",
1131061da546Spatrick             "Commands for editing and viewing frame recognizers.",
1132061da546Spatrick             "frame recognizer [<sub-command-options>] ") {
1133061da546Spatrick     LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd(
1134061da546Spatrick                               interpreter)));
1135061da546Spatrick     LoadSubCommand(
1136061da546Spatrick         "clear",
1137061da546Spatrick         CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter)));
1138061da546Spatrick     LoadSubCommand(
1139061da546Spatrick         "delete",
1140061da546Spatrick         CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter)));
1141061da546Spatrick     LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList(
1142061da546Spatrick                                interpreter)));
1143061da546Spatrick     LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo(
1144061da546Spatrick                                interpreter)));
1145061da546Spatrick   }
1146061da546Spatrick 
1147061da546Spatrick   ~CommandObjectFrameRecognizer() override = default;
1148061da546Spatrick };
1149061da546Spatrick 
1150061da546Spatrick #pragma mark CommandObjectMultiwordFrame
1151061da546Spatrick 
1152061da546Spatrick // CommandObjectMultiwordFrame
1153061da546Spatrick 
1154061da546Spatrick CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
1155061da546Spatrick     CommandInterpreter &interpreter)
1156061da546Spatrick     : CommandObjectMultiword(interpreter, "frame",
1157061da546Spatrick                              "Commands for selecting and "
1158061da546Spatrick                              "examing the current "
1159061da546Spatrick                              "thread's stack frames.",
1160061da546Spatrick                              "frame <subcommand> [<subcommand-options>]") {
1161061da546Spatrick   LoadSubCommand("diagnose",
1162061da546Spatrick                  CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
1163061da546Spatrick   LoadSubCommand("info",
1164061da546Spatrick                  CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1165061da546Spatrick   LoadSubCommand("select",
1166061da546Spatrick                  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1167061da546Spatrick   LoadSubCommand("variable",
1168061da546Spatrick                  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
1169061da546Spatrick #if LLDB_ENABLE_PYTHON
1170061da546Spatrick   LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer(
1171061da546Spatrick                                    interpreter)));
1172061da546Spatrick #endif
1173061da546Spatrick }
1174061da546Spatrick 
1175061da546Spatrick CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
1176