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, ConstString module,
115 llvm::ArrayRef<ConstString> symbols,
116 Mangled::NamePreference symbol_mangling, bool first_instruction_only) {
117 m_recognizers.push_front({(uint32_t)m_recognizers.size(), recognizer, false,
118 module, RegularExpressionSP(), symbols,
119 RegularExpressionSP(), symbol_mangling,
120 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 ConstString(), 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.GetCString(), entry.symbols, entry.symbol_mangling,
155 false);
156 }
157 }
158}
159
161 bool enabled) {
162 auto found =
163 llvm::find_if(m_recognizers, [recognizer_id](const RegisteredEntry &e) {
164 return e.recognizer_id == recognizer_id;
165 });
166 if (found == m_recognizers.end())
167 return false;
168 found->enabled = enabled;
170 return true;
171}
172
174 uint32_t recognizer_id) {
175 auto found =
176 llvm::find_if(m_recognizers, [recognizer_id](const RegisteredEntry &e) {
177 return e.recognizer_id == recognizer_id;
178 });
179 if (found == m_recognizers.end())
180 return false;
181 m_recognizers.erase(found);
183 return true;
184}
185
190
193 const SymbolContext &symctx = frame->GetSymbolContext(
194 eSymbolContextModule | eSymbolContextFunction | eSymbolContextSymbol);
195 ModuleSP module_sp = symctx.module_sp;
196 if (!module_sp)
197 return StackFrameRecognizerSP();
198 llvm::StringRef module_name = module_sp->GetFileSpec().GetFilename();
199 Address start_addr;
200 if (symctx.symbol)
201 start_addr = symctx.symbol->GetAddress();
202 else if (symctx.function)
203 start_addr = symctx.function->GetAddress();
204 else
205 return StackFrameRecognizerSP();
206 Address current_addr = frame->GetFrameCodeAddress();
207
208 // The symbol's start address may fall inside a non-executable function
209 // header (as on WebAssembly), which no frame's PC can equal. Compare against
210 // the first instruction instead.
211 if (TargetSP target_sp = frame->CalculateTarget())
212 if (Architecture *arch = target_sp->GetArchitecturePlugin())
213 start_addr = arch->SkipFunctionHeader(start_addr);
214
215 for (const auto &entry : m_recognizers) {
216 if (!entry.enabled)
217 continue;
218
219 if (entry.module)
220 if (entry.module != module_name)
221 continue;
222
223 if (entry.module_regexp)
224 if (!entry.module_regexp->Execute(module_name))
225 continue;
226
227 ConstString function_name = symctx.GetFunctionName(entry.symbol_mangling);
228
229 if (!entry.symbols.empty())
230 if (!llvm::is_contained(entry.symbols, function_name))
231 continue;
232
233 if (entry.symbol_regexp)
234 if (!entry.symbol_regexp->Execute(function_name.GetStringRef()))
235 continue;
236
237 if (entry.first_instruction_only)
238 if (start_addr != current_addr)
239 continue;
240
241 return entry.recognizer;
242 }
243 return StackFrameRecognizerSP();
244}
245
248 auto recognizer = GetRecognizerForFrame(frame);
249 if (!recognizer)
250 return RecognizedStackFrameSP();
251 return recognizer->RecognizeFrame(frame);
252}
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:430
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.
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 &parent, 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