kit

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

print_backtrace.c (3293B)


      1 /* __kit_print_backtrace format test (the in-process half of the L3a
      2  * round-trip).
      3  *
      4  * Overrides the weak __kit_backtrace_write sink to capture the emitted bytes,
      5  * calls __kit_print_backtrace() from the bottom of a known @[.noinline]
      6  * recursion, then parses the captured "#N 0xADDR" lines in process. Asserts:
      7  * the sink was called and ends on a line boundary; every line is "#<i> 0x<hex>"
      8  * with a sequential index and a non-zero address; and the recursive frames
      9  * share a return address (so the printed chain really followed the frame
     10  * links). The address text is exactly what `kit addr2line -e <image>` consumes,
     11  * so a clean parse here is the in-process complement of test/rt/addr2line.sh.
     12  * Exits 42. Runs under test/rt/run.sh across the aa64/x64/rv64 tuples. */
     13 #include <kit/backtrace.h>
     14 
     15 #define DEPTH 6
     16 #define CAP 1024
     17 #define MAXLINES 128
     18 
     19 static char g_buf[CAP];
     20 static int g_len;
     21 
     22 /* Override the weak rt default: capture the raw bytes instead of discarding.
     23  * The signature must match the header's (size_t) under -Werror. */
     24 void __kit_backtrace_write(const char* buf, size_t len) {
     25   size_t i;
     26   for (i = 0; i < len && g_len < CAP; i++) g_buf[g_len++] = buf[i];
     27 }
     28 
     29 /* Non-tail recursion (work after the call) so every level keeps a live frame,
     30  * and noinline so the chain survives if the harness opt level rises. */
     31 __attribute__((noinline)) static int recurse(int n) {
     32   if (n > 0) {
     33     int r = recurse(n - 1);
     34     return r + 1;
     35   }
     36   __kit_print_backtrace();
     37   return 0;
     38 }
     39 
     40 int test_main(void) {
     41   int idx[MAXLINES];
     42   unsigned long addr[MAXLINES];
     43   int cnt = 0;
     44   int i = 0;
     45 
     46   recurse(DEPTH);
     47 
     48   if (g_len <= 0) return 1;               /* the sink must have been called */
     49   if (g_buf[g_len - 1] != '\n') return 2; /* every line is terminated */
     50 
     51   /* Parse each "#<dec> 0x<hex>\n" line strictly, recording index and address.
     52    */
     53   while (i < g_len) {
     54     int v = 0;
     55     unsigned long a = 0;
     56     if (g_buf[i] != '#') return 3;
     57     i++;
     58     if (i >= g_len || g_buf[i] < '0' || g_buf[i] > '9') return 4;
     59     while (i < g_len && g_buf[i] >= '0' && g_buf[i] <= '9')
     60       v = v * 10 + (g_buf[i++] - '0');
     61     if (i + 2 >= g_len || g_buf[i] != ' ' || g_buf[i + 1] != '0' ||
     62         g_buf[i + 2] != 'x')
     63       return 5;
     64     i += 3;
     65     if (i >= g_len || g_buf[i] == '\n') return 6; /* need >= 1 hex digit */
     66     while (i < g_len && g_buf[i] != '\n') {
     67       char c = g_buf[i];
     68       int h;
     69       if (c >= '0' && c <= '9')
     70         h = c - '0';
     71       else if (c >= 'a' && c <= 'f')
     72         h = c - 'a' + 10;
     73       else
     74         return 7;
     75       a = (a << 4) | (unsigned long)h;
     76       i++;
     77     }
     78     if (i >= g_len || g_buf[i] != '\n') return 8;
     79     i++; /* consume the newline */
     80     if (cnt >= MAXLINES) break;
     81     idx[cnt] = v;
     82     addr[cnt] = a;
     83     cnt++;
     84   }
     85 
     86   /* The chain holds at least the recurse() frames plus test_main. */
     87   if (cnt < DEPTH + 1) return 9;
     88   for (i = 0; i < cnt; i++) {
     89     if (idx[i] != i) return 10;  /* frame numbers are sequential from 0 */
     90     if (addr[i] == 0) return 11; /* a real frame never has a null retaddr */
     91   }
     92   /* #1..#DEPTH all return to the single recursive call site, so consecutive
     93    * recursive frames share a return address. (#0 is the print call site.) */
     94   if (addr[1] != addr[2]) return 12;
     95 
     96   return 42;
     97 }