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