2929#include " clang/CodeGen/ModuleBuilder.h"
3030
3131#include < memory>
32+ #include < type_traits>
3233
3334using namespace lldb ;
3435using namespace lldb_private ;
@@ -51,6 +52,9 @@ const std::vector<std::string> &getBoundsSafetySoftTrapRuntimeFuncs() {
5152#define SOFT_TRAP_FALLBACK_CATEGORY \
5253 SOFT_TRAP_CATEGORY_PREFIX " Bounds check failed"
5354
55+ using ComputedStopInfo =
56+ std::pair<std::optional<std::string>, std::optional<uint32_t >>;
57+
5458class InstrumentationBoundsSafetyStopInfo : public StopInfo {
5559public:
5660 ~InstrumentationBoundsSafetyStopInfo () override = default ;
@@ -76,16 +80,14 @@ class InstrumentationBoundsSafetyStopInfo : public StopInfo {
7680private:
7781 InstrumentationBoundsSafetyStopInfo (Thread &thread);
7882
79- std::pair<std::optional<std::string>, std::optional< uint32_t >>
83+ ComputedStopInfo
8084 ComputeStopReasonAndSuggestedStackFrame (bool &warning_emitted_for_failure);
8185
82- std::pair<std::string, std::optional<uint32_t >>
83- ComputeStopReasonAndSuggestedStackFrameWithDebugInfo (
86+ ComputedStopInfo ComputeStopReasonAndSuggestedStackFrameWithDebugInfo (
8487 lldb::StackFrameSP parent_sf, lldb::user_id_t debugger_id,
8588 bool &warning_emitted_for_failure);
8689
87- std::pair<std::optional<std::string>, std::optional<uint32_t >>
88- ComputeStopReasonAndSuggestedStackFrameWithoutDebugInfo (
90+ ComputedStopInfo ComputeStopReasonAndSuggestedStackFrameWithoutDebugInfo (
8991 ThreadSP thread_sp, lldb::user_id_t debugger_id,
9092 bool &warning_emitted_for_failure);
9193};
@@ -118,24 +120,33 @@ InstrumentationBoundsSafetyStopInfo::InstrumentationBoundsSafetyStopInfo(
118120 }
119121}
120122
121- std::pair<std::optional<std::string>, std::optional<uint32_t >>
123+ // Helper functions to make it convenient to log a failure and then return.
124+ template <typename T, typename ... ArgTys>
125+ [[nodiscard]] T LogBeforeReturn (ArgTys &&...Args) {
126+ Log *log_category = GetLog (LLDBLog::InstrumentationRuntime);
127+ LLDB_LOG (log_category, Args...);
128+ return T ();
129+ }
130+
131+ template <typename ... ArgTys>
132+ [[nodiscard]] ComputedStopInfo LogBeforeReturnCSI (ArgTys &&...Args) {
133+ return LogBeforeReturn<ComputedStopInfo>(Args...);
134+ }
135+
136+ ComputedStopInfo
122137InstrumentationBoundsSafetyStopInfo::ComputeStopReasonAndSuggestedStackFrame (
123138 bool &warning_emitted_for_failure) {
124- Log *log_category = GetLog (LLDBLog::InstrumentationRuntime);
125139 ThreadSP thread_sp = GetThread ();
126- if (!thread_sp) {
127- LLDB_LOG (log_category, " failed to get thread while stopped" );
128- return {};
129- }
140+ if (!thread_sp)
141+ return LogBeforeReturnCSI (" failed to get thread while stopped" );
130142
131143 lldb::user_id_t debugger_id =
132144 thread_sp->GetProcess ()->GetTarget ().GetDebugger ().GetID ();
133145
134146 StackFrameSP parent_sf = thread_sp->GetStackFrameAtIndex (1 );
135- if (!parent_sf) {
136- LLDB_LOG (log_category, " got nullptr when fetching stackframe at index 1" );
137- return {};
138- }
147+ if (!parent_sf)
148+ return LogBeforeReturnCSI (
149+ " got nullptr when fetching stackframe at index 1" );
139150
140151 if (parent_sf->HasDebugInformation ())
141152 return ComputeStopReasonAndSuggestedStackFrameWithDebugInfo (
@@ -147,8 +158,7 @@ InstrumentationBoundsSafetyStopInfo::ComputeStopReasonAndSuggestedStackFrame(
147158 thread_sp, debugger_id, warning_emitted_for_failure);
148159}
149160
150- std::pair<std::string, std::optional<uint32_t >>
151- InstrumentationBoundsSafetyStopInfo::
161+ ComputedStopInfo InstrumentationBoundsSafetyStopInfo::
152162 ComputeStopReasonAndSuggestedStackFrameWithDebugInfo (
153163 lldb::StackFrameSP parent_sf, lldb::user_id_t debugger_id,
154164 bool &warning_emitted_for_failure) {
@@ -165,13 +175,11 @@ InstrumentationBoundsSafetyStopInfo::
165175
166176 auto MaybeTrapReason =
167177 clang::CodeGen::DemangleTrapReasonInDebugInfo (TrapReasonFuncName);
168- if (!MaybeTrapReason.has_value ()) {
169- LLDB_LOG (
170- GetLog (LLDBLog::InstrumentationRuntime),
178+ if (!MaybeTrapReason.has_value ())
179+ return LogBeforeReturnCSI (
171180 " clang::CodeGen::DemangleTrapReasonInDebugInfo(\" {0}\" ) call failed" ,
172181 TrapReasonFuncName);
173- return {};
174- }
182+
175183 llvm::StringRef category = MaybeTrapReason.value ().first ;
176184 llvm::StringRef message = MaybeTrapReason.value ().second ;
177185
@@ -198,18 +206,15 @@ InstrumentationBoundsSafetyStopInfo::
198206 return std::make_pair (stop_reason, parent_sf->GetFrameIndex () + 1 );
199207}
200208
201- std::pair<std::optional<std::string>, std::optional<uint32_t >>
202- InstrumentationBoundsSafetyStopInfo::
209+ ComputedStopInfo InstrumentationBoundsSafetyStopInfo::
203210 ComputeStopReasonAndSuggestedStackFrameWithoutDebugInfo (
204211 ThreadSP thread_sp, lldb::user_id_t debugger_id,
205212 bool &warning_emitted_for_failure) {
206213
207- Log *log_category = GetLog (LLDBLog::InstrumentationRuntime);
208214 StackFrameSP softtrap_sf = thread_sp->GetStackFrameAtIndex (0 );
209- if (!softtrap_sf) {
210- LLDB_LOG (log_category, " got nullptr when fetching stackframe at index 0" );
211- return {};
212- }
215+ if (!softtrap_sf)
216+ return LogBeforeReturnCSI (
217+ " got nullptr when fetching stackframe at index 0" );
213218 llvm::StringRef trap_reason_func_name = softtrap_sf->GetFunctionName ();
214219
215220 if (trap_reason_func_name == BoundsSafetySoftTrapMinimal) {
@@ -242,29 +247,25 @@ InstrumentationBoundsSafetyStopInfo::
242247 // __bounds_safety_soft_trap_s has one argument which is a pointer to a string
243248 // describing the trap or a nullptr.
244249 if (trap_reason_func_name != BoundsSafetySoftTrapStr) {
245- LLDB_LOG (log_category,
246- " unexpected function name. Expected \" {0}\" but got \" {1}\" " ,
247- BoundsSafetySoftTrapStr.data (), trap_reason_func_name.data ());
248250 assert (0 && " hit breakpoint for unexpected function name" );
249- return {};
251+ return LogBeforeReturnCSI (
252+ " unexpected function name. Expected \" {0}\" but got \" {1}\" " ,
253+ BoundsSafetySoftTrapStr.data (), trap_reason_func_name.data ());
250254 }
251255
252256 RegisterContextSP rc = thread_sp->GetRegisterContext ();
253- if (!rc) {
254- LLDB_LOG (log_category, " failed to get register context" );
255- return {};
256- }
257+ if (!rc)
258+ return LogBeforeReturnCSI (" failed to get register context" );
257259
258260 // FIXME: LLDB should have an API that tells us for the current target if
259261 // `LLDB_REGNUM_GENERIC_ARG1` can be used.
260262 // https://github.com/llvm/llvm-project/issues/168602
261263 // Don't try for architectures where examining the first register won't
262264 // work.
263265 ProcessSP process = thread_sp->GetProcess ();
264- if (!process) {
265- LLDB_LOG (log_category, " failed to get process" );
266- return {};
267- }
266+ if (!process)
267+ return LogBeforeReturnCSI (" failed to get process" );
268+
268269 switch (process->GetTarget ().GetArchitecture ().GetCore ()) {
269270 case ArchSpec::eCore_x86_32_i386:
270271 case ArchSpec::eCore_x86_32_i486:
@@ -288,22 +289,16 @@ InstrumentationBoundsSafetyStopInfo::
288289 // Examine the register for the first argument.
289290 const RegisterInfo *arg0_info = rc->GetRegisterInfo (
290291 lldb::RegisterKind::eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1);
291- if (!arg0_info) {
292- LLDB_LOG (log_category,
293- " failed to get register info for LLDB_REGNUM_GENERIC_ARG1" );
294- return {};
295- }
292+ if (!arg0_info)
293+ return LogBeforeReturnCSI (
294+ " failed to get register info for LLDB_REGNUM_GENERIC_ARG1" );
296295 RegisterValue reg_value;
297- if (!rc->ReadRegister (arg0_info, reg_value)) {
298- LLDB_LOG (log_category, " failed to read register {0}" , arg0_info->name );
299- return {};
300- }
296+ if (!rc->ReadRegister (arg0_info, reg_value))
297+ return LogBeforeReturnCSI (" failed to read register {0}" , arg0_info->name );
301298 uint64_t reg_value_as_int = reg_value.GetAsUInt64 (UINT64_MAX);
302- if (reg_value_as_int == UINT64_MAX) {
303- LLDB_LOG (log_category, " failed to read register {0} as a UInt64" ,
304- arg0_info->name );
305- return {};
306- }
299+ if (reg_value_as_int == UINT64_MAX)
300+ return LogBeforeReturnCSI (" failed to read register {0} as a UInt64" ,
301+ arg0_info->name );
307302
308303 if (reg_value_as_int == 0 ) {
309304 // nullptr arg. The compiler will pass that if no trap reason string was
@@ -322,12 +317,11 @@ InstrumentationBoundsSafetyStopInfo::
322317 Status error_status;
323318 thread_sp->GetProcess ()->ReadCStringFromMemory (reg_value_as_int, out_string,
324319 error_status);
325- if (error_status.Fail ()) {
326- LLDB_LOG (log_category, " failed to read C string from address {0}" ,
327- (void *)reg_value_as_int);
328- return {};
329- }
330- LLDB_LOG (log_category,
320+ if (error_status.Fail ())
321+ return LogBeforeReturnCSI (" failed to read C string from address {0}" ,
322+ (void *)reg_value_as_int);
323+
324+ LLDB_LOG (GetLog (LLDBLog::InstrumentationRuntime),
331325 " read C string from {0} found in register {1}: \" {2}\" " ,
332326 (void *)reg_value_as_int, arg0_info->name , out_string.c_str ());
333327 std::string stop_reason;
@@ -402,31 +396,23 @@ bool InstrumentationRuntimeBoundsSafety::NotifyBreakpointHit(
402396 InstrumentationRuntimeBoundsSafety *const instance =
403397 static_cast <InstrumentationRuntimeBoundsSafety *>(baton);
404398
405- Log *log_category = GetLog (LLDBLog::InstrumentationRuntime);
406399 ProcessSP process_sp = instance->GetProcessSP ();
407- if (!process_sp) {
408- LLDB_LOG (log_category, " failed to get process from baton" );
409- return false ;
410- }
400+ if (!process_sp)
401+ return LogBeforeReturn<bool >(" failed to get process from baton" );
411402 ThreadSP thread_sp = context->exe_ctx_ref .GetThreadSP ();
412- if (!thread_sp) {
413- LLDB_LOG (log_category,
414- " failed to get thread from StoppointCallbackContext" );
415- return false ;
416- }
417- if (process_sp != context->exe_ctx_ref .GetProcessSP ()) {
418- LLDB_LOG (log_category,
419- " process from baton ({0}) and StoppointCallbackContext ({1}) do "
420- " not match" ,
421- (void *)process_sp.get (),
422- (void *)context->exe_ctx_ref .GetProcessSP ().get ());
423- return false ;
424- }
403+ if (!thread_sp)
404+ return LogBeforeReturn<bool >(
405+ " failed to get thread from StoppointCallbackContext" );
425406
426- if (process_sp->GetModIDRef ().IsLastResumeForUserExpression ()) {
427- LLDB_LOG (log_category, " IsLastResumeForUserExpression is true" );
428- return false ;
429- }
407+ if (process_sp != context->exe_ctx_ref .GetProcessSP ())
408+ return LogBeforeReturn<bool >(
409+ " process from baton ({0}) and StoppointCallbackContext ({1}) do "
410+ " not match" ,
411+ (void *)process_sp.get (),
412+ (void *)context->exe_ctx_ref .GetProcessSP ().get ());
413+
414+ if (process_sp->GetModIDRef ().IsLastResumeForUserExpression ())
415+ return LogBeforeReturn<bool >(" IsLastResumeForUserExpression is true" );
430416
431417 // Maybe the stop reason and stackframe selection should be done by
432418 // a stackframe recognizer instead?
@@ -440,12 +426,9 @@ void InstrumentationRuntimeBoundsSafety::Activate() {
440426 if (IsActive ())
441427 return ;
442428
443- Log *log_category = GetLog (LLDBLog::InstrumentationRuntime);
444429 ProcessSP process_sp = GetProcessSP ();
445- if (!process_sp) {
446- LLDB_LOG (log_category, " could not get process during Activate()" );
447- return ;
448- }
430+ if (!process_sp)
431+ return LogBeforeReturn<void >(" could not get process during Activate()" );
449432
450433 BreakpointSP breakpoint = process_sp->GetTarget ().CreateBreakpoint (
451434 /* containingModules=*/ nullptr ,
@@ -457,15 +440,15 @@ void InstrumentationRuntimeBoundsSafety::Activate() {
457440 /* request_hardware*/ false );
458441
459442 if (!breakpoint)
460- return ;
443+ return LogBeforeReturn<void >(" failed to create breakpoint" );
444+
461445 if (!breakpoint->HasResolvedLocations ()) {
462- LLDB_LOG (log_category,
463- " breakpoint {0} for BoundsSafety soft traps did not resolve to "
464- " any locations" ,
465- breakpoint->GetID ());
466446 assert (0 && " breakpoint has no resolved locations" );
467447 process_sp->GetTarget ().RemoveBreakpointByID (breakpoint->GetID ());
468- return ;
448+ return LogBeforeReturn<void >(
449+ " breakpoint {0} for BoundsSafety soft traps did not resolve to "
450+ " any locations" ,
451+ breakpoint->GetID ());
469452 }
470453
471454 // Note: When `sync=true` the suggested stackframe is completely ignored. So
@@ -475,7 +458,8 @@ void InstrumentationRuntimeBoundsSafety::Activate() {
475458 /* sync=*/ false );
476459 breakpoint->SetBreakpointKind (" bounds-safety-soft-trap" );
477460 SetBreakpointID (breakpoint->GetID ());
478- LLDB_LOG (log_category, " created breakpoint {0} for BoundsSafety soft traps" ,
461+ LLDB_LOG (GetLog (LLDBLog::InstrumentationRuntime),
462+ " created breakpoint {0} for BoundsSafety soft traps" ,
479463 breakpoint->GetID ());
480464 SetActive (true );
481465}
0 commit comments