1 //===-- CommandObjectFrame.cpp --------------------------------------------===//
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
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"
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
{
52 class CommandOptions
: public Options
{
54 CommandOptions() { OptionParsingStarting(nullptr); }
56 ~CommandOptions() override
= default;
58 Status
SetOptionValue(uint32_t option_idx
, llvm::StringRef option_arg
,
59 ExecutionContext
*execution_context
) override
{
61 const int short_option
= m_getopt_table
[option_idx
].val
;
62 switch (short_option
) {
64 reg
= ConstString(option_arg
);
69 if (option_arg
.getAsInteger(0, *address
)) {
71 error
.SetErrorStringWithFormat("invalid address argument '%s'",
72 option_arg
.str().c_str());
78 if (option_arg
.getAsInteger(0, *offset
)) {
80 error
.SetErrorStringWithFormat("invalid offset argument '%s'",
81 option_arg
.str().c_str());
86 llvm_unreachable("Unimplemented option");
92 void OptionParsingStarting(ExecutionContext
*execution_context
) override
{
98 llvm::ArrayRef
<OptionDefinition
> GetDefinitions() override
{
99 return llvm::ArrayRef(g_frame_diag_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",
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
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
; }
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
) {
145 "`frame diagnose --address` is incompatible with other arguments.");
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));
153 StopInfoSP stop_info_sp
= thread
->GetStopInfo();
155 result
.AppendError("No arguments provided, and no stop info.");
159 valobj_sp
= StopInfo::GetCrashingDereference(stop_info_sp
);
163 result
.AppendError("No diagnosis available.");
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(" =");
178 DumpValueObjectOptions options
;
179 options
.SetDeclPrintingHelper(helper
);
180 ValueObjectPrinter
printer(valobj_sp
.get(), &result
.GetOutputStream(),
182 printer
.PrintValueObject();
185 CommandOptions m_options
;
188 #pragma mark CommandObjectFrameInfo
190 // CommandObjectFrameInfo
192 class CommandObjectFrameInfo
: public CommandObjectParsed
{
194 CommandObjectFrameInfo(CommandInterpreter
&interpreter
)
195 : CommandObjectParsed(interpreter
, "frame info",
196 "List information about the current "
197 "stack frame in the current thread.",
199 eCommandRequiresFrame
| eCommandTryTargetAPILock
|
200 eCommandProcessMustBeLaunched
|
201 eCommandProcessMustBePaused
) {}
203 ~CommandObjectFrameInfo() override
= default;
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
{
221 class CommandOptions
: public Options
{
223 CommandOptions() { OptionParsingStarting(nullptr); }
225 ~CommandOptions() override
= default;
227 Status
SetOptionValue(uint32_t option_idx
, llvm::StringRef option_arg
,
228 ExecutionContext
*execution_context
) override
{
230 const int short_option
= m_getopt_table
[option_idx
].val
;
231 switch (short_option
) {
234 if (option_arg
.getAsInteger(0, offset
) || offset
== INT32_MIN
) {
235 error
.SetErrorStringWithFormat("invalid frame offset argument '%s'",
236 option_arg
.str().c_str());
238 relative_frame_offset
= offset
;
243 llvm_unreachable("Unimplemented option");
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'.)",
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
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;
287 HandleArgumentCompletion(CompletionRequest
&request
,
288 OptionElementVector
&opt_element_vector
) override
{
289 if (request
.GetCursorIndex() != 0)
292 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
293 GetCommandInterpreter(), lldb::eFrameIndexCompletion
, request
, nullptr);
296 Options
*GetOptions() override
{ return &m_options
; }
299 void DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
300 // No need to check "thread" for validity as eCommandRequiresThread ensures
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
)
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
;
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.");
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
);
333 frame_idx
= frame_requested
;
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
;
341 if (frame_idx
== num_frames
- 1) {
342 // If we are already at the top of the stack, just warn and don't
344 result
.AppendError("Already at the top of the stack.");
347 frame_idx
= num_frames
- 1;
352 if (command
.GetArgumentCount() > 1) {
353 result
.AppendErrorWithFormat(
354 "too many arguments; expected frame-index, saw '%s'.\n",
356 m_options
.GenerateOptionUsage(
357 result
.GetErrorStream(), *this,
358 GetCommandInterpreter().GetDebugger().GetTerminalWidth());
362 if (command
.GetArgumentCount() == 1) {
363 if (command
[0].ref().getAsInteger(0, frame_idx
)) {
364 result
.AppendErrorWithFormat("invalid frame index argument '%s'.",
368 } else if (command
.GetArgumentCount() == 0) {
369 frame_idx
= thread
->GetSelectedFrameIndex(SelectMostRelevantFrame
);
370 if (frame_idx
== UINT32_MAX
) {
376 bool success
= thread
->SetSelectedFrameByIndexNoisily(
377 frame_idx
, result
.GetOutputStream());
379 m_exe_ctx
.SetFrameSP(thread
->GetSelectedFrame(SelectMostRelevantFrame
));
380 result
.SetStatus(eReturnStatusSuccessFinishResult
);
382 result
.AppendErrorWithFormat("Frame index (%u) out of range.\n",
387 CommandOptions m_options
;
390 #pragma mark CommandObjectFrameVariable
391 // List images with associated information
392 class CommandObjectFrameVariable
: public CommandObjectParsed
{
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.",
401 eCommandRequiresFrame
| eCommandTryTargetAPILock
|
402 eCommandProcessMustBeLaunched
| eCommandProcessMustBePaused
|
403 eCommandRequiresProcess
),
405 true), // Include the frame specific options by passing "true"
406 m_option_format(eFormatDefault
) {
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
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
,
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
; }
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
,
456 llvm::StringRef
GetScopeString(VariableSP var_sp
) {
458 return llvm::StringRef();
460 switch (var_sp
->GetScope()) {
461 case eValueTypeVariableGlobal
:
463 case eValueTypeVariableStatic
:
465 case eValueTypeVariableArgument
:
467 case eValueTypeVariableLocal
:
469 case eValueTypeVariableThreadLocal
:
475 return llvm::StringRef();
478 /// Returns true if `scope` matches any of the options in `m_option_variable`.
479 bool ScopeRequested(lldb::ValueType 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
:
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
®ex
,
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()))
516 matches
.AddVariableIfUnique(var
);
520 return matches
.toArrayRef().drop_front(previous_num_vars
);
524 void DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
525 // No need to check "frame" for validity as eCommandRequiresFrame ensures
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.
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()),
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
,
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;
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
);
585 result
.AppendErrorWithFormat(
586 "no variables matched the regular expression '%s'.",
590 for (const VariableSP
&var_sp
: *results
) {
591 valobj_sp
= frame
->GetValueObjectForFrameVariable(
592 var_sp
, m_varobj_options
.use_dynamic
);
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
,
609 valobj_sp
->Dump(result
.GetOutputStream(), options
);
613 if (llvm::Error err
= regex
.GetError())
614 result
.AppendError(llvm::toString(std::move(err
)));
616 result
.AppendErrorWithFormat(
617 "unknown regex error when compiling '%s'", entry
.c_str());
619 } else // No regex, either exact variable names or variable
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
,
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);
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
);
653 if (auto error_cstr
= error
.AsCString(nullptr))
654 result
.AppendError(error_cstr
);
656 result
.AppendErrorWithFormat(
657 "unable to find any variable expression path that matches "
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()))
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
);
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())
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);
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(),
732 // Increment statistics.
733 TargetStats
&target_stats
= GetSelectedOrDummyTarget().GetStatistics();
734 if (result
.Succeeded())
735 target_stats
.GetFrameVariableStats().NotifySuccess();
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
{
753 class CommandOptions
: public Options
{
755 CommandOptions() = default;
756 ~CommandOptions() override
= default;
758 Status
SetOptionValue(uint32_t option_idx
, llvm::StringRef option_arg
,
759 ExecutionContext
*execution_context
) override
{
761 const int short_option
= m_getopt_table
[option_idx
].val
;
763 switch (short_option
) {
766 value
= OptionArgParser::ToBoolean(option_arg
, true, &success
);
768 m_first_instruction_only
= value
;
770 error
.SetErrorStringWithFormat(
771 "invalid boolean value '%s' passed for -f option",
772 option_arg
.str().c_str());
776 m_class_name
= std::string(option_arg
);
779 m_module
= std::string(option_arg
);
782 m_symbols
.push_back(std::string(option_arg
));
788 llvm_unreachable("Unimplemented option");
794 void OptionParsingStarting(ExecutionContext
*execution_context
) override
{
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
;
811 bool m_first_instruction_only
;
814 CommandOptions m_options
;
816 Options
*GetOptions() override
{ return &m_options
; }
819 void DoExecute(Args
&command
, CommandReturnObject
&result
) override
;
822 CommandObjectFrameRecognizerAdd(CommandInterpreter
&interpreter
)
823 : CommandObjectParsed(interpreter
, "frame recognizer add",
824 "Add a new frame recognizer.", nullptr) {
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)
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
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':
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
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());
884 if (m_options
.m_module
.empty()) {
885 result
.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
890 if (m_options
.m_symbols
.empty()) {
891 result
.AppendErrorWithFormat(
892 "%s needs at least one symbol name (-n argument).\n",
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",
904 ScriptInterpreter
*interpreter
= GetDebugger().GetScriptInterpreter();
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
) {
917 RegularExpressionSP(new RegularExpression(m_options
.m_module
));
919 RegularExpressionSP(new RegularExpression(m_options
.m_symbols
.front()));
920 GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer(
921 recognizer_sp
, module
, func
, m_options
.m_first_instruction_only
);
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
);
931 result
.SetStatus(eReturnStatusSuccessFinishNoResult
);
934 class CommandObjectFrameRecognizerClear
: public CommandObjectParsed
{
936 CommandObjectFrameRecognizerClear(CommandInterpreter
&interpreter
)
937 : CommandObjectParsed(interpreter
, "frame recognizer clear",
938 "Delete all frame recognizers.", nullptr) {}
940 ~CommandObjectFrameRecognizerClear() override
= default;
943 void DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
944 GetSelectedOrDummyTarget()
945 .GetFrameRecognizerManager()
946 .RemoveAllRecognizers();
947 result
.SetStatus(eReturnStatusSuccessFinishResult
);
951 class CommandObjectFrameRecognizerDelete
: public CommandObjectParsed
{
953 CommandObjectFrameRecognizerDelete(CommandInterpreter
&interpreter
)
954 : CommandObjectParsed(interpreter
, "frame recognizer delete",
955 "Delete an existing frame recognizer by id.",
957 CommandArgumentData thread_arg
{eArgTypeRecognizerID
, eArgRepeatPlain
};
958 m_arguments
.push_back({thread_arg
});
961 ~CommandObjectFrameRecognizerDelete() override
= default;
964 HandleArgumentCompletion(CompletionRequest
&request
,
965 OptionElementVector
&opt_element_vector
) override
{
966 if (request
.GetCursorIndex() != 0)
969 GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach(
970 [&request
](uint32_t rid
, std::string rname
, std::string module
,
971 llvm::ArrayRef
<lldb_private::ConstString
> symbols
,
975 rname
= "(internal)";
979 strm
<< ", module " << module
;
980 if (!symbols
.empty())
981 for (auto &symbol
: symbols
)
982 strm
<< ", symbol " << symbol
;
986 request
.TryCompleteCurrentArg(std::to_string(rid
), strm
.GetString());
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?",
996 result
.AppendMessage("Operation cancelled...");
1000 GetSelectedOrDummyTarget()
1001 .GetFrameRecognizerManager()
1002 .RemoveAllRecognizers();
1003 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1007 if (command
.GetArgumentCount() != 1) {
1008 result
.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
1009 m_cmd_name
.c_str());
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));
1020 if (!GetSelectedOrDummyTarget()
1021 .GetFrameRecognizerManager()
1022 .RemoveRecognizerWithID(recognizer_id
)) {
1023 result
.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
1024 command
.GetArgumentAtIndex(0));
1027 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1031 class CommandObjectFrameRecognizerList
: public CommandObjectParsed
{
1033 CommandObjectFrameRecognizerList(CommandInterpreter
&interpreter
)
1034 : CommandObjectParsed(interpreter
, "frame recognizer list",
1035 "Show a list of active frame recognizers.",
1038 ~CommandObjectFrameRecognizerList() override
= default;
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();
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
;
1059 stream
<< " (regexp)";
1068 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1070 result
.GetOutputStream().PutCString("no matching results found.\n");
1071 result
.SetStatus(eReturnStatusSuccessFinishNoResult
);
1076 class CommandObjectFrameRecognizerInfo
: public CommandObjectParsed
{
1078 CommandObjectFrameRecognizerInfo(CommandInterpreter
&interpreter
)
1079 : CommandObjectParsed(
1080 interpreter
, "frame recognizer info",
1081 "Show which frame recognizer is applied a stack frame (if any).",
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
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;
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.",
1110 Process
*process
= m_exe_ctx
.GetProcessPtr();
1111 if (process
== nullptr) {
1112 result
.AppendError("no process");
1115 Thread
*thread
= m_exe_ctx
.GetThreadPtr();
1116 if (thread
== nullptr) {
1117 result
.AppendError("no thread");
1120 if (command
.GetArgumentCount() != 1) {
1121 result
.AppendErrorWithFormat(
1122 "'%s' takes exactly one frame index argument.\n", m_cmd_name
.c_str());
1126 StackFrameSP frame_sp
= thread
->GetStackFrameAtIndex(frame_index
);
1128 result
.AppendErrorWithFormat("no frame with index %u", frame_index
);
1132 auto recognizer
= GetSelectedOrDummyTarget()
1133 .GetFrameRecognizerManager()
1134 .GetRecognizerForFrame(frame_sp
);
1136 Stream
&output_stream
= result
.GetOutputStream();
1137 output_stream
.Printf("frame %d ", frame_index
);
1139 output_stream
<< "is recognized by ";
1140 output_stream
<< recognizer
->GetName();
1142 output_stream
<< "not recognized by any recognizer";
1144 output_stream
.EOL();
1145 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1149 class CommandObjectFrameRecognizer
: public CommandObjectMultiword
{
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(
1160 CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter
)));
1163 CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter
)));
1164 LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList(
1166 LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo(
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(
1198 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;