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 CommandArgumentData index_arg;
118
119 // Define the first (and only) variant of this arg.
120 index_arg.arg_type = eArgTypeFrameIndex;
122
123 // There is only one variant this argument could be; put it into the
124 // argument entry.
125 arg.push_back(index_arg);
126
127 // Push the data for the first argument into the m_arguments vector.
128 m_arguments.push_back(arg);
129 }
130
131 ~CommandObjectFrameDiagnose() override = default;
132
133 Options *GetOptions() override { return &m_options; }
134
135protected:
136 bool DoExecute(Args &command, CommandReturnObject &result) override {
137 Thread *thread = m_exe_ctx.GetThreadPtr();
139
140 ValueObjectSP valobj_sp;
141
142 if (m_options.address) {
143 if (m_options.reg || m_options.offset) {
144 result.AppendError(
145 "`frame diagnose --address` is incompatible with other arguments.");
146 return false;
147 }
148 valobj_sp = frame_sp->GuessValueForAddress(*m_options.address);
149 } else if (m_options.reg) {
150 valobj_sp = frame_sp->GuessValueForRegisterAndOffset(
151 *m_options.reg, m_options.offset.value_or(0));
152 } else {
153 StopInfoSP stop_info_sp = thread->GetStopInfo();
154 if (!stop_info_sp) {
155 result.AppendError("No arguments provided, and no stop info.");
156 return false;
157 }
158
159 valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
160 }
161
162 if (!valobj_sp) {
163 result.AppendError("No diagnosis available.");
164 return false;
165 }
166
168 [&valobj_sp](ConstString type, ConstString var,
169 const DumpValueObjectOptions &opts,
170 Stream &stream) -> bool {
171 const ValueObject::GetExpressionPathFormat format = ValueObject::
172 GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
173 valobj_sp->GetExpressionPath(stream, format);
174 stream.PutCString(" =");
175 return true;
176 };
177
179 options.SetDeclPrintingHelper(helper);
180 ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(),
181 options);
182 printer.PrintValueObject();
183
184 return true;
185 }
186
188};
189
190#pragma mark CommandObjectFrameInfo
191
192// CommandObjectFrameInfo
193
195public:
197 : CommandObjectParsed(interpreter, "frame info",
198 "List information about the current "
199 "stack frame in the current thread.",
200 "frame info",
201 eCommandRequiresFrame | eCommandTryTargetAPILock |
202 eCommandProcessMustBeLaunched |
203 eCommandProcessMustBePaused) {}
204
205 ~CommandObjectFrameInfo() override = default;
206
207protected:
208 bool DoExecute(Args &command, CommandReturnObject &result) override {
211 return result.Succeeded();
212 }
213};
214
215#pragma mark CommandObjectFrameSelect
216
217// CommandObjectFrameSelect
218
219#define LLDB_OPTIONS_frame_select
220#include "CommandOptions.inc"
221
223public:
224 class CommandOptions : public Options {
225 public:
227
228 ~CommandOptions() override = default;
229
230 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
231 ExecutionContext *execution_context) override {
233 const int short_option = m_getopt_table[option_idx].val;
234 switch (short_option) {
235 case 'r': {
236 int32_t offset = 0;
237 if (option_arg.getAsInteger(0, offset) || offset == INT32_MIN) {
238 error.SetErrorStringWithFormat("invalid frame offset argument '%s'",
239 option_arg.str().c_str());
240 } else
241 relative_frame_offset = offset;
242 break;
243 }
244
245 default:
246 llvm_unreachable("Unimplemented option");
247 }
248
249 return error;
250 }
251
252 void OptionParsingStarting(ExecutionContext *execution_context) override {
253 relative_frame_offset.reset();
254 }
255
256 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
257 return llvm::ArrayRef(g_frame_select_options);
258 }
259
260 std::optional<int32_t> relative_frame_offset;
261 };
262
264 : CommandObjectParsed(interpreter, "frame select",
265 "Select the current stack frame by "
266 "index from within the current thread "
267 "(see 'thread backtrace'.)",
268 nullptr,
269 eCommandRequiresThread | eCommandTryTargetAPILock |
270 eCommandProcessMustBeLaunched |
271 eCommandProcessMustBePaused) {
273 CommandArgumentData index_arg;
274
275 // Define the first (and only) variant of this arg.
276 index_arg.arg_type = eArgTypeFrameIndex;
278
279 // There is only one variant this argument could be; put it into the
280 // argument entry.
281 arg.push_back(index_arg);
282
283 // Push the data for the first argument into the m_arguments vector.
284 m_arguments.push_back(arg);
285 }
286
287 ~CommandObjectFrameSelect() override = default;
288
289 void
291 OptionElementVector &opt_element_vector) override {
292 if (request.GetCursorIndex() != 0)
293 return;
294
297 }
298
299 Options *GetOptions() override { return &m_options; }
300
301protected:
302 bool DoExecute(Args &command, CommandReturnObject &result) override {
303 // No need to check "thread" for validity as eCommandRequiresThread ensures
304 // it is valid
305 Thread *thread = m_exe_ctx.GetThreadPtr();
306
307 uint32_t frame_idx = UINT32_MAX;
309 // The one and only argument is a signed relative frame index
311 if (frame_idx == UINT32_MAX)
312 frame_idx = 0;
313
315 if (static_cast<int32_t>(frame_idx) >=
317 frame_idx += *m_options.relative_frame_offset;
318 else {
319 if (frame_idx == 0) {
320 // If you are already at the bottom of the stack, then just warn
321 // and don't reset the frame.
322 result.AppendError("Already at the bottom of the stack.");
323 return false;
324 } else
325 frame_idx = 0;
326 }
327 } else if (*m_options.relative_frame_offset > 0) {
328 // I don't want "up 20" where "20" takes you past the top of the stack
329 // to produce an error, but rather to just go to the top. OTOH, start
330 // by seeing if the requested frame exists, in which case we can avoid
331 // counting the stack here...
332 const uint32_t frame_requested = frame_idx
334 StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_requested);
335 if (frame_sp)
336 frame_idx = frame_requested;
337 else {
338 // The request went past the stack, so handle that case:
339 const uint32_t num_frames = thread->GetStackFrameCount();
340 if (static_cast<int32_t>(num_frames - frame_idx) >
342 frame_idx += *m_options.relative_frame_offset;
343 else {
344 if (frame_idx == num_frames - 1) {
345 // If we are already at the top of the stack, just warn and don't
346 // reset the frame.
347 result.AppendError("Already at the top of the stack.");
348 return false;
349 } else
350 frame_idx = num_frames - 1;
351 }
352 }
353 }
354 } else {
355 if (command.GetArgumentCount() > 1) {
357 "too many arguments; expected frame-index, saw '%s'.\n",
358 command[0].c_str());
360 result.GetErrorStream(), *this,
361 GetCommandInterpreter().GetDebugger().GetTerminalWidth());
362 return false;
363 }
364
365 if (command.GetArgumentCount() == 1) {
366 if (command[0].ref().getAsInteger(0, frame_idx)) {
367 result.AppendErrorWithFormat("invalid frame index argument '%s'.",
368 command[0].c_str());
369 return false;
370 }
371 } else if (command.GetArgumentCount() == 0) {
373 if (frame_idx == UINT32_MAX) {
374 frame_idx = 0;
375 }
376 }
377 }
378
379 bool success = thread->SetSelectedFrameByIndexNoisily(
380 frame_idx, result.GetOutputStream());
381 if (success) {
384 } else {
385 result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
386 frame_idx);
387 }
388
389 return result.Succeeded();
390 }
391
393};
394
395#pragma mark CommandObjectFrameVariable
396// List images with associated information
398public:
401 interpreter, "frame variable",
402 "Show variables for the current stack frame. Defaults to all "
403 "arguments and local variables in scope. Names of argument, "
404 "local, file static and file global variables can be specified.",
405 nullptr,
406 eCommandRequiresFrame | eCommandTryTargetAPILock |
407 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
408 eCommandRequiresProcess),
410 true), // Include the frame specific options by passing "true"
412 SetHelpLong(R"(
413Children of aggregate variables can be specified such as 'var->child.x'. In
414'frame variable', the operators -> and [] do not invoke operator overloads if
415they exist, but directly access the specified element. If you want to trigger
416operator overloads use the expression command to print the variable instead.
417
418It is worth noting that except for overloaded operators, when printing local
419variables 'expr local_var' and 'frame var local_var' produce the same results.
420However, 'frame variable' is more efficient, since it uses debug information and
421memory reads directly, rather than parsing and evaluating an expression, which
422may even involve JITing and running code in the target program.)");
423
425 CommandArgumentData var_name_arg;
426
427 // Define the first (and only) variant of this arg.
428 var_name_arg.arg_type = eArgTypeVarName;
429 var_name_arg.arg_repetition = eArgRepeatStar;
430
431 // There is only one variant this argument could be; put it into the
432 // argument entry.
433 arg.push_back(var_name_arg);
434
435 // Push the data for the first argument into the m_arguments vector.
436 m_arguments.push_back(arg);
437
445 }
446
447 ~CommandObjectFrameVariable() override = default;
448
449 Options *GetOptions() override { return &m_option_group; }
450
451 void
453 OptionElementVector &opt_element_vector) override {
454 // Arguments are the standard source file completer.
457 nullptr);
458 }
459
460protected:
461 llvm::StringRef GetScopeString(VariableSP var_sp) {
462 if (!var_sp)
463 return llvm::StringRef();
464
465 switch (var_sp->GetScope()) {
467 return "GLOBAL: ";
469 return "STATIC: ";
471 return "ARG: ";
473 return "LOCAL: ";
475 return "THREAD: ";
476 default:
477 break;
478 }
479
480 return llvm::StringRef();
481 }
482
483 /// Returns true if `scope` matches any of the options in `m_option_variable`.
485 switch (scope) {
498 return false;
499 }
500 }
501
502 /// Finds all the variables in `all_variables` whose name matches `regex`,
503 /// inserting them into `matches`. Variables already contained in `matches`
504 /// are not inserted again.
505 /// Nullopt is returned in case of no matches.
506 /// A sub-range of `matches` with all newly inserted variables is returned.
507 /// This may be empty if all matches were already contained in `matches`.
508 std::optional<llvm::ArrayRef<VariableSP>>
510 VariableList &matches,
511 const VariableList &all_variables) {
512 bool any_matches = false;
513 const size_t previous_num_vars = matches.GetSize();
514
515 for (const VariableSP &var : all_variables) {
516 if (!var->NameMatches(regex) || !ScopeRequested(var->GetScope()))
517 continue;
518 any_matches = true;
519 matches.AddVariableIfUnique(var);
520 }
521
522 if (any_matches)
523 return matches.toArrayRef().drop_front(previous_num_vars);
524 return std::nullopt;
525 }
526
527 bool DoExecute(Args &command, CommandReturnObject &result) override {
528 // No need to check "frame" for validity as eCommandRequiresFrame ensures
529 // it is valid
531
532 Stream &s = result.GetOutputStream();
533
534 // Using a regex should behave like looking for an exact name match: it
535 // also finds globals.
537
538 // Be careful about the stack frame, if any summary formatter runs code, it
539 // might clear the StackFrameList for the thread. So hold onto a shared
540 // pointer to the frame so it stays alive.
541
543 VariableList *variable_list =
545
546 if (error.Fail() && (!variable_list || variable_list->GetSize() == 0)) {
547 result.AppendError(error.AsCString());
548
549 }
550 ValueObjectSP valobj_sp;
551
552 TypeSummaryImplSP summary_format_sp;
556 summary_format_sp);
558 summary_format_sp = std::make_shared<StringSummaryFormat>(
561
564 summary_format_sp));
565
566 const SymbolContext &sym_ctx =
567 frame->GetSymbolContext(eSymbolContextFunction);
568 if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
570
571 if (variable_list) {
572 const Format format = m_option_format.GetFormat();
573 options.SetFormat(format);
574
575 if (!command.empty()) {
576 VariableList regex_var_list;
577
578 // If we have any args to the variable command, we will make variable
579 // objects from them...
580 for (auto &entry : command) {
582 llvm::StringRef name_str = entry.ref();
583 RegularExpression regex(name_str);
584 if (regex.IsValid()) {
585 std::optional<llvm::ArrayRef<VariableSP>> results =
586 findUniqueRegexMatches(regex, regex_var_list, *variable_list);
587 if (!results) {
589 "no variables matched the regular expression '%s'.",
590 entry.c_str());
591 continue;
592 }
593 for (const VariableSP &var_sp : *results) {
594 valobj_sp = frame->GetValueObjectForFrameVariable(
596 if (valobj_sp) {
597 std::string scope_string;
599 scope_string = GetScopeString(var_sp).str();
600
601 if (!scope_string.empty())
602 s.PutCString(scope_string);
603
605 var_sp->GetDeclaration().GetFile()) {
606 bool show_fullpaths = false;
607 bool show_module = true;
608 if (var_sp->DumpDeclaration(&s, show_fullpaths,
609 show_module))
610 s.PutCString(": ");
611 }
612 valobj_sp->Dump(result.GetOutputStream(), options);
613 }
614 }
615 } else {
616 if (llvm::Error err = regex.GetError())
617 result.AppendError(llvm::toString(std::move(err)));
618 else
620 "unknown regex error when compiling '%s'", entry.c_str());
621 }
622 } else // No regex, either exact variable names or variable
623 // expressions.
624 {
626 uint32_t expr_path_options =
630 lldb::VariableSP var_sp;
631 valobj_sp = frame->GetValueForVariableExpressionPath(
632 entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
633 var_sp, error);
634 if (valobj_sp) {
635 std::string scope_string;
637 scope_string = GetScopeString(var_sp).str();
638
639 if (!scope_string.empty())
640 s.PutCString(scope_string);
641 if (m_option_variable.show_decl && var_sp &&
642 var_sp->GetDeclaration().GetFile()) {
643 var_sp->GetDeclaration().DumpStopContext(&s, false);
644 s.PutCString(": ");
645 }
646
647 options.SetFormat(format);
649 valobj_sp->GetPreferredDisplayLanguage());
650
651 Stream &output_stream = result.GetOutputStream();
653 valobj_sp->GetParent() ? entry.c_str() : nullptr);
654 valobj_sp->Dump(output_stream, options);
655 } else {
656 if (auto error_cstr = error.AsCString(nullptr))
657 result.AppendError(error_cstr);
658 else
660 "unable to find any variable expression path that matches "
661 "'%s'.",
662 entry.c_str());
663 }
664 }
665 }
666 } else // No command arg specified. Use variable_list, instead.
667 {
668 const size_t num_variables = variable_list->GetSize();
669 if (num_variables > 0) {
670 for (size_t i = 0; i < num_variables; i++) {
671 VariableSP var_sp = variable_list->GetVariableAtIndex(i);
672 if (!ScopeRequested(var_sp->GetScope()))
673 continue;
674 std::string scope_string;
676 scope_string = GetScopeString(var_sp).str();
677
678 // Use the variable object code to make sure we are using the same
679 // APIs as the public API will be using...
680 valobj_sp = frame->GetValueObjectForFrameVariable(
682 if (valobj_sp) {
683 // When dumping all variables, don't print any variables that are
684 // not in scope to avoid extra unneeded output
685 if (valobj_sp->IsInScope()) {
686 if (!valobj_sp->GetTargetSP()
687 ->GetDisplayRuntimeSupportValues() &&
688 valobj_sp->IsRuntimeSupportValue())
689 continue;
690
691 if (!scope_string.empty())
692 s.PutCString(scope_string);
693
695 var_sp->GetDeclaration().GetFile()) {
696 var_sp->GetDeclaration().DumpStopContext(&s, false);
697 s.PutCString(": ");
698 }
699
700 options.SetFormat(format);
702 valobj_sp->GetPreferredDisplayLanguage());
704 var_sp ? var_sp->GetName().AsCString() : nullptr);
705 valobj_sp->Dump(result.GetOutputStream(), options);
706 }
707 }
708 }
709 }
710 }
711 if (result.GetStatus() != eReturnStatusFailed)
713 }
714
716 auto recognized_frame = frame->GetRecognizedFrame();
717 if (recognized_frame) {
718 ValueObjectListSP recognized_arg_list =
719 recognized_frame->GetRecognizedArguments();
720 if (recognized_arg_list) {
721 for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
724 rec_value_sp->GetPreferredDisplayLanguage());
725 options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
726 rec_value_sp->Dump(result.GetOutputStream(), options);
727 }
728 }
729 }
730 }
731
733 m_cmd_name);
734
735 // Increment statistics.
736 bool res = result.Succeeded();
738 if (res)
739 target_stats.GetFrameVariableStats().NotifySuccess();
740 else
741 target_stats.GetFrameVariableStats().NotifyFailure();
742 return res;
743 }
744
749};
750
751#pragma mark CommandObjectFrameRecognizer
752
753#define LLDB_OPTIONS_frame_recognizer_add
754#include "CommandOptions.inc"
755
757private:
758 class CommandOptions : public Options {
759 public:
760 CommandOptions() = default;
761 ~CommandOptions() override = default;
762
763 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
764 ExecutionContext *execution_context) override {
766 const int short_option = m_getopt_table[option_idx].val;
767
768 switch (short_option) {
769 case 'f': {
770 bool value, success;
771 value = OptionArgParser::ToBoolean(option_arg, true, &success);
772 if (success) {
774 } else {
775 error.SetErrorStringWithFormat(
776 "invalid boolean value '%s' passed for -f option",
777 option_arg.str().c_str());
778 }
779 } break;
780 case 'l':
781 m_class_name = std::string(option_arg);
782 break;
783 case 's':
784 m_module = std::string(option_arg);
785 break;
786 case 'n':
787 m_symbols.push_back(std::string(option_arg));
788 break;
789 case 'x':
790 m_regex = true;
791 break;
792 default:
793 llvm_unreachable("Unimplemented option");
794 }
795
796 return error;
797 }
798
799 void OptionParsingStarting(ExecutionContext *execution_context) override {
800 m_module = "";
801 m_symbols.clear();
802 m_class_name = "";
803 m_regex = false;
805 }
806
807 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
808 return llvm::ArrayRef(g_frame_recognizer_add_options);
809 }
810
811 // Instance variables to hold the values for command options.
812 std::string m_class_name;
813 std::string m_module;
814 std::vector<std::string> m_symbols;
817 };
818
820
821 Options *GetOptions() override { return &m_options; }
822
823protected:
824 bool DoExecute(Args &command, CommandReturnObject &result) override;
825
826public:
828 : CommandObjectParsed(interpreter, "frame recognizer add",
829 "Add a new frame recognizer.", nullptr) {
830 SetHelpLong(R"(
831Frame recognizers allow for retrieving information about special frames based on
832ABI, arguments or other special properties of that frame, even without source
833code or debug info. Currently, one use case is to extract function arguments
834that would otherwise be unaccesible, or augment existing arguments.
835
836Adding a custom frame recognizer is possible by implementing a Python class
837and using the 'frame recognizer add' command. The Python class should have a
838'get_recognized_arguments' method and it will receive an argument of type
839lldb.SBFrame representing the current frame that we are trying to recognize.
840The method should return a (possibly empty) list of lldb.SBValue objects that
841represent the recognized arguments.
842
843An example of a recognizer that retrieves the file descriptor values from libc
844functions 'read', 'write' and 'close' follows:
845
846 class LibcFdRecognizer(object):
847 def get_recognized_arguments(self, frame):
848 if frame.name in ["read", "write", "close"]:
849 fd = frame.EvaluateExpression("$arg1").unsigned
850 target = frame.thread.process.target
851 value = target.CreateValueFromExpression("fd", "(int)%d" % fd)
852 return [value]
853 return []
854
855The file containing this implementation can be imported via 'command script
856import' and then we can register this recognizer with 'frame recognizer add'.
857It's important to restrict the recognizer to the libc library (which is
858libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
859in other modules:
860
861(lldb) command script import .../fd_recognizer.py
862(lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
863
864When the program is stopped at the beginning of the 'read' function in libc, we
865can view the recognizer arguments in 'frame variable':
866
867(lldb) b read
868(lldb) r
869Process 1234 stopped
870* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
871 frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
872(lldb) frame variable
873(int) fd = 3
874
875 )");
876 }
878};
879
881 CommandReturnObject &result) {
882#if LLDB_ENABLE_PYTHON
883 if (m_options.m_class_name.empty()) {
885 "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
886 return false;
887 }
888
889 if (m_options.m_module.empty()) {
890 result.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
891 m_cmd_name.c_str());
892 return false;
893 }
894
895 if (m_options.m_symbols.empty()) {
897 "%s needs at least one symbol name (-n argument).\n",
898 m_cmd_name.c_str());
899 return false;
900 }
901
902 if (m_options.m_regex && m_options.m_symbols.size() > 1) {
904 "%s needs only one symbol regular expression (-n argument).\n",
905 m_cmd_name.c_str());
906 return false;
907 }
908
910
911 if (interpreter &&
912 !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
913 result.AppendWarning("The provided class does not exist - please define it "
914 "before attempting to use this frame recognizer");
915 }
916
917 StackFrameRecognizerSP recognizer_sp =
919 interpreter, m_options.m_class_name.c_str()));
920 if (m_options.m_regex) {
921 auto module =
923 auto func =
926 recognizer_sp, module, func, m_options.m_first_instruction_only);
927 } else {
928 auto module = ConstString(m_options.m_module);
929 std::vector<ConstString> symbols(m_options.m_symbols.begin(),
930 m_options.m_symbols.end());
932 recognizer_sp, module, symbols, m_options.m_first_instruction_only);
933 }
934#endif
935
937 return result.Succeeded();
938}
939
941public:
943 : CommandObjectParsed(interpreter, "frame recognizer clear",
944 "Delete all frame recognizers.", nullptr) {}
945
947
948protected:
949 bool DoExecute(Args &command, CommandReturnObject &result) override {
954 return result.Succeeded();
955 }
956};
957
959public:
961 : CommandObjectParsed(interpreter, "frame recognizer delete",
962 "Delete an existing frame recognizer by id.",
963 nullptr) {
965 m_arguments.push_back({thread_arg});
966 }
967
969
970 void
972 OptionElementVector &opt_element_vector) override {
973 if (request.GetCursorIndex() != 0)
974 return;
975
977 [&request](uint32_t rid, std::string rname, std::string module,
978 llvm::ArrayRef<lldb_private::ConstString> symbols,
979 bool regexp) {
980 StreamString strm;
981 if (rname.empty())
982 rname = "(internal)";
983
984 strm << rname;
985 if (!module.empty())
986 strm << ", module " << module;
987 if (!symbols.empty())
988 for (auto &symbol : symbols)
989 strm << ", symbol " << symbol;
990 if (regexp)
991 strm << " (regexp)";
992
993 request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString());
994 });
995 }
996
997protected:
998 bool DoExecute(Args &command, CommandReturnObject &result) override {
999 if (command.GetArgumentCount() == 0) {
1001 "About to delete all frame recognizers, do you want to do that?",
1002 true)) {
1003 result.AppendMessage("Operation cancelled...");
1004 return false;
1005 }
1006
1011 return result.Succeeded();
1012 }
1013
1014 if (command.GetArgumentCount() != 1) {
1015 result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
1016 m_cmd_name.c_str());
1017 return false;
1018 }
1019
1020 uint32_t recognizer_id;
1021 if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) {
1022 result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
1023 command.GetArgumentAtIndex(0));
1024 return false;
1025 }
1026
1028 .GetFrameRecognizerManager()
1029 .RemoveRecognizerWithID(recognizer_id)) {
1030 result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
1031 command.GetArgumentAtIndex(0));
1032 return false;
1033 }
1035 return result.Succeeded();
1036 }
1037};
1038
1040public:
1042 : CommandObjectParsed(interpreter, "frame recognizer list",
1043 "Show a list of active frame recognizers.",
1044 nullptr) {}
1045
1047
1048protected:
1049 bool DoExecute(Args &command, CommandReturnObject &result) override {
1050 bool any_printed = false;
1052 [&result, &any_printed](
1053 uint32_t recognizer_id, std::string name, std::string module,
1054 llvm::ArrayRef<ConstString> symbols, bool regexp) {
1055 Stream &stream = result.GetOutputStream();
1056
1057 if (name.empty())
1058 name = "(internal)";
1059
1060 stream << std::to_string(recognizer_id) << ": " << name;
1061 if (!module.empty())
1062 stream << ", module " << module;
1063 if (!symbols.empty())
1064 for (auto &symbol : symbols)
1065 stream << ", symbol " << symbol;
1066 if (regexp)
1067 stream << " (regexp)";
1068
1069 stream.EOL();
1070 stream.Flush();
1071
1072 any_printed = true;
1073 });
1074
1075 if (any_printed)
1077 else {
1078 result.GetOutputStream().PutCString("no matching results found.\n");
1080 }
1081 return result.Succeeded();
1082 }
1083};
1084
1086public:
1089 interpreter, "frame recognizer info",
1090 "Show which frame recognizer is applied a stack frame (if any).",
1091 nullptr) {
1093 CommandArgumentData index_arg;
1094
1095 // Define the first (and only) variant of this arg.
1096 index_arg.arg_type = eArgTypeFrameIndex;
1097 index_arg.arg_repetition = eArgRepeatPlain;
1098
1099 // There is only one variant this argument could be; put it into the
1100 // argument entry.
1101 arg.push_back(index_arg);
1102
1103 // Push the data for the first argument into the m_arguments vector.
1104 m_arguments.push_back(arg);
1105 }
1106
1108
1109protected:
1110 bool DoExecute(Args &command, CommandReturnObject &result) override {
1111 const char *frame_index_str = command.GetArgumentAtIndex(0);
1112 uint32_t frame_index;
1113 if (!llvm::to_integer(frame_index_str, frame_index)) {
1114 result.AppendErrorWithFormat("'%s' is not a valid frame index.",
1115 frame_index_str);
1116 return false;
1117 }
1118
1119 Process *process = m_exe_ctx.GetProcessPtr();
1120 if (process == nullptr) {
1121 result.AppendError("no process");
1122 return false;
1123 }
1124 Thread *thread = m_exe_ctx.GetThreadPtr();
1125 if (thread == nullptr) {
1126 result.AppendError("no thread");
1127 return false;
1128 }
1129 if (command.GetArgumentCount() != 1) {
1130 result.AppendErrorWithFormat(
1131 "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
1132 return false;
1133 }
1134
1135 StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
1136 if (!frame_sp) {
1137 result.AppendErrorWithFormat("no frame with index %u", frame_index);
1138 return false;
1139 }
1140
1141 auto recognizer = GetSelectedOrDummyTarget()
1143 .GetRecognizerForFrame(frame_sp);
1144
1145 Stream &output_stream = result.GetOutputStream();
1146 output_stream.Printf("frame %d ", frame_index);
1147 if (recognizer) {
1148 output_stream << "is recognized by ";
1149 output_stream << recognizer->GetName();
1150 } else {
1151 output_stream << "not recognized by any recognizer";
1152 }
1153 output_stream.EOL();
1155 return result.Succeeded();
1156 }
1157};
1158
1160public:
1163 interpreter, "frame recognizer",
1164 "Commands for editing and viewing frame recognizers.",
1165 "frame recognizer [<sub-command-options>] ") {
1167 interpreter)));
1169 "clear",
1172 "delete",
1175 interpreter)));
1177 interpreter)));
1178 }
1179
1180 ~CommandObjectFrameRecognizer() override = default;
1181};
1182
1183#pragma mark CommandObjectMultiwordFrame
1184
1185// CommandObjectMultiwordFrame
1186
1188 CommandInterpreter &interpreter)
1189 : CommandObjectMultiword(interpreter, "frame",
1190 "Commands for selecting and "
1191 "examing the current "
1192 "thread's stack frames.",
1193 "frame <subcommand> [<subcommand-options>]") {
1194 LoadSubCommand("diagnose",
1196 LoadSubCommand("info",
1197 CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1198 LoadSubCommand("select",
1199 CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1200 LoadSubCommand("variable",
1202#if LLDB_ENABLE_PYTHON
1204 interpreter)));
1205#endif
1206}
1207
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
bool DoExecute(Args &command, CommandReturnObject &result) override
CommandObjectFrameInfo(CommandInterpreter &interpreter)
bool 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)
bool DoExecute(Args &command, CommandReturnObject &result) override
~CommandObjectFrameRecognizerAdd() override=default
CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
~CommandObjectFrameRecognizerClear() override=default
bool DoExecute(Args &command, CommandReturnObject &result) override
bool DoExecute(Args &command, CommandReturnObject &result) override
~CommandObjectFrameRecognizerDelete() override=default
void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override
The input array contains a parsed version of the line.
CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
~CommandObjectFrameRecognizerInfo() override=default
bool DoExecute(Args &command, CommandReturnObject &result) override
bool DoExecute(Args &command, CommandReturnObject &result) override
CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
~CommandObjectFrameRecognizerList() override=default
~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
bool DoExecute(Args &command, CommandReturnObject &result) override
~CommandObjectFrameSelect() override=default
CommandObjectFrameSelect(CommandInterpreter &interpreter)
Options * GetOptions() override
void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override
The input array contains a parsed version of the line.
Options * GetOptions() override
OptionGroupVariable m_option_variable
void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override
The input array contains a parsed version of the line.
OptionGroupValueObjectDisplay m_varobj_options
bool DoExecute(Args &command, CommandReturnObject &result) override
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)
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
static bool InvokeCommonCompletionCallbacks(CommandInterpreter &interpreter, uint32_t completion_mask, lldb_private::CompletionRequest &request, SearchFilter *searcher)
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
std::vector< CommandArgumentData > CommandArgumentEntry
virtual void SetHelpLong(llvm::StringRef str)
ExecutionContext m_exe_ctx
std::vector< CommandArgumentEntry > m_arguments
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:1632
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:502
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:336
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:41
@ eExpressionPathOptionsInspectAnonymousUnions
Definition: StackFrame.h:49
@ eExpressionPathOptionsAllowDirectIVarAccess
Definition: StackFrame.h:48
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:1449
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:107
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition: Stream.cpp:63
virtual void Flush()=0
Flush the stream.
size_t EOL()
Output and End of Line character to the stream.
Definition: Stream.cpp:128
Defines a symbol context baton that can be handed other debug core functions.
Definition: SymbolContext.h:33
Function * function
The Function for a given query.
A class that represents statistics for a since lldb_private::Target.
Definition: Statistics.h:134
StatsSuccessFail & GetFrameVariableStats()
Definition: Statistics.h:145
TargetStats & GetStatistics()
Definition: Target.h:1601
StackFrameRecognizerManager & GetFrameRecognizerManager()
Definition: Target.h:1452
virtual lldb::StackFrameSP GetStackFrameAtIndex(uint32_t idx)
Definition: Thread.h:397
lldb::StackFrameSP GetSelectedFrame(SelectMostRelevant select_most_relevant)
Definition: Thread.cpp:262
uint32_t GetSelectedFrameIndex(SelectMostRelevant select_most_relevant)
Definition: Thread.h:433
lldb::StopInfoSP GetStopInfo()
Definition: Thread.cpp:338
bool SetSelectedFrameByIndexNoisily(uint32_t frame_idx, Stream &output_stream)
Definition: Thread.cpp:291
virtual uint32_t GetStackFrameCount()
Definition: Thread.h:393
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:104
#define LLDB_OPT_SET_ALL
Definition: lldb-defines.h:103
#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
@ eFrameIndexCompletion
@ eVariablePathCompletion
std::shared_ptr< lldb_private::StackFrame > StackFrameSP
Definition: lldb-forward.h:399
std::shared_ptr< lldb_private::TypeSummaryImpl > TypeSummaryImplSP
Definition: lldb-forward.h:450
std::shared_ptr< lldb_private::CommandObject > CommandObjectSP
Definition: lldb-forward.h:315
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
Definition: lldb-forward.h:458
Format
Display format definitions.
std::shared_ptr< lldb_private::RegularExpression > RegularExpressionSP
Definition: lldb-forward.h:376
std::shared_ptr< lldb_private::ValueObjectList > ValueObjectListSP
Definition: lldb-forward.h:462
@ eReturnStatusFailed
@ eReturnStatusSuccessFinishResult
@ eReturnStatusSuccessFinishNoResult
@ eArgTypeFrameIndex
@ eArgTypeRecognizerID
std::shared_ptr< lldb_private::Variable > VariableSP
Definition: lldb-forward.h:460
std::shared_ptr< lldb_private::StackFrameRecognizer > StackFrameRecognizerSP
Definition: lldb-forward.h:403
std::shared_ptr< lldb_private::StopInfo > StopInfoSP
Definition: lldb-forward.h:406
@ 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
Used to build individual command argument lists.
Definition: CommandObject.h:93
static bool ToBoolean(llvm::StringRef s, bool fail_value, bool *success_ptr)