print_backtrace.c (2595B)
1 /* 2 * __kit_print_backtrace -- raw (unsymbolized) backtrace print, built on the 3 * freestanding __kit_backtrace frame-pointer walk. See doc/plan/BACKTRACE.md 4 * (L3a) and rt/include/kit/backtrace.h for the contract. 5 * 6 * Each captured return address is written as a "#<n> 0x<hex>\n" line to the 7 * weak __kit_backtrace_write sink. Symbolization is deliberately out of 8 * process: pipe the addresses to `kit addr2line -e <image>`. The integer 9 * formatting is done by hand so the panic path drags in no printf/libc and 10 * stays usable from a crash handler. 11 */ 12 #include <kit/backtrace.h> 13 #include <stdint.h> 14 15 /* Weak default sink: discard. A host start file / runtime overrides this to 16 * route the bytes to write(2), a serial port, etc. Keeping it weak means a 17 * freestanding image that never wires a sink still links and runs. */ 18 __attribute__((weak)) void __kit_backtrace_write(const char* buf, size_t len) { 19 (void)buf; 20 (void)len; 21 } 22 23 #define KIT_BT_PRINT_MAX 64 24 25 /* Format "#<idx> 0x<hex>\n" into `out` and return the byte count. `out` must 26 * hold the longest line: '#' + up to 10 decimal digits (u32 idx) + " 0x" + up 27 * to 16 hex digits (64-bit pointer) + '\n' == 31 bytes; the caller's line[48] 28 * is comfortably large. The hex address uses uintptr_t so it is not truncated 29 * on an LLP64 target, where `unsigned long` would be too narrow. */ 30 static int bt_format_frame(char* out, unsigned idx, void* addr) { 31 static const char hexd[] = "0123456789abcdef"; 32 char digits[10]; 33 uintptr_t a = (uintptr_t)addr; 34 int started = 0, shift, k = 0, j = 0; 35 36 out[k++] = '#'; 37 do { 38 digits[j++] = (char)('0' + (int)(idx % 10u)); 39 idx /= 10u; 40 } while (idx); 41 while (j > 0) out[k++] = digits[--j]; 42 43 out[k++] = ' '; 44 out[k++] = '0'; 45 out[k++] = 'x'; 46 /* Most-significant nibble first; suppress leading zeros but always emit at 47 * least the final nibble so an address of 0 still prints as "0x0". */ 48 for (shift = (int)(sizeof(uintptr_t) * 8) - 4; shift >= 0; shift -= 4) { 49 unsigned nib = (unsigned)((a >> shift) & 0xfu); 50 if (nib != 0u || started || shift == 0) { 51 out[k++] = hexd[nib]; 52 started = 1; 53 } 54 } 55 out[k++] = '\n'; 56 return k; 57 } 58 59 void __kit_print_backtrace(void) { 60 void* frames[KIT_BT_PRINT_MAX]; 61 char line[48]; 62 int n, i; 63 64 /* skip == 1 hides __kit_print_backtrace's own frame, so frame #0 is the 65 * return address into its direct caller. */ 66 n = __kit_backtrace(frames, KIT_BT_PRINT_MAX, 1); 67 for (i = 0; i < n; i++) { 68 int len = bt_format_frame(line, (unsigned)i, frames[i]); 69 __kit_backtrace_write(line, (size_t)len); 70 } 71 }