[PowerPC] Collect some CallLowering arguments into a struct. [NFC]
[llvm-project.git] / lldb / source / Commands / CommandObjectFrame.cpp
blob50d5c751de5c06ceac8b9bafbea558ebdf089712
1 //===-- CommandObjectFrame.cpp ----------------------------------*- C++ -*-===//
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/Host/StringConvert.h"
16 #include "lldb/Interpreter/CommandInterpreter.h"
17 #include "lldb/Interpreter/CommandReturnObject.h"
18 #include "lldb/Interpreter/OptionGroupFormat.h"
19 #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
20 #include "lldb/Interpreter/OptionGroupVariable.h"
21 #include "lldb/Interpreter/Options.h"
22 #include "lldb/Symbol/Function.h"
23 #include "lldb/Symbol/SymbolContext.h"
24 #include "lldb/Symbol/Variable.h"
25 #include "lldb/Symbol/VariableList.h"
26 #include "lldb/Target/StackFrame.h"
27 #include "lldb/Target/StackFrameRecognizer.h"
28 #include "lldb/Target/StopInfo.h"
29 #include "lldb/Target/Target.h"
30 #include "lldb/Target/Thread.h"
31 #include "lldb/Utility/Args.h"
33 #include <memory>
34 #include <string>
36 using namespace lldb;
37 using namespace lldb_private;
39 #pragma mark CommandObjectFrameDiagnose
41 // CommandObjectFrameInfo
43 // CommandObjectFrameDiagnose
45 #define LLDB_OPTIONS_frame_diag
46 #include "CommandOptions.inc"
48 class CommandObjectFrameDiagnose : public CommandObjectParsed {
49 public:
50 class CommandOptions : public Options {
51 public:
52 CommandOptions() : Options() { OptionParsingStarting(nullptr); }
54 ~CommandOptions() override = default;
56 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
57 ExecutionContext *execution_context) override {
58 Status error;
59 const int short_option = m_getopt_table[option_idx].val;
60 switch (short_option) {
61 case 'r':
62 reg = ConstString(option_arg);
63 break;
65 case 'a': {
66 address.emplace();
67 if (option_arg.getAsInteger(0, *address)) {
68 address.reset();
69 error.SetErrorStringWithFormat("invalid address argument '%s'",
70 option_arg.str().c_str());
72 } break;
74 case 'o': {
75 offset.emplace();
76 if (option_arg.getAsInteger(0, *offset)) {
77 offset.reset();
78 error.SetErrorStringWithFormat("invalid offset argument '%s'",
79 option_arg.str().c_str());
81 } break;
83 default:
84 llvm_unreachable("Unimplemented option");
87 return error;
90 void OptionParsingStarting(ExecutionContext *execution_context) override {
91 address.reset();
92 reg.reset();
93 offset.reset();
96 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
97 return llvm::makeArrayRef(g_frame_diag_options);
100 // Options.
101 llvm::Optional<lldb::addr_t> address;
102 llvm::Optional<ConstString> reg;
103 llvm::Optional<int64_t> offset;
106 CommandObjectFrameDiagnose(CommandInterpreter &interpreter)
107 : CommandObjectParsed(interpreter, "frame diagnose",
108 "Try to determine what path path the current stop "
109 "location used to get to a register or address",
110 nullptr,
111 eCommandRequiresThread | eCommandTryTargetAPILock |
112 eCommandProcessMustBeLaunched |
113 eCommandProcessMustBePaused),
114 m_options() {
115 CommandArgumentEntry arg;
116 CommandArgumentData index_arg;
118 // Define the first (and only) variant of this arg.
119 index_arg.arg_type = eArgTypeFrameIndex;
120 index_arg.arg_repetition = eArgRepeatOptional;
122 // There is only one variant this argument could be; put it into the
123 // argument entry.
124 arg.push_back(index_arg);
126 // Push the data for the first argument into the m_arguments vector.
127 m_arguments.push_back(arg);
130 ~CommandObjectFrameDiagnose() override = default;
132 Options *GetOptions() override { return &m_options; }
134 protected:
135 bool DoExecute(Args &command, CommandReturnObject &result) override {
136 Thread *thread = m_exe_ctx.GetThreadPtr();
137 StackFrameSP frame_sp = thread->GetSelectedFrame();
139 ValueObjectSP valobj_sp;
141 if (m_options.address.hasValue()) {
142 if (m_options.reg.hasValue() || m_options.offset.hasValue()) {
143 result.AppendError(
144 "`frame diagnose --address` is incompatible with other arguments.");
145 result.SetStatus(eReturnStatusFailed);
146 return false;
148 valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue());
149 } else if (m_options.reg.hasValue()) {
150 valobj_sp = frame_sp->GuessValueForRegisterAndOffset(
151 m_options.reg.getValue(), m_options.offset.getValueOr(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 result.SetStatus(eReturnStatusFailed);
157 return false;
160 valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
163 if (!valobj_sp) {
164 result.AppendError("No diagnosis available.");
165 result.SetStatus(eReturnStatusFailed);
166 return false;
169 DumpValueObjectOptions::DeclPrintingHelper helper =
170 [&valobj_sp](ConstString type, ConstString var,
171 const DumpValueObjectOptions &opts,
172 Stream &stream) -> bool {
173 const ValueObject::GetExpressionPathFormat format = ValueObject::
174 GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
175 const bool qualify_cxx_base_classes = false;
176 valobj_sp->GetExpressionPath(stream, qualify_cxx_base_classes, format);
177 stream.PutCString(" =");
178 return true;
181 DumpValueObjectOptions options;
182 options.SetDeclPrintingHelper(helper);
183 ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(),
184 options);
185 printer.PrintValueObject();
187 return true;
190 protected:
191 CommandOptions m_options;
194 #pragma mark CommandObjectFrameInfo
196 // CommandObjectFrameInfo
198 class CommandObjectFrameInfo : public CommandObjectParsed {
199 public:
200 CommandObjectFrameInfo(CommandInterpreter &interpreter)
201 : CommandObjectParsed(interpreter, "frame info",
202 "List information about the current "
203 "stack frame in the current thread.",
204 "frame info",
205 eCommandRequiresFrame | eCommandTryTargetAPILock |
206 eCommandProcessMustBeLaunched |
207 eCommandProcessMustBePaused) {}
209 ~CommandObjectFrameInfo() override = default;
211 protected:
212 bool DoExecute(Args &command, CommandReturnObject &result) override {
213 m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream());
214 result.SetStatus(eReturnStatusSuccessFinishResult);
215 return result.Succeeded();
219 #pragma mark CommandObjectFrameSelect
221 // CommandObjectFrameSelect
223 #define LLDB_OPTIONS_frame_select
224 #include "CommandOptions.inc"
226 class CommandObjectFrameSelect : public CommandObjectParsed {
227 public:
228 class CommandOptions : public Options {
229 public:
230 CommandOptions() : Options() { OptionParsingStarting(nullptr); }
232 ~CommandOptions() override = default;
234 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
235 ExecutionContext *execution_context) override {
236 Status error;
237 const int short_option = m_getopt_table[option_idx].val;
238 switch (short_option) {
239 case 'r': {
240 int32_t offset = 0;
241 if (option_arg.getAsInteger(0, offset) || offset == INT32_MIN) {
242 error.SetErrorStringWithFormat("invalid frame offset argument '%s'",
243 option_arg.str().c_str());
244 } else
245 relative_frame_offset = offset;
246 break;
249 default:
250 llvm_unreachable("Unimplemented option");
253 return error;
256 void OptionParsingStarting(ExecutionContext *execution_context) override {
257 relative_frame_offset.reset();
260 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
261 return llvm::makeArrayRef(g_frame_select_options);
264 llvm::Optional<int32_t> relative_frame_offset;
267 CommandObjectFrameSelect(CommandInterpreter &interpreter)
268 : CommandObjectParsed(interpreter, "frame select",
269 "Select the current stack frame by "
270 "index from within the current thread "
271 "(see 'thread backtrace'.)",
272 nullptr,
273 eCommandRequiresThread | eCommandTryTargetAPILock |
274 eCommandProcessMustBeLaunched |
275 eCommandProcessMustBePaused),
276 m_options() {
277 CommandArgumentEntry arg;
278 CommandArgumentData index_arg;
280 // Define the first (and only) variant of this arg.
281 index_arg.arg_type = eArgTypeFrameIndex;
282 index_arg.arg_repetition = eArgRepeatOptional;
284 // There is only one variant this argument could be; put it into the
285 // argument entry.
286 arg.push_back(index_arg);
288 // Push the data for the first argument into the m_arguments vector.
289 m_arguments.push_back(arg);
292 ~CommandObjectFrameSelect() override = default;
294 Options *GetOptions() override { return &m_options; }
296 protected:
297 bool DoExecute(Args &command, CommandReturnObject &result) override {
298 // No need to check "thread" for validity as eCommandRequiresThread ensures
299 // it is valid
300 Thread *thread = m_exe_ctx.GetThreadPtr();
302 uint32_t frame_idx = UINT32_MAX;
303 if (m_options.relative_frame_offset.hasValue()) {
304 // The one and only argument is a signed relative frame index
305 frame_idx = thread->GetSelectedFrameIndex();
306 if (frame_idx == UINT32_MAX)
307 frame_idx = 0;
309 if (*m_options.relative_frame_offset < 0) {
310 if (static_cast<int32_t>(frame_idx) >=
311 -*m_options.relative_frame_offset)
312 frame_idx += *m_options.relative_frame_offset;
313 else {
314 if (frame_idx == 0) {
315 // If you are already at the bottom of the stack, then just warn
316 // and don't reset the frame.
317 result.AppendError("Already at the bottom of the stack.");
318 result.SetStatus(eReturnStatusFailed);
319 return false;
320 } else
321 frame_idx = 0;
323 } else if (*m_options.relative_frame_offset > 0) {
324 // I don't want "up 20" where "20" takes you past the top of the stack
325 // to produce
326 // an error, but rather to just go to the top. So I have to count the
327 // stack here...
328 const uint32_t num_frames = thread->GetStackFrameCount();
329 if (static_cast<int32_t>(num_frames - frame_idx) >
330 *m_options.relative_frame_offset)
331 frame_idx += *m_options.relative_frame_offset;
332 else {
333 if (frame_idx == num_frames - 1) {
334 // If we are already at the top of the stack, just warn and don't
335 // reset the frame.
336 result.AppendError("Already at the top of the stack.");
337 result.SetStatus(eReturnStatusFailed);
338 return false;
339 } else
340 frame_idx = num_frames - 1;
343 } else {
344 if (command.GetArgumentCount() > 1) {
345 result.AppendErrorWithFormat(
346 "too many arguments; expected frame-index, saw '%s'.\n",
347 command[0].c_str());
348 m_options.GenerateOptionUsage(
349 result.GetErrorStream(), this,
350 GetCommandInterpreter().GetDebugger().GetTerminalWidth());
351 return false;
354 if (command.GetArgumentCount() == 1) {
355 if (command[0].ref().getAsInteger(0, frame_idx)) {
356 result.AppendErrorWithFormat("invalid frame index argument '%s'.",
357 command[0].c_str());
358 result.SetStatus(eReturnStatusFailed);
359 return false;
361 } else if (command.GetArgumentCount() == 0) {
362 frame_idx = thread->GetSelectedFrameIndex();
363 if (frame_idx == UINT32_MAX) {
364 frame_idx = 0;
369 bool success = thread->SetSelectedFrameByIndexNoisily(
370 frame_idx, result.GetOutputStream());
371 if (success) {
372 m_exe_ctx.SetFrameSP(thread->GetSelectedFrame());
373 result.SetStatus(eReturnStatusSuccessFinishResult);
374 } else {
375 result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
376 frame_idx);
377 result.SetStatus(eReturnStatusFailed);
380 return result.Succeeded();
383 protected:
384 CommandOptions m_options;
387 #pragma mark CommandObjectFrameVariable
388 // List images with associated information
389 class CommandObjectFrameVariable : public CommandObjectParsed {
390 public:
391 CommandObjectFrameVariable(CommandInterpreter &interpreter)
392 : CommandObjectParsed(
393 interpreter, "frame variable",
394 "Show variables for the current stack frame. Defaults to all "
395 "arguments and local variables in scope. Names of argument, "
396 "local, file static and file global variables can be specified. "
397 "Children of aggregate variables can be specified such as "
398 "'var->child.x'. The -> and [] operators in 'frame variable' do "
399 "not invoke operator overloads if they exist, but directly access "
400 "the specified element. If you want to trigger operator overloads "
401 "use the expression command to print the variable instead."
402 "\nIt is worth noting that except for overloaded "
403 "operators, when printing local variables 'expr local_var' and "
404 "'frame var local_var' produce the same "
405 "results. However, 'frame variable' is more efficient, since it "
406 "uses debug information and memory reads directly, rather than "
407 "parsing and evaluating an expression, which may even involve "
408 "JITing and running code in the target program.",
409 nullptr,
410 eCommandRequiresFrame | eCommandTryTargetAPILock |
411 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
412 eCommandRequiresProcess),
413 m_option_group(),
414 m_option_variable(
415 true), // Include the frame specific options by passing "true"
416 m_option_format(eFormatDefault), m_varobj_options() {
417 CommandArgumentEntry arg;
418 CommandArgumentData var_name_arg;
420 // Define the first (and only) variant of this arg.
421 var_name_arg.arg_type = eArgTypeVarName;
422 var_name_arg.arg_repetition = eArgRepeatStar;
424 // There is only one variant this argument could be; put it into the
425 // argument entry.
426 arg.push_back(var_name_arg);
428 // Push the data for the first argument into the m_arguments vector.
429 m_arguments.push_back(arg);
431 m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
432 m_option_group.Append(&m_option_format,
433 OptionGroupFormat::OPTION_GROUP_FORMAT |
434 OptionGroupFormat::OPTION_GROUP_GDB_FMT,
435 LLDB_OPT_SET_1);
436 m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
437 m_option_group.Finalize();
440 ~CommandObjectFrameVariable() override = default;
442 Options *GetOptions() override { return &m_option_group; }
444 void
445 HandleArgumentCompletion(CompletionRequest &request,
446 OptionElementVector &opt_element_vector) override {
447 // Arguments are the standard source file completer.
448 CommandCompletions::InvokeCommonCompletionCallbacks(
449 GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion,
450 request, nullptr);
453 protected:
454 llvm::StringRef GetScopeString(VariableSP var_sp) {
455 if (!var_sp)
456 return llvm::StringRef::withNullAsEmpty(nullptr);
458 switch (var_sp->GetScope()) {
459 case eValueTypeVariableGlobal:
460 return "GLOBAL: ";
461 case eValueTypeVariableStatic:
462 return "STATIC: ";
463 case eValueTypeVariableArgument:
464 return "ARG: ";
465 case eValueTypeVariableLocal:
466 return "LOCAL: ";
467 case eValueTypeVariableThreadLocal:
468 return "THREAD: ";
469 default:
470 break;
473 return llvm::StringRef::withNullAsEmpty(nullptr);
476 bool DoExecute(Args &command, CommandReturnObject &result) override {
477 // No need to check "frame" for validity as eCommandRequiresFrame ensures
478 // it is valid
479 StackFrame *frame = m_exe_ctx.GetFramePtr();
481 Stream &s = result.GetOutputStream();
483 // Be careful about the stack frame, if any summary formatter runs code, it
484 // might clear the StackFrameList for the thread. So hold onto a shared
485 // pointer to the frame so it stays alive.
487 VariableList *variable_list =
488 frame->GetVariableList(m_option_variable.show_globals);
490 VariableSP var_sp;
491 ValueObjectSP valobj_sp;
493 TypeSummaryImplSP summary_format_sp;
494 if (!m_option_variable.summary.IsCurrentValueEmpty())
495 DataVisualization::NamedSummaryFormats::GetSummaryFormat(
496 ConstString(m_option_variable.summary.GetCurrentValue()),
497 summary_format_sp);
498 else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
499 summary_format_sp = std::make_shared<StringSummaryFormat>(
500 TypeSummaryImpl::Flags(),
501 m_option_variable.summary_string.GetCurrentValue());
503 DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
504 eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault,
505 summary_format_sp));
507 const SymbolContext &sym_ctx =
508 frame->GetSymbolContext(eSymbolContextFunction);
509 if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
510 m_option_variable.show_globals = true;
512 if (variable_list) {
513 const Format format = m_option_format.GetFormat();
514 options.SetFormat(format);
516 if (!command.empty()) {
517 VariableList regex_var_list;
519 // If we have any args to the variable command, we will make variable
520 // objects from them...
521 for (auto &entry : command) {
522 if (m_option_variable.use_regex) {
523 const size_t regex_start_index = regex_var_list.GetSize();
524 llvm::StringRef name_str = entry.ref();
525 RegularExpression regex(name_str);
526 if (regex.IsValid()) {
527 size_t num_matches = 0;
528 const size_t num_new_regex_vars =
529 variable_list->AppendVariablesIfUnique(regex, regex_var_list,
530 num_matches);
531 if (num_new_regex_vars > 0) {
532 for (size_t regex_idx = regex_start_index,
533 end_index = regex_var_list.GetSize();
534 regex_idx < end_index; ++regex_idx) {
535 var_sp = regex_var_list.GetVariableAtIndex(regex_idx);
536 if (var_sp) {
537 valobj_sp = frame->GetValueObjectForFrameVariable(
538 var_sp, m_varobj_options.use_dynamic);
539 if (valobj_sp) {
540 std::string scope_string;
541 if (m_option_variable.show_scope)
542 scope_string = GetScopeString(var_sp).str();
544 if (!scope_string.empty())
545 s.PutCString(scope_string);
547 if (m_option_variable.show_decl &&
548 var_sp->GetDeclaration().GetFile()) {
549 bool show_fullpaths = false;
550 bool show_module = true;
551 if (var_sp->DumpDeclaration(&s, show_fullpaths,
552 show_module))
553 s.PutCString(": ");
555 valobj_sp->Dump(result.GetOutputStream(), options);
559 } else if (num_matches == 0) {
560 result.GetErrorStream().Printf("error: no variables matched "
561 "the regular expression '%s'.\n",
562 entry.c_str());
564 } else {
565 if (llvm::Error err = regex.GetError())
566 result.GetErrorStream().Printf(
567 "error: %s\n", llvm::toString(std::move(err)).c_str());
568 else
569 result.GetErrorStream().Printf(
570 "error: unknown regex error when compiling '%s'\n",
571 entry.c_str());
573 } else // No regex, either exact variable names or variable
574 // expressions.
576 Status error;
577 uint32_t expr_path_options =
578 StackFrame::eExpressionPathOptionCheckPtrVsMember |
579 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
580 StackFrame::eExpressionPathOptionsInspectAnonymousUnions;
581 lldb::VariableSP var_sp;
582 valobj_sp = frame->GetValueForVariableExpressionPath(
583 entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
584 var_sp, error);
585 if (valobj_sp) {
586 std::string scope_string;
587 if (m_option_variable.show_scope)
588 scope_string = GetScopeString(var_sp).str();
590 if (!scope_string.empty())
591 s.PutCString(scope_string);
592 if (m_option_variable.show_decl && var_sp &&
593 var_sp->GetDeclaration().GetFile()) {
594 var_sp->GetDeclaration().DumpStopContext(&s, false);
595 s.PutCString(": ");
598 options.SetFormat(format);
599 options.SetVariableFormatDisplayLanguage(
600 valobj_sp->GetPreferredDisplayLanguage());
602 Stream &output_stream = result.GetOutputStream();
603 options.SetRootValueObjectName(
604 valobj_sp->GetParent() ? entry.c_str() : nullptr);
605 valobj_sp->Dump(output_stream, options);
606 } else {
607 const char *error_cstr = error.AsCString(nullptr);
608 if (error_cstr)
609 result.GetErrorStream().Printf("error: %s\n", error_cstr);
610 else
611 result.GetErrorStream().Printf("error: unable to find any "
612 "variable expression path that "
613 "matches '%s'.\n",
614 entry.c_str());
618 } else // No command arg specified. Use variable_list, instead.
620 const size_t num_variables = variable_list->GetSize();
621 if (num_variables > 0) {
622 for (size_t i = 0; i < num_variables; i++) {
623 var_sp = variable_list->GetVariableAtIndex(i);
624 switch (var_sp->GetScope()) {
625 case eValueTypeVariableGlobal:
626 if (!m_option_variable.show_globals)
627 continue;
628 break;
629 case eValueTypeVariableStatic:
630 if (!m_option_variable.show_globals)
631 continue;
632 break;
633 case eValueTypeVariableArgument:
634 if (!m_option_variable.show_args)
635 continue;
636 break;
637 case eValueTypeVariableLocal:
638 if (!m_option_variable.show_locals)
639 continue;
640 break;
641 default:
642 continue;
643 break;
645 std::string scope_string;
646 if (m_option_variable.show_scope)
647 scope_string = GetScopeString(var_sp).str();
649 // Use the variable object code to make sure we are using the same
650 // APIs as the public API will be using...
651 valobj_sp = frame->GetValueObjectForFrameVariable(
652 var_sp, m_varobj_options.use_dynamic);
653 if (valobj_sp) {
654 // When dumping all variables, don't print any variables that are
655 // not in scope to avoid extra unneeded output
656 if (valobj_sp->IsInScope()) {
657 if (!valobj_sp->GetTargetSP()
658 ->GetDisplayRuntimeSupportValues() &&
659 valobj_sp->IsRuntimeSupportValue())
660 continue;
662 if (!scope_string.empty())
663 s.PutCString(scope_string);
665 if (m_option_variable.show_decl &&
666 var_sp->GetDeclaration().GetFile()) {
667 var_sp->GetDeclaration().DumpStopContext(&s, false);
668 s.PutCString(": ");
671 options.SetFormat(format);
672 options.SetVariableFormatDisplayLanguage(
673 valobj_sp->GetPreferredDisplayLanguage());
674 options.SetRootValueObjectName(
675 var_sp ? var_sp->GetName().AsCString() : nullptr);
676 valobj_sp->Dump(result.GetOutputStream(), options);
682 result.SetStatus(eReturnStatusSuccessFinishResult);
685 if (m_option_variable.show_recognized_args) {
686 auto recognized_frame = frame->GetRecognizedFrame();
687 if (recognized_frame) {
688 ValueObjectListSP recognized_arg_list =
689 recognized_frame->GetRecognizedArguments();
690 if (recognized_arg_list) {
691 for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
692 options.SetFormat(m_option_format.GetFormat());
693 options.SetVariableFormatDisplayLanguage(
694 rec_value_sp->GetPreferredDisplayLanguage());
695 options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
696 rec_value_sp->Dump(result.GetOutputStream(), options);
702 if (m_interpreter.TruncationWarningNecessary()) {
703 result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
704 m_cmd_name.c_str());
705 m_interpreter.TruncationWarningGiven();
708 // Increment statistics.
709 bool res = result.Succeeded();
710 Target &target = GetSelectedOrDummyTarget();
711 if (res)
712 target.IncrementStats(StatisticKind::FrameVarSuccess);
713 else
714 target.IncrementStats(StatisticKind::FrameVarFailure);
715 return res;
718 protected:
719 OptionGroupOptions m_option_group;
720 OptionGroupVariable m_option_variable;
721 OptionGroupFormat m_option_format;
722 OptionGroupValueObjectDisplay m_varobj_options;
725 #pragma mark CommandObjectFrameRecognizer
727 #define LLDB_OPTIONS_frame_recognizer_add
728 #include "CommandOptions.inc"
730 class CommandObjectFrameRecognizerAdd : public CommandObjectParsed {
731 private:
732 class CommandOptions : public Options {
733 public:
734 CommandOptions() : Options() {}
735 ~CommandOptions() override = default;
737 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
738 ExecutionContext *execution_context) override {
739 Status error;
740 const int short_option = m_getopt_table[option_idx].val;
742 switch (short_option) {
743 case 'l':
744 m_class_name = std::string(option_arg);
745 break;
746 case 's':
747 m_module = std::string(option_arg);
748 break;
749 case 'n':
750 m_function = std::string(option_arg);
751 break;
752 case 'x':
753 m_regex = true;
754 break;
755 default:
756 llvm_unreachable("Unimplemented option");
759 return error;
762 void OptionParsingStarting(ExecutionContext *execution_context) override {
763 m_module = "";
764 m_function = "";
765 m_class_name = "";
766 m_regex = false;
769 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
770 return llvm::makeArrayRef(g_frame_recognizer_add_options);
773 // Instance variables to hold the values for command options.
774 std::string m_class_name;
775 std::string m_module;
776 std::string m_function;
777 bool m_regex;
780 CommandOptions m_options;
782 Options *GetOptions() override { return &m_options; }
784 protected:
785 bool DoExecute(Args &command, CommandReturnObject &result) override;
787 public:
788 CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)
789 : CommandObjectParsed(interpreter, "frame recognizer add",
790 "Add a new frame recognizer.", nullptr),
791 m_options() {
792 SetHelpLong(R"(
793 Frame recognizers allow for retrieving information about special frames based on
794 ABI, arguments or other special properties of that frame, even without source
795 code or debug info. Currently, one use case is to extract function arguments
796 that would otherwise be unaccesible, or augment existing arguments.
798 Adding a custom frame recognizer is possible by implementing a Python class
799 and using the 'frame recognizer add' command. The Python class should have a
800 'get_recognized_arguments' method and it will receive an argument of type
801 lldb.SBFrame representing the current frame that we are trying to recognize.
802 The method should return a (possibly empty) list of lldb.SBValue objects that
803 represent the recognized arguments.
805 An example of a recognizer that retrieves the file descriptor values from libc
806 functions 'read', 'write' and 'close' follows:
808 class LibcFdRecognizer(object):
809 def get_recognized_arguments(self, frame):
810 if frame.name in ["read", "write", "close"]:
811 fd = frame.EvaluateExpression("$arg1").unsigned
812 value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd)
813 return [value]
814 return []
816 The file containing this implementation can be imported via 'command script
817 import' and then we can register this recognizer with 'frame recognizer add'.
818 It's important to restrict the recognizer to the libc library (which is
819 libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
820 in other modules:
822 (lldb) command script import .../fd_recognizer.py
823 (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
825 When the program is stopped at the beginning of the 'read' function in libc, we
826 can view the recognizer arguments in 'frame variable':
828 (lldb) b read
829 (lldb) r
830 Process 1234 stopped
831 * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
832 frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
833 (lldb) frame variable
834 (int) fd = 3
836 )");
838 ~CommandObjectFrameRecognizerAdd() override = default;
841 bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command,
842 CommandReturnObject &result) {
843 #if LLDB_ENABLE_PYTHON
844 if (m_options.m_class_name.empty()) {
845 result.AppendErrorWithFormat(
846 "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
847 result.SetStatus(eReturnStatusFailed);
848 return false;
851 if (m_options.m_module.empty()) {
852 result.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
853 m_cmd_name.c_str());
854 result.SetStatus(eReturnStatusFailed);
855 return false;
858 if (m_options.m_function.empty()) {
859 result.AppendErrorWithFormat("%s needs a function name (-n argument).\n",
860 m_cmd_name.c_str());
861 result.SetStatus(eReturnStatusFailed);
862 return false;
865 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
867 if (interpreter &&
868 !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
869 result.AppendWarning("The provided class does not exist - please define it "
870 "before attempting to use this frame recognizer");
873 StackFrameRecognizerSP recognizer_sp =
874 StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(
875 interpreter, m_options.m_class_name.c_str()));
876 if (m_options.m_regex) {
877 auto module =
878 RegularExpressionSP(new RegularExpression(m_options.m_module));
879 auto func =
880 RegularExpressionSP(new RegularExpression(m_options.m_function));
881 StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
882 } else {
883 auto module = ConstString(m_options.m_module);
884 auto func = ConstString(m_options.m_function);
885 StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
887 #endif
889 result.SetStatus(eReturnStatusSuccessFinishNoResult);
890 return result.Succeeded();
893 class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
894 public:
895 CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
896 : CommandObjectParsed(interpreter, "frame recognizer clear",
897 "Delete all frame recognizers.", nullptr) {}
899 ~CommandObjectFrameRecognizerClear() override = default;
901 protected:
902 bool DoExecute(Args &command, CommandReturnObject &result) override {
903 StackFrameRecognizerManager::RemoveAllRecognizers();
904 result.SetStatus(eReturnStatusSuccessFinishResult);
905 return result.Succeeded();
909 class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
910 public:
911 CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
912 : CommandObjectParsed(interpreter, "frame recognizer delete",
913 "Delete an existing frame recognizer.", nullptr) {}
915 ~CommandObjectFrameRecognizerDelete() override = default;
917 protected:
918 bool DoExecute(Args &command, CommandReturnObject &result) override {
919 if (command.GetArgumentCount() == 0) {
920 if (!m_interpreter.Confirm(
921 "About to delete all frame recognizers, do you want to do that?",
922 true)) {
923 result.AppendMessage("Operation cancelled...");
924 result.SetStatus(eReturnStatusFailed);
925 return false;
928 StackFrameRecognizerManager::RemoveAllRecognizers();
929 result.SetStatus(eReturnStatusSuccessFinishResult);
930 return result.Succeeded();
933 if (command.GetArgumentCount() != 1) {
934 result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
935 m_cmd_name.c_str());
936 result.SetStatus(eReturnStatusFailed);
937 return false;
940 uint32_t recognizer_id =
941 StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0);
943 StackFrameRecognizerManager::RemoveRecognizerWithID(recognizer_id);
944 result.SetStatus(eReturnStatusSuccessFinishResult);
945 return result.Succeeded();
949 class CommandObjectFrameRecognizerList : public CommandObjectParsed {
950 public:
951 CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
952 : CommandObjectParsed(interpreter, "frame recognizer list",
953 "Show a list of active frame recognizers.",
954 nullptr) {}
956 ~CommandObjectFrameRecognizerList() override = default;
958 protected:
959 bool DoExecute(Args &command, CommandReturnObject &result) override {
960 bool any_printed = false;
961 StackFrameRecognizerManager::ForEach(
962 [&result, &any_printed](uint32_t recognizer_id, std::string name,
963 std::string function, std::string symbol,
964 bool regexp) {
965 if (name == "")
966 name = "(internal)";
967 result.GetOutputStream().Printf(
968 "%d: %s, module %s, function %s%s\n", recognizer_id, name.c_str(),
969 function.c_str(), symbol.c_str(), regexp ? " (regexp)" : "");
970 any_printed = true;
973 if (any_printed)
974 result.SetStatus(eReturnStatusSuccessFinishResult);
975 else {
976 result.GetOutputStream().PutCString("no matching results found.\n");
977 result.SetStatus(eReturnStatusSuccessFinishNoResult);
979 return result.Succeeded();
983 class CommandObjectFrameRecognizerInfo : public CommandObjectParsed {
984 public:
985 CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
986 : CommandObjectParsed(
987 interpreter, "frame recognizer info",
988 "Show which frame recognizer is applied a stack frame (if any).",
989 nullptr) {
990 CommandArgumentEntry arg;
991 CommandArgumentData index_arg;
993 // Define the first (and only) variant of this arg.
994 index_arg.arg_type = eArgTypeFrameIndex;
995 index_arg.arg_repetition = eArgRepeatPlain;
997 // There is only one variant this argument could be; put it into the
998 // argument entry.
999 arg.push_back(index_arg);
1001 // Push the data for the first argument into the m_arguments vector.
1002 m_arguments.push_back(arg);
1005 ~CommandObjectFrameRecognizerInfo() override = default;
1007 protected:
1008 bool DoExecute(Args &command, CommandReturnObject &result) override {
1009 Process *process = m_exe_ctx.GetProcessPtr();
1010 if (process == nullptr) {
1011 result.AppendError("no process");
1012 result.SetStatus(eReturnStatusFailed);
1013 return false;
1015 Thread *thread = m_exe_ctx.GetThreadPtr();
1016 if (thread == nullptr) {
1017 result.AppendError("no thread");
1018 result.SetStatus(eReturnStatusFailed);
1019 return false;
1021 if (command.GetArgumentCount() != 1) {
1022 result.AppendErrorWithFormat(
1023 "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
1024 result.SetStatus(eReturnStatusFailed);
1025 return false;
1028 uint32_t frame_index =
1029 StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0);
1030 StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
1031 if (!frame_sp) {
1032 result.AppendErrorWithFormat("no frame with index %u", frame_index);
1033 result.SetStatus(eReturnStatusFailed);
1034 return false;
1037 auto recognizer =
1038 StackFrameRecognizerManager::GetRecognizerForFrame(frame_sp);
1040 Stream &output_stream = result.GetOutputStream();
1041 output_stream.Printf("frame %d ", frame_index);
1042 if (recognizer) {
1043 output_stream << "is recognized by ";
1044 output_stream << recognizer->GetName();
1045 } else {
1046 output_stream << "not recognized by any recognizer";
1048 output_stream.EOL();
1049 result.SetStatus(eReturnStatusSuccessFinishResult);
1050 return result.Succeeded();
1054 class CommandObjectFrameRecognizer : public CommandObjectMultiword {
1055 public:
1056 CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
1057 : CommandObjectMultiword(
1058 interpreter, "frame recognizer",
1059 "Commands for editing and viewing frame recognizers.",
1060 "frame recognizer [<sub-command-options>] ") {
1061 LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd(
1062 interpreter)));
1063 LoadSubCommand(
1064 "clear",
1065 CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter)));
1066 LoadSubCommand(
1067 "delete",
1068 CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter)));
1069 LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList(
1070 interpreter)));
1071 LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo(
1072 interpreter)));
1075 ~CommandObjectFrameRecognizer() override = default;
1078 #pragma mark CommandObjectMultiwordFrame
1080 // CommandObjectMultiwordFrame
1082 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
1083 CommandInterpreter &interpreter)
1084 : CommandObjectMultiword(interpreter, "frame",
1085 "Commands for selecting and "
1086 "examing the current "
1087 "thread's stack frames.",
1088 "frame <subcommand> [<subcommand-options>]") {
1089 LoadSubCommand("diagnose",
1090 CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
1091 LoadSubCommand("info",
1092 CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1093 LoadSubCommand("select",
1094 CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1095 LoadSubCommand("variable",
1096 CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
1097 #if LLDB_ENABLE_PYTHON
1098 LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer(
1099 interpreter)));
1100 #endif
1103 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;