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 printer.PrintValueObject();
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) {
226 error.SetErrorStringWithFormat("invalid frame offset argument '%s'",
227 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
281 if (static_cast<int32_t>(frame_idx) >=
283 frame_idx += *m_options.relative_frame_offset;
284 else {
285 if (frame_idx == 0) {
286 // If you are already at the bottom of the stack, then just warn
287 // and don't reset the frame.
288 result.AppendError("Already at the bottom of the stack.");
289 return;
290 } else
291 frame_idx = 0;
292 }
293 } else if (*m_options.relative_frame_offset > 0) {
294 // I don't want "up 20" where "20" takes you past the top of the stack
295 // to produce an error, but rather to just go to the top. OTOH, start
296 // by seeing if the requested frame exists, in which case we can avoid
297 // counting the stack here...
298 const uint32_t frame_requested = frame_idx
300 StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_requested);
301 if (frame_sp)
302 frame_idx = frame_requested;
303 else {
304 // The request went past the stack, so handle that case:
305 const uint32_t num_frames = thread->GetStackFrameCount();
306 if (static_cast<int32_t>(num_frames - frame_idx) >
308 frame_idx += *m_options.relative_frame_offset;
309 else {
310 if (frame_idx == num_frames - 1) {
311 // If we are already at the top of the stack, just warn and don't
312 // reset the frame.
313 result.AppendError("Already at the top of the stack.");
314 return;
315 } else
316 frame_idx = num_frames - 1;
317 }
318 }
319 }
320 } else {
321 if (command.GetArgumentCount() > 1) {
323 "too many arguments; expected frame-index, saw '%s'.\n",
324 command[0].c_str());
326 result.GetErrorStream(), *this,
327 GetCommandInterpreter().GetDebugger().GetTerminalWidth());
328 return;
329 }
330
331 if (command.GetArgumentCount() == 1) {
332 if (command[0].ref().getAsInteger(0, frame_idx)) {
333 result.AppendErrorWithFormat("invalid frame index argument '%s'.",
334 command[0].c_str());
335 return;
336 }
337 } else if (command.GetArgumentCount() == 0) {
339 if (frame_idx == UINT32_MAX) {
340 frame_idx = 0;
341 }
342 }
343 }
344
345 bool success = thread->SetSelectedFrameByIndexNoisily(
346 frame_idx, result.GetOutputStream());
347 if (success) {
350 } else {
351 result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
352 frame_idx);
353 }
354 }
355
357};
358
359#pragma mark CommandObjectFrameVariable
360// List images with associated information
362public:
365 interpreter, "frame variable",
366 "Show variables for the current stack frame. Defaults to all "
367 "arguments and local variables in scope. Names of argument, "
368 "local, file static and file global variables can be specified.",
369 nullptr,
370 eCommandRequiresFrame | eCommandTryTargetAPILock |
371 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
372 eCommandRequiresProcess),
374 true), // Include the frame specific options by passing "true"
376 SetHelpLong(R"(
377Children of aggregate variables can be specified such as 'var->child.x'. In
378'frame variable', the operators -> and [] do not invoke operator overloads if
379they exist, but directly access the specified element. If you want to trigger
380operator overloads use the expression command to print the variable instead.
381
382It is worth noting that except for overloaded operators, when printing local
383variables 'expr local_var' and 'frame var local_var' produce the same results.
384However, 'frame variable' is more efficient, since it uses debug information and
385memory reads directly, rather than parsing and evaluating an expression, which
386may even involve JITing and running code in the target program.)");
387
389
397 }
398
399 ~CommandObjectFrameVariable() override = default;
400
401 Options *GetOptions() override { return &m_option_group; }
402
403protected:
404 llvm::StringRef GetScopeString(VariableSP var_sp) {
405 if (!var_sp)
406 return llvm::StringRef();
407
408 switch (var_sp->GetScope()) {
410 return "GLOBAL: ";
412 return "STATIC: ";
414 return "ARG: ";
416 return "LOCAL: ";
418 return "THREAD: ";
419 default:
420 break;
421 }
422
423 return llvm::StringRef();
424 }
425
426 /// Returns true if `scope` matches any of the options in `m_option_variable`.
428 switch (scope) {
441 case eValueTypeVTable:
443 return false;
444 }
445 llvm_unreachable("Unexpected scope value");
446 }
447
448 /// Finds all the variables in `all_variables` whose name matches `regex`,
449 /// inserting them into `matches`. Variables already contained in `matches`
450 /// are not inserted again.
451 /// Nullopt is returned in case of no matches.
452 /// A sub-range of `matches` with all newly inserted variables is returned.
453 /// This may be empty if all matches were already contained in `matches`.
454 std::optional<llvm::ArrayRef<VariableSP>>
456 VariableList &matches,
457 const VariableList &all_variables) {
458 bool any_matches = false;
459 const size_t previous_num_vars = matches.GetSize();
460
461 for (const VariableSP &var : all_variables) {
462 if (!var->NameMatches(regex) || !ScopeRequested(var->GetScope()))
463 continue;
464 any_matches = true;
465 matches.AddVariableIfUnique(var);
466 }
467
468 if (any_matches)
469 return matches.toArrayRef().drop_front(previous_num_vars);
470 return std::nullopt;
471 }
472
473 void DoExecute(Args &command, CommandReturnObject &result) override {
474 // No need to check "frame" for validity as eCommandRequiresFrame ensures
475 // it is valid
477
478 Stream &s = result.GetOutputStream();
479
480 // Using a regex should behave like looking for an exact name match: it
481 // also finds globals.
483
484 // Be careful about the stack frame, if any summary formatter runs code, it
485 // might clear the StackFrameList for the thread. So hold onto a shared
486 // pointer to the frame so it stays alive.
487
489 VariableList *variable_list =
491
492 if (error.Fail() && (!variable_list || variable_list->GetSize() == 0)) {
493 result.AppendError(error.AsCString());
494
495 }
496 ValueObjectSP valobj_sp;
497
498 TypeSummaryImplSP summary_format_sp;
502 summary_format_sp);
504 summary_format_sp = std::make_shared<StringSummaryFormat>(
507
510 summary_format_sp));
511
512 const SymbolContext &sym_ctx =
513 frame->GetSymbolContext(eSymbolContextFunction);
514 if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
516
517 if (variable_list) {
518 const Format format = m_option_format.GetFormat();
519 options.SetFormat(format);
520
521 if (!command.empty()) {
522 VariableList regex_var_list;
523
524 // If we have any args to the variable command, we will make variable
525 // objects from them...
526 for (auto &entry : command) {
528 llvm::StringRef name_str = entry.ref();
529 RegularExpression regex(name_str);
530 if (regex.IsValid()) {
531 std::optional<llvm::ArrayRef<VariableSP>> results =
532 findUniqueRegexMatches(regex, regex_var_list, *variable_list);
533 if (!results) {
535 "no variables matched the regular expression '%s'.",
536 entry.c_str());
537 continue;
538 }
539 for (const VariableSP &var_sp : *results) {
540 valobj_sp = frame->GetValueObjectForFrameVariable(
542 if (valobj_sp) {
543 std::string scope_string;
545 scope_string = GetScopeString(var_sp).str();
546
547 if (!scope_string.empty())
548 s.PutCString(scope_string);
549
551 var_sp->GetDeclaration().GetFile()) {
552 bool show_fullpaths = false;
553 bool show_module = true;
554 if (var_sp->DumpDeclaration(&s, show_fullpaths,
555 show_module))
556 s.PutCString(": ");
557 }
558 valobj_sp->Dump(result.GetOutputStream(), options);
559 }
560 }
561 } else {
562 if (llvm::Error err = regex.GetError())
563 result.AppendError(llvm::toString(std::move(err)));
564 else
566 "unknown regex error when compiling '%s'", entry.c_str());
567 }
568 } else // No regex, either exact variable names or variable
569 // expressions.
570 {
572 uint32_t expr_path_options =
576 lldb::VariableSP var_sp;
577 valobj_sp = frame->GetValueForVariableExpressionPath(
578 entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
579 var_sp, error);
580 if (valobj_sp) {
581 std::string scope_string;
583 scope_string = GetScopeString(var_sp).str();
584
585 if (!scope_string.empty())
586 s.PutCString(scope_string);
587 if (m_option_variable.show_decl && var_sp &&
588 var_sp->GetDeclaration().GetFile()) {
589 var_sp->GetDeclaration().DumpStopContext(&s, false);
590 s.PutCString(": ");
591 }
592
593 options.SetFormat(format);
595 valobj_sp->GetPreferredDisplayLanguage());
596
597 Stream &output_stream = result.GetOutputStream();
599 valobj_sp->GetParent() ? entry.c_str() : nullptr);
600 valobj_sp->Dump(output_stream, options);
601 } else {
602 if (auto error_cstr = error.AsCString(nullptr))
603 result.AppendError(error_cstr);
604 else
606 "unable to find any variable expression path that matches "
607 "'%s'.",
608 entry.c_str());
609 }
610 }
611 }
612 } else // No command arg specified. Use variable_list, instead.
613 {
614 const size_t num_variables = variable_list->GetSize();
615 if (num_variables > 0) {
616 for (size_t i = 0; i < num_variables; i++) {
617 VariableSP var_sp = variable_list->GetVariableAtIndex(i);
618 if (!ScopeRequested(var_sp->GetScope()))
619 continue;
620 std::string scope_string;
622 scope_string = GetScopeString(var_sp).str();
623
624 // Use the variable object code to make sure we are using the same
625 // APIs as the public API will be using...
626 valobj_sp = frame->GetValueObjectForFrameVariable(
628 if (valobj_sp) {
629 // When dumping all variables, don't print any variables that are
630 // not in scope to avoid extra unneeded output
631 if (valobj_sp->IsInScope()) {
632 if (!valobj_sp->GetTargetSP()
633 ->GetDisplayRuntimeSupportValues() &&
634 valobj_sp->IsRuntimeSupportValue())
635 continue;
636
637 if (!scope_string.empty())
638 s.PutCString(scope_string);
639
641 var_sp->GetDeclaration().GetFile()) {
642 var_sp->GetDeclaration().DumpStopContext(&s, false);
643 s.PutCString(": ");
644 }
645
646 options.SetFormat(format);
648 valobj_sp->GetPreferredDisplayLanguage());
650 var_sp ? var_sp->GetName().AsCString() : nullptr);
651 valobj_sp->Dump(result.GetOutputStream(), options);
652 }
653 }
654 }
655 }
656 }
657 if (result.GetStatus() != eReturnStatusFailed)
659 }
660
662 auto recognized_frame = frame->GetRecognizedFrame();
663 if (recognized_frame) {
664 ValueObjectListSP recognized_arg_list =
665 recognized_frame->GetRecognizedArguments();
666 if (recognized_arg_list) {
667 for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
670 rec_value_sp->GetPreferredDisplayLanguage());
671 options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
672 rec_value_sp->Dump(result.GetOutputStream(), options);
673 }
674 }
675 }
676 }
677
679 m_cmd_name);
680
681 // Increment statistics.
683 if (result.Succeeded())
684 target_stats.GetFrameVariableStats().NotifySuccess();
685 else
686 target_stats.GetFrameVariableStats().NotifyFailure();
687 }
688
693};
694
695#pragma mark CommandObjectFrameRecognizer
696
697#define LLDB_OPTIONS_frame_recognizer_add
698#include "CommandOptions.inc"
699
701private:
702 class CommandOptions : public Options {
703 public:
704 CommandOptions() = default;
705 ~CommandOptions() override = default;
706
707 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
708 ExecutionContext *execution_context) override {
710 const int short_option = m_getopt_table[option_idx].val;
711
712 switch (short_option) {
713 case 'f': {
714 bool value, success;
715 value = OptionArgParser::ToBoolean(option_arg, true, &success);
716 if (success) {
718 } else {
719 error.SetErrorStringWithFormat(
720 "invalid boolean value '%s' passed for -f option",
721 option_arg.str().c_str());
722 }
723 } break;
724 case 'l':
725 m_class_name = std::string(option_arg);
726 break;
727 case 's':
728 m_module = std::string(option_arg);
729 break;
730 case 'n':
731 m_symbols.push_back(std::string(option_arg));
732 break;
733 case 'x':
734 m_regex = true;
735 break;
736 default:
737 llvm_unreachable("Unimplemented option");
738 }
739
740 return error;
741 }
742
743 void OptionParsingStarting(ExecutionContext *execution_context) override {
744 m_module = "";
745 m_symbols.clear();
746 m_class_name = "";
747 m_regex = false;
749 }
750
751 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
752 return llvm::ArrayRef(g_frame_recognizer_add_options);
753 }
754
755 // Instance variables to hold the values for command options.
756 std::string m_class_name;
757 std::string m_module;
758 std::vector<std::string> m_symbols;
761 };
762
764
765 Options *GetOptions() override { return &m_options; }
766
767protected:
768 void DoExecute(Args &command, CommandReturnObject &result) override;
769
770public:
772 : CommandObjectParsed(interpreter, "frame recognizer add",
773 "Add a new frame recognizer.", nullptr) {
774 SetHelpLong(R"(
775Frame recognizers allow for retrieving information about special frames based on
776ABI, arguments or other special properties of that frame, even without source
777code or debug info. Currently, one use case is to extract function arguments
778that would otherwise be unaccesible, or augment existing arguments.
779
780Adding a custom frame recognizer is possible by implementing a Python class
781and using the 'frame recognizer add' command. The Python class should have a
782'get_recognized_arguments' method and it will receive an argument of type
783lldb.SBFrame representing the current frame that we are trying to recognize.
784The method should return a (possibly empty) list of lldb.SBValue objects that
785represent the recognized arguments.
786
787An example of a recognizer that retrieves the file descriptor values from libc
788functions 'read', 'write' and 'close' follows:
789
790 class LibcFdRecognizer(object):
791 def get_recognized_arguments(self, frame):
792 if frame.name in ["read", "write", "close"]:
793 fd = frame.EvaluateExpression("$arg1").unsigned
794 target = frame.thread.process.target
795 value = target.CreateValueFromExpression("fd", "(int)%d" % fd)
796 return [value]
797 return []
798
799The file containing this implementation can be imported via 'command script
800import' and then we can register this recognizer with 'frame recognizer add'.
801It's important to restrict the recognizer to the libc library (which is
802libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
803in other modules:
804
805(lldb) command script import .../fd_recognizer.py
806(lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
807
808When the program is stopped at the beginning of the 'read' function in libc, we
809can view the recognizer arguments in 'frame variable':
810
811(lldb) b read
812(lldb) r
813Process 1234 stopped
814* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
815 frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
816(lldb) frame variable
817(int) fd = 3
818
819 )");
820 }
822};
823
825 CommandReturnObject &result) {
826#if LLDB_ENABLE_PYTHON
827 if (m_options.m_class_name.empty()) {
829 "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
830 return;
831 }
832
833 if (m_options.m_module.empty()) {
834 result.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
835 m_cmd_name.c_str());
836 return;
837 }
838
839 if (m_options.m_symbols.empty()) {
841 "%s needs at least one symbol name (-n argument).\n",
842 m_cmd_name.c_str());
843 return;
844 }
845
846 if (m_options.m_regex && m_options.m_symbols.size() > 1) {
848 "%s needs only one symbol regular expression (-n argument).\n",
849 m_cmd_name.c_str());
850 return;
851 }
852
854
855 if (interpreter &&
856 !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
857 result.AppendWarning("The provided class does not exist - please define it "
858 "before attempting to use this frame recognizer");
859 }
860
861 StackFrameRecognizerSP recognizer_sp =
863 interpreter, m_options.m_class_name.c_str()));
864 if (m_options.m_regex) {
865 auto module =
867 auto func =
870 recognizer_sp, module, func, m_options.m_first_instruction_only);
871 } else {
872 auto module = ConstString(m_options.m_module);
873 std::vector<ConstString> symbols(m_options.m_symbols.begin(),
874 m_options.m_symbols.end());
876 recognizer_sp, module, symbols, m_options.m_first_instruction_only);
877 }
878#endif
879
881}
882
884public:
886 : CommandObjectParsed(interpreter, "frame recognizer clear",
887 "Delete all frame recognizers.", nullptr) {}
888
890
891protected:
892 void DoExecute(Args &command, CommandReturnObject &result) override {
897 }
898};
899
901public:
903 : CommandObjectParsed(interpreter, "frame recognizer delete",
904 "Delete an existing frame recognizer by id.",
905 nullptr) {
907 }
908
910
911 void
913 OptionElementVector &opt_element_vector) override {
914 if (request.GetCursorIndex() != 0)
915 return;
916
918 [&request](uint32_t rid, std::string rname, std::string module,
919 llvm::ArrayRef<lldb_private::ConstString> symbols,
920 bool regexp) {
921 StreamString strm;
922 if (rname.empty())
923 rname = "(internal)";
924
925 strm << rname;
926 if (!module.empty())
927 strm << ", module " << module;
928 if (!symbols.empty())
929 for (auto &symbol : symbols)
930 strm << ", symbol " << symbol;
931 if (regexp)
932 strm << " (regexp)";
933
934 request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString());
935 });
936 }
937
938protected:
939 void DoExecute(Args &command, CommandReturnObject &result) override {
940 if (command.GetArgumentCount() == 0) {
942 "About to delete all frame recognizers, do you want to do that?",
943 true)) {
944 result.AppendMessage("Operation cancelled...");
945 return;
946 }
947
952 return;
953 }
954
955 if (command.GetArgumentCount() != 1) {
956 result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
957 m_cmd_name.c_str());
958 return;
959 }
960
961 uint32_t recognizer_id;
962 if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) {
963 result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
964 command.GetArgumentAtIndex(0));
965 return;
966 }
967
969 .GetFrameRecognizerManager()
970 .RemoveRecognizerWithID(recognizer_id)) {
971 result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
972 command.GetArgumentAtIndex(0));
973 return;
974 }
976 }
977};
978
980public:
982 : CommandObjectParsed(interpreter, "frame recognizer list",
983 "Show a list of active frame recognizers.",
984 nullptr) {}
985
987
988protected:
989 void DoExecute(Args &command, CommandReturnObject &result) override {
990 bool any_printed = false;
992 [&result, &any_printed](
993 uint32_t recognizer_id, std::string name, std::string module,
994 llvm::ArrayRef<ConstString> symbols, bool regexp) {
995 Stream &stream = result.GetOutputStream();
996
997 if (name.empty())
998 name = "(internal)";
999
1000 stream << std::to_string(recognizer_id) << ": " << name;
1001 if (!module.empty())
1002 stream << ", module " << module;
1003 if (!symbols.empty())
1004 for (auto &symbol : symbols)
1005 stream << ", symbol " << symbol;
1006 if (regexp)
1007 stream << " (regexp)";
1008
1009 stream.EOL();
1010 stream.Flush();
1011
1012 any_printed = true;
1013 });
1014
1015 if (any_printed)
1017 else {
1018 result.GetOutputStream().PutCString("no matching results found.\n");
1020 }
1021 }
1022};
1023
1025public:
1028 interpreter, "frame recognizer info",
1029 "Show which frame recognizer is applied a stack frame (if any).",
1030 nullptr) {
1032 }
1033
1035
1036protected:
1037 void DoExecute(Args &command, CommandReturnObject &result) override {
1038 const char *frame_index_str = command.GetArgumentAtIndex(0);
1039 uint32_t frame_index;
1040 if (!llvm::to_integer(frame_index_str, frame_index)) {
1041 result.AppendErrorWithFormat("'%s' is not a valid frame index.",
1042 frame_index_str);
1043 return;
1044 }
1045
1046 Process *process = m_exe_ctx.GetProcessPtr();
1047 if (process == nullptr) {
1048 result.AppendError("no process");
1049 return;
1050 }
1051 Thread *thread = m_exe_ctx.GetThreadPtr();
1052 if (thread == nullptr) {
1053 result.AppendError("no thread");
1054 return;
1055 }
1056 if (command.GetArgumentCount() != 1) {
1057 result.AppendErrorWithFormat(
1058 "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
1059 return;
1060 }
1061
1062 StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
1063 if (!frame_sp) {
1064 result.AppendErrorWithFormat("no frame with index %u", frame_index);
1065 return;
1066 }
1067
1068 auto recognizer = GetSelectedOrDummyTarget()
1070 .GetRecognizerForFrame(frame_sp);
1071
1072 Stream &output_stream = result.GetOutputStream();
1073 output_stream.Printf("frame %d ", frame_index);
1074 if (recognizer) {
1075 output_stream << "is recognized by ";
1076 output_stream << recognizer->GetName();
1077 } else {
1078 output_stream << "not recognized by any recognizer";
1079 }
1080 output_stream.EOL();
1082 }
1083};
1084
1086public:
1089 interpreter, "frame recognizer",
1090 "Commands for editing and viewing frame recognizers.",
1091 "frame recognizer [<sub-command-options>] ") {
1093 interpreter)));
1095 "clear",
1098 "delete",
1101 interpreter)));
1103 interpreter)));
1104 }
1105
1106 ~CommandObjectFrameRecognizer() override = default;
1107};
1108
1109#pragma mark CommandObjectMultiwordFrame
1110
1111// CommandObjectMultiwordFrame
1112
1114 CommandInterpreter &interpreter)
1115 : CommandObjectMultiword(interpreter, "frame",
1116 "Commands for selecting and "
1117 "examing the current "
1118 "thread's stack frames.",
1119 "frame <subcommand> [<subcommand-options>]") {
1120 LoadSubCommand("diagnose",
1122 LoadSubCommand("info",
1123 CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1124 LoadSubCommand("select",
1125 CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1126 LoadSubCommand("variable",
1128#if LLDB_ENABLE_PYTHON
1130 interpreter)));
1131#endif
1132}
1133
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
Target & GetSelectedOrDummyTarget(bool prefer_dummy=false)
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:1652
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:511
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:340
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:42
@ eExpressionPathOptionsInspectAnonymousUnions
Definition: StackFrame.h:50
@ eExpressionPathOptionsAllowDirectIVarAccess
Definition: StackFrame.h:49
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:1456
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:139
StatsSuccessFail & GetFrameVariableStats()
Definition: Statistics.h:151
TargetStats & GetStatistics()
Definition: Target.h:1607
StackFrameRecognizerManager & GetFrameRecognizerManager()
Definition: Target.h:1457
virtual lldb::StackFrameSP GetStackFrameAtIndex(uint32_t idx)
Definition: Thread.h:405
lldb::StackFrameSP GetSelectedFrame(SelectMostRelevant select_most_relevant)
Definition: Thread.cpp:265
uint32_t GetSelectedFrameIndex(SelectMostRelevant select_most_relevant)
Definition: Thread.h:441
lldb::StopInfoSP GetStopInfo()
Definition: Thread.cpp:341
bool SetSelectedFrameByIndexNoisily(uint32_t frame_idx, Stream &output_stream)
Definition: Thread.cpp:294
virtual uint32_t GetStackFrameCount()
GetStackFrameCount can be expensive.
Definition: Thread.h:401
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.
Definition: SBAttachInfo.h:14
std::vector< OptionArgElement > OptionElementVector
Definition: Options.h:43
Definition: SBAddress.h:15
std::shared_ptr< lldb_private::StackFrame > StackFrameSP
Definition: lldb-forward.h:412
std::shared_ptr< lldb_private::TypeSummaryImpl > TypeSummaryImplSP
Definition: lldb-forward.h:463
std::shared_ptr< lldb_private::CommandObject > CommandObjectSP
Definition: lldb-forward.h:325
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
Definition: lldb-forward.h:472
Format
Display format definitions.
std::shared_ptr< lldb_private::RegularExpression > RegularExpressionSP
Definition: lldb-forward.h:389
std::shared_ptr< lldb_private::ValueObjectList > ValueObjectListSP
Definition: lldb-forward.h:476
@ eReturnStatusFailed
@ eReturnStatusSuccessFinishResult
@ eReturnStatusSuccessFinishNoResult
@ eArgTypeFrameIndex
@ eArgTypeRecognizerID
std::shared_ptr< lldb_private::Variable > VariableSP
Definition: lldb-forward.h:474
std::shared_ptr< lldb_private::StackFrameRecognizer > StackFrameRecognizerSP
Definition: lldb-forward.h:416
std::shared_ptr< lldb_private::StopInfo > StopInfoSP
Definition: lldb-forward.h:419
@ 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)