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 }