diff --git a/src/util/log/fd_log.h b/src/util/log/fd_log.h index 479e0f18299..6310bb176e9 100644 --- a/src/util/log/fd_log.h +++ b/src/util/log/fd_log.h @@ -266,6 +266,11 @@ #define FD_TEST_CUSTOM(c,err) do { if( FD_UNLIKELY( !(c) ) ) FD_LOG_ERR(( "FAIL: %s", (err) )); } while(0) +/* FD_TEST_BRK is like FD_TEST but drops into a debugger on failure. */ + +#define FD_TEST_BRK(c) do { if( FD_UNLIKELY( !(c) ) ) FD_LOG_WARNING(( "FAIL: %s", #c )); __asm__("int $3"); } while(0) + + /* Macros for doing hexedit / tcpdump-like logging of memory regions. E.g. diff --git a/src/util/spad/fd_spad.c b/src/util/spad/fd_spad.c index 257bc36d2e5..f706b3fd07b 100644 --- a/src/util/spad/fd_spad.c +++ b/src/util/spad/fd_spad.c @@ -69,10 +69,17 @@ fd_spad_frame_hi_debug( fd_spad_t * spad ) { return SELECT_DEBUG_IMPL(fd_spad_frame_hi)( spad ); } -void +fd_spad_debug_state_t fd_spad_push_debug( fd_spad_t * spad ) { + fd_spad_debug_state_t state; + state.frame_free = spad->frame_free; + state.mem_used = spad->mem_used; + state.spad = spad; + if( FD_UNLIKELY( !fd_spad_frame_free( spad ) ) ) FD_LOG_CRIT(( "too many frames" )); SELECT_DEBUG_IMPL(fd_spad_push)( spad ); + + return state; } void @@ -314,3 +321,17 @@ fd_spad_vtable = { .malloc = fd_spad_valloc_malloc, .free = fd_spad_valloc_free }; + +void +fd_spad_private_frame_end_debug( fd_spad_debug_state_t * _spad_state ) { + fd_spad_pop( _spad_state->spad ); + + if(_spad_state->frame_free != _spad_state->spad->frame_free ) { + FD_LOG_WARNING(("%lu != %lu", _spad_state->frame_free, _spad_state->spad->frame_free)); + FD_TEST_BRK( _spad_state->frame_free == _spad_state->spad->frame_free ); + } + if( _spad_state->mem_used != _spad_state->spad->mem_used ) { + FD_LOG_WARNING(("%lu != %lu", _spad_state->mem_used, _spad_state->spad->mem_used)); + FD_TEST_BRK( _spad_state->mem_used == _spad_state->spad->mem_used ); + } +} diff --git a/src/util/spad/fd_spad.h b/src/util/spad/fd_spad.h index 6750107d291..f8ca97ecd4d 100644 --- a/src/util/spad/fd_spad.h +++ b/src/util/spad/fd_spad.h @@ -93,6 +93,13 @@ FD_STATIC_ASSERT( FD_SPAD_ALLOC_ALIGN_DEFAULT >= FD_MSAN_ALIGN, /* spad internals */ +struct fd_spad_debug_state { + ulong frame_free; /* number of frames free, in [0,FD_SPAD_FRAME_MAX] */ + ulong mem_used; /* number of spad memory bytes used, in [0,mem_max] */ + fd_spad_t *spad; +}; +typedef struct fd_spad_debug_state fd_spad_debug_state_t; + struct __attribute__((aligned(FD_SPAD_ALIGN))) fd_spad_private { /* This point is FD_SPAD_ALIGN aligned */ @@ -360,6 +367,19 @@ fd_spad_private_frame_end( fd_spad_t ** _spad ) { /* declared here to avoid a fd fd_spad_pop( *_spad ); } +void fd_spad_private_frame_end_debug( fd_spad_debug_state_t * _spad_state); + +#if defined(FD_SPAD_USE_HANDHOLDING) + +#define FD_SPAD_FRAME_BEGIN(spad) do { \ + __attribute__((cleanup(fd_spad_private_frame_end_debug))) fd_spad_debug_state_t _spad_state; \ + _spad_state = fd_spad_push_debug( spad ); \ + do + +#define FD_SPAD_FRAME_END while(0); } while(0) + +#else + #define FD_SPAD_FRAME_BEGIN(spad) do { \ fd_spad_t * _spad __attribute__((cleanup(fd_spad_private_frame_end))) = (spad); \ fd_spad_push( _spad ); \ @@ -367,6 +387,9 @@ fd_spad_private_frame_end( fd_spad_t ** _spad ) { /* declared here to avoid a fd #define FD_SPAD_FRAME_END while(0); } while(0) +#endif + + /* fd_spad_alloc allocates sz bytes with alignment align from spad. Returns a pointer in the caller's address space to the first byte of the allocation (will be non-NULL with alignment align). Assumes spad @@ -492,7 +515,7 @@ void * fd_spad_delete_debug ( void * shspad ulong fd_spad_alloc_max_debug( fd_spad_t const * spad, ulong align ); void * fd_spad_frame_lo_debug ( fd_spad_t * spad ); void * fd_spad_frame_hi_debug ( fd_spad_t * spad ); -void fd_spad_push_debug ( fd_spad_t * spad ); +fd_spad_debug_state_t fd_spad_push_debug ( fd_spad_t * spad ); void fd_spad_pop_debug ( fd_spad_t * spad ); void * fd_spad_alloc_check ( fd_spad_t * spad, ulong align, ulong sz ); #define fd_spad_alloc_debug fd_spad_alloc_check