diff --git a/core/box/tls_sll_box.h b/core/box/tls_sll_box.h index b340588b..5559b382 100644 --- a/core/box/tls_sll_box.h +++ b/core/box/tls_sll_box.h @@ -25,6 +25,7 @@ #include #include // For fprintf in debug #include // For abort in debug +#include "../ptr_trace.h" // Debug-only: pointer next read/write tracing #include "../hakmem_tiny_config.h" // For TINY_NUM_CLASSES // External TLS SLL state (defined elsewhere) @@ -70,7 +71,7 @@ static inline bool tls_sll_push(int class_idx, void* ptr, uint32_t capacity) { #else const size_t next_offset = 0; #endif - *(void**)((uint8_t*)ptr + next_offset) = g_tls_sll_head[class_idx]; + PTR_NEXT_WRITE("tls_push", class_idx, ptr, next_offset, g_tls_sll_head[class_idx]); g_tls_sll_head[class_idx] = ptr; g_tls_sll_count[class_idx]++; @@ -106,7 +107,7 @@ static inline bool tls_sll_pop(int class_idx, void** out) { #else const size_t next_offset = 0; #endif - void* next = *(void**)((uint8_t*)base + next_offset); + void* next; PTR_NEXT_READ("tls_pop", class_idx, base, next_offset, next); g_tls_sll_head[class_idx] = next; if (g_tls_sll_count[class_idx] > 0) { g_tls_sll_count[class_idx]--; @@ -169,7 +170,7 @@ static inline uint32_t tls_sll_splice(int class_idx, void* chain_head, uint32_t const size_t next_offset = 0; #endif for (uint32_t i = 1; i < to_move; i++) { - void* next = *(void**)((uint8_t*)tail + next_offset); + void* next; PTR_NEXT_READ("tls_sp_trav", class_idx, tail, next_offset, next); if (!next) { // Chain shorter than expected, adjust to_move to_move = i; @@ -179,7 +180,7 @@ static inline uint32_t tls_sll_splice(int class_idx, void* chain_head, uint32_t } // Splice chain to SLL head - *(void**)((uint8_t*)tail + next_offset) = g_tls_sll_head[class_idx]; + PTR_NEXT_WRITE("tls_sp_link", class_idx, tail, next_offset, g_tls_sll_head[class_idx]); g_tls_sll_head[class_idx] = chain_head; g_tls_sll_count[class_idx] += to_move; diff --git a/core/ptr_trace.h b/core/ptr_trace.h new file mode 100644 index 00000000..9b872750 --- /dev/null +++ b/core/ptr_trace.h @@ -0,0 +1,93 @@ +// ptr_trace.h - Pointer link read/write tracing (Debug-only, macro-replaceable) +// +// Purpose: +// - Centrally instrument single-linked list next pointer reads/writes +// - Zero overhead in release builds (macros devolve to raw ops) +// - Compact TLS ring for triage; optional dump at exit via env +// +// Usage: +// - Replace direct next ops with PTR_NEXT_WRITE / PTR_NEXT_READ +// - Tag with a short literal (e.g., "tls_push", "tls_pop", "splice") +// - Offsets should be header-aware (C0–C6: +1, C7: +0) +// +// Control: +// - Compile-time: HAKMEM_PTR_TRACE (default: 1 for debug, 0 for release) +// - Runtime dump: HAKMEM_PTR_TRACE_DUMP=1 (prints ring at exit) + +#pragma once + +#include +#include + +#ifndef HAKMEM_PTR_TRACE +# if !HAKMEM_BUILD_RELEASE +# define HAKMEM_PTR_TRACE 1 +# else +# define HAKMEM_PTR_TRACE 0 +# endif +#endif + +#if HAKMEM_PTR_TRACE +#include + +typedef struct { + const char* tag; // literal tag + int class_idx; // tiny class (0..7) + void* node; // node address (base) + void* val; // written/read value + size_t off; // offset used for access +} ptr_trace_ev_t; + +#ifndef PTR_TRACE_CAP +# define PTR_TRACE_CAP 256 +#endif + +static __thread ptr_trace_ev_t g_ptr_trace_ring[PTR_TRACE_CAP]; +static __thread uint32_t g_ptr_trace_idx = 0; +static __thread int g_ptr_trace_dump_registered = 0; + +static inline void ptr_trace_record(const char* tag, int cls, void* node, void* val, size_t off) { + uint32_t i = g_ptr_trace_idx++; + g_ptr_trace_ring[i & (PTR_TRACE_CAP - 1)] = (ptr_trace_ev_t){ tag, cls, node, val, off }; +} + +static inline void ptr_trace_try_register_dump(void) { + if (g_ptr_trace_dump_registered) return; + g_ptr_trace_dump_registered = 1; + const char* env = getenv("HAKMEM_PTR_TRACE_DUMP"); + if (!(env && *env && *env != '0')) return; + static void __attribute__((destructor)) ptr_trace_dump(void) { + fprintf(stderr, "\n[PTR_TRACE_DUMP] last=%u (cap=%u)\n", g_ptr_trace_idx, (unsigned)PTR_TRACE_CAP); + uint32_t n = (g_ptr_trace_idx < PTR_TRACE_CAP) ? g_ptr_trace_idx : PTR_TRACE_CAP; + for (uint32_t k = 0; k < n; k++) { + const ptr_trace_ev_t* e = &g_ptr_trace_ring[(g_ptr_trace_idx - n + k) & (PTR_TRACE_CAP - 1)]; + fprintf(stderr, "[%3u] tag=%s cls=%d node=%p val=%p off=%zu\n", + k, e->tag ? e->tag : "?", e->class_idx, e->node, e->val, e->off); + } + } +} + +#define PTR_NEXT_WRITE(tag, cls, node, off, value) do { \ + void** __p = (void**)((uint8_t*)(node) + (off)); \ + *__p = (value); \ + ptr_trace_record((tag), (cls), (node), (value), (off)); \ + ptr_trace_try_register_dump(); \ +} while(0) + +#define PTR_NEXT_READ(tag, cls, node, off, out_var) do { \ + void** __p = (void**)((uint8_t*)(node) + (off)); \ + (out_var) = *__p; \ + ptr_trace_record((tag), (cls), (node), (out_var), (off)); \ + ptr_trace_try_register_dump(); \ +} while(0) + +#else // HAKMEM_PTR_TRACE == 0 + +#define PTR_NEXT_WRITE(tag, cls, node, off, value) \ + (*(void**)((uint8_t*)(node) + (off)) = (value)) + +#define PTR_NEXT_READ(tag, cls, node, off, out_var) \ + ((out_var) = *(void**)((uint8_t*)(node) + (off))) + +#endif // HAKMEM_PTR_TRACE + diff --git a/hakmem.d b/hakmem.d index 9b7eceb4..fd9209f1 100644 --- a/hakmem.d +++ b/hakmem.d @@ -23,8 +23,9 @@ hakmem.o: core/hakmem.c core/hakmem.h core/hakmem_build_flags.h \ core/box/hak_free_api.inc.h core/hakmem_tiny_superslab.h \ core/box/../tiny_free_fast_v2.inc.h core/box/../tiny_region_id.h \ core/box/../hakmem_build_flags.h core/box/../hakmem_tiny_config.h \ - core/box/../box/tls_sll_box.h core/box/../box/../hakmem_tiny_config.h \ - core/box/front_gate_classifier.h core/box/hak_wrappers.inc.h + core/box/../box/tls_sll_box.h core/box/../box/../ptr_trace.h \ + core/box/../box/../hakmem_tiny_config.h core/box/front_gate_classifier.h \ + core/box/hak_wrappers.inc.h core/hakmem.h: core/hakmem_build_flags.h: core/hakmem_config.h: @@ -82,6 +83,7 @@ core/box/../tiny_region_id.h: core/box/../hakmem_build_flags.h: core/box/../hakmem_tiny_config.h: core/box/../box/tls_sll_box.h: +core/box/../box/../ptr_trace.h: core/box/../box/../hakmem_tiny_config.h: core/box/front_gate_classifier.h: core/box/hak_wrappers.inc.h: