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 }