kit

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

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 }