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