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