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/DataFormatters/DataVisualization.h"
11 #include "lldb/DataFormatters/ValueObjectPrinter.h"
12 #include "lldb/Host/Config.h"
13 #include "lldb/Host/OptionParser.h"
14 #include "lldb/Interpreter/CommandInterpreter.h"
15 #include "lldb/Interpreter/CommandOptionArgumentTable.h"
16 #include "lldb/Interpreter/CommandReturnObject.h"
17 #include "lldb/Interpreter/OptionArgParser.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"
32 #include "lldb/ValueObject/ValueObject.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
= Status::FromErrorStringWithFormat(
72 "invalid address argument '%s'", option_arg
.str().c_str());
78 if (option_arg
.getAsInteger(0, *offset
)) {
80 error
= Status::FromErrorStringWithFormat(
81 "invalid offset argument '%s'", 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 AddSimpleArgumentList(eArgTypeFrameIndex
, eArgRepeatOptional
);
119 ~CommandObjectFrameDiagnose() override
= default;
121 Options
*GetOptions() override
{ return &m_options
; }
124 void DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
125 Thread
*thread
= m_exe_ctx
.GetThreadPtr();
126 StackFrameSP frame_sp
= thread
->GetSelectedFrame(SelectMostRelevantFrame
);
128 ValueObjectSP valobj_sp
;
130 if (m_options
.address
) {
131 if (m_options
.reg
|| m_options
.offset
) {
133 "`frame diagnose --address` is incompatible with other arguments.");
136 valobj_sp
= frame_sp
->GuessValueForAddress(*m_options
.address
);
137 } else if (m_options
.reg
) {
138 valobj_sp
= frame_sp
->GuessValueForRegisterAndOffset(
139 *m_options
.reg
, m_options
.offset
.value_or(0));
141 StopInfoSP stop_info_sp
= thread
->GetStopInfo();
143 result
.AppendError("No arguments provided, and no stop info.");
147 valobj_sp
= StopInfo::GetCrashingDereference(stop_info_sp
);
151 result
.AppendError("No diagnosis available.");
155 DumpValueObjectOptions::DeclPrintingHelper helper
=
156 [&valobj_sp
](ConstString type
, ConstString var
,
157 const DumpValueObjectOptions
&opts
,
158 Stream
&stream
) -> bool {
159 const ValueObject::GetExpressionPathFormat format
= ValueObject::
160 GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers
;
161 valobj_sp
->GetExpressionPath(stream
, format
);
162 stream
.PutCString(" =");
166 DumpValueObjectOptions options
;
167 options
.SetDeclPrintingHelper(helper
);
168 // We've already handled the case where the value object sp is null, so
169 // this is just to make sure future changes don't skip that:
170 assert(valobj_sp
.get() && "Must have a valid ValueObject to print");
171 ValueObjectPrinter
printer(*valobj_sp
, &result
.GetOutputStream(), options
);
172 if (llvm::Error error
= printer
.PrintValueObject())
173 result
.AppendError(toString(std::move(error
)));
176 CommandOptions m_options
;
179 #pragma mark CommandObjectFrameInfo
181 // CommandObjectFrameInfo
183 class CommandObjectFrameInfo
: public CommandObjectParsed
{
185 CommandObjectFrameInfo(CommandInterpreter
&interpreter
)
186 : CommandObjectParsed(interpreter
, "frame info",
187 "List information about the current "
188 "stack frame in the current thread.",
190 eCommandRequiresFrame
| eCommandTryTargetAPILock
|
191 eCommandProcessMustBeLaunched
|
192 eCommandProcessMustBePaused
) {}
194 ~CommandObjectFrameInfo() override
= default;
197 void DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
198 m_exe_ctx
.GetFrameRef().DumpUsingSettingsFormat(&result
.GetOutputStream());
199 result
.SetStatus(eReturnStatusSuccessFinishResult
);
203 #pragma mark CommandObjectFrameSelect
205 // CommandObjectFrameSelect
207 #define LLDB_OPTIONS_frame_select
208 #include "CommandOptions.inc"
210 class CommandObjectFrameSelect
: public CommandObjectParsed
{
212 class CommandOptions
: public Options
{
214 CommandOptions() { OptionParsingStarting(nullptr); }
216 ~CommandOptions() override
= default;
218 Status
SetOptionValue(uint32_t option_idx
, llvm::StringRef option_arg
,
219 ExecutionContext
*execution_context
) override
{
221 const int short_option
= m_getopt_table
[option_idx
].val
;
222 switch (short_option
) {
225 if (option_arg
.getAsInteger(0, offset
) || offset
== INT32_MIN
) {
226 error
= Status::FromErrorStringWithFormat(
227 "invalid frame offset argument '%s'", option_arg
.str().c_str());
229 relative_frame_offset
= offset
;
234 llvm_unreachable("Unimplemented option");
240 void OptionParsingStarting(ExecutionContext
*execution_context
) override
{
241 relative_frame_offset
.reset();
244 llvm::ArrayRef
<OptionDefinition
> GetDefinitions() override
{
245 return llvm::ArrayRef(g_frame_select_options
);
248 std::optional
<int32_t> relative_frame_offset
;
251 CommandObjectFrameSelect(CommandInterpreter
&interpreter
)
252 : CommandObjectParsed(interpreter
, "frame select",
253 "Select the current stack frame by "
254 "index from within the current thread "
255 "(see 'thread backtrace'.)",
257 eCommandRequiresThread
| eCommandTryTargetAPILock
|
258 eCommandProcessMustBeLaunched
|
259 eCommandProcessMustBePaused
) {
260 AddSimpleArgumentList(eArgTypeFrameIndex
, eArgRepeatOptional
);
263 ~CommandObjectFrameSelect() override
= default;
265 Options
*GetOptions() override
{ return &m_options
; }
268 void DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
269 // No need to check "thread" for validity as eCommandRequiresThread ensures
271 Thread
*thread
= m_exe_ctx
.GetThreadPtr();
273 uint32_t frame_idx
= UINT32_MAX
;
274 if (m_options
.relative_frame_offset
) {
275 // The one and only argument is a signed relative frame index
276 frame_idx
= thread
->GetSelectedFrameIndex(SelectMostRelevantFrame
);
277 if (frame_idx
== UINT32_MAX
)
280 // If moving up/down by one, skip over hidden frames.
281 if (*m_options
.relative_frame_offset
== 1 ||
282 *m_options
.relative_frame_offset
== -1) {
283 uint32_t candidate_idx
= frame_idx
;
284 const unsigned max_depth
= 12;
285 for (unsigned num_try
= 0; num_try
< max_depth
; ++num_try
) {
286 if (candidate_idx
== 0 && *m_options
.relative_frame_offset
== -1) {
287 candidate_idx
= UINT32_MAX
;
290 candidate_idx
+= *m_options
.relative_frame_offset
;
291 if (auto candidate_sp
= thread
->GetStackFrameAtIndex(candidate_idx
)) {
292 if (candidate_sp
->IsHidden())
294 // Now candidate_idx is the first non-hidden frame.
297 candidate_idx
= UINT32_MAX
;
300 if (candidate_idx
!= UINT32_MAX
)
301 m_options
.relative_frame_offset
= candidate_idx
- frame_idx
;
304 if (*m_options
.relative_frame_offset
< 0) {
305 if (static_cast<int32_t>(frame_idx
) >=
306 -*m_options
.relative_frame_offset
)
307 frame_idx
+= *m_options
.relative_frame_offset
;
309 if (frame_idx
== 0) {
310 // If you are already at the bottom of the stack, then just warn
311 // and don't reset the frame.
312 result
.AppendError("Already at the bottom of the stack.");
317 } else if (*m_options
.relative_frame_offset
> 0) {
318 // I don't want "up 20" where "20" takes you past the top of the stack
319 // to produce an error, but rather to just go to the top. OTOH, start
320 // by seeing if the requested frame exists, in which case we can avoid
321 // counting the stack here...
322 const uint32_t frame_requested
= frame_idx
323 + *m_options
.relative_frame_offset
;
324 StackFrameSP frame_sp
= thread
->GetStackFrameAtIndex(frame_requested
);
326 frame_idx
= frame_requested
;
328 // The request went past the stack, so handle that case:
329 const uint32_t num_frames
= thread
->GetStackFrameCount();
330 if (static_cast<int32_t>(num_frames
- frame_idx
) >
331 *m_options
.relative_frame_offset
)
332 frame_idx
+= *m_options
.relative_frame_offset
;
334 if (frame_idx
== num_frames
- 1) {
335 // If we are already at the top of the stack, just warn and don't
337 result
.AppendError("Already at the top of the stack.");
340 frame_idx
= num_frames
- 1;
345 if (command
.GetArgumentCount() > 1) {
346 result
.AppendErrorWithFormat(
347 "too many arguments; expected frame-index, saw '%s'.\n",
349 m_options
.GenerateOptionUsage(
350 result
.GetErrorStream(), *this,
351 GetCommandInterpreter().GetDebugger().GetTerminalWidth());
355 if (command
.GetArgumentCount() == 1) {
356 if (command
[0].ref().getAsInteger(0, frame_idx
)) {
357 result
.AppendErrorWithFormat("invalid frame index argument '%s'.",
361 } else if (command
.GetArgumentCount() == 0) {
362 frame_idx
= thread
->GetSelectedFrameIndex(SelectMostRelevantFrame
);
363 if (frame_idx
== UINT32_MAX
) {
369 bool success
= thread
->SetSelectedFrameByIndexNoisily(
370 frame_idx
, result
.GetOutputStream());
372 m_exe_ctx
.SetFrameSP(thread
->GetSelectedFrame(SelectMostRelevantFrame
));
373 result
.SetStatus(eReturnStatusSuccessFinishResult
);
375 result
.AppendErrorWithFormat("Frame index (%u) out of range.\n",
380 CommandOptions m_options
;
383 #pragma mark CommandObjectFrameVariable
384 // List images with associated information
385 class CommandObjectFrameVariable
: public CommandObjectParsed
{
387 CommandObjectFrameVariable(CommandInterpreter
&interpreter
)
388 : CommandObjectParsed(
389 interpreter
, "frame variable",
390 "Show variables for the current stack frame. Defaults to all "
391 "arguments and local variables in scope. Names of argument, "
392 "local, file static and file global variables can be specified.",
394 eCommandRequiresFrame
| eCommandTryTargetAPILock
|
395 eCommandProcessMustBeLaunched
| eCommandProcessMustBePaused
|
396 eCommandRequiresProcess
),
398 true), // Include the frame specific options by passing "true"
399 m_option_format(eFormatDefault
) {
401 Children of aggregate variables can be specified such as 'var->child.x'. In
402 'frame variable', the operators -> and [] do not invoke operator overloads if
403 they exist, but directly access the specified element. If you want to trigger
404 operator overloads use the expression command to print the variable instead.
406 It is worth noting that except for overloaded operators, when printing local
407 variables 'expr local_var' and 'frame var local_var' produce the same results.
408 However, 'frame variable' is more efficient, since it uses debug information and
409 memory reads directly, rather than parsing and evaluating an expression, which
410 may even involve JITing and running code in the target program.)");
412 AddSimpleArgumentList(eArgTypeVarName
, eArgRepeatStar
);
414 m_option_group
.Append(&m_option_variable
, LLDB_OPT_SET_ALL
, LLDB_OPT_SET_1
);
415 m_option_group
.Append(&m_option_format
,
416 OptionGroupFormat::OPTION_GROUP_FORMAT
|
417 OptionGroupFormat::OPTION_GROUP_GDB_FMT
,
419 m_option_group
.Append(&m_varobj_options
, LLDB_OPT_SET_ALL
, LLDB_OPT_SET_1
);
420 m_option_group
.Finalize();
423 ~CommandObjectFrameVariable() override
= default;
425 Options
*GetOptions() override
{ return &m_option_group
; }
428 llvm::StringRef
GetScopeString(VariableSP var_sp
) {
430 return llvm::StringRef();
432 switch (var_sp
->GetScope()) {
433 case eValueTypeVariableGlobal
:
435 case eValueTypeVariableStatic
:
437 case eValueTypeVariableArgument
:
439 case eValueTypeVariableLocal
:
441 case eValueTypeVariableThreadLocal
:
447 return llvm::StringRef();
450 /// Returns true if `scope` matches any of the options in `m_option_variable`.
451 bool ScopeRequested(lldb::ValueType scope
) {
453 case eValueTypeVariableGlobal
:
454 case eValueTypeVariableStatic
:
455 return m_option_variable
.show_globals
;
456 case eValueTypeVariableArgument
:
457 return m_option_variable
.show_args
;
458 case eValueTypeVariableLocal
:
459 return m_option_variable
.show_locals
;
460 case eValueTypeInvalid
:
461 case eValueTypeRegister
:
462 case eValueTypeRegisterSet
:
463 case eValueTypeConstResult
:
464 case eValueTypeVariableThreadLocal
:
465 case eValueTypeVTable
:
466 case eValueTypeVTableEntry
:
469 llvm_unreachable("Unexpected scope value");
472 /// Finds all the variables in `all_variables` whose name matches `regex`,
473 /// inserting them into `matches`. Variables already contained in `matches`
474 /// are not inserted again.
475 /// Nullopt is returned in case of no matches.
476 /// A sub-range of `matches` with all newly inserted variables is returned.
477 /// This may be empty if all matches were already contained in `matches`.
478 std::optional
<llvm::ArrayRef
<VariableSP
>>
479 findUniqueRegexMatches(RegularExpression
®ex
,
480 VariableList
&matches
,
481 const VariableList
&all_variables
) {
482 bool any_matches
= false;
483 const size_t previous_num_vars
= matches
.GetSize();
485 for (const VariableSP
&var
: all_variables
) {
486 if (!var
->NameMatches(regex
) || !ScopeRequested(var
->GetScope()))
489 matches
.AddVariableIfUnique(var
);
493 return matches
.toArrayRef().drop_front(previous_num_vars
);
497 void DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
498 // No need to check "frame" for validity as eCommandRequiresFrame ensures
500 StackFrame
*frame
= m_exe_ctx
.GetFramePtr();
502 Stream
&s
= result
.GetOutputStream();
504 // Using a regex should behave like looking for an exact name match: it
505 // also finds globals.
506 m_option_variable
.show_globals
|= m_option_variable
.use_regex
;
508 // Be careful about the stack frame, if any summary formatter runs code, it
509 // might clear the StackFrameList for the thread. So hold onto a shared
510 // pointer to the frame so it stays alive.
513 VariableList
*variable_list
=
514 frame
->GetVariableList(m_option_variable
.show_globals
, &error
);
516 if (error
.Fail() && (!variable_list
|| variable_list
->GetSize() == 0)) {
517 result
.AppendError(error
.AsCString());
520 ValueObjectSP valobj_sp
;
522 TypeSummaryImplSP summary_format_sp
;
523 if (!m_option_variable
.summary
.IsCurrentValueEmpty())
524 DataVisualization::NamedSummaryFormats::GetSummaryFormat(
525 ConstString(m_option_variable
.summary
.GetCurrentValue()),
527 else if (!m_option_variable
.summary_string
.IsCurrentValueEmpty())
528 summary_format_sp
= std::make_shared
<StringSummaryFormat
>(
529 TypeSummaryImpl::Flags(),
530 m_option_variable
.summary_string
.GetCurrentValue());
532 DumpValueObjectOptions
options(m_varobj_options
.GetAsDumpOptions(
533 eLanguageRuntimeDescriptionDisplayVerbosityFull
, eFormatDefault
,
536 const SymbolContext
&sym_ctx
=
537 frame
->GetSymbolContext(eSymbolContextFunction
);
538 if (sym_ctx
.function
&& sym_ctx
.function
->IsTopLevelFunction())
539 m_option_variable
.show_globals
= true;
542 const Format format
= m_option_format
.GetFormat();
543 options
.SetFormat(format
);
545 if (!command
.empty()) {
546 VariableList regex_var_list
;
548 // If we have any args to the variable command, we will make variable
549 // objects from them...
550 for (auto &entry
: command
) {
551 if (m_option_variable
.use_regex
) {
552 llvm::StringRef name_str
= entry
.ref();
553 RegularExpression
regex(name_str
);
554 if (regex
.IsValid()) {
555 std::optional
<llvm::ArrayRef
<VariableSP
>> results
=
556 findUniqueRegexMatches(regex
, regex_var_list
, *variable_list
);
558 result
.AppendErrorWithFormat(
559 "no variables matched the regular expression '%s'.",
563 for (const VariableSP
&var_sp
: *results
) {
564 valobj_sp
= frame
->GetValueObjectForFrameVariable(
565 var_sp
, m_varobj_options
.use_dynamic
);
567 std::string scope_string
;
568 if (m_option_variable
.show_scope
)
569 scope_string
= GetScopeString(var_sp
).str();
571 if (!scope_string
.empty())
572 s
.PutCString(scope_string
);
574 if (m_option_variable
.show_decl
&&
575 var_sp
->GetDeclaration().GetFile()) {
576 bool show_fullpaths
= false;
577 bool show_module
= true;
578 if (var_sp
->DumpDeclaration(&s
, show_fullpaths
,
582 auto &strm
= result
.GetOutputStream();
583 if (llvm::Error error
= valobj_sp
->Dump(strm
, options
))
584 result
.AppendError(toString(std::move(error
)));
588 if (llvm::Error err
= regex
.GetError())
589 result
.AppendError(llvm::toString(std::move(err
)));
591 result
.AppendErrorWithFormat(
592 "unknown regex error when compiling '%s'", entry
.c_str());
594 } else // No regex, either exact variable names or variable
598 uint32_t expr_path_options
=
599 StackFrame::eExpressionPathOptionCheckPtrVsMember
|
600 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess
|
601 StackFrame::eExpressionPathOptionsInspectAnonymousUnions
;
602 lldb::VariableSP var_sp
;
603 valobj_sp
= frame
->GetValueForVariableExpressionPath(
604 entry
.ref(), m_varobj_options
.use_dynamic
, expr_path_options
,
607 std::string scope_string
;
608 if (m_option_variable
.show_scope
)
609 scope_string
= GetScopeString(var_sp
).str();
611 if (!scope_string
.empty())
612 s
.PutCString(scope_string
);
613 if (m_option_variable
.show_decl
&& var_sp
&&
614 var_sp
->GetDeclaration().GetFile()) {
615 var_sp
->GetDeclaration().DumpStopContext(&s
, false);
619 options
.SetFormat(format
);
620 options
.SetVariableFormatDisplayLanguage(
621 valobj_sp
->GetPreferredDisplayLanguage());
623 Stream
&output_stream
= result
.GetOutputStream();
624 options
.SetRootValueObjectName(
625 valobj_sp
->GetParent() ? entry
.c_str() : nullptr);
626 if (llvm::Error error
= valobj_sp
->Dump(output_stream
, options
))
627 result
.AppendError(toString(std::move(error
)));
629 if (auto error_cstr
= error
.AsCString(nullptr))
630 result
.AppendError(error_cstr
);
632 result
.AppendErrorWithFormat(
633 "unable to find any variable expression path that matches "
639 } else // No command arg specified. Use variable_list, instead.
641 const size_t num_variables
= variable_list
->GetSize();
642 if (num_variables
> 0) {
643 for (size_t i
= 0; i
< num_variables
; i
++) {
644 VariableSP var_sp
= variable_list
->GetVariableAtIndex(i
);
645 if (!ScopeRequested(var_sp
->GetScope()))
647 std::string scope_string
;
648 if (m_option_variable
.show_scope
)
649 scope_string
= GetScopeString(var_sp
).str();
651 // Use the variable object code to make sure we are using the same
652 // APIs as the public API will be using...
653 valobj_sp
= frame
->GetValueObjectForFrameVariable(
654 var_sp
, m_varobj_options
.use_dynamic
);
656 // When dumping all variables, don't print any variables that are
657 // not in scope to avoid extra unneeded output
658 if (valobj_sp
->IsInScope()) {
659 if (!valobj_sp
->GetTargetSP()
660 ->GetDisplayRuntimeSupportValues() &&
661 valobj_sp
->IsRuntimeSupportValue())
664 if (!scope_string
.empty())
665 s
.PutCString(scope_string
);
667 if (m_option_variable
.show_decl
&&
668 var_sp
->GetDeclaration().GetFile()) {
669 var_sp
->GetDeclaration().DumpStopContext(&s
, false);
673 options
.SetFormat(format
);
674 options
.SetVariableFormatDisplayLanguage(
675 valobj_sp
->GetPreferredDisplayLanguage());
676 options
.SetRootValueObjectName(
677 var_sp
? var_sp
->GetName().AsCString() : nullptr);
678 if (llvm::Error error
=
679 valobj_sp
->Dump(result
.GetOutputStream(), options
))
680 result
.AppendError(toString(std::move(error
)));
686 if (result
.GetStatus() != eReturnStatusFailed
)
687 result
.SetStatus(eReturnStatusSuccessFinishResult
);
690 if (m_option_variable
.show_recognized_args
) {
691 auto recognized_frame
= frame
->GetRecognizedFrame();
692 if (recognized_frame
) {
693 ValueObjectListSP recognized_arg_list
=
694 recognized_frame
->GetRecognizedArguments();
695 if (recognized_arg_list
) {
696 for (auto &rec_value_sp
: recognized_arg_list
->GetObjects()) {
697 options
.SetFormat(m_option_format
.GetFormat());
698 options
.SetVariableFormatDisplayLanguage(
699 rec_value_sp
->GetPreferredDisplayLanguage());
700 options
.SetRootValueObjectName(rec_value_sp
->GetName().AsCString());
701 if (llvm::Error error
=
702 rec_value_sp
->Dump(result
.GetOutputStream(), options
))
703 result
.AppendError(toString(std::move(error
)));
709 m_interpreter
.PrintWarningsIfNecessary(result
.GetOutputStream(),
712 // Increment statistics.
713 TargetStats
&target_stats
= GetTarget().GetStatistics();
714 if (result
.Succeeded())
715 target_stats
.GetFrameVariableStats().NotifySuccess();
717 target_stats
.GetFrameVariableStats().NotifyFailure();
720 OptionGroupOptions m_option_group
;
721 OptionGroupVariable m_option_variable
;
722 OptionGroupFormat m_option_format
;
723 OptionGroupValueObjectDisplay m_varobj_options
;
726 #pragma mark CommandObjectFrameRecognizer
728 #define LLDB_OPTIONS_frame_recognizer_add
729 #include "CommandOptions.inc"
731 class CommandObjectFrameRecognizerAdd
: public CommandObjectParsed
{
733 class CommandOptions
: public Options
{
735 CommandOptions() = default;
736 ~CommandOptions() override
= default;
738 Status
SetOptionValue(uint32_t option_idx
, llvm::StringRef option_arg
,
739 ExecutionContext
*execution_context
) override
{
741 const int short_option
= m_getopt_table
[option_idx
].val
;
743 switch (short_option
) {
746 value
= OptionArgParser::ToBoolean(option_arg
, true, &success
);
748 m_first_instruction_only
= value
;
750 error
= Status::FromErrorStringWithFormat(
751 "invalid boolean value '%s' passed for -f option",
752 option_arg
.str().c_str());
756 m_class_name
= std::string(option_arg
);
759 m_module
= std::string(option_arg
);
762 m_symbols
.push_back(std::string(option_arg
));
768 llvm_unreachable("Unimplemented option");
774 void OptionParsingStarting(ExecutionContext
*execution_context
) override
{
779 m_first_instruction_only
= true;
782 llvm::ArrayRef
<OptionDefinition
> GetDefinitions() override
{
783 return llvm::ArrayRef(g_frame_recognizer_add_options
);
786 // Instance variables to hold the values for command options.
787 std::string m_class_name
;
788 std::string m_module
;
789 std::vector
<std::string
> m_symbols
;
791 bool m_first_instruction_only
;
794 CommandOptions m_options
;
796 Options
*GetOptions() override
{ return &m_options
; }
799 void DoExecute(Args
&command
, CommandReturnObject
&result
) override
;
802 CommandObjectFrameRecognizerAdd(CommandInterpreter
&interpreter
)
803 : CommandObjectParsed(interpreter
, "frame recognizer add",
804 "Add a new frame recognizer.", nullptr) {
806 Frame recognizers allow for retrieving information about special frames based on
807 ABI, arguments or other special properties of that frame, even without source
808 code or debug info. Currently, one use case is to extract function arguments
809 that would otherwise be unaccesible, or augment existing arguments.
811 Adding a custom frame recognizer is possible by implementing a Python class
812 and using the 'frame recognizer add' command. The Python class should have a
813 'get_recognized_arguments' method and it will receive an argument of type
814 lldb.SBFrame representing the current frame that we are trying to recognize.
815 The method should return a (possibly empty) list of lldb.SBValue objects that
816 represent the recognized arguments.
818 An example of a recognizer that retrieves the file descriptor values from libc
819 functions 'read', 'write' and 'close' follows:
821 class LibcFdRecognizer(object):
822 def get_recognized_arguments(self, frame):
823 if frame.name in ["read
", "write
", "close
"]:
824 fd = frame.EvaluateExpression("$arg1
").unsigned
825 target = frame.thread.process.target
826 value = target.CreateValueFromExpression("fd
", "(int)%d
" % fd)
830 The file containing this implementation can be imported via 'command script
831 import' and then we can register this recognizer with 'frame recognizer add'.
832 It's important to restrict the recognizer to the libc library (which is
833 libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
836 (lldb) command script import .../fd_recognizer.py
837 (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
839 When the program is stopped at the beginning of the 'read' function in libc, we
840 can view the recognizer arguments in 'frame variable':
845 * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
846 frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
847 (lldb) frame variable
852 ~CommandObjectFrameRecognizerAdd() override
= default;
855 void CommandObjectFrameRecognizerAdd::DoExecute(Args
&command
,
856 CommandReturnObject
&result
) {
857 #if LLDB_ENABLE_PYTHON
858 if (m_options
.m_class_name
.empty()) {
859 result
.AppendErrorWithFormat(
860 "%s needs a Python class name (-l argument).\n", m_cmd_name
.c_str());
864 if (m_options
.m_module
.empty()) {
865 result
.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
870 if (m_options
.m_symbols
.empty()) {
871 result
.AppendErrorWithFormat(
872 "%s needs at least one symbol name (-n argument).\n",
877 if (m_options
.m_regex
&& m_options
.m_symbols
.size() > 1) {
878 result
.AppendErrorWithFormat(
879 "%s needs only one symbol regular expression (-n argument).\n",
884 ScriptInterpreter
*interpreter
= GetDebugger().GetScriptInterpreter();
887 !interpreter
->CheckObjectExists(m_options
.m_class_name
.c_str())) {
888 result
.AppendWarning("The provided class does not exist - please define it "
889 "before attempting to use this frame recognizer");
892 StackFrameRecognizerSP recognizer_sp
=
893 StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(
894 interpreter
, m_options
.m_class_name
.c_str()));
895 if (m_options
.m_regex
) {
897 RegularExpressionSP(new RegularExpression(m_options
.m_module
));
899 RegularExpressionSP(new RegularExpression(m_options
.m_symbols
.front()));
900 GetTarget().GetFrameRecognizerManager().AddRecognizer(
901 recognizer_sp
, module
, func
, Mangled::NamePreference::ePreferDemangled
,
902 m_options
.m_first_instruction_only
);
904 auto module
= ConstString(m_options
.m_module
);
905 std::vector
<ConstString
> symbols(m_options
.m_symbols
.begin(),
906 m_options
.m_symbols
.end());
907 GetTarget().GetFrameRecognizerManager().AddRecognizer(
908 recognizer_sp
, module
, symbols
,
909 Mangled::NamePreference::ePreferDemangled
,
910 m_options
.m_first_instruction_only
);
914 result
.SetStatus(eReturnStatusSuccessFinishNoResult
);
917 class CommandObjectFrameRecognizerClear
: public CommandObjectParsed
{
919 CommandObjectFrameRecognizerClear(CommandInterpreter
&interpreter
)
920 : CommandObjectParsed(interpreter
, "frame recognizer clear",
921 "Delete all frame recognizers.", nullptr) {}
923 ~CommandObjectFrameRecognizerClear() override
= default;
926 void DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
927 GetTarget().GetFrameRecognizerManager().RemoveAllRecognizers();
928 result
.SetStatus(eReturnStatusSuccessFinishResult
);
933 PrintRecognizerDetails(Stream
&strm
, const std::string
&name
, bool enabled
,
934 const std::string
&module
,
935 llvm::ArrayRef
<lldb_private::ConstString
> symbols
,
936 Mangled::NamePreference symbol_mangling
, bool regexp
) {
938 strm
<< "[disabled] ";
940 strm
<< name
<< ", ";
943 strm
<< "module " << module
<< ", ";
945 switch (symbol_mangling
) {
946 case Mangled::NamePreference ::ePreferMangled
:
947 strm
<< "mangled symbol ";
949 case Mangled::NamePreference ::ePreferDemangled
:
950 strm
<< "demangled symbol ";
952 case Mangled::NamePreference ::ePreferDemangledWithoutArguments
:
953 strm
<< "demangled (no args) symbol ";
960 llvm::interleaveComma(symbols
, strm
);
963 // Base class for commands which accept a single frame recognizer as an argument
964 class CommandObjectWithFrameRecognizerArg
: public CommandObjectParsed
{
966 CommandObjectWithFrameRecognizerArg(CommandInterpreter
&interpreter
,
968 const char *help
= nullptr,
969 const char *syntax
= nullptr,
971 : CommandObjectParsed(interpreter
, name
, help
, syntax
, flags
) {
972 AddSimpleArgumentList(eArgTypeRecognizerID
);
976 HandleArgumentCompletion(CompletionRequest
&request
,
977 OptionElementVector
&opt_element_vector
) override
{
978 if (request
.GetCursorIndex() != 0)
981 GetTarget().GetFrameRecognizerManager().ForEach(
982 [&request
](uint32_t rid
, bool enabled
, std::string rname
,
984 llvm::ArrayRef
<lldb_private::ConstString
> symbols
,
985 Mangled::NamePreference symbol_mangling
, bool regexp
) {
988 rname
= "(internal)";
990 PrintRecognizerDetails(strm
, rname
, enabled
, module
, symbols
,
991 symbol_mangling
, regexp
);
993 request
.TryCompleteCurrentArg(std::to_string(rid
), strm
.GetString());
997 virtual void DoExecuteWithId(CommandReturnObject
&result
,
998 uint32_t recognizer_id
) = 0;
1000 void DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
1001 uint32_t recognizer_id
;
1002 if (!llvm::to_integer(command
.GetArgumentAtIndex(0), recognizer_id
)) {
1003 result
.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
1004 command
.GetArgumentAtIndex(0));
1008 DoExecuteWithId(result
, recognizer_id
);
1012 class CommandObjectFrameRecognizerEnable
1013 : public CommandObjectWithFrameRecognizerArg
{
1015 CommandObjectFrameRecognizerEnable(CommandInterpreter
&interpreter
)
1016 : CommandObjectWithFrameRecognizerArg(
1017 interpreter
, "frame recognizer enable",
1018 "Enable a frame recognizer by id.", nullptr) {
1019 AddSimpleArgumentList(eArgTypeRecognizerID
);
1022 ~CommandObjectFrameRecognizerEnable() override
= default;
1025 void DoExecuteWithId(CommandReturnObject
&result
,
1026 uint32_t recognizer_id
) override
{
1027 auto &recognizer_mgr
= GetTarget().GetFrameRecognizerManager();
1028 if (!recognizer_mgr
.SetEnabledForID(recognizer_id
, true)) {
1029 result
.AppendErrorWithFormat("'%u' is not a valid recognizer id.\n",
1033 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1037 class CommandObjectFrameRecognizerDisable
1038 : public CommandObjectWithFrameRecognizerArg
{
1040 CommandObjectFrameRecognizerDisable(CommandInterpreter
&interpreter
)
1041 : CommandObjectWithFrameRecognizerArg(
1042 interpreter
, "frame recognizer disable",
1043 "Disable a frame recognizer by id.", nullptr) {
1044 AddSimpleArgumentList(eArgTypeRecognizerID
);
1047 ~CommandObjectFrameRecognizerDisable() override
= default;
1050 void DoExecuteWithId(CommandReturnObject
&result
,
1051 uint32_t recognizer_id
) override
{
1052 auto &recognizer_mgr
= GetTarget().GetFrameRecognizerManager();
1053 if (!recognizer_mgr
.SetEnabledForID(recognizer_id
, false)) {
1054 result
.AppendErrorWithFormat("'%u' is not a valid recognizer id.\n",
1058 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1062 class CommandObjectFrameRecognizerDelete
1063 : public CommandObjectWithFrameRecognizerArg
{
1065 CommandObjectFrameRecognizerDelete(CommandInterpreter
&interpreter
)
1066 : CommandObjectWithFrameRecognizerArg(
1067 interpreter
, "frame recognizer delete",
1068 "Delete an existing frame recognizer by id.", nullptr) {
1069 AddSimpleArgumentList(eArgTypeRecognizerID
);
1072 ~CommandObjectFrameRecognizerDelete() override
= default;
1075 void DoExecuteWithId(CommandReturnObject
&result
,
1076 uint32_t recognizer_id
) override
{
1077 auto &recognizer_mgr
= GetTarget().GetFrameRecognizerManager();
1078 if (!recognizer_mgr
.RemoveRecognizerWithID(recognizer_id
)) {
1079 result
.AppendErrorWithFormat("'%u' is not a valid recognizer id.\n",
1083 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1087 class CommandObjectFrameRecognizerList
: public CommandObjectParsed
{
1089 CommandObjectFrameRecognizerList(CommandInterpreter
&interpreter
)
1090 : CommandObjectParsed(interpreter
, "frame recognizer list",
1091 "Show a list of active frame recognizers.",
1094 ~CommandObjectFrameRecognizerList() override
= default;
1097 void DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
1098 bool any_printed
= false;
1099 GetTarget().GetFrameRecognizerManager().ForEach(
1101 &any_printed
](uint32_t recognizer_id
, bool enabled
, std::string name
,
1102 std::string module
, llvm::ArrayRef
<ConstString
> symbols
,
1103 Mangled::NamePreference symbol_mangling
, bool regexp
) {
1104 Stream
&stream
= result
.GetOutputStream();
1107 name
= "(internal)";
1109 stream
<< std::to_string(recognizer_id
) << ": ";
1110 PrintRecognizerDetails(stream
, name
, enabled
, module
, symbols
,
1111 symbol_mangling
, regexp
);
1120 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1122 result
.GetOutputStream().PutCString("no matching results found.\n");
1123 result
.SetStatus(eReturnStatusSuccessFinishNoResult
);
1128 class CommandObjectFrameRecognizerInfo
: public CommandObjectParsed
{
1130 CommandObjectFrameRecognizerInfo(CommandInterpreter
&interpreter
)
1131 : CommandObjectParsed(
1132 interpreter
, "frame recognizer info",
1133 "Show which frame recognizer is applied a stack frame (if any).",
1135 AddSimpleArgumentList(eArgTypeFrameIndex
);
1138 ~CommandObjectFrameRecognizerInfo() override
= default;
1141 void DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
1142 const char *frame_index_str
= command
.GetArgumentAtIndex(0);
1143 uint32_t frame_index
;
1144 if (!llvm::to_integer(frame_index_str
, frame_index
)) {
1145 result
.AppendErrorWithFormat("'%s' is not a valid frame index.",
1150 Process
*process
= m_exe_ctx
.GetProcessPtr();
1151 if (process
== nullptr) {
1152 result
.AppendError("no process");
1155 Thread
*thread
= m_exe_ctx
.GetThreadPtr();
1156 if (thread
== nullptr) {
1157 result
.AppendError("no thread");
1160 if (command
.GetArgumentCount() != 1) {
1161 result
.AppendErrorWithFormat(
1162 "'%s' takes exactly one frame index argument.\n", m_cmd_name
.c_str());
1166 StackFrameSP frame_sp
= thread
->GetStackFrameAtIndex(frame_index
);
1168 result
.AppendErrorWithFormat("no frame with index %u", frame_index
);
1173 GetTarget().GetFrameRecognizerManager().GetRecognizerForFrame(frame_sp
);
1175 Stream
&output_stream
= result
.GetOutputStream();
1176 output_stream
.Printf("frame %d ", frame_index
);
1178 output_stream
<< "is recognized by ";
1179 output_stream
<< recognizer
->GetName();
1181 output_stream
<< "not recognized by any recognizer";
1183 output_stream
.EOL();
1184 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1188 class CommandObjectFrameRecognizer
: public CommandObjectMultiword
{
1190 CommandObjectFrameRecognizer(CommandInterpreter
&interpreter
)
1191 : CommandObjectMultiword(
1192 interpreter
, "frame recognizer",
1193 "Commands for editing and viewing frame recognizers.",
1194 "frame recognizer [<sub-command-options>] ") {
1195 LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo(
1197 LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList(
1199 LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd(
1203 CommandObjectSP(new CommandObjectFrameRecognizerEnable(interpreter
)));
1206 CommandObjectSP(new CommandObjectFrameRecognizerDisable(interpreter
)));
1209 CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter
)));
1212 CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter
)));
1215 ~CommandObjectFrameRecognizer() override
= default;
1218 #pragma mark CommandObjectMultiwordFrame
1220 // CommandObjectMultiwordFrame
1222 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
1223 CommandInterpreter
&interpreter
)
1224 : CommandObjectMultiword(interpreter
, "frame",
1225 "Commands for selecting and "
1226 "examining the current "
1227 "thread's stack frames.",
1228 "frame <subcommand> [<subcommand-options>]") {
1229 LoadSubCommand("diagnose",
1230 CommandObjectSP(new CommandObjectFrameDiagnose(interpreter
)));
1231 LoadSubCommand("info",
1232 CommandObjectSP(new CommandObjectFrameInfo(interpreter
)));
1233 LoadSubCommand("select",
1234 CommandObjectSP(new CommandObjectFrameSelect(interpreter
)));
1235 LoadSubCommand("variable",
1236 CommandObjectSP(new CommandObjectFrameVariable(interpreter
)));
1237 #if LLDB_ENABLE_PYTHON
1238 LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer(
1243 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;