29#include "clang/CodeGen/ModuleBuilder.h"
39constexpr llvm::StringLiteral
41constexpr llvm::StringLiteral
44constexpr std::array<llvm::StringLiteral, 2>
49#define SOFT_TRAP_CATEGORY_PREFIX "Soft "
50#define SOFT_TRAP_FALLBACK_CATEGORY \
51 SOFT_TRAP_CATEGORY_PREFIX "Bounds check failed"
54 std::pair<std::optional<std::string>, std::optional<uint32_t>>;
64 std::optional<uint32_t>
86 bool &warning_emitted_for_failure);
90 bool &warning_emitted_for_failure);
100 bool warning_emitted_for_failure =
false;
101 auto [MaybeDescription, MaybeSuggestedStackIndex] =
103 if (MaybeDescription)
105 if (MaybeSuggestedStackIndex)
106 m_value = MaybeSuggestedStackIndex.value();
110 if ((!MaybeDescription.has_value()) && !warning_emitted_for_failure) {
113 thread_sp->GetProcess()->GetTarget().GetDebugger().GetID();
115 "specific BoundsSafety trap reason could not be computed",
122template <
typename T,
typename... ArgTys>
128template <
typename... ArgTys>
135 bool &warning_emitted_for_failure) {
138 return LogFailedCSI(
"failed to get thread while stopped");
141 thread_sp->GetProcess()->GetTarget().GetDebugger().GetID();
143 StackFrameSP parent_sf = thread_sp->GetStackFrameAtIndex(1);
145 return LogFailedCSI(
"got nullptr when fetching stackframe at index 1");
147 if (parent_sf->HasDebugInformation())
149 parent_sf, debugger_id, warning_emitted_for_failure);
154 thread_sp, debugger_id, warning_emitted_for_failure);
160 bool &warning_emitted_for_failure) {
170 const char *TrapReasonFuncName = parent_sf->GetFunctionName();
172 auto MaybeTrapReason =
173 clang::CodeGen::DemangleTrapReasonInDebugInfo(TrapReasonFuncName);
174 if (!MaybeTrapReason.has_value())
176 "clang::CodeGen::DemangleTrapReasonInDebugInfo(\"{0}\") call failed",
179 llvm::StringRef category = MaybeTrapReason.value().first;
180 llvm::StringRef message = MaybeTrapReason.value().second;
183 std::string stop_reason;
184 llvm::raw_string_ostream ss(stop_reason);
186 if (category.empty())
187 ss <<
"<empty category>";
190 if (message.empty()) {
193 "specific BoundsSafety trap reason is not "
194 "available because the compiler omitted it from the debug info",
197 ss <<
": " << message;
202 return std::make_pair(stop_reason, parent_sf->GetFrameIndex() + 1);
208 bool &warning_emitted_for_failure) {
210 StackFrameSP softtrap_sf = thread_sp->GetStackFrameAtIndex(0);
212 return LogFailedCSI(
"got nullptr when fetching stackframe at index 0");
213 llvm::StringRef trap_reason_func_name = softtrap_sf->GetFunctionName();
233 llvm::raw_string_ostream ss(
warning);
234 ss <<
"specific BoundsSafety trap reason is not available because debug "
235 "info is missing on the caller of '"
238 warning_emitted_for_failure =
true;
245 assert(0 &&
"hit breakpoint for unexpected function name");
247 "unexpected function name. Expected \"{0}\" but got \"{1}\"",
260 ProcessSP process = thread_sp->GetProcess();
264 switch (process->GetTarget().GetArchitecture().GetCore()) {
272 llvm::raw_string_ostream ss(
warning);
273 ss <<
"specific BoundsSafety trap reason cannot be inferred on x86 when "
277 warning_emitted_for_failure =
true;
289 "failed to get register info for LLDB_REGNUM_GENERIC_ARG1");
291 if (!rc->ReadRegister(arg0_info, reg_value))
295 return LogFailedCSI(
"failed to read register {0} as a UInt64",
298 if (reg_value_as_int == 0) {
302 "specific BoundsSafety trap reason cannot be inferred because the "
303 "compiler omitted the reason",
305 warning_emitted_for_failure =
true;
311 std::string out_string;
313 thread_sp->GetProcess()->ReadCStringFromMemory(reg_value_as_int, out_string,
315 if (error_status.
Fail())
316 return LogFailedCSI(
"failed to read C string from address {0}",
317 (
void *)reg_value_as_int);
320 "read C string from {0} found in register {1}: \"{2}\"",
321 (
void *)reg_value_as_int, arg0_info->
name, out_string.c_str());
322 std::string stop_reason;
323 llvm::raw_string_ostream SS(stop_reason);
325 if (!stop_reason.empty()) {
326 SS <<
": " << out_string;
330 return {stop_reason, 0};
346 "BoundsSafety instrumentation runtime plugin.",
371 if (module_sp->FindFirstSymbolWithNameAndType(test_sym,
373 LLDB_LOG(log_category,
"found \"{0}\" in {1}",
375 module_sp->GetObjectName().AsCString(
"<unknown module>"));
380 "did not find BoundsSafety soft trap functions in module {0}",
381 module_sp->GetObjectName().AsCString(
"<unknown module>"));
388 assert(baton &&
"null baton");
401 "failed to get thread from StoppointCallbackContext");
405 "process from baton ({0}) and StoppointCallbackContext ({1}) do "
407 (
void *)process_sp.get(),
410 if (process_sp->GetModIDRef().IsLastResumeForUserExpression())
415 thread_sp->SetStopInfo(
417 CreateInstrumentationBoundsSafetyStopInfo(*thread_sp));
429 std::vector<std::string> breakpoints;
431 breakpoints.emplace_back(breakpoint_func);
433 BreakpointSP breakpoint = process_sp->GetTarget().CreateBreakpoint(
435 nullptr, breakpoints, eFunctionNameTypeFull,
445 if (!breakpoint->HasResolvedLocations()) {
446 assert(0 &&
"breakpoint has no resolved locations");
447 process_sp->GetTarget().RemoveBreakpointByID(breakpoint->GetID());
449 "breakpoint {0} for BoundsSafety soft traps did not resolve to "
451 breakpoint->GetID());
456 breakpoint->SetCallback(
459 breakpoint->SetBreakpointKind(
"bounds-safety-soft-trap");
462 "created breakpoint {0} for BoundsSafety soft traps",
463 breakpoint->GetID());
474 "{0}removed breakpoint {1} for BoundsSafety soft traps",
477 LLDB_LOG(log_category,
"no process available during Deactivate()");
static llvm::raw_ostream & warning(Stream &strm)
ComputedStopInfo LogFailedCSI(ArgTys &&...Args)
#define SOFT_TRAP_FALLBACK_CATEGORY
std::pair< std::optional< std::string >, std::optional< uint32_t > > ComputedStopInfo
#define SOFT_TRAP_CATEGORY_PREFIX
constexpr llvm::StringLiteral BoundsSafetySoftTrapMinimal("__bounds_safety_soft_trap")
T LogBeforeReturn(ArgTys &&...Args)
constexpr std::array< llvm::StringLiteral, 2 > getBoundsSafetySoftTrapRuntimeFuncs()
constexpr llvm::StringLiteral BoundsSafetySoftTrapStr("__bounds_safety_soft_trap_s")
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
#define LLDB_PLUGIN_DEFINE(PluginName)
~InstrumentationBoundsSafetyStopInfo() override=default
ComputedStopInfo ComputeStopReasonAndSuggestedStackFrameWithoutDebugInfo(ThreadSP thread_sp, lldb::user_id_t debugger_id, bool &warning_emitted_for_failure)
const char * GetDescription() override
ComputedStopInfo ComputeStopReasonAndSuggestedStackFrameWithDebugInfo(lldb::StackFrameSP parent_sf, lldb::user_id_t debugger_id, bool &warning_emitted_for_failure)
std::optional< uint32_t > GetSuggestedStackFrameIndex(bool inlined_stack) override
This gives the StopInfo a chance to suggest a stack frame to select.
lldb::StopReason GetStopReason() const override
InstrumentationBoundsSafetyStopInfo(Thread &thread)
bool DoShouldNotify(Event *event_ptr) override
static lldb::StopInfoSP CreateInstrumentationBoundsSafetyStopInfo(Thread &thread)
ComputedStopInfo ComputeStopReasonAndSuggestedStackFrame(bool &warning_emitted_for_failure)
A command line argument class.
A uniqued constant string class.
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
static void ReportWarning(std::string message, std::optional< lldb::user_id_t > debugger_id=std::nullopt, std::once_flag *once=nullptr)
Report warning events.
lldb::ThreadSP GetThreadSP() const
Get accessor that creates a strong reference from the weak thread reference contained in this object.
lldb::ProcessSP GetProcessSP() const
Get accessor that creates a strong reference from the weak process reference contained in this object...
~InstrumentationRuntimeBoundsSafety() override
static lldb::InstrumentationRuntimeSP CreateInstance(const lldb::ProcessSP &process_sp)
static bool NotifyBreakpointHit(void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id)
static lldb::InstrumentationRuntimeType GetTypeStatic()
static llvm::StringRef GetPluginNameStatic()
InstrumentationRuntimeBoundsSafety(const lldb::ProcessSP &process_sp)
bool CheckIfRuntimeIsValid(const lldb::ModuleSP module_sp) override
Check whether module_sp corresponds to a valid runtime library.
const RegularExpression & GetPatternForRuntimeLibrary() override
Return a regular expression which can be used to identify a valid version of the runtime library.
void Activate() override
Register a breakpoint in the runtime library and perform any other necessary initialization.
void SetBreakpointID(lldb::user_id_t ID)
void SetActive(bool IsActive)
lldb::user_id_t GetBreakpointID() const
lldb::ProcessSP GetProcessSP()
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static bool UnregisterPlugin(ABICreateInstance create_callback)
uint64_t GetAsUInt64(uint64_t fail_value=UINT64_MAX, bool *success_ptr=nullptr) const
bool Fail() const
Test for error condition.
std::string m_description
StructuredData::ObjectSP m_extended_info
lldb::ThreadSP GetThread() const
StopInfo(Thread &thread, uint64_t value)
General Outline: When we hit a breakpoint we need to package up whatever information is needed to eva...
ExecutionContextRef exe_ctx_ref
#define LLDB_INVALID_BREAK_ID
#define LLDB_REGNUM_GENERIC_ARG1
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
std::shared_ptr< lldb_private::StackFrame > StackFrameSP
std::shared_ptr< lldb_private::Thread > ThreadSP
@ eLanguageTypeUnknown
Unknown or invalid language value.
std::shared_ptr< lldb_private::Breakpoint > BreakpointSP
std::shared_ptr< lldb_private::Process > ProcessSP
InstrumentationRuntimeType
@ eInstrumentationRuntimeTypeBoundsSafety
std::shared_ptr< lldb_private::StopInfo > StopInfoSP
StopReason
Thread stop reasons.
@ eStopReasonInstrumentation
std::shared_ptr< lldb_private::RegisterContext > RegisterContextSP
std::shared_ptr< lldb_private::InstrumentationRuntime > InstrumentationRuntimeSP
std::shared_ptr< lldb_private::Module > ModuleSP
@ eRegisterKindGeneric
insn ptr reg, stack ptr reg, etc not specific to any particular target
Every register is described in detail including its name, alternate name (optional),...
const char * name
Name of this register, can't be NULL.