kit

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

addr2line.c (5198B)


      1 #include <kit/core.h>
      2 #include <kit/dwarf.h>
      3 #include <kit/object.h>
      4 #include <stdint.h>
      5 #include <stdlib.h>
      6 #include <string.h>
      7 
      8 #include "driver.h"
      9 #include "dwarfsym.h"
     10 
     11 #define A2L_TOOL "addr2line"
     12 
     13 typedef struct A2lOpts {
     14   const char* exe_path;
     15   int functions; /* -f */
     16   int pretty;    /* -p */
     17   int basenames; /* --basenames */
     18   int show_addr; /* -a */
     19 } A2lOpts;
     20 
     21 static void a2l_strip_basename(const char** path_ptr) {
     22   const char* s = *path_ptr;
     23   const char* slash = NULL;
     24   const char* p;
     25   if (!s) return;
     26   for (p = s; *p; ++p)
     27     if (*p == '/') slash = p;
     28   if (slash) *path_ptr = slash + 1;
     29 }
     30 
     31 static void a2l_translate(DriverDwarfSym* sym, uint64_t addr,
     32                           const A2lOpts* opts) {
     33   DriverSymLoc loc;
     34 
     35   /* Share the DWARF open + func/line queries with `kit symbolize`; the two
     36    * tools differ only in how they format the result. */
     37   driver_dwarfsym_lookup(sym, addr, opts->functions, &loc);
     38 
     39   if (opts->show_addr) driver_printf("0x%llx", (unsigned long long)addr);
     40 
     41   if (opts->pretty) {
     42     if (opts->show_addr) driver_printf(": ");
     43     if (loc.have_func)
     44       driver_printf("%.*s at ", (int)loc.func.len, loc.func.s);
     45     else if (opts->functions)
     46       driver_printf("?? at ");
     47     if (loc.have_line) {
     48       const char* f = loc.file.s;
     49       if (opts->basenames) a2l_strip_basename(&f);
     50       driver_printf("%s:%u", f, loc.line);
     51       if (loc.col) driver_printf(":%u", loc.col);
     52     } else {
     53       driver_printf("??:0");
     54     }
     55     driver_printf("\n");
     56     return;
     57   }
     58 
     59   /* default or -f, -a modes */
     60   if (opts->show_addr) driver_printf(": ");
     61 
     62   if (opts->functions) {
     63     if (loc.have_func)
     64       driver_printf("%.*s\n", (int)loc.func.len, loc.func.s);
     65     else
     66       driver_printf("??\n");
     67   }
     68 
     69   if (loc.have_line) {
     70     const char* f = loc.file.s;
     71     if (opts->basenames) a2l_strip_basename(&f);
     72     driver_printf("%s:%u", f, loc.line);
     73     if (loc.col) driver_printf(":%u", loc.col);
     74   } else {
     75     driver_printf("??:0");
     76   }
     77   driver_printf("\n");
     78 }
     79 
     80 void driver_help_addr2line(void) {
     81   driver_printf(
     82       "%.*s",
     83       KIT_SLICE_ARG(KIT_SLICE_LIT(
     84           "kit addr2line — translate addresses to file:line using debug "
     85           "info\n"
     86           "\n"
     87           "USAGE\n"
     88           "  kit addr2line [OPTIONS] -e FILE [ADDR...]\n"
     89           "\n"
     90           "OPTIONS\n"
     91           "  -e FILE              object file with debug info (required)\n"
     92           "  -a, --addresses      print the address before each line\n"
     93           "  -f, --functions      print function names\n"
     94           "  -p, --pretty-print   compact single-line output\n"
     95           "  --basenames          strip directory from file paths\n"
     96           "  -h, --help           show this help\n"
     97           "\n"
     98           "If no addresses are given on the command line, addresses are read\n"
     99           "from standard input, one per line (hex).\n")));
    100 }
    101 
    102 int driver_addr2line(int argc, char** argv) {
    103   DriverEnv env;
    104   A2lOpts opts;
    105   DriverDwarfSym sym;
    106   int i, rc = 1, opened = 0;
    107   int stdin_addr_count = 0;
    108 
    109   if (argc < 2 || driver_argv_wants_help(argc, argv, 1)) {
    110     driver_help_addr2line();
    111     return 0;
    112   }
    113 
    114   memset(&opts, 0, sizeof opts);
    115   driver_env_init(&env);
    116 
    117   for (i = 1; i < argc; ++i) {
    118     const char* a = argv[i];
    119     if (driver_streq(a, "-e")) {
    120       if (i + 1 >= argc) {
    121         driver_errf(A2L_TOOL, "-e requires a path");
    122         rc = 2;
    123         goto done;
    124       }
    125       opts.exe_path = argv[++i];
    126       continue;
    127     }
    128     if (driver_streq(a, "-a") || driver_streq(a, "--addresses")) {
    129       opts.show_addr = 1;
    130       continue;
    131     }
    132     if (driver_streq(a, "-f") || driver_streq(a, "--functions")) {
    133       opts.functions = 1;
    134       continue;
    135     }
    136     if (driver_streq(a, "-p") || driver_streq(a, "--pretty-print")) {
    137       opts.pretty = 1;
    138       continue;
    139     }
    140     if (driver_streq(a, "--basenames")) {
    141       opts.basenames = 1;
    142       continue;
    143     }
    144     if (a[0] == '-' && a[1] != '\0') {
    145       driver_errf(A2L_TOOL, "unknown option: %s", a);
    146       rc = 2;
    147       goto done;
    148     }
    149   }
    150 
    151   if (!opts.exe_path) {
    152     driver_errf(A2L_TOOL, "no object file specified (-e FILE)");
    153     rc = 2;
    154     goto done;
    155   }
    156 
    157   /* open() memsets `sym` before any fallible step, so once we are past this
    158    * point driver_dwarfsym_close is always safe — even on a partial failure. */
    159   opened = 1;
    160   if (driver_dwarfsym_open(&sym, &env, A2L_TOOL, opts.exe_path) != 0) {
    161     rc = 1;
    162     goto done;
    163   }
    164 
    165   /* scan for positional addresses */
    166   for (i = 1; i < argc; ++i) {
    167     const char* a = argv[i];
    168     if (a[0] == '-' && a[1] != '\0') {
    169       if (driver_streq(a, "-e")) {
    170         ++i;
    171         continue;
    172       }
    173       continue;
    174     }
    175     {
    176       uint64_t addr = (uint64_t)strtoull(a, NULL, 16);
    177       a2l_translate(&sym, addr, &opts);
    178       stdin_addr_count++;
    179     }
    180   }
    181 
    182   if (stdin_addr_count == 0) {
    183     char line[256];
    184     for (;;) {
    185       int n = driver_read_line(line, sizeof line);
    186       if (n <= 0) break;
    187       {
    188         uint64_t addr = (uint64_t)strtoull(line, NULL, 16);
    189         a2l_translate(&sym, addr, &opts);
    190       }
    191     }
    192   }
    193 
    194   rc = 0;
    195 
    196 done:
    197   if (opened) driver_dwarfsym_close(&sym);
    198   driver_env_fini(&env);
    199   return rc;
    200 }