LLDB mainline
StackFrameRecognizer.cpp
Go to the documentation of this file.
1//===-- StackFrameRecognizer.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//===----------------------------------------------------------------------===//
8
11#include "lldb/Core/Debugger.h"
12#include "lldb/Core/Module.h"
15#include "lldb/Symbol/Symbol.h"
17#include "lldb/Target/Target.h"
20#include "llvm/Support/FormatVariadic.h"
21
22using namespace lldb;
23using namespace lldb_private;
24
29
30public:
32 lldb::StackFrameSP most_relevant_frame,
33 lldb::ValueObjectSP exception,
34 std::string stop_desc)
35 : m_hidden(hidden), m_most_relevant_frame(std::move(most_relevant_frame)),
36 m_exception(std::move(exception)) {
37 m_arguments = std::move(args);
38 m_stop_desc = std::move(stop_desc);
39 }
40 bool ShouldHide() override { return m_hidden; }
45};
46
48 ScriptInterpreter *interpreter, const char *pclass)
49 : m_python_class(pclass) {
50 if (!interpreter)
51 return;
52
54 if (!m_interface_sp)
55 return;
56
57 ScriptedMetadata scripted_metadata(m_python_class, nullptr);
58 auto obj_or_err = m_interface_sp->CreatePluginObject(scripted_metadata);
59 if (!obj_or_err) {
60 // CreatePluginObject has no error-return channel back to the command
61 // handler that requested this recognizer, so report the detailed error
62 // (which may include a Python backtrace) via the diagnostic system.
64 llvm::formatv("failed to create ScriptedStackFrameRecognizer: {0}",
65 llvm::toString(obj_or_err.takeError()))
66 .str(),
67 interpreter->GetDebugger().GetID());
68 m_interface_sp.reset();
69 }
70}
71
74 if (!m_interface_sp)
76
77 ValueObjectListSP args = m_interface_sp->GetRecognizedArguments(frame);
78 auto args_synthesized = std::make_shared<ValueObjectList>();
79 if (args) {
80 for (const auto &o : args->GetObjects())
81 args_synthesized->Append(ValueObjectRecognizerSynthesizedValue::Create(
83 }
84
85 bool hidden = m_interface_sp->ShouldHide(frame);
86 lldb::StackFrameSP most_relevant =
87 m_interface_sp->SelectMostRelevantFrame(frame);
88 lldb::ValueObjectSP exception = m_interface_sp->GetException(frame);
89 std::string stop_desc = m_interface_sp->GetStopDescription(frame);
90
92 args_synthesized, hidden, std::move(most_relevant), std::move(exception),
93 std::move(stop_desc)));
94}
95
97 uint32_t n = m_generation;
98 n = (n + 1) & ((1 << 16) - 1);
99 m_generation = n;
100}
101
103 StackFrameRecognizerSP recognizer, ConstString module,
104 llvm::ArrayRef<ConstString> symbols,
105 Mangled::NamePreference symbol_mangling, bool first_instruction_only) {
106 m_recognizers.push_front({(uint32_t)m_recognizers.size(), recognizer, false,
107 module, RegularExpressionSP(), symbols,
108 RegularExpressionSP(), symbol_mangling,
109 first_instruction_only, true});
111}
112
115 RegularExpressionSP symbol, Mangled::NamePreference symbol_mangling,
116 bool first_instruction_only) {
117 m_recognizers.push_front({(uint32_t)m_recognizers.size(), recognizer, true,
118 ConstString(), module, std::vector<ConstString>(),
119 symbol, symbol_mangling, first_instruction_only,
120 true});
122}
123
125 const std::function<void(
126 uint32_t, bool, std::string, std::string, llvm::ArrayRef<ConstString>,
127 Mangled::NamePreference name_preference, bool)> &callback) {
128 for (auto entry : m_recognizers) {
129 if (entry.is_regexp) {
130 std::string module_name;
131 std::string symbol_name;
132
133 if (entry.module_regexp)
134 module_name = entry.module_regexp->GetText().str();
135 if (entry.symbol_regexp)
136 symbol_name = entry.symbol_regexp->GetText().str();
137
138 callback(entry.recognizer_id, entry.enabled, entry.recognizer->GetName(),
139 module_name, llvm::ArrayRef(ConstString(symbol_name)),
140 entry.symbol_mangling, true);
141 } else {
142 callback(entry.recognizer_id, entry.enabled, entry.recognizer->GetName(),
143 entry.module.GetCString(), entry.symbols, entry.symbol_mangling,
144 false);
145 }
146 }
147}
148
150 bool enabled) {
151 auto found =
152 llvm::find_if(m_recognizers, [recognizer_id](const RegisteredEntry &e) {
153 return e.recognizer_id == recognizer_id;
154 });
155 if (found == m_recognizers.end())
156 return false;
157 found->enabled = enabled;
159 return true;
160}
161
163 uint32_t recognizer_id) {
164 auto found =
165 llvm::find_if(m_recognizers, [recognizer_id](const RegisteredEntry &e) {
166 return e.recognizer_id == recognizer_id;
167 });
168 if (found == m_recognizers.end())
169 return false;
170 m_recognizers.erase(found);
172 return true;
173}
174
179
182 const SymbolContext &symctx = frame->GetSymbolContext(
183 eSymbolContextModule | eSymbolContextFunction | eSymbolContextSymbol);
184 ModuleSP module_sp = symctx.module_sp;
185 if (!module_sp)
186 return StackFrameRecognizerSP();
187 llvm::StringRef module_name = module_sp->GetFileSpec().GetFilename();
188 const Symbol *symbol = symctx.symbol;
189 if (!symbol)
190 return StackFrameRecognizerSP();
191 Address start_addr = symbol->GetAddress();
192 Address current_addr = frame->GetFrameCodeAddress();
193
194 // The symbol's start address may fall inside a non-executable function
195 // header (as on WebAssembly), which no frame's PC can equal. Compare against
196 // the first instruction instead.
197 if (TargetSP target_sp = frame->CalculateTarget())
198 if (Architecture *arch = target_sp->GetArchitecturePlugin())
199 start_addr = arch->SkipFunctionHeader(start_addr);
200
201 for (const auto &entry : m_recognizers) {
202 if (!entry.enabled)
203 continue;
204
205 if (entry.module)
206 if (entry.module != module_name)
207 continue;
208
209 if (entry.module_regexp)
210 if (!entry.module_regexp->Execute(module_name))
211 continue;
212
213 ConstString function_name = symctx.GetFunctionName(entry.symbol_mangling);
214
215 if (!entry.symbols.empty())
216 if (!llvm::is_contained(entry.symbols, function_name))
217 continue;
218
219 if (entry.symbol_regexp)
220 if (!entry.symbol_regexp->Execute(function_name.GetStringRef()))
221 continue;
222
223 if (entry.first_instruction_only)
224 if (start_addr != current_addr)
225 continue;
226
227 return entry.recognizer;
228 }
229 return StackFrameRecognizerSP();
230}
231
234 auto recognizer = GetRecognizerForFrame(frame);
235 if (!recognizer)
236 return RecognizedStackFrameSP();
237 return recognizer->RecognizeFrame(frame);
238}
lldb::StackFrameSP GetMostRelevantFrame() override
lldb::ValueObjectSP GetExceptionObject() override
ScriptedRecognizedStackFrame(ValueObjectListSP args, bool hidden, lldb::StackFrameSP most_relevant_frame, lldb::ValueObjectSP exception, std::string stop_desc)
bool ShouldHide() override
Controls whether this frame should be filtered out when displaying backtraces, for example.
A section + offset based address class.
Definition Address.h:62
A uniqued constant string class.
Definition ConstString.h:40
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
static void ReportError(std::string message, std::optional< lldb::user_id_t > debugger_id=std::nullopt, std::once_flag *once=nullptr)
Report error events.
This class provides extra information about a stack frame that was provided by a specific stack frame...
virtual lldb::ScriptedStackFrameRecognizerInterfaceSP CreateScriptedStackFrameRecognizerInterface()
Debugger & GetDebugger()
Get the debugger associated with this script interpreter.
ScriptedStackFrameRecognizer(lldb_private::ScriptInterpreter *interpreter, const char *pclass)
lldb::RecognizedStackFrameSP RecognizeFrame(lldb::StackFrameSP frame) override
lldb::ScriptedStackFrameRecognizerInterfaceSP m_interface_sp
void BumpGeneration()
Increase the generation counter.
void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, ConstString module, llvm::ArrayRef< ConstString > symbols, Mangled::NamePreference symbol_mangling, bool first_instruction_only=true)
Add a new recognizer that triggers on a given symbol name.
void ForEach(std::function< void(uint32_t recognizer_id, bool enabled, std::string recognizer_name, std::string module, llvm::ArrayRef< ConstString > symbols, Mangled::NamePreference name_preference, bool regexp)> const &callback)
lldb::StackFrameRecognizerSP GetRecognizerForFrame(lldb::StackFrameSP frame)
lldb::RecognizedStackFrameSP RecognizeFrame(lldb::StackFrameSP frame)
bool RemoveRecognizerWithID(uint32_t recognizer_id)
bool SetEnabledForID(uint32_t recognizer_id, bool enabled)
Defines a symbol context baton that can be handed other debug core functions.
ConstString GetFunctionName(Mangled::NamePreference preference=Mangled::ePreferDemangled) const
Find a name of the innermost function for the symbol context.
lldb::ModuleSP module_sp
The Module for a given query.
Symbol * symbol
The Symbol for a given query.
Address GetAddress() const
Definition Symbol.h:89
static lldb::ValueObjectSP Create(ValueObject &parent, lldb::ValueType type)
A class that represents a running process on the host machine.
std::shared_ptr< lldb_private::StackFrame > StackFrameSP
std::shared_ptr< lldb_private::RecognizedStackFrame > RecognizedStackFrameSP
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
std::shared_ptr< lldb_private::RegularExpression > RegularExpressionSP
std::shared_ptr< lldb_private::ValueObjectList > ValueObjectListSP
@ eValueTypeVariableArgument
function argument variables
std::shared_ptr< lldb_private::StackFrameRecognizer > StackFrameRecognizerSP
std::shared_ptr< lldb_private::Target > TargetSP
std::shared_ptr< lldb_private::Module > ModuleSP
lldb::user_id_t GetID() const
Get accessor for the user ID.
Definition UserID.h:47