kit

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

print_backtrace.c (3287B)


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