LLDB mainline
CommandObjectFrame.cpp
Go to the documentation of this file.
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//===----------------------------------------------------------------------===//
12#include "lldb/Host/Config.h"
29#include "lldb/Target/Target.h"
30#include "lldb/Target/Thread.h"
31#include "lldb/Utility/Args.h"
33
34#include <memory>
35#include <optional>
36#include <string>
37
38using namespace lldb;
39using namespace lldb_private;
40
41#pragma mark CommandObjectFrameDiagnose
42
43// CommandObjectFrameInfo
44
45// CommandObjectFrameDiagnose
46
47#define LLDB_OPTIONS_frame_diag
48#include "CommandOptions.inc"
49
51public:
52 class CommandOptions : public Options {
53 public:
55
56 ~CommandOptions() override = default;
57
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) {
63 case 'r':
64 reg = ConstString(option_arg);
65 break;
66
67 case 'a': {
68 address.emplace();
69 if (option_arg.getAsInteger(0, *address)) {
70 address.reset();
72 "invalid address argument '%s'", option_arg.str().c_str());
73 }
74 } break;
75
76 case 'o': {
77 offset.emplace();
78 if (option_arg.getAsInteger(0, *offset)) {
79 offset.reset();
81 "invalid offset argument '%s'", option_arg.str().c_str());
82 }
83 } break;
84
85 default:
86 llvm_unreachable("Unimplemented option");
87 }
88
89 return error;
90 }
91
92 void OptionParsingStarting(ExecutionContext *execution_context) override {
93 address.reset();
94 reg.reset();
95 offset.reset();
96 }
97
98 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
99 return llvm::ArrayRef(g_frame_diag_options);
100 }
101
102 // Options.
103 std::optional<lldb::addr_t> address;
104 std::optional<ConstString> reg;
105 std::optional<int64_t> offset;
106 };
107
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) {
117 }
118
119 ~CommandObjectFrameDiagnose() override = default;
120
121 Options *GetOptions() override { return &m_options; }
122
123protected:
124 void DoExecute(Args &command, CommandReturnObject &result) override {
125 Thread *thread = m_exe_ctx.GetThreadPtr();
127
128 ValueObjectSP valobj_sp;
129
130 if (m_options.address) {
131 if (m_options.reg || m_options.offset) {
132 result.AppendError(
133 "`frame diagnose --address` is incompatible with other arguments.");
134 return;
135 }
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));
140 } else {
141 StopInfoSP stop_info_sp = thread->GetStopInfo();
142 if (!stop_info_sp) {
143 result.AppendError("No arguments provided, and no stop info.");
144 return;
145 }
146
147 valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
148 }
149
150 if (!valobj_sp) {
151 result.AppendError("No diagnosis available.");
152 return;
153 }
154
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(" =");
163 return true;
164 };
165
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)));
174 }
175
177};
178
179#pragma mark CommandObjectFrameInfo
180
181// CommandObjectFrameInfo
182
184public:
186 : CommandObjectParsed(interpreter, "frame info",
187 "List information about the current "
188 "stack frame in the current thread.",
189 "frame info",
190 eCommandRequiresFrame | eCommandTryTargetAPILock |
191 eCommandProcessMustBeLaunched |
192 eCommandProcessMustBePaused) {}
193
194 ~CommandObjectFrameInfo() override = default;
195
196protected:
197 void DoExecute(Args &command, CommandReturnObject &result) override {
200 }
201};
202
203#pragma mark CommandObjectFrameSelect
204
205// CommandObjectFrameSelect
206
207#define LLDB_OPTIONS_frame_select
208#include "CommandOptions.inc"
209
211public:
212 class CommandOptions : public Options {
213 public:
215
216 ~CommandOptions() override = default;
217
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) {
223 case 'r': {
224 int32_t offset = 0;
225 if (option_arg.getAsInteger(0, offset) || offset == INT32_MIN) {
227 "invalid frame offset argument '%s'", option_arg.str().c_str());
228 } else
229 relative_frame_offset = offset;
230 break;
231 }
232
233 default:
234 llvm_unreachable("Unimplemented option");
235 }
236
237 return error;
238 }
239
240 void OptionParsingStarting(ExecutionContext *execution_context) override {
241 relative_frame_offset.reset();
242 }
243
244 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
245 return llvm::ArrayRef(g_frame_select_options);
246 }
247
248 std::optional<int32_t> relative_frame_offset;
249 };
250
252 : CommandObjectParsed(interpreter, "frame select",
253 "Select the current stack frame by "
254 "index from within the current thread "
255 "(see 'thread backtrace'.)",
256 nullptr,
257 eCommandRequiresThread | eCommandTryTargetAPILock |
258 eCommandProcessMustBeLaunched |
259 eCommandProcessMustBePaused) {
261 }
262
263 ~CommandObjectFrameSelect() override = default;
264
265 Options *GetOptions() override { return &m_options; }
266
267protected:
268 void DoExecute(Args &command, CommandReturnObject &result) override {
269 // No need to check "thread" for validity as eCommandRequiresThread ensures
270 // it is valid
271 Thread *thread = m_exe_ctx.GetThreadPtr();
272
273 uint32_t frame_idx = UINT32_MAX;
275 // The one and only argument is a signed relative frame index
277 if (frame_idx == UINT32_MAX)
278 frame_idx = 0;
279
280 // If moving up/down by one, skip over hidden frames.
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;
288 break;
289 }
290 candidate_idx += *m_options.relative_frame_offset;
291 if (auto candidate_sp = thread->GetStackFrameAtIndex(candidate_idx)) {
292 if (candidate_sp->IsHidden())
293 continue;
294 // Now candidate_idx is the first non-hidden frame.
295 break;
296 }
297 candidate_idx = UINT32_MAX;
298 break;
299 };
300 if (candidate_idx != UINT32_MAX)
301 m_options.relative_frame_offset = candidate_idx - frame_idx;
302 }
303
305 if (static_cast<int32_t>(frame_idx) >=
307 frame_idx += *m_options.relative_frame_offset;
308 else {
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.");
313 return;
314 } else
315 frame_idx = 0;
316 }
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
324 StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_requested);
325 if (frame_sp)
326 frame_idx = frame_requested;
327 else {
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) >
332 frame_idx += *m_options.relative_frame_offset;
333 else {
334 if (frame_idx == num_frames - 1) {
335 // If we are already at the top of the stack, just warn and don't
336 // reset the frame.
337 result.AppendError("Already at the top of the stack.");
338 return;
339 } else
340 frame_idx = num_frames - 1;
341 }
342 }
343 }
344 } else {
345 if (command.GetArgumentCount() > 1) {
347 "too many arguments; expected frame-index, saw '%s'.\n",
348 command[0].c_str());
350 result.GetErrorStream(), *this,
351 GetCommandInterpreter().GetDebugger().GetTerminalWidth());
352 return;
353 }
354
355 if (command.GetArgumentCount() == 1) {
356 if (command[0].ref().getAsInteger(0, frame_idx)) {
357 result.AppendErrorWithFormat("invalid frame index argument '%s'.",
358 command[0].c_str());
359 return;
360 }
361 } else if (command.GetArgumentCount() == 0) {
363 if (frame_idx == UINT32_MAX) {
364 frame_idx = 0;
365 }
366 }
367 }
368
369 bool success = thread->SetSelectedFrameByIndexNoisily(
370 frame_idx, result.GetOutputStream());
371 if (success) {
374 } else {
375 result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
376 frame_idx);
377 }
378 }
379
381};
382
383#pragma mark CommandObjectFrameVariable
384// List images with associated information
386public:
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.",
393 nullptr,
394 eCommandRequiresFrame | eCommandTryTargetAPILock |
395 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
396 eCommandRequiresProcess),
398 true), // Include the frame specific options by passing "true"
400 SetHelpLong(R"(
401Children of aggregate variables can be specified such as 'var->child.x'. In
402'frame variable', the operators -> and [] do not invoke operator overloads if
403they exist, but directly access the specified element. If you want to trigger
404operator overloads use the expression command to print the variable instead.
405
406It is worth noting that except for overloaded operators, when printing local
407variables 'expr local_var' and 'frame var local_var' produce the same results.
408However, 'frame variable' is more efficient, since it uses debug information and
409memory reads directly, rather than parsing and evaluating an expression, which
410may even involve JITing and running code in the target program.)");
411
413
421 }
422
423 ~CommandObjectFrameVariable() override = default;
424
425 Options *GetOptions() override { return &m_option_group; }
426
427protected:
428 llvm::StringRef GetScopeString(VariableSP var_sp) {
429 if (!var_sp)
430 return llvm::StringRef();
431
432 switch (var_sp->GetScope()) {
434 return "GLOBAL: ";
436 return "STATIC: ";
438 return "ARG: ";
440 return "LOCAL: ";
442 return "THREAD: ";
443 default:
444 break;
445 }
446
447 return llvm::StringRef();
448 }
449
450 /// Returns true if `scope` matches any of the options in `m_option_variable`.
452 switch (scope) {
465 case eValueTypeVTable:
467 return false;
468 }
469 llvm_unreachable("Unexpected scope value");
470 }
471
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>>
480 VariableList &matches,
481 const VariableList &all_variables) {
482 bool any_matches = false;
483 const size_t previous_num_vars = matches.GetSize();
484
485 for (const VariableSP &var : all_variables) {
486 if (!var->NameMatches(regex) || !ScopeRequested(var->GetScope()))
487 continue;
488 any_matches = true;
489 matches.AddVariableIfUnique(var);
490 }
491
492 if (any_matches)
493 return matches.toArrayRef().drop_front(previous_num_vars);
494 return std::nullopt;
495 }
496
497 void DoExecute(Args &command, CommandReturnObject &result) override {
498 // No need to check "frame" for validity as eCommandRequiresFrame ensures
499 // it is valid
501
502 Stream &s = result.GetOutputStream();
503
504 // Using a regex should behave like looking for an exact name match: it
505 // also finds globals.
507
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.
511
513 VariableList *variable_list =
515
516 if (error.Fail() && (!variable_list || variable_list->GetSize() == 0)) {
517 result.AppendError(error.AsCString());
518
519 }
520 ValueObjectSP valobj_sp;
521
522 TypeSummaryImplSP summary_format_sp;
526 summary_format_sp);
528 summary_format_sp = std::make_shared<StringSummaryFormat>(
531
534 summary_format_sp));
535
536 const SymbolContext &sym_ctx =
537 frame->GetSymbolContext(eSymbolContextFunction);
538 if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
540
541 if (variable_list) {
542 const Format format = m_option_format.GetFormat();
543 options.SetFormat(format);
544
545 if (!command.empty()) {
546 VariableList regex_var_list;
547
548 // If we have any args to the variable command, we will make variable
549 // objects from them...
550 for (auto &entry : command) {
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);
557 if (!results) {
559 "no variables matched the regular expression '%s'.",
560 entry.c_str());
561 continue;
562 }
563 for (const VariableSP &var_sp : *results) {
564 valobj_sp = frame->GetValueObjectForFrameVariable(
566 if (valobj_sp) {
567 std::string scope_string;
569 scope_string = GetScopeString(var_sp).str();
570
571 if (!scope_string.empty())
572 s.PutCString(scope_string);
573
575 var_sp->GetDeclaration().GetFile()) {
576 bool show_fullpaths = false;
577 bool show_module = true;
578 if (var_sp->DumpDeclaration(&s, show_fullpaths,
579 show_module))
580 s.PutCString(": ");
581 }
582 auto &strm = result.GetOutputStream();
583 if (llvm::Error error = valobj_sp->Dump(strm, options))
584 result.AppendError(toString(std::move(error)));
585 }
586 }
587 } else {
588 if (llvm::Error err = regex.GetError())
589 result.AppendError(llvm::toString(std::move(err)));
590 else
592 "unknown regex error when compiling '%s'", entry.c_str());
593 }
594 } else // No regex, either exact variable names or variable
595 // expressions.
596 {
598 uint32_t expr_path_options =
602 lldb::VariableSP var_sp;
603 valobj_sp = frame->GetValueForVariableExpressionPath(
604 entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
605 var_sp, error);
606 if (valobj_sp) {
607 std::string scope_string;
609 scope_string = GetScopeString(var_sp).str();
610
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);
616 s.PutCString(": ");
617 }
618
619 options.SetFormat(format);
621 valobj_sp->GetPreferredDisplayLanguage());
622
623 Stream &output_stream = result.GetOutputStream();
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)));
628 } else {
629 if (auto error_cstr = error.AsCString(nullptr))
630 result.AppendError(error_cstr);
631 else
633 "unable to find any variable expression path that matches "
634 "'%s'.",
635 entry.c_str());
636 }
637 }
638 }
639 } else // No command arg specified. Use variable_list, instead.
640 {
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()))
646 continue;
647 std::string scope_string;
649 scope_string = GetScopeString(var_sp).str();
650
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(
655 if (valobj_sp) {
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())
662 continue;
663
664 if (!scope_string.empty())
665 s.PutCString(scope_string);
666
668 var_sp->GetDeclaration().GetFile()) {
669 var_sp->GetDeclaration().DumpStopContext(&s, false);
670 s.PutCString(": ");
671 }
672
673 options.SetFormat(format);
675 valobj_sp->GetPreferredDisplayLanguage());
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)));
681 }
682 }
683 }
684 }
685 }
686 if (result.GetStatus() != eReturnStatusFailed)
688 }
689
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()) {
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)));
704 }
705 }
706 }
707 }
708
710 m_cmd_name);
711
712 // Increment statistics.
713 TargetStats &target_stats = GetTarget().GetStatistics();
714 if (result.Succeeded())
715 target_stats.GetFrameVariableStats().NotifySuccess();
716 else
717 target_stats.GetFrameVariableStats().NotifyFailure();
718 }
719
724};
725
726#pragma mark CommandObjectFrameRecognizer
727
728#define LLDB_OPTIONS_frame_recognizer_add
729#include "CommandOptions.inc"
730
732private:
733 class CommandOptions : public Options {
734 public:
735 CommandOptions() = default;
736 ~CommandOptions() override = default;
737
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;
742
743 switch (short_option) {
744 case 'f': {
745 bool value, success;
746 value = OptionArgParser::ToBoolean(option_arg, true, &success);
747 if (success) {
749 } else {
751 "invalid boolean value '%s' passed for -f option",
752 option_arg.str().c_str());
753 }
754 } break;
755 case 'l':
756 m_class_name = std::string(option_arg);
757 break;
758 case 's':
759 m_module = std::string(option_arg);
760 break;
761 case 'n':
762 m_symbols.push_back(std::string(option_arg));
763 break;
764 case 'x':
765 m_regex = true;
766 break;
767 default:
768 llvm_unreachable("Unimplemented option");
769 }
770
771 return error;
772 }
773
774 void OptionParsingStarting(ExecutionContext *execution_context) override {
775 m_module = "";
776 m_symbols.clear();
777 m_class_name = "";
778 m_regex = false;
780 }
781
782 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
783 return llvm::ArrayRef(g_frame_recognizer_add_options);
784 }
785
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;
792 };
793
795
796 Options *GetOptions() override { return &m_options; }
797
798protected:
799 void DoExecute(Args &command, CommandReturnObject &result) override;
800
801public:
803 : CommandObjectParsed(interpreter, "frame recognizer add",
804 "Add a new frame recognizer.", nullptr) {
805 SetHelpLong(R"(
806Frame recognizers allow for retrieving information about special frames based on
807ABI, arguments or other special properties of that frame, even without source
808code or debug info. Currently, one use case is to extract function arguments
809that would otherwise be unaccesible, or augment existing arguments.
810
811Adding a custom frame recognizer is possible by implementing a Python class
812and 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
814lldb.SBFrame representing the current frame that we are trying to recognize.
815The method should return a (possibly empty) list of lldb.SBValue objects that
816represent the recognized arguments.
817
818An example of a recognizer that retrieves the file descriptor values from libc
819functions 'read', 'write' and 'close' follows:
820
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)
827 return [value]
828 return []
829
830The file containing this implementation can be imported via 'command script
831import' and then we can register this recognizer with 'frame recognizer add'.
832It's important to restrict the recognizer to the libc library (which is
833libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
834in other modules:
835
836(lldb) command script import .../fd_recognizer.py
837(lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
838
839When the program is stopped at the beginning of the 'read' function in libc, we
840can view the recognizer arguments in 'frame variable':
841
842(lldb) b read
843(lldb) r
844Process 1234 stopped
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
848(int) fd = 3
849
850 )");
851 }
853};
854
856 CommandReturnObject &result) {
857#if LLDB_ENABLE_PYTHON
858 if (m_options.m_class_name.empty()) {
860 "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
861 return;
862 }
863
864 if (m_options.m_module.empty()) {
865 result.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
866 m_cmd_name.c_str());
867 return;
868 }
869
870 if (m_options.m_symbols.empty()) {
872 "%s needs at least one symbol name (-n argument).\n",
873 m_cmd_name.c_str());
874 return;
875 }
876
877 if (m_options.m_regex && m_options.m_symbols.size() > 1) {
879 "%s needs only one symbol regular expression (-n argument).\n",
880 m_cmd_name.c_str());
881 return;
882 }
883
885
886 if (interpreter &&
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");
890 }
891
892 StackFrameRecognizerSP recognizer_sp =
894 interpreter, m_options.m_class_name.c_str()));
895 if (m_options.m_regex) {
896 auto module =
898 auto func =
901 recognizer_sp, module, func, Mangled::NamePreference::ePreferDemangled,
903 } else {
904 auto module = ConstString(m_options.m_module);
905 std::vector<ConstString> symbols(m_options.m_symbols.begin(),
906 m_options.m_symbols.end());
908 recognizer_sp, module, symbols,
909 Mangled::NamePreference::ePreferDemangled,
911 }
912#endif
913
915}
916
918public:
920 : CommandObjectParsed(interpreter, "frame recognizer clear",
921 "Delete all frame recognizers.", nullptr) {}
922
924
925protected:
926 void DoExecute(Args &command, CommandReturnObject &result) override {
929 }
930};
931
932static void
933PrintRecognizerDetails(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) {
937 if (!enabled)
938 strm << "[disabled] ";
939
940 strm << name << ", ";
941
942 if (!module.empty())
943 strm << "module " << module << ", ";
944
945 switch (symbol_mangling) {
946 case Mangled::NamePreference ::ePreferMangled:
947 strm << "mangled symbol ";
948 break;
949 case Mangled::NamePreference ::ePreferDemangled:
950 strm << "demangled symbol ";
951 break;
952 case Mangled::NamePreference ::ePreferDemangledWithoutArguments:
953 strm << "demangled (no args) symbol ";
954 break;
955 }
956
957 if (regexp)
958 strm << "regex ";
959
960 llvm::interleaveComma(symbols, strm);
961}
962
963// Base class for commands which accept a single frame recognizer as an argument
965public:
967 const char *name,
968 const char *help = nullptr,
969 const char *syntax = nullptr,
970 uint32_t flags = 0)
971 : CommandObjectParsed(interpreter, name, help, syntax, flags) {
973 }
974
975 void
977 OptionElementVector &opt_element_vector) override {
978 if (request.GetCursorIndex() != 0)
979 return;
980
982 [&request](uint32_t rid, bool enabled, std::string rname,
983 std::string module,
984 llvm::ArrayRef<lldb_private::ConstString> symbols,
985 Mangled::NamePreference symbol_mangling, bool regexp) {
986 StreamString strm;
987 if (rname.empty())
988 rname = "(internal)";
989
990 PrintRecognizerDetails(strm, rname, enabled, module, symbols,
991 symbol_mangling, regexp);
992
993 request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString());
994 });
995 }
996
998 uint32_t recognizer_id) = 0;
999
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));
1005 return;
1006 }
1007
1008 DoExecuteWithId(result, recognizer_id);
1009 }
1010};
1011
1014public:
1017 interpreter, "frame recognizer enable",
1018 "Enable a frame recognizer by id.", nullptr) {
1020 }
1021
1023
1024protected:
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",
1030 recognizer_id);
1031 return;
1032 }
1034 }
1035};
1036
1039public:
1042 interpreter, "frame recognizer disable",
1043 "Disable a frame recognizer by id.", nullptr) {
1045 }
1046
1048
1049protected:
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",
1055 recognizer_id);
1056 return;
1057 }
1059 }
1060};
1061
1064public:
1067 interpreter, "frame recognizer delete",
1068 "Delete an existing frame recognizer by id.", nullptr) {
1070 }
1071
1073
1074protected:
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",
1080 recognizer_id);
1081 return;
1082 }
1084 }
1085};
1086
1088public:
1090 : CommandObjectParsed(interpreter, "frame recognizer list",
1091 "Show a list of active frame recognizers.",
1092 nullptr) {}
1093
1095
1096protected:
1097 void DoExecute(Args &command, CommandReturnObject &result) override {
1098 bool any_printed = false;
1100 [&result,
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();
1105
1106 if (name.empty())
1107 name = "(internal)";
1108
1109 stream << std::to_string(recognizer_id) << ": ";
1110 PrintRecognizerDetails(stream, name, enabled, module, symbols,
1111 symbol_mangling, regexp);
1112
1113 stream.EOL();
1114 stream.Flush();
1115
1116 any_printed = true;
1117 });
1118
1119 if (any_printed)
1121 else {
1122 result.GetOutputStream().PutCString("no matching results found.\n");
1124 }
1125 }
1126};
1127
1129public:
1132 interpreter, "frame recognizer info",
1133 "Show which frame recognizer is applied a stack frame (if any).",
1134 nullptr) {
1136 }
1137
1139
1140protected:
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.",
1146 frame_index_str);
1147 return;
1148 }
1149
1150 Process *process = m_exe_ctx.GetProcessPtr();
1151 if (process == nullptr) {
1152 result.AppendError("no process");
1153 return;
1154 }
1155 Thread *thread = m_exe_ctx.GetThreadPtr();
1156 if (thread == nullptr) {
1157 result.AppendError("no thread");
1158 return;
1159 }
1160 if (command.GetArgumentCount() != 1) {
1161 result.AppendErrorWithFormat(
1162 "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
1163 return;
1164 }
1165
1166 StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
1167 if (!frame_sp) {
1168 result.AppendErrorWithFormat("no frame with index %u", frame_index);
1169 return;
1170 }
1171
1172 auto recognizer =
1174
1175 Stream &output_stream = result.GetOutputStream();
1176 output_stream.Printf("frame %d ", frame_index);
1177 if (recognizer) {
1178 output_stream << "is recognized by ";
1179 output_stream << recognizer->GetName();
1180 } else {
1181 output_stream << "not recognized by any recognizer";
1182 }
1183 output_stream.EOL();
1185 }
1186};
1187
1189public:
1192 interpreter, "frame recognizer",
1193 "Commands for editing and viewing frame recognizers.",
1194 "frame recognizer [<sub-command-options>] ") {
1196 interpreter)));
1198 interpreter)));
1200 interpreter)));
1202 "enable",
1205 "disable",
1208 "delete",
1211 "clear",
1213 }
1214
1215 ~CommandObjectFrameRecognizer() override = default;
1216};
1217
1218#pragma mark CommandObjectMultiwordFrame
1219
1220// CommandObjectMultiwordFrame
1221
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",
1231 LoadSubCommand("info",
1232 CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1233 LoadSubCommand("select",
1234 CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1235 LoadSubCommand("variable",
1237#if LLDB_ENABLE_PYTHON
1239 interpreter)));
1240#endif
1241}
1242
static void PrintRecognizerDetails(Stream &strm, const std::string &name, bool enabled, const std::string &module, llvm::ArrayRef< lldb_private::ConstString > symbols, Mangled::NamePreference symbol_mangling, bool regexp)
static llvm::raw_ostream & error(Stream &strm)
void OptionParsingStarting(ExecutionContext *execution_context) override
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override
Set the value of an option.
~CommandObjectFrameDiagnose() override=default
CommandObjectFrameDiagnose(CommandInterpreter &interpreter)
Options * GetOptions() override
void DoExecute(Args &command, CommandReturnObject &result) override
CommandObjectFrameInfo(CommandInterpreter &interpreter)
void DoExecute(Args &command, CommandReturnObject &result) override
~CommandObjectFrameInfo() override=default
void OptionParsingStarting(ExecutionContext *execution_context) override
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override
Set the value of an option.
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)
void DoExecute(Args &command, CommandReturnObject &result) override
~CommandObjectFrameRecognizerAdd() override=default
CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
~CommandObjectFrameRecognizerClear() override=default
void DoExecute(Args &command, CommandReturnObject &result) override
~CommandObjectFrameRecognizerDelete() override=default
CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
void DoExecuteWithId(CommandReturnObject &result, uint32_t recognizer_id) override
CommandObjectFrameRecognizerDisable(CommandInterpreter &interpreter)
void DoExecuteWithId(CommandReturnObject &result, uint32_t recognizer_id) override
~CommandObjectFrameRecognizerDisable() override=default
void DoExecuteWithId(CommandReturnObject &result, uint32_t recognizer_id) override
CommandObjectFrameRecognizerEnable(CommandInterpreter &interpreter)
~CommandObjectFrameRecognizerEnable() override=default
CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
~CommandObjectFrameRecognizerInfo() override=default
void DoExecute(Args &command, CommandReturnObject &result) override
CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
~CommandObjectFrameRecognizerList() override=default
void DoExecute(Args &command, CommandReturnObject &result) override
~CommandObjectFrameRecognizer() override=default
CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override
Set the value of an option.
void OptionParsingStarting(ExecutionContext *execution_context) override
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
~CommandObjectFrameSelect() override=default
CommandObjectFrameSelect(CommandInterpreter &interpreter)
Options * GetOptions() override
void DoExecute(Args &command, CommandReturnObject &result) override
Options * GetOptions() override
OptionGroupVariable m_option_variable
OptionGroupValueObjectDisplay m_varobj_options
bool ScopeRequested(lldb::ValueType scope)
Returns true if scope matches any of the options in m_option_variable.
llvm::StringRef GetScopeString(VariableSP var_sp)
std::optional< llvm::ArrayRef< VariableSP > > findUniqueRegexMatches(RegularExpression &regex, VariableList &matches, const VariableList &all_variables)
Finds all the variables in all_variables whose name matches regex, inserting them into matches.
~CommandObjectFrameVariable() override=default
CommandObjectFrameVariable(CommandInterpreter &interpreter)
void DoExecute(Args &command, CommandReturnObject &result) override
void DoExecute(Args &command, CommandReturnObject &result) override
void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override
The default version handles argument definitions that have only one argument type,...
CommandObjectWithFrameRecognizerArg(CommandInterpreter &interpreter, const char *name, const char *help=nullptr, const char *syntax=nullptr, uint32_t flags=0)
virtual void DoExecuteWithId(CommandReturnObject &result, uint32_t recognizer_id)=0
A command line argument class.
Definition: Args.h:33
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
Definition: Args.h:120
const char * GetArgumentAtIndex(size_t idx) const
Gets the NULL terminated C string argument pointer for the argument at index idx.
Definition: Args.cpp:273
bool empty() const
Definition: Args.h:122
void PrintWarningsIfNecessary(Stream &s, const std::string &cmd_name)
CommandObjectMultiwordFrame(CommandInterpreter &interpreter)
bool LoadSubCommand(llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_obj) override
virtual void SetHelpLong(llvm::StringRef str)
void AddSimpleArgumentList(lldb::CommandArgumentType arg_type, ArgumentRepetitionType repetition_type=eArgRepeatPlain)
ExecutionContext m_exe_ctx
CommandInterpreter & GetCommandInterpreter()
CommandInterpreter & m_interpreter
void void AppendError(llvm::StringRef in_string)
void SetStatus(lldb::ReturnStatus status)
void AppendErrorWithFormat(const char *format,...) __attribute__((format(printf
lldb::ReturnStatus GetStatus() const
void void AppendWarning(llvm::StringRef in_string)
"lldb/Utility/ArgCompletionRequest.h"
void TryCompleteCurrentArg(llvm::StringRef completion, llvm::StringRef description="")
Adds a possible completion string if the completion would complete the current argument.
A uniqued constant string class.
Definition: ConstString.h:40
static bool GetSummaryFormat(ConstString type, lldb::TypeSummaryImplSP &entry)
ScriptInterpreter * GetScriptInterpreter(bool can_create=true, std::optional< lldb::ScriptLanguage > language={})
Definition: Debugger.cpp:1719
DumpValueObjectOptions & SetVariableFormatDisplayLanguage(lldb::LanguageType lang=lldb::eLanguageTypeUnknown)
std::function< bool(ConstString, ConstString, const DumpValueObjectOptions &, Stream &)> DeclPrintingHelper
DumpValueObjectOptions & SetDeclPrintingHelper(DeclPrintingHelper helper)
DumpValueObjectOptions & SetRootValueObjectName(const char *name=nullptr)
DumpValueObjectOptions & SetFormat(lldb::Format format=lldb::eFormatDefault)
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
void SetFrameSP(const lldb::StackFrameSP &frame_sp)
Set accessor to set only the frame shared pointer.
StackFrame * GetFramePtr() const
Returns a pointer to the frame object.
StackFrame & GetFrameRef() const
Returns a reference to the thread object.
Process * GetProcessPtr() const
Returns a pointer to the process object.
Thread * GetThreadPtr() const
Returns a pointer to the thread object.
bool IsTopLevelFunction()
Get whether this function represents a 'top-level' function.
Definition: Function.cpp:539
static const uint32_t OPTION_GROUP_GDB_FMT
static const uint32_t OPTION_GROUP_FORMAT
void Append(OptionGroup *group)
Append options from a OptionGroup class.
Definition: Options.cpp:788
DumpValueObjectOptions GetAsDumpOptions(LanguageRuntimeDescriptionDisplayVerbosity lang_descr_verbosity=eLanguageRuntimeDescriptionDisplayVerbosityFull, lldb::Format format=lldb::eFormatDefault, lldb::TypeSummaryImplSP summary_sp=lldb::TypeSummaryImplSP())
const char * GetCurrentValue() const
A command line option parsing protocol class.
Definition: Options.h:58
void GenerateOptionUsage(Stream &strm, CommandObject &cmd, uint32_t screen_width)
Definition: Options.cpp:427
std::vector< Option > m_getopt_table
Definition: Options.h:198
A plug-in interface definition class for debugging a process.
Definition: Process.h:343
bool IsValid() const
Test if this object contains a valid regular expression.
llvm::Error GetError() const
Return an error if the regular expression failed to compile.
virtual bool CheckObjectExists(const char *name)
Python implementation for frame recognizers.
void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, ConstString module, llvm::ArrayRef< ConstString > symbols, Mangled::NamePreference symbol_mangling, bool first_instruction_only=true)
Add a new recognizer that triggers on a given symbol name.
void ForEach(std::function< void(uint32_t recognizer_id, bool enabled, std::string recognizer_name, std::string module, llvm::ArrayRef< ConstString > symbols, Mangled::NamePreference name_preference, bool regexp)> const &callback)
lldb::StackFrameRecognizerSP GetRecognizerForFrame(lldb::StackFrameSP frame)
This base class provides an interface to stack frames.
Definition: StackFrame.h:44
@ eExpressionPathOptionsInspectAnonymousUnions
Definition: StackFrame.h:52
@ eExpressionPathOptionsAllowDirectIVarAccess
Definition: StackFrame.h:51
VariableList * GetVariableList(bool get_file_globals, Status *error_ptr)
Retrieve the list of variables that are in scope at this StackFrame's pc.
Definition: StackFrame.cpp:425
void DumpUsingSettingsFormat(Stream *strm, bool show_unique=false, const char *frame_marker=nullptr)
Print a description for this frame using the frame-format formatter settings.
lldb::ValueObjectSP GetValueForVariableExpressionPath(llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic, uint32_t options, lldb::VariableSP &var_sp, Status &error)
Create a ValueObject for a variable name / pathname, possibly including simple dereference/child sele...
Definition: StackFrame.cpp:509
lldb::ValueObjectSP GetValueObjectForFrameVariable(const lldb::VariableSP &variable_sp, lldb::DynamicValueType use_dynamic)
Create a ValueObject for a given Variable in this StackFrame.
const SymbolContext & GetSymbolContext(lldb::SymbolContextItem resolve_scope)
Provide a SymbolContext for this StackFrame's current pc value.
Definition: StackFrame.cpp:301
lldb::RecognizedStackFrameSP GetRecognizedFrame()
An error handling class.
Definition: Status.h:115
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Definition: Status.cpp:106
static lldb::ValueObjectSP GetCrashingDereference(lldb::StopInfoSP &stop_info_sp, lldb::addr_t *crashing_address=nullptr)
Definition: StopInfo.cpp:1541
llvm::StringRef GetString() const
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:134
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition: Stream.cpp:65
virtual void Flush()=0
Flush the stream.
size_t EOL()
Output and End of Line character to the stream.
Definition: Stream.cpp:155
Defines a symbol context baton that can be handed other debug core functions.
Definition: SymbolContext.h:34
Function * function
The Function for a given query.
A class that represents statistics for a since lldb_private::Target.
Definition: Statistics.h:265
StatsSuccessFail & GetFrameVariableStats()
Definition: Statistics.h:279
TargetStats & GetStatistics()
Definition: Target.h:1640
StackFrameRecognizerManager & GetFrameRecognizerManager()
Definition: Target.h:1487
virtual lldb::StackFrameSP GetStackFrameAtIndex(uint32_t idx)
Definition: Thread.h:408
lldb::StackFrameSP GetSelectedFrame(SelectMostRelevant select_most_relevant)
Definition: Thread.cpp:271
uint32_t GetSelectedFrameIndex(SelectMostRelevant select_most_relevant)
Definition: Thread.h:444
lldb::StopInfoSP GetStopInfo()
Definition: Thread.cpp:347
bool SetSelectedFrameByIndexNoisily(uint32_t frame_idx, Stream &output_stream)
Definition: Thread.cpp:300
virtual uint32_t GetStackFrameCount()
GetStackFrameCount can be expensive.
Definition: Thread.h:404
bool AddVariableIfUnique(const lldb::VariableSP &var_sp)
lldb::VariableSP GetVariableAtIndex(size_t idx) const
llvm::ArrayRef< lldb::VariableSP > toArrayRef()
Definition: VariableList.h:78
#define LLDB_OPT_SET_1
Definition: lldb-defines.h:111
#define LLDB_OPT_SET_ALL
Definition: lldb-defines.h:110
#define UINT32_MAX
Definition: lldb-defines.h:19
@ SelectMostRelevantFrame
A class that represents a running process on the host machine.
std::vector< OptionArgElement > OptionElementVector
Definition: Options.h:43
const char * toString(AppleArm64ExceptionClass EC)
Definition: SBAddress.h:15
std::shared_ptr< lldb_private::StackFrame > StackFrameSP
Definition: lldb-forward.h:424
std::shared_ptr< lldb_private::TypeSummaryImpl > TypeSummaryImplSP
Definition: lldb-forward.h:475
std::shared_ptr< lldb_private::CommandObject > CommandObjectSP
Definition: lldb-forward.h:333
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
Definition: lldb-forward.h:484
Format
Display format definitions.
std::shared_ptr< lldb_private::RegularExpression > RegularExpressionSP
Definition: lldb-forward.h:397
std::shared_ptr< lldb_private::ValueObjectList > ValueObjectListSP
Definition: lldb-forward.h:488
@ eReturnStatusFailed
@ eReturnStatusSuccessFinishResult
@ eReturnStatusSuccessFinishNoResult
@ eArgTypeFrameIndex
@ eArgTypeRecognizerID
std::shared_ptr< lldb_private::Variable > VariableSP
Definition: lldb-forward.h:486
std::shared_ptr< lldb_private::StackFrameRecognizer > StackFrameRecognizerSP
Definition: lldb-forward.h:428
std::shared_ptr< lldb_private::StopInfo > StopInfoSP
Definition: lldb-forward.h:431
@ eValueTypeVTableEntry
function pointer in virtual function table
@ eValueTypeVTable
virtual function table
@ eValueTypeInvalid
@ eValueTypeVariableGlobal
globals variable
@ eValueTypeConstResult
constant result variables
@ eValueTypeVariableLocal
function local variables
@ eValueTypeVariableArgument
function argument variables
@ eValueTypeRegister
stack frame register value
@ eValueTypeVariableStatic
static variable
@ eValueTypeRegisterSet
A collection of stack frame register values.
@ eValueTypeVariableThreadLocal
thread local storage variable
static bool ToBoolean(llvm::StringRef s, bool fail_value, bool *success_ptr)