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 }