kit

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

size.c (10702B)


      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 typedef struct SizeAgg {
     32   uint64_t text;
     33   uint64_t data;
     34   uint64_t bss;
     35   uint64_t total;
     36 } SizeAgg;
     37 
     38 static void size_classify_section(const KitObjSecInfo* sec, int* is_text,
     39                                   int* is_data, int* is_bss) {
     40   int alloc = (sec->flags & KIT_SF_ALLOC) != 0;
     41   int exec = (sec->flags & KIT_SF_EXEC) != 0;
     42   int write = (sec->flags & KIT_SF_WRITE) != 0;
     43 
     44   *is_text = 0;
     45   *is_data = 0;
     46   *is_bss = 0;
     47 
     48   if (!alloc) return;
     49   if (sec->kind == KIT_SEC_DEBUG) return;
     50 
     51   if (sec->kind == KIT_SEC_TEXT || exec) {
     52     *is_text = 1;
     53     return;
     54   }
     55   if (sec->kind == KIT_SEC_BSS) {
     56     *is_bss = 1;
     57     return;
     58   }
     59   if (sec->kind == KIT_SEC_RODATA) {
     60     *is_data = 1;
     61     return;
     62   }
     63   if (sec->kind == KIT_SEC_DATA || write) {
     64     *is_data = 1;
     65     return;
     66   }
     67   *is_data = 1;
     68 }
     69 
     70 static SizeAgg size_compute_obj(KitObjFile* of, const SizeOpts* opts) {
     71   SizeAgg a;
     72   uint32_t ns, i;
     73   memset(&a, 0, sizeof a);
     74   ns = kit_obj_nsections(of);
     75   for (i = 0; i < ns; ++i) {
     76     KitObjSecInfo sec;
     77     int is_text, is_data, is_bss;
     78     if (kit_obj_section(of, i, &sec) != KIT_OK) continue;
     79     size_classify_section(&sec, &is_text, &is_data, &is_bss);
     80     if (is_text) a.text += sec.size;
     81     if (is_data) a.data += sec.size;
     82     if (is_bss) a.bss += sec.size;
     83   }
     84   if (opts->common) {
     85     KitObjSymIter* it = NULL;
     86     if (kit_obj_symiter_new(of, &it) == KIT_OK) {
     87       for (;;) {
     88         KitObjSymInfo si;
     89         if (kit_obj_symiter_next(it, &si) != KIT_ITER_ITEM) break;
     90         if (si.kind == KIT_SK_COMMON) a.bss += si.size;
     91       }
     92       kit_obj_symiter_free(it);
     93     }
     94   }
     95   a.total = a.text + a.data + a.bss;
     96   return a;
     97 }
     98 
     99 static void size_print_val(uint64_t v, SizeRadix radix, int width, char* buf,
    100                            size_t buf_size) {
    101   switch (radix) {
    102     case SIZE_RAD_DEC:
    103       snprintf(buf, buf_size, "%*llu", width, (unsigned long long)v);
    104       break;
    105     case SIZE_RAD_OCT:
    106       snprintf(buf, buf_size, "%*llo", width, (unsigned long long)v);
    107       break;
    108     default: /* hex */
    109       snprintf(buf, buf_size, "%*llx", width, (unsigned long long)v);
    110       break;
    111   }
    112 }
    113 
    114 static int size_width(SizeRadix radix) {
    115   return (radix == SIZE_RAD_OCT) ? 10 : (radix == SIZE_RAD_DEC) ? 8 : 7;
    116 }
    117 
    118 static void size_print_berkeley_header(const SizeOpts* opts) {
    119   int w = size_width(opts->radix);
    120   driver_printf("   %-*s   %-*s   %-*s   %8s   %7s  filename\n", w, "text", w,
    121                 "data", w, "bss", "dec", "hex");
    122 }
    123 
    124 static void size_print_berkeley_sums(const SizeAgg* a, const char* name,
    125                                      const SizeOpts* opts) {
    126   int w = size_width(opts->radix);
    127   char text_buf[32], data_buf[32], bss_buf[32], dec_buf[32], hex_buf[32];
    128   size_print_val(a->text, opts->radix, w, text_buf, sizeof text_buf);
    129   size_print_val(a->data, opts->radix, w, data_buf, sizeof data_buf);
    130   size_print_val(a->bss, opts->radix, w, bss_buf, sizeof bss_buf);
    131   size_print_val(a->total, SIZE_RAD_DEC, 8, dec_buf, sizeof dec_buf);
    132   size_print_val(a->total, SIZE_RAD_HEX, 7, hex_buf, sizeof hex_buf);
    133   driver_printf("  %s  %s  %s  %s  %s  %s\n", text_buf, data_buf, bss_buf,
    134                 dec_buf, hex_buf, name);
    135 }
    136 
    137 static void size_print_sysv(KitObjFile* of, const char* name,
    138                             const SizeOpts* opts) {
    139   uint32_t ns, i;
    140   driver_printf("%s  :\n", name);
    141   driver_printf("section          size      addr\n");
    142   ns = kit_obj_nsections(of);
    143   for (i = 0; i < ns; ++i) {
    144     KitObjSecInfo sec;
    145     if (kit_obj_section(of, i, &sec) != KIT_OK) continue;
    146     if (!(sec.flags & KIT_SF_ALLOC)) continue;
    147     if (sec.kind == KIT_SEC_DEBUG) continue;
    148     /* addr is the load vaddr in a linked image, 0 for relocatables. */
    149     driver_printf("%-16.16s %08llx %08llx\n",
    150                   sec.name.len ? sec.name.s : "(anon)",
    151                   (unsigned long long)sec.size, (unsigned long long)sec.addr);
    152   }
    153   {
    154     SizeAgg a = size_compute_obj(of, opts);
    155     driver_printf("Total           %08llx\n", (unsigned long long)a.total);
    156   }
    157 }
    158 
    159 static int size_process_file(const KitContext* ctx, const KitSlice* input,
    160                              const char* path, const SizeOpts* opts,
    161                              SizeAgg* total_out, int* any_out) {
    162   KitBinFmt fmt = kit_detect_fmt(input->data, input->len);
    163   if (fmt == KIT_BIN_AR) {
    164     KitArIter* it = NULL;
    165     if (kit_ar_iter_new(ctx, input, &it) != KIT_OK) {
    166       driver_errf(SIZE_TOOL, "%s: not a recognized archive", path);
    167       return 1;
    168     }
    169     for (;;) {
    170       KitArMember m;
    171       if (kit_ar_iter_next(it, &m) != KIT_ITER_ITEM) break;
    172       KitObjFile* of = NULL;
    173       KitSlice mb;
    174       mb.data = m.data;
    175       mb.len = m.size;
    176       if (kit_obj_open(ctx, KIT_SLICE_NULL, &mb, &of) == KIT_OK) {
    177         SizeAgg a = size_compute_obj(of, opts);
    178         if (opts->fmt == SIZE_FMT_BERKELEY) {
    179           char nmbuf[512];
    180           snprintf(nmbuf, sizeof nmbuf, "%.*s(%.*s)",
    181                    path ? (int)strlen(path) : 0, path ? path : "",
    182                    (int)m.name.len, m.name.s);
    183           size_print_berkeley_sums(&a, nmbuf, opts);
    184         } else {
    185           char nmbuf[512];
    186           snprintf(nmbuf, sizeof nmbuf, "%s(%.*s)", path, (int)m.name.len,
    187                    m.name.s);
    188           size_print_sysv(of, nmbuf, opts);
    189         }
    190         total_out->text += a.text;
    191         total_out->data += a.data;
    192         total_out->bss += a.bss;
    193         total_out->total += a.total;
    194         *any_out = 1;
    195         kit_obj_free(of);
    196       }
    197     }
    198     kit_ar_iter_free(it);
    199   } else {
    200     KitObjFile* of = NULL;
    201     if (kit_obj_open(ctx, kit_slice_cstr(path), input, &of) != KIT_OK) {
    202       driver_errf(SIZE_TOOL, "%s: not a recognized object file", path);
    203       return 1;
    204     }
    205     {
    206       SizeAgg a = size_compute_obj(of, opts);
    207       if (opts->fmt == SIZE_FMT_BERKELEY) {
    208         size_print_berkeley_sums(&a, path, opts);
    209       } else {
    210         size_print_sysv(of, path, opts);
    211       }
    212       total_out->text += a.text;
    213       total_out->data += a.data;
    214       total_out->bss += a.bss;
    215       total_out->total += a.total;
    216     }
    217     *any_out = 1;
    218     kit_obj_free(of);
    219   }
    220   return 0;
    221 }
    222 
    223 void driver_help_size(void) {
    224   driver_printf(
    225       "%.*s",
    226       KIT_SLICE_ARG(KIT_SLICE_LIT(
    227           "kit size — display section sizes of object files\n"
    228           "\n"
    229           "USAGE\n"
    230           "  kit size [OPTIONS] FILE...\n"
    231           "\n"
    232           "OPTIONS\n"
    233           "  -A, --format sysv     SysV output (section-by-section)\n"
    234           "  -B, --format berkeley  Berkeley output (default)\n"
    235           "  -d                     sizes in decimal\n"
    236           "  -o                     sizes in octal\n"
    237           "  -x                     sizes in hexadecimal\n"
    238           "  --common               include COMMON symbols in bss total\n"
    239           "  -t, --totals           print a totals line (Berkeley only)\n"
    240           "  -h, --help             show this help\n")));
    241 }
    242 
    243 int driver_size(int argc, char** argv) {
    244   DriverEnv env;
    245   KitContext ctx;
    246   SizeOpts opts;
    247   SizeAgg totals;
    248   int i, rc = 1, any_input = 0, any_output = 0;
    249 
    250   if (argc < 2 || driver_argv_wants_help(argc, argv, 1)) {
    251     driver_help_size();
    252     return 0;
    253   }
    254 
    255   memset(&opts, 0, sizeof opts);
    256   memset(&totals, 0, sizeof totals);
    257   opts.radix = SIZE_RAD_HEX;
    258   driver_env_init(&env);
    259   ctx = driver_env_to_context(&env);
    260 
    261   for (i = 1; i < argc; ++i) {
    262     const char* a = argv[i];
    263     if (driver_streq(a, "-A") || driver_streq(a, "--format=sysv")) {
    264       opts.fmt = SIZE_FMT_SYSV;
    265       continue;
    266     }
    267     if (driver_streq(a, "-B") || driver_streq(a, "--format=berkeley")) {
    268       opts.fmt = SIZE_FMT_BERKELEY;
    269       continue;
    270     }
    271     if (driver_streq(a, "-d")) {
    272       opts.radix = SIZE_RAD_DEC;
    273       continue;
    274     }
    275     if (driver_streq(a, "-o")) {
    276       opts.radix = SIZE_RAD_OCT;
    277       continue;
    278     }
    279     if (driver_streq(a, "-x")) {
    280       opts.radix = SIZE_RAD_HEX;
    281       continue;
    282     }
    283     if (driver_streq(a, "--common")) {
    284       opts.common = 1;
    285       continue;
    286     }
    287     if (driver_streq(a, "-t") || driver_streq(a, "--totals")) {
    288       opts.totals = 1;
    289       continue;
    290     }
    291     if (a[0] == '-') {
    292       driver_errf(SIZE_TOOL, "unknown option: %s", a);
    293       rc = 2;
    294       goto done;
    295     }
    296     any_input = 1;
    297   }
    298 
    299   if (!any_input) {
    300     driver_errf(SIZE_TOOL, "no input files");
    301     rc = 2;
    302     goto done;
    303   }
    304 
    305   if (opts.fmt == SIZE_FMT_BERKELEY) size_print_berkeley_header(&opts);
    306 
    307   for (i = 1; i < argc; ++i) {
    308     const char* a = argv[i];
    309     if (driver_streq(a, "-A") || driver_streq(a, "--format=sysv") ||
    310         driver_streq(a, "-B") || driver_streq(a, "--format=berkeley") ||
    311         driver_streq(a, "-d") || driver_streq(a, "-o") ||
    312         driver_streq(a, "-x") || driver_streq(a, "--common") ||
    313         driver_streq(a, "-t") || driver_streq(a, "--totals")) {
    314       continue;
    315     }
    316     {
    317       const char* path = a;
    318       DriverLoad ld = {0};
    319       KitSlice input;
    320       if (driver_load_bytes(&env.file_io, SIZE_TOOL, path, &ld, &input) != 0) {
    321         rc = 1;
    322         goto done;
    323       }
    324       if (size_process_file(&ctx, &input, path, &opts, &totals, &any_output) !=
    325           0) {
    326         driver_release_bytes(&env.file_io, &ld);
    327         rc = 1;
    328         goto done;
    329       }
    330       driver_release_bytes(&env.file_io, &ld);
    331     }
    332   }
    333 
    334   if (!any_output) {
    335     driver_errf(SIZE_TOOL, "no input files");
    336     rc = 2;
    337     goto done;
    338   }
    339 
    340   if (opts.totals && opts.fmt == SIZE_FMT_BERKELEY) {
    341     int w = size_width(opts.radix);
    342     char text_buf[32], data_buf[32], bss_buf[32], dec_buf[32], hex_buf[32];
    343     size_print_val(totals.text, opts.radix, w, text_buf, sizeof text_buf);
    344     size_print_val(totals.data, opts.radix, w, data_buf, sizeof data_buf);
    345     size_print_val(totals.bss, opts.radix, w, bss_buf, sizeof bss_buf);
    346     size_print_val(totals.total, SIZE_RAD_DEC, 8, dec_buf, sizeof dec_buf);
    347     size_print_val(totals.total, SIZE_RAD_HEX, 7, hex_buf, sizeof hex_buf);
    348     driver_printf(" %s %s %s %s %s (TOTALS)\n", text_buf, data_buf, bss_buf,
    349                   dec_buf, hex_buf);
    350   }
    351 
    352   rc = 0;
    353 done:
    354   driver_env_fini(&env);
    355   return rc;
    356 }