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//===----------------------------------------------------------------------===//
13#include "lldb/Host/Config.h"
30#include "lldb/Target/Target.h"
31#include "lldb/Target/Thread.h"
32#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();
71 error.SetErrorStringWithFormat("invalid address argument '%s'",
72 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();
80 error.SetErrorStringWithFormat("invalid offset argument '%s'",
81 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(),
172 options);
173 if (llvm::Error error = printer.PrintValueObject())
174 result.AppendError(toString(std::move(error)));
175 }
176
178};
179
180#pragma mark CommandObjectFrameInfo
181
182// CommandObjectFrameInfo
183
185public:
187 : CommandObjectParsed(interpreter, "frame info",
188 "List information about the current "
189 "stack frame in the current thread.",
190 "frame info",
191 eCommandRequiresFrame | eCommandTryTargetAPILock |
192 eCommandProcessMustBeLaunched |
193 eCommandProcessMustBePaused) {}
194
195 ~CommandObjectFrameInfo() override = default;
196
197protected:
198 void DoExecute(Args &command, CommandReturnObject &result) override {
201 }
202};
203
204#pragma mark CommandObjectFrameSelect
205
206// CommandObjectFrameSelect
207
208#define LLDB_OPTIONS_frame_select
209#include "CommandOptions.inc"
210
212public:
213 class CommandOptions : public Options {
214 public:
216
217 ~CommandOptions() override = default;
218
219 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
220 ExecutionContext *execution_context) override {
222 const int short_option = m_getopt_table[option_idx].val;
223 switch (short_option) {
224 case 'r': {
225 int32_t offset = 0;
226 if (option_arg.getAsInteger(0, offset) || offset == INT32_MIN) {
227 error.SetErrorStringWithFormat("invalid frame offset argument '%s'",
228 option_arg.str().c_str());
229 } else
230 relative_frame_offset = offset;
231 break;
232 }
233
234 default:
235 llvm_unreachable("Unimplemented option");
236 }
237
238 return error;
239 }
240
241 void OptionParsingStarting(ExecutionContext *execution_context) override {
242 relative_frame_offset.reset();
243 }
244
245 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
246 return llvm::ArrayRef(g_frame_select_options);
247 }
248
249 std::optional<int32_t> relative_frame_offset;
250 };
251
253 : CommandObjectParsed(interpreter, "frame select",
254 "Select the current stack frame by "
255 "index from within the current thread "
256 "(see 'thread backtrace'.)",
257 nullptr,
258 eCommandRequiresThread | eCommandTryTargetAPILock |
259 eCommandProcessMustBeLaunched |
260 eCommandProcessMustBePaused) {
262 }
263
264 ~CommandObjectFrameSelect() override = default;
265
266 Options *GetOptions() override { return &m_options; }
267
268protected:
269 void DoExecute(Args &command, CommandReturnObject &result) override {
270 // No need to check "thread" for validity as eCommandRequiresThread ensures
271 // it is valid
272 Thread *thread = m_exe_ctx.GetThreadPtr();
273
274 uint32_t frame_idx = UINT32_MAX;
276 // The one and only argument is a signed relative frame index
278 if (frame_idx == UINT32_MAX)
279 frame_idx = 0;
280
281 // If moving up/down by one, skip over hidden frames.
284 uint32_t candidate_idx = frame_idx;
285 const unsigned max_depth = 12;
286 for (unsigned num_try = 0; num_try < max_depth; ++num_try) {
287 if (candidate_idx == 0 && *m_options.relative_frame_offset == -1) {
288 candidate_idx = UINT32_MAX;
289 break;
290 }
291 candidate_idx += *m_options.relative_frame_offset;
292 if (auto candidate_sp = thread->GetStackFrameAtIndex(candidate_idx)) {
293 if (candidate_sp->IsHidden())
294 continue;
295 // Now candidate_idx is the first non-hidden frame.
296 break;
297 }
298 candidate_idx = UINT32_MAX;
299 break;
300 };
301 if (candidate_idx != UINT32_MAX)
302 m_options.relative_frame_offset = candidate_idx - frame_idx;
303 }
304
306 if (static_cast<int32_t>(frame_idx) >=
308 frame_idx += *m_options.relative_frame_offset;
309 else {
310 if (frame_idx == 0) {
311 // If you are already at the bottom of the stack, then just warn
312 // and don't reset the frame.
313 result.AppendError("Already at the bottom of the stack.");
314 return;
315 } else
316 frame_idx = 0;
317 }
318 } else if (*m_options.relative_frame_offset > 0) {
319 // I don't want "up 20" where "20" takes you past the top of the stack
320 // to produce an error, but rather to just go to the top. OTOH, start
321 // by seeing if the requested frame exists, in which case we can avoid
322 // counting the stack here...
323 const uint32_t frame_requested = frame_idx
325 StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_requested);
326 if (frame_sp)
327 frame_idx = frame_requested;
328 else {
329 // The request went past the stack, so handle that case:
330 const uint32_t num_frames = thread->GetStackFrameCount();
331 if (static_cast<int32_t>(num_frames - frame_idx) >
333 frame_idx += *m_options.relative_frame_offset;
334 else {
335 if (frame_idx == num_frames - 1) {
336 // If we are already at the top of the stack, just warn and don't
337 // reset the frame.
338 result.AppendError("Already at the top of the stack.");
339 return;
340 } else
341 frame_idx = num_frames - 1;
342 }
343 }
344 }
345 } else {
346 if (command.GetArgumentCount() > 1) {
348 "too many arguments; expected frame-index, saw '%s'.\n",
349 command[0].c_str());
351 result.GetErrorStream(), *this,
352 GetCommandInterpreter().GetDebugger().GetTerminalWidth());
353 return;
354 }
355
356 if (command.GetArgumentCount() == 1) {
357 if (command[0].ref().getAsInteger(0, frame_idx)) {
358 result.AppendErrorWithFormat("invalid frame index argument '%s'.",
359 command[0].c_str());
360 return;
361 }
362 } else if (command.GetArgumentCount() == 0) {
364 if (frame_idx == UINT32_MAX) {
365 frame_idx = 0;
366 }
367 }
368 }
369
370 bool success = thread->SetSelectedFrameByIndexNoisily(
371 frame_idx, result.GetOutputStream());
372 if (success) {
375 } else {
376 result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
377 frame_idx);
378 }
379 }
380
382};
383
384#pragma mark CommandObjectFrameVariable
385// List images with associated information
387public:
390 interpreter, "frame variable",
391 "Show variables for the current stack frame. Defaults to all "
392 "arguments and local variables in scope. Names of argument, "
393 "local, file static and file global variables can be specified.",
394 nullptr,
395 eCommandRequiresFrame | eCommandTryTargetAPILock |
396 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
397 eCommandRequiresProcess),
399 true), // Include the frame specific options by passing "true"
401 SetHelpLong(R"(
402Children of aggregate variables can be specified such as 'var->child.x'. In
403'frame variable', the operators -> and [] do not invoke operator overloads if
404they exist, but directly access the specified element. If you want to trigger
405operator overloads use the expression command to print the variable instead.
406
407It is worth noting that except for overloaded operators, when printing local
408variables 'expr local_var' and 'frame var local_var' produce the same results.
409However, 'frame variable' is more efficient, since it uses debug information and
410memory reads directly, rather than parsing and evaluating an expression, which
411may even involve JITing and running code in the target program.)");
412
414
422 }
423
424 ~CommandObjectFrameVariable() override = default;
425
426 Options *GetOptions() override { return &m_option_group; }
427
428protected:
429 llvm::StringRef GetScopeString(VariableSP var_sp) {
430 if (!var_sp)
431 return llvm::StringRef();
432
433 switch (var_sp->GetScope()) {
435 return "GLOBAL: ";
437 return "STATIC: ";
439 return "ARG: ";
441 return "LOCAL: ";
443 return "THREAD: ";
444 default:
445 break;
446 }
447
448 return llvm::StringRef();
449 }
450
451 /// Returns true if `scope` matches any of the options in `m_option_variable`.
453 switch (scope) {
466 case eValueTypeVTable:
468 return false;
469 }
470 llvm_unreachable("Unexpected scope value");
471 }
472
473 /// Finds all the variables in `all_variables` whose name matches `regex`,
474 /// inserting them into `matches`. Variables already contained in `matches`
475 /// are not inserted again.
476 /// Nullopt is returned in case of no matches.
477 /// A sub-range of `matches` with all newly inserted variables is returned.
478 /// This may be empty if all matches were already contained in `matches`.
479 std::optional<llvm::ArrayRef<VariableSP>>
481 VariableList &matches,
482 const VariableList &all_variables) {
483 bool any_matches = false;
484 const size_t previous_num_vars = matches.GetSize();
485
486 for (const VariableSP &var : all_variables) {
487 if (!var->NameMatches(regex) || !ScopeRequested(var->GetScope()))
488 continue;
489 any_matches = true;
490 matches.AddVariableIfUnique(var);
491 }
492
493 if (any_matches)
494 return matches.toArrayRef().drop_front(previous_num_vars);
495 return std::nullopt;
496 }
497
498 void DoExecute(Args &command, CommandReturnObject &result) override {
499 // No need to check "frame" for validity as eCommandRequiresFrame ensures
500 // it is valid
502
503 Stream &s = result.GetOutputStream();
504
505 // Using a regex should behave like looking for an exact name match: it
506 // also finds globals.
508
509 // Be careful about the stack frame, if any summary formatter runs code, it
510 // might clear the StackFrameList for the thread. So hold onto a shared
511 // pointer to the frame so it stays alive.
512
514 VariableList *variable_list =
516
517 if (error.Fail() && (!variable_list || variable_list->GetSize() == 0)) {
518 result.AppendError(error.AsCString());
519
520 }
521 ValueObjectSP valobj_sp;
522
523 TypeSummaryImplSP summary_format_sp;
527 summary_format_sp);
529 summary_format_sp = std::make_shared<StringSummaryFormat>(
532
535 summary_format_sp));
536
537 const SymbolContext &sym_ctx =
538 frame->GetSymbolContext(eSymbolContextFunction);
539 if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
541
542 if (variable_list) {
543 const Format format = m_option_format.GetFormat();
544 options.SetFormat(format);
545
546 if (!command.empty()) {
547 VariableList regex_var_list;
548
549 // If we have any args to the variable command, we will make variable
550 // objects from them...
551 for (auto &entry : command) {
553 llvm::StringRef name_str = entry.ref();
554 RegularExpression regex(name_str);
555 if (regex.IsValid()) {
556 std::optional<llvm::ArrayRef<VariableSP>> results =
557 findUniqueRegexMatches(regex, regex_var_list, *variable_list);
558 if (!results) {
560 "no variables matched the regular expression '%s'.",
561 entry.c_str());
562 continue;
563 }
564 for (const VariableSP &var_sp : *results) {
565 valobj_sp = frame->GetValueObjectForFrameVariable(
567 if (valobj_sp) {
568 std::string scope_string;
570 scope_string = GetScopeString(var_sp).str();
571
572 if (!scope_string.empty())
573 s.PutCString(scope_string);
574
576 var_sp->GetDeclaration().GetFile()) {
577 bool show_fullpaths = false;
578 bool show_module = true;
579 if (var_sp->DumpDeclaration(&s, show_fullpaths,
580 show_module))
581 s.PutCString(": ");
582 }
583 auto &strm = result.GetOutputStream();
584 if (llvm::Error error = valobj_sp->Dump(strm, options))
585 result.AppendError(toString(std::move(error)));
586 }
587 }
588 } else {
589 if (llvm::Error err = regex.GetError())
590 result.AppendError(llvm::toString(std::move(err)));
591 else
593 "unknown regex error when compiling '%s'", entry.c_str());
594 }
595 } else // No regex, either exact variable names or variable
596 // expressions.
597 {
599 uint32_t expr_path_options =
603 lldb::VariableSP var_sp;
604 valobj_sp = frame->GetValueForVariableExpressionPath(
605 entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
606 var_sp, error);
607 if (valobj_sp) {
608 std::string scope_string;
610 scope_string = GetScopeString(var_sp).str();
611
612 if (!scope_string.empty())
613 s.PutCString(scope_string);
614 if (m_option_variable.show_decl && var_sp &&
615 var_sp->GetDeclaration().GetFile()) {
616 var_sp->GetDeclaration().DumpStopContext(&s, false);
617 s.PutCString(": ");
618 }
619
620 options.SetFormat(format);
622 valobj_sp->GetPreferredDisplayLanguage());
623
624 Stream &output_stream = result.GetOutputStream();
626 valobj_sp->GetParent() ? entry.c_str() : nullptr);
627 if (llvm::Error error = valobj_sp->Dump(output_stream, options))
628 result.AppendError(toString(std::move(error)));
629 } else {
630 if (auto error_cstr = error.AsCString(nullptr))
631 result.AppendError(error_cstr);
632 else
634 "unable to find any variable expression path that matches "
635 "'%s'.",
636 entry.c_str());
637 }
638 }
639 }
640 } else // No command arg specified. Use variable_list, instead.
641 {
642 const size_t num_variables = variable_list->GetSize();
643 if (num_variables > 0) {
644 for (size_t i = 0; i < num_variables; i++) {
645 VariableSP var_sp = variable_list->GetVariableAtIndex(i);
646 if (!ScopeRequested(var_sp->GetScope()))
647 continue;
648 std::string scope_string;
650 scope_string = GetScopeString(var_sp).str();
651
652 // Use the variable object code to make sure we are using the same
653 // APIs as the public API will be using...
654 valobj_sp = frame->GetValueObjectForFrameVariable(
656 if (valobj_sp) {
657 // When dumping all variables, don't print any variables that are
658 // not in scope to avoid extra unneeded output
659 if (valobj_sp->IsInScope()) {
660 if (!valobj_sp->GetTargetSP()
661 ->GetDisplayRuntimeSupportValues() &&
662 valobj_sp->IsRuntimeSupportValue())
663 continue;
664
665 if (!scope_string.empty())
666 s.PutCString(scope_string);
667
669 var_sp->GetDeclaration().GetFile()) {
670 var_sp->GetDeclaration().DumpStopContext(&s, false);
671 s.PutCString(": ");
672 }
673
674 options.SetFormat(format);
676 valobj_sp->GetPreferredDisplayLanguage());
678 var_sp ? var_sp->GetName().AsCString() : nullptr);
679 if (llvm::Error error =
680 valobj_sp->Dump(result.GetOutputStream(), options))
681 result.AppendError(toString(std::move(error)));
682 }
683 }
684 }
685 }
686 }
687 if (result.GetStatus() != eReturnStatusFailed)
689 }
690
692 auto recognized_frame = frame->GetRecognizedFrame();
693 if (recognized_frame) {
694 ValueObjectListSP recognized_arg_list =
695 recognized_frame->GetRecognizedArguments();
696 if (recognized_arg_list) {
697 for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
700 rec_value_sp->GetPreferredDisplayLanguage());
701 options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
702 if (llvm::Error error =
703 rec_value_sp->Dump(result.GetOutputStream(), options))
704 result.AppendError(toString(std::move(error)));
705 }
706 }
707 }
708 }
709
711 m_cmd_name);
712
713 // Increment statistics.
714 TargetStats &target_stats = GetTarget().GetStatistics();
715 if (result.Succeeded())
716 target_stats.GetFrameVariableStats().NotifySuccess();
717 else
718 target_stats.GetFrameVariableStats().NotifyFailure();
719 }
720
725};
726
727#pragma mark CommandObjectFrameRecognizer
728
729#define LLDB_OPTIONS_frame_recognizer_add
730#include "CommandOptions.inc"
731
733private:
734 class CommandOptions : public Options {
735 public:
736 CommandOptions() = default;
737 ~CommandOptions() override = default;
738
739 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
740 ExecutionContext *execution_context) override {
742 const int short_option = m_getopt_table[option_idx].val;
743
744 switch (short_option) {
745 case 'f': {
746 bool value, success;
747 value = OptionArgParser::ToBoolean(option_arg, true, &success);
748 if (success) {
750 } else {
751 error.SetErrorStringWithFormat(
752 "invalid boolean value '%s' passed for -f option",
753 option_arg.str().c_str());
754 }
755 } break;
756 case 'l':
757 m_class_name = std::string(option_arg);
758 break;
759 case 's':
760 m_module = std::string(option_arg);
761 break;
762 case 'n':
763 m_symbols.push_back(std::string(option_arg));
764 break;
765 case 'x':
766 m_regex = true;
767 break;
768 default:
769 llvm_unreachable("Unimplemented option");
770 }
771
772 return error;
773 }
774
775 void OptionParsingStarting(ExecutionContext *execution_context) override {
776 m_module = "";
777 m_symbols.clear();
778 m_class_name = "";
779 m_regex = false;
781 }
782
783 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
784 return llvm::ArrayRef(g_frame_recognizer_add_options);
785 }
786
787 // Instance variables to hold the values for command options.
788 std::string m_class_name;
789 std::string m_module;
790 std::vector<std::string> m_symbols;
793 };
794
796
797 Options *GetOptions() override { return &m_options; }
798
799protected:
800 void DoExecute(Args &command, CommandReturnObject &result) override;
801
802public:
804 : CommandObjectParsed(interpreter, "frame recognizer add",
805 "Add a new frame recognizer.", nullptr) {
806 SetHelpLong(R"(
807Frame recognizers allow for retrieving information about special frames based on
808ABI, arguments or other special properties of that frame, even without source
809code or debug info. Currently, one use case is to extract function arguments
810that would otherwise be unaccesible, or augment existing arguments.
811
812Adding a custom frame recognizer is possible by implementing a Python class
813and using the 'frame recognizer add' command. The Python class should have a
814'get_recognized_arguments' method and it will receive an argument of type
815lldb.SBFrame representing the current frame that we are trying to recognize.
816The method should return a (possibly empty) list of lldb.SBValue objects that
817represent the recognized arguments.
818
819An example of a recognizer that retrieves the file descriptor values from libc
820functions 'read', 'write' and 'close' follows:
821
822 class LibcFdRecognizer(object):
823 def get_recognized_arguments(self, frame):
824 if frame.name in ["read", "write", "close"]:
825 fd = frame.EvaluateExpression("$arg1").unsigned
826 target = frame.thread.process.target
827 value = target.CreateValueFromExpression("fd", "(int)%d" % fd)
828 return [value]
829 return []
830
831The file containing this implementation can be imported via 'command script
832import' and then we can register this recognizer with 'frame recognizer add'.
833It's important to restrict the recognizer to the libc library (which is
834libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
835in other modules:
836
837(lldb) command script import .../fd_recognizer.py
838(lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
839
840When the program is stopped at the beginning of the 'read' function in libc, we
841can view the recognizer arguments in 'frame variable':
842
843(lldb) b read
844(lldb) r
845Process 1234 stopped
846* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
847 frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
848(lldb) frame variable
849(int) fd = 3
850
851 )");
852 }
854};
855
857 CommandReturnObject &result) {
858#if LLDB_ENABLE_PYTHON
859 if (m_options.m_class_name.empty()) {
861 "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
862 return;
863 }
864
865 if (m_options.m_module.empty()) {
866 result.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
867 m_cmd_name.c_str());
868 return;
869 }
870
871 if (m_options.m_symbols.empty()) {
873 "%s needs at least one symbol name (-n argument).\n",
874 m_cmd_name.c_str());
875 return;
876 }
877
878 if (m_options.m_regex && m_options.m_symbols.size() > 1) {
880 "%s needs only one symbol regular expression (-n argument).\n",
881 m_cmd_name.c_str());
882 return;
883 }
884
886
887 if (interpreter &&
888 !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
889 result.AppendWarning("The provided class does not exist - please define it "
890 "before attempting to use this frame recognizer");
891 }
892
893 StackFrameRecognizerSP recognizer_sp =
895 interpreter, m_options.m_class_name.c_str()));
896 if (m_options.m_regex) {
897 auto module =
899 auto func =
902 recognizer_sp, module, func, m_options.m_first_instruction_only);
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, m_options.m_first_instruction_only);
909 }
910#endif
911
913}
914
916public:
918 : CommandObjectParsed(interpreter, "frame recognizer clear",
919 "Delete all frame recognizers.", nullptr) {}
920
922
923protected:
924 void DoExecute(Args &command, CommandReturnObject &result) override {
927 }
928};
929
931public:
933 : CommandObjectParsed(interpreter, "frame recognizer delete",
934 "Delete an existing frame recognizer by id.",
935 nullptr) {
937 }
938
940
941 void
943 OptionElementVector &opt_element_vector) override {
944 if (request.GetCursorIndex() != 0)
945 return;
946
948 [&request](uint32_t rid, std::string rname, std::string module,
949 llvm::ArrayRef<lldb_private::ConstString> symbols,
950 bool regexp) {
951 StreamString strm;
952 if (rname.empty())
953 rname = "(internal)";
954
955 strm << rname;
956 if (!module.empty())
957 strm << ", module " << module;
958 if (!symbols.empty())
959 for (auto &symbol : symbols)
960 strm << ", symbol " << symbol;
961 if (regexp)
962 strm << " (regexp)";
963
964 request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString());
965 });
966 }
967
968protected:
969 void DoExecute(Args &command, CommandReturnObject &result) override {
970 if (command.GetArgumentCount() == 0) {
972 "About to delete all frame recognizers, do you want to do that?",
973 true)) {
974 result.AppendMessage("Operation cancelled...");
975 return;
976 }
977
980 return;
981 }
982
983 if (command.GetArgumentCount() != 1) {
984 result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
985 m_cmd_name.c_str());
986 return;
987 }
988
989 uint32_t recognizer_id;
990 if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) {
991 result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
992 command.GetArgumentAtIndex(0));
993 return;
994 }
995
996 if (!GetTarget().GetFrameRecognizerManager().RemoveRecognizerWithID(
997 recognizer_id)) {
998 result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
999 command.GetArgumentAtIndex(0));
1000 return;
1001 }
1003 }
1004};
1005
1007public:
1009 : CommandObjectParsed(interpreter, "frame recognizer list",
1010 "Show a list of active frame recognizers.",
1011 nullptr) {}
1012
1014
1015protected:
1016 void DoExecute(Args &command, CommandReturnObject &result) override {
1017 bool any_printed = false;
1019 [&result, &any_printed](
1020 uint32_t recognizer_id, std::string name, std::string module,
1021 llvm::ArrayRef<ConstString> symbols, bool regexp) {
1022 Stream &stream = result.GetOutputStream();
1023
1024 if (name.empty())
1025 name = "(internal)";
1026
1027 stream << std::to_string(recognizer_id) << ": " << name;
1028 if (!module.empty())
1029 stream << ", module " << module;
1030 if (!symbols.empty())
1031 for (auto &symbol : symbols)
1032 stream << ", symbol " << symbol;
1033 if (regexp)
1034 stream << " (regexp)";
1035
1036 stream.EOL();
1037 stream.Flush();
1038
1039 any_printed = true;
1040 });
1041
1042 if (any_printed)
1044 else {
1045 result.GetOutputStream().PutCString("no matching results found.\n");
1047 }
1048 }
1049};
1050
1052public:
1055 interpreter, "frame recognizer info",
1056 "Show which frame recognizer is applied a stack frame (if any).",
1057 nullptr) {
1059 }
1060
1062
1063protected:
1064 void DoExecute(Args &command, CommandReturnObject &result) override {
1065 const char *frame_index_str = command.GetArgumentAtIndex(0);
1066 uint32_t frame_index;
1067 if (!llvm::to_integer(frame_index_str, frame_index)) {
1068 result.AppendErrorWithFormat("'%s' is not a valid frame index.",
1069 frame_index_str);
1070 return;
1071 }
1072
1073 Process *process = m_exe_ctx.GetProcessPtr();
1074 if (process == nullptr) {
1075 result.AppendError("no process");
1076 return;
1077 }
1078 Thread *thread = m_exe_ctx.GetThreadPtr();
1079 if (thread == nullptr) {
1080 result.AppendError("no thread");
1081 return;
1082 }
1083 if (command.GetArgumentCount() != 1) {
1084 result.AppendErrorWithFormat(
1085 "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
1086 return;
1087 }
1088
1089 StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
1090 if (!frame_sp) {
1091 result.AppendErrorWithFormat("no frame with index %u", frame_index);
1092 return;
1093 }
1094
1095 auto recognizer =
1097
1098 Stream &output_stream = result.GetOutputStream();
1099 output_stream.Printf("frame %d ", frame_index);
1100 if (recognizer) {
1101 output_stream << "is recognized by ";
1102 output_stream << recognizer->GetName();
1103 } else {
1104 output_stream << "not recognized by any recognizer";
1105 }
1106 output_stream.EOL();
1108 }
1109};
1110
1112public:
1115 interpreter, "frame recognizer",
1116 "Commands for editing and viewing frame recognizers.",
1117 "frame recognizer [<sub-command-options>] ") {
1119 interpreter)));
1121 "clear",
1124 "delete",
1127 interpreter)));
1129 interpreter)));
1130 }
1131
1132 ~CommandObjectFrameRecognizer() override = default;
1133};
1134
1135#pragma mark CommandObjectMultiwordFrame
1136
1137// CommandObjectMultiwordFrame
1138
1140 CommandInterpreter &interpreter)
1141 : CommandObjectMultiword(interpreter, "frame",
1142 "Commands for selecting and "
1143 "examing the current "
1144 "thread's stack frames.",
1145 "frame <subcommand> [<subcommand-options>]") {
1146 LoadSubCommand("diagnose",
1148 LoadSubCommand("info",
1149 CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1150 LoadSubCommand("select",
1151 CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1152 LoadSubCommand("variable",
1154#if LLDB_ENABLE_PYTHON
1156 interpreter)));
1157#endif
1158}
1159
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
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,...
CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
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
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:116
const char * GetArgumentAtIndex(size_t idx) const
Gets the NULL terminated C string argument pointer for the argument at index idx.
Definition: Args.cpp:263
bool empty() const
Definition: Args.h:118
bool Confirm(llvm::StringRef message, bool default_answer)
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 AppendMessage(llvm::StringRef in_string)
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:1684
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:512
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:755
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:395
std::vector< Option > m_getopt_table
Definition: Options.h:198
A plug-in interface definition class for debugging a process.
Definition: Process.h:341
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.
lldb::StackFrameRecognizerSP GetRecognizerForFrame(lldb::StackFrameSP frame)
void ForEach(std::function< void(uint32_t recognizer_id, std::string recognizer_name, std::string module, llvm::ArrayRef< ConstString > symbols, bool regexp)> const &callback)
void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, ConstString module, llvm::ArrayRef< ConstString > symbols, bool first_instruction_only=true)
This base class provides an interface to stack frames.
Definition: StackFrame.h:43
@ eExpressionPathOptionsInspectAnonymousUnions
Definition: StackFrame.h:51
@ eExpressionPathOptionsAllowDirectIVarAccess
Definition: StackFrame.h:50
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:424
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:508
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:300
lldb::RecognizedStackFrameSP GetRecognizedFrame()
An error handling class.
Definition: Status.h:44
static lldb::ValueObjectSP GetCrashingDereference(lldb::StopInfoSP &stop_info_sp, lldb::addr_t *crashing_address=nullptr)
Definition: StopInfo.cpp:1484
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:179
StatsSuccessFail & GetFrameVariableStats()
Definition: Statistics.h:193
TargetStats & GetStatistics()
Definition: Target.h:1623
StackFrameRecognizerManager & GetFrameRecognizerManager()
Definition: Target.h:1473
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:420
std::shared_ptr< lldb_private::TypeSummaryImpl > TypeSummaryImplSP
Definition: lldb-forward.h:471
std::shared_ptr< lldb_private::CommandObject > CommandObjectSP
Definition: lldb-forward.h:331
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
Definition: lldb-forward.h:480
Format
Display format definitions.
std::shared_ptr< lldb_private::RegularExpression > RegularExpressionSP
Definition: lldb-forward.h:395
std::shared_ptr< lldb_private::ValueObjectList > ValueObjectListSP
Definition: lldb-forward.h:484
@ eReturnStatusFailed
@ eReturnStatusSuccessFinishResult
@ eReturnStatusSuccessFinishNoResult
@ eArgTypeFrameIndex
@ eArgTypeRecognizerID
std::shared_ptr< lldb_private::Variable > VariableSP
Definition: lldb-forward.h:482
std::shared_ptr< lldb_private::StackFrameRecognizer > StackFrameRecognizerSP
Definition: lldb-forward.h:424
std::shared_ptr< lldb_private::StopInfo > StopInfoSP
Definition: lldb-forward.h:427
@ 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)