kit

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

size.c (11281B)


      1 #include <kit/archive.h>
      2 #include <kit/core.h>
      3 #include <kit/object.h>
      4 #include <stdint.h>
      5 #include <stdio.h>
      6 #include <stdlib.h>
      7 #include <string.h>
      8 
      9 #include "driver.h"
     10 
     11 #define SIZE_TOOL "size"
     12 
     13 typedef enum SizeFmt {
     14   SIZE_FMT_BERKELEY,
     15   SIZE_FMT_SYSV,
     16 } SizeFmt;
     17 
     18 typedef enum SizeRadix {
     19   SIZE_RAD_HEX,
     20   SIZE_RAD_DEC,
     21   SIZE_RAD_OCT,
     22 } SizeRadix;
     23 
     24 typedef struct SizeOpts {
     25   SizeFmt fmt;     /* -A => SYSV, default BERKELEY */
     26   SizeRadix radix; /* default hex; -d => DEC, -o => OCT */
     27   int common;      /* --common */
     28   int totals;      /* -t / --totals (berkeley only) */
     29 } SizeOpts;
     30 
     31 /* Section size classification + aggregation now live in libkit
     32  * (kit_obj_section_size_class / kit_obj_size_totals). size_compute_obj is a
     33  * thin shim that maps the tool's --common flag onto the public totals call. */
     34 static KitObjSizeTotals size_compute_obj(KitObjFile* of, const SizeOpts* opts) {
     35   KitObjSizeTotals a;
     36   if (kit_obj_size_totals(of, opts->common != 0, &a) != KIT_OK)
     37     memset(&a, 0, sizeof a);
     38   return a;
     39 }
     40 
     41 static void size_print_val(uint64_t v, SizeRadix radix, int width, char* buf,
     42                            size_t buf_size) {
     43   switch (radix) {
     44     case SIZE_RAD_DEC:
     45       snprintf(buf, buf_size, "%*llu", width, (unsigned long long)v);
     46       break;
     47     case SIZE_RAD_OCT:
     48       snprintf(buf, buf_size, "%*llo", width, (unsigned long long)v);
     49       break;
     50     default: /* hex */
     51       snprintf(buf, buf_size, "%*llx", width, (unsigned long long)v);
     52       break;
     53   }
     54 }
     55 
     56 static int size_width(SizeRadix radix) {
     57   return (radix == SIZE_RAD_OCT) ? 10 : (radix == SIZE_RAD_DEC) ? 8 : 7;
     58 }
     59 
     60 static void size_print_berkeley_header(const SizeOpts* opts) {
     61   int w = size_width(opts->radix);
     62   driver_printf("   %-*s   %-*s   %-*s   %8s   %7s  filename\n", w, "text", w,
     63                 "data", w, "bss", "dec", "hex");
     64 }
     65 
     66 static void size_begin_output(const SizeOpts* opts, int* begun) {
     67   if (*begun) return;
     68   if (opts->fmt == SIZE_FMT_BERKELEY) size_print_berkeley_header(opts);
     69   *begun = 1;
     70 }
     71 
     72 static void size_print_berkeley_sums(const KitObjSizeTotals* a, const char* name,
     73                                      const SizeOpts* opts) {
     74   int w = size_width(opts->radix);
     75   char text_buf[32], data_buf[32], bss_buf[32], dec_buf[32], hex_buf[32];
     76   size_print_val(a->text, opts->radix, w, text_buf, sizeof text_buf);
     77   size_print_val(a->data, opts->radix, w, data_buf, sizeof data_buf);
     78   size_print_val(a->bss, opts->radix, w, bss_buf, sizeof bss_buf);
     79   size_print_val(a->total, SIZE_RAD_DEC, 8, dec_buf, sizeof dec_buf);
     80   size_print_val(a->total, SIZE_RAD_HEX, 7, hex_buf, sizeof hex_buf);
     81   driver_printf("  %s  %s  %s  %s  %s  %s\n", text_buf, data_buf, bss_buf,
     82                 dec_buf, hex_buf, name);
     83 }
     84 
     85 static void size_print_sysv(KitObjFile* of, const char* name,
     86                             const SizeOpts* opts) {
     87   uint32_t ns, i;
     88   driver_printf("%s  :\n", name);
     89   driver_printf("section          size      addr\n");
     90   ns = kit_obj_nsections(of);
     91   for (i = 0; i < ns; ++i) {
     92     KitObjSecInfo sec;
     93     if (kit_obj_section(of, i, &sec) != KIT_OK) continue;
     94     if (!(sec.flags & KIT_SF_ALLOC)) continue;
     95     if (sec.kind == KIT_SEC_DEBUG) continue;
     96     /* addr is the load vaddr in a linked image, 0 for relocatables. */
     97     driver_printf("%-16.16s %08llx %08llx\n",
     98                   sec.name.len ? sec.name.s : "(anon)",
     99                   (unsigned long long)sec.size, (unsigned long long)sec.addr);
    100   }
    101   {
    102     KitObjSizeTotals a = size_compute_obj(of, opts);
    103     driver_printf("Total           %08llx\n", (unsigned long long)a.total);
    104   }
    105 }
    106 
    107 static int size_process_file(const KitContext* ctx, const KitSlice* input,
    108                              const char* path, const SizeOpts* opts,
    109                              KitObjSizeTotals* total_out, int* any_out,
    110                              int* output_begun) {
    111   KitBinFmt fmt = kit_detect_fmt(input->data, input->len);
    112   if (fmt == KIT_BIN_AR) {
    113     KitArIter* it = NULL;
    114     int failed = 0;
    115     int valid_members = 0;
    116     if (kit_ar_iter_new(ctx, input, &it) != KIT_OK) {
    117       driver_errf(SIZE_TOOL, "%s: not a recognized archive", path);
    118       return 1;
    119     }
    120     for (;;) {
    121       KitArMember m;
    122       KitIterResult ir = kit_ar_iter_next(it, &m);
    123       if (ir == KIT_ITER_END) break;
    124       if (ir == KIT_ITER_ERROR) {
    125         driver_errf(SIZE_TOOL, "%s: corrupt archive", path);
    126         failed = 1;
    127         break;
    128       }
    129       KitObjFile* of = NULL;
    130       KitSlice mb;
    131       char nmbuf[512];
    132       mb.data = m.data;
    133       mb.len = m.size;
    134       snprintf(nmbuf, sizeof nmbuf, "%s(%.*s)", path, (int)m.name.len,
    135                m.name.s);
    136       if (kit_obj_open(ctx, kit_slice_cstr(nmbuf), &mb, &of) == KIT_OK) {
    137         KitObjSizeTotals a = size_compute_obj(of, opts);
    138         size_begin_output(opts, output_begun);
    139         if (opts->fmt == SIZE_FMT_BERKELEY) {
    140           size_print_berkeley_sums(&a, nmbuf, opts);
    141         } else {
    142           size_print_sysv(of, nmbuf, opts);
    143         }
    144         total_out->text += a.text;
    145         total_out->data += a.data;
    146         total_out->bss += a.bss;
    147         total_out->total += a.total;
    148         *any_out = 1;
    149         ++valid_members;
    150         kit_obj_free(of);
    151       } else {
    152         driver_errf(SIZE_TOOL, "%s: not a recognized object file", nmbuf);
    153         failed = 1;
    154       }
    155     }
    156     kit_ar_iter_free(it);
    157     if (!valid_members && !failed) {
    158       driver_errf(SIZE_TOOL, "%s: archive contains no object members", path);
    159       failed = 1;
    160     }
    161     return failed;
    162   } else {
    163     KitObjFile* of = NULL;
    164     if (kit_obj_open(ctx, kit_slice_cstr(path), input, &of) != KIT_OK) {
    165       driver_errf(SIZE_TOOL, "%s: not a recognized object file", path);
    166       return 1;
    167     }
    168     {
    169       KitObjSizeTotals a = size_compute_obj(of, opts);
    170       size_begin_output(opts, output_begun);
    171       if (opts->fmt == SIZE_FMT_BERKELEY) {
    172         size_print_berkeley_sums(&a, path, opts);
    173       } else {
    174         size_print_sysv(of, path, opts);
    175       }
    176       total_out->text += a.text;
    177       total_out->data += a.data;
    178       total_out->bss += a.bss;
    179       total_out->total += a.total;
    180     }
    181     *any_out = 1;
    182     kit_obj_free(of);
    183   }
    184   return 0;
    185 }
    186 
    187 void driver_help_size(void) {
    188   driver_printf(
    189       "%.*s",
    190       KIT_SLICE_ARG(KIT_SLICE_LIT(
    191           "kit size — display section sizes of objects and linked images\n"
    192           "\n"
    193           "USAGE\n"
    194           "  kit size [OPTIONS] FILE...\n"
    195           "\n"
    196           "DESCRIPTION\n"
    197           "  Reads ELF, Mach-O, COFF/PE, and Wasm objects or linked images;\n"
    198           "  POSIX ar archives are reported member by member. The default is\n"
    199           "  Berkeley format in decimal: text, data, bss, total decimal/hex,\n"
    200           "  and filename. SysV format prints each section and its address.\n"
    201           "\n"
    202           "OPTIONS\n"
    203           "  -A, --format sysv     SysV output (section-by-section)\n"
    204           "  -B, --format berkeley  Berkeley output (default)\n"
    205           "  -d                     sizes in decimal\n"
    206           "  -o                     sizes in octal\n"
    207           "  -x                     sizes in hexadecimal\n"
    208           "  --common               include COMMON symbols in bss total\n"
    209           "  -t, --totals           print a totals line (Berkeley only)\n"
    210           "  -h, --help             show this help\n"
    211           "\n"
    212           "EXAMPLES\n"
    213           "  kit size app\n"
    214           "  kit size -A -x app\n"
    215           "  kit size -B -t a.o b.o\n"
    216           "  kit size libfoo.a\n"
    217           "\n"
    218           "EXIT CODES\n"
    219           "  0   success           1   object/archive or I/O error\n"
    220           "  2   bad usage\n")));
    221 }
    222 
    223 int driver_size(int argc, char** argv) {
    224   DriverEnv env;
    225   KitContext ctx;
    226   SizeOpts opts;
    227   KitObjSizeTotals totals;
    228   int i, rc = 1, any_input = 0, any_output = 0;
    229   int output_begun = 0, had_error = 0, options_done = 0;
    230 
    231   if (argc < 2) {
    232     driver_help_size();
    233     return 0;
    234   }
    235 
    236   memset(&opts, 0, sizeof opts);
    237   memset(&totals, 0, sizeof totals);
    238   opts.radix = SIZE_RAD_HEX;
    239   driver_env_init(&env);
    240   ctx = driver_env_to_context(&env);
    241 
    242   for (i = 1; i < argc; ++i) {
    243     const char* a = argv[i];
    244     if (!options_done && driver_streq(a, "--")) {
    245       options_done = 1;
    246       continue;
    247     }
    248     if (!options_done &&
    249         (driver_streq(a, "-h") || driver_streq(a, "--help"))) {
    250       driver_help_size();
    251       rc = 0;
    252       goto done;
    253     }
    254     if (!options_done &&
    255         (driver_streq(a, "-A") || driver_streq(a, "--format=sysv"))) {
    256       opts.fmt = SIZE_FMT_SYSV;
    257       continue;
    258     }
    259     if (!options_done &&
    260         (driver_streq(a, "-B") || driver_streq(a, "--format=berkeley"))) {
    261       opts.fmt = SIZE_FMT_BERKELEY;
    262       continue;
    263     }
    264     if (!options_done && driver_streq(a, "-d")) {
    265       opts.radix = SIZE_RAD_DEC;
    266       continue;
    267     }
    268     if (!options_done && driver_streq(a, "-o")) {
    269       opts.radix = SIZE_RAD_OCT;
    270       continue;
    271     }
    272     if (!options_done && driver_streq(a, "-x")) {
    273       opts.radix = SIZE_RAD_HEX;
    274       continue;
    275     }
    276     if (!options_done && driver_streq(a, "--common")) {
    277       opts.common = 1;
    278       continue;
    279     }
    280     if (!options_done &&
    281         (driver_streq(a, "-t") || driver_streq(a, "--totals"))) {
    282       opts.totals = 1;
    283       continue;
    284     }
    285     if (!options_done && a[0] == '-') {
    286       driver_errf(SIZE_TOOL, "unknown option: %s", a);
    287       rc = 2;
    288       goto done;
    289     }
    290     any_input = 1;
    291   }
    292 
    293   if (!any_input) {
    294     driver_errf(SIZE_TOOL, "no input files");
    295     rc = 2;
    296     goto done;
    297   }
    298 
    299   options_done = 0;
    300   for (i = 1; i < argc; ++i) {
    301     const char* a = argv[i];
    302     if (!options_done && driver_streq(a, "--")) {
    303       options_done = 1;
    304       continue;
    305     }
    306     if (!options_done &&
    307         (driver_streq(a, "-A") || driver_streq(a, "--format=sysv") ||
    308          driver_streq(a, "-B") || driver_streq(a, "--format=berkeley") ||
    309          driver_streq(a, "-d") || driver_streq(a, "-o") ||
    310          driver_streq(a, "-x") || driver_streq(a, "--common") ||
    311          driver_streq(a, "-t") || driver_streq(a, "--totals"))) {
    312       continue;
    313     }
    314     {
    315       const char* path = a;
    316       DriverLoad ld = {0};
    317       KitSlice input;
    318       if (driver_load_bytes(&env.file_io, SIZE_TOOL, path, &ld, &input) != 0) {
    319         had_error = 1;
    320         continue;
    321       }
    322       if (size_process_file(&ctx, &input, path, &opts, &totals, &any_output,
    323                             &output_begun) != 0)
    324         had_error = 1;
    325       driver_release_bytes(&env.file_io, &ld);
    326     }
    327   }
    328 
    329   if (!any_output) {
    330     rc = 1;
    331     goto done;
    332   }
    333 
    334   if (opts.totals && opts.fmt == SIZE_FMT_BERKELEY) {
    335     int w = size_width(opts.radix);
    336     char text_buf[32], data_buf[32], bss_buf[32], dec_buf[32], hex_buf[32];
    337     size_print_val(totals.text, opts.radix, w, text_buf, sizeof text_buf);
    338     size_print_val(totals.data, opts.radix, w, data_buf, sizeof data_buf);
    339     size_print_val(totals.bss, opts.radix, w, bss_buf, sizeof bss_buf);
    340     size_print_val(totals.total, SIZE_RAD_DEC, 8, dec_buf, sizeof dec_buf);
    341     size_print_val(totals.total, SIZE_RAD_HEX, 7, hex_buf, sizeof hex_buf);
    342     driver_printf(" %s %s %s %s %s (TOTALS)\n", text_buf, data_buf, bss_buf,
    343                   dec_buf, hex_buf);
    344   }
    345 
    346   rc = had_error ? 1 : 0;
    347 done:
    348   driver_env_fini(&env);
    349   return rc;
    350 }