backtrace_capture.c (2409B)
1 /* __kit_backtrace capture test: a known-depth non-tail recursion, captured via 2 * the freestanding frame-pointer walk. Verifies depth, that every captured 3 * return address is non-null, that the recursive frames share a call site (so 4 * the walk really follows the chain), the `skip` and `max` bounds, then exits 5 * 42 on success. Runs under test/rt/run.sh across the aa64/x64/rv64 tuples. */ 6 #include <kit/backtrace.h> 7 8 #define DEPTH 6 9 10 /* Non-tail recursion (work after the call) so each level keeps a live frame, 11 * and noinline so the chain is real even if the harness opt level rises. The 12 * captures happen at the deepest frame, where at least DEPTH+1 frames exist — 13 * so the `max` bound is exercised against a stack deeper than the cap (the top 14 * of test_main only has a couple of frames above it). */ 15 __attribute__((noinline)) static int recurse(int n, void** buf, int cap, 16 int skip, int* out, int* capped) { 17 if (n > 0) { 18 int r = recurse(n - 1, buf, cap, skip, out, capped); 19 return r + 1; 20 } 21 *out = __kit_backtrace(buf, cap, skip); 22 if (capped) { 23 void* small[3]; 24 *capped = __kit_backtrace(small, 3, 0); /* deep stack, so this fills 3 */ 25 } 26 return n; 27 } 28 29 int test_main(void) { 30 void* buf0[64]; 31 void* buf2[64]; 32 int n0 = 0, n2 = 0, capped = 0; 33 int i; 34 35 recurse(DEPTH, buf0, 64, 0, &n0, &capped); 36 37 /* The chain holds at least the recurse() frames plus test_main. */ 38 if (n0 < DEPTH + 1) return 1; 39 40 /* A real frame never has a null return address (the walk stops at the 41 * synthetic stack origin before recording it). */ 42 for (i = 0; i < n0; i++) 43 if (buf0[i] == 0) return 2; 44 45 /* buf0[1..DEPTH] are all the address after the single recursive call site, 46 * so consecutive recursive frames share a return address. */ 47 if (buf0[1] != buf0[2]) return 3; 48 49 /* skip drops the innermost frames: skip=2 yields exactly two fewer entries 50 * and shifts the trace, so buf2[0] is the old buf0[2]. */ 51 recurse(DEPTH, buf2, 64, 2, &n2, (int*)0); 52 if (n2 != n0 - 2) return 4; 53 if (buf2[0] != buf0[2]) return 5; 54 55 /* max is honored: against a stack deeper than the cap, exactly `max` are 56 * written (never more). */ 57 if (capped != 3) return 6; 58 59 /* Degenerate inputs return 0, not a crash. */ 60 if (__kit_backtrace(buf0, 0, 0) != 0) return 7; 61 if (__kit_backtrace((void**)0, 8, 0) != 0) return 8; 62 63 return 42; 64 }