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