kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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 }