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