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"
16#include "lldb/Symbol/Symbol.h"
18#include "lldb/Target/Target.h"
21#include "llvm/Support/FormatVariadic.h"
22
23using namespace lldb;
24using namespace lldb_private;
25
27public:
29 lldb::StackFrameSP most_relevant_frame,
30 lldb::ValueObjectSP exception,
31 std::string stop_desc,
32 lldb::ThreadPlanSP step_through_plan_sp)
33 : m_hidden(hidden), m_most_relevant_frame(std::move(most_relevant_frame)),
34 m_exception(std::move(exception)),
35 m_thread_plan_sp(std::move(step_through_plan_sp)) {
36 m_arguments = std::move(args);
37 m_stop_desc = std::move(stop_desc);
38 }
39 bool ShouldHide() override { return m_hidden; }
44
46
47protected:
52};
53
55 ScriptInterpreter *interpreter, const char *pclass)
56 : m_python_class(pclass) {
57 if (!interpreter)
58 return;
59
61 if (!m_interface_sp)
62 return;
63
64 ScriptedMetadata scripted_metadata(m_python_class, nullptr);
65 auto obj_or_err = m_interface_sp->CreatePluginObject(scripted_metadata);
66 if (!obj_or_err) {
67 // CreatePluginObject has no error-return channel back to the command
68 // handler that requested this recognizer, so report the detailed error
69 // (which may include a Python backtrace) via the diagnostic system.
71 llvm::formatv("failed to create ScriptedStackFrameRecognizer: {0}",
72 llvm::toString(obj_or_err.takeError()))
73 .str(),
74 interpreter->GetDebugger().GetID());
75 m_interface_sp.reset();
76 }
77}
78
81 if (!m_interface_sp)
83
84 ValueObjectListSP args = m_interface_sp->GetRecognizedArguments(frame);
85 auto args_synthesized = std::make_shared<ValueObjectList>();
86 if (args) {
87 for (const auto &o : args->GetObjects())
88 args_synthesized->Append(ValueObjectRecognizerSynthesizedValue::Create(
90 }
91
92 bool hidden = m_interface_sp->ShouldHide(frame);
93 lldb::StackFrameSP most_relevant =
94 m_interface_sp->SelectMostRelevantFrame(frame);
95 lldb::ValueObjectSP exception = m_interface_sp->GetException(frame);
96 std::string stop_desc = m_interface_sp->GetStopDescription(frame);
97 // We only do step through if we're at the zeroth frame:
98 lldb::ThreadPlanSP step_through_sp;
99 if (frame->GetConcreteFrameIndex() == 0)
100 step_through_sp = m_interface_sp->GetStepThroughPlan(frame->GetThread());
101
103 args_synthesized, hidden, std::move(most_relevant), std::move(exception),
104 std::move(stop_desc), std::move(step_through_sp)));
105}
106
108 uint32_t n = m_generation;
109 n = (n + 1) & ((1 << 16) - 1);
110 m_generation = n;
111}
112
114 StackFrameRecognizerSP recognizer, std::string module,
115 std::vector<ConstString> symbols, Mangled::NamePreference symbol_mangling,
116 bool first_instruction_only) {
117 m_recognizers.push_front({(uint32_t)m_recognizers.size(), recognizer, false,
118 std::move(module), RegularExpressionSP(),
119 std::move(symbols), RegularExpressionSP(),
120 symbol_mangling, first_instruction_only, true});
122}
123
126 RegularExpressionSP symbol, Mangled::NamePreference symbol_mangling,
127 bool first_instruction_only) {
128 m_recognizers.push_front({(uint32_t)m_recognizers.size(), recognizer, true,
129 std::string(), module, std::vector<ConstString>(),
130 symbol, symbol_mangling, first_instruction_only,
131 true});
133}
134
136 const std::function<void(
137 uint32_t, bool, std::string, std::string, llvm::ArrayRef<ConstString>,
138 Mangled::NamePreference name_preference, bool)> &callback) {
139 for (auto entry : m_recognizers) {
140 if (entry.is_regexp) {
141 std::string module_name;
142 std::string symbol_name;
143
144 if (entry.module_regexp)
145 module_name = entry.module_regexp->GetText().str();
146 if (entry.symbol_regexp)
147 symbol_name = entry.symbol_regexp->GetText().str();
148
149 callback(entry.recognizer_id, entry.enabled, entry.recognizer->GetName(),
150 module_name, llvm::ArrayRef(ConstString(symbol_name)),
151 entry.symbol_mangling, true);
152 } else {
153 callback(entry.recognizer_id, entry.enabled, entry.recognizer->GetName(),
154 entry.module, entry.symbols, entry.symbol_mangling, false);
155 }
156 }
157}
158
160 bool enabled) {
161 auto found =
162 llvm::find_if(m_recognizers, [recognizer_id](const RegisteredEntry &e) {
163 return e.recognizer_id == recognizer_id;
164 });
165 if (found == m_recognizers.end())
166 return false;
167 found->enabled = enabled;
169 return true;
170}
171
173 uint32_t recognizer_id) {
174 auto found =
175 llvm::find_if(m_recognizers, [recognizer_id](const RegisteredEntry &e) {
176 return e.recognizer_id == recognizer_id;
177 });
178 if (found == m_recognizers.end())
179 return false;
180 m_recognizers.erase(found);
182 return true;
183}
184
189
192 const SymbolContext &symctx = frame->GetSymbolContext(
193 eSymbolContextModule | eSymbolContextFunction | eSymbolContextSymbol);
194 ModuleSP module_sp = symctx.module_sp;
195 if (!module_sp)
196 return StackFrameRecognizerSP();
197 llvm::StringRef module_name = module_sp->GetFileSpec().GetFilename();
198 Address start_addr;
199 if (symctx.symbol)
200 start_addr = symctx.symbol->GetAddress();
201 else if (symctx.function)
202 start_addr = symctx.function->GetAddress();
203 else
204 return StackFrameRecognizerSP();
205 Address current_addr = frame->GetFrameCodeAddress();
206
207 // The symbol's start address may fall inside a non-executable function
208 // header (as on WebAssembly), which no frame's PC can equal. Compare against
209 // the first instruction instead.
210 if (TargetSP target_sp = frame->CalculateTarget())
211 if (Architecture *arch = target_sp->GetArchitecturePlugin())
212 start_addr = arch->SkipFunctionHeader(start_addr);
213
214 for (const auto &entry : m_recognizers) {
215 if (!entry.enabled)
216 continue;
217
218 if (!entry.module.empty() && entry.module != module_name)
219 continue;
220
221 if (entry.module_regexp)
222 if (!entry.module_regexp->Execute(module_name))
223 continue;
224
225 ConstString function_name = symctx.GetFunctionName(entry.symbol_mangling);
226
227 if (!entry.symbols.empty())
228 if (!llvm::is_contained(entry.symbols, function_name))
229 continue;
230
231 if (entry.symbol_regexp)
232 if (!entry.symbol_regexp->Execute(function_name.GetStringRef()))
233 continue;
234
235 if (entry.first_instruction_only)
236 if (start_addr != current_addr)
237 continue;
238
239 return entry.recognizer;
240 }
241 return StackFrameRecognizerSP();
242}
243
246 auto recognizer = GetRecognizerForFrame(frame);
247 if (!recognizer)
248 return RecognizedStackFrameSP();
249 return recognizer->RecognizeFrame(frame);
250}
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, lldb::ThreadPlanSP step_through_plan_sp)
bool ShouldHide() override
Controls whether this frame should be filtered out when displaying backtraces, for example.
lldb::ThreadPlanSP GetStepThroughPlan() override
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.
const Address & GetAddress() const
Return the address of the function (its entry point).
Definition Function.h:439
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 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)
void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, std::string module, std::vector< ConstString > symbols, Mangled::NamePreference symbol_mangling, bool first_instruction_only=true)
Add a new recognizer that triggers on a given symbol name.
Defines a symbol context baton that can be handed other debug core functions.
Function * function
The Function for a given query.
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:98
static lldb::ValueObjectSP Create(ValueObject &valobj, lldb::ValueType type)
A class that represents a running process on the host machine.
std::shared_ptr< lldb_private::ThreadPlan > ThreadPlanSP
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