Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/elftoolchain/size/size.c
39586 views
1
/*-
2
* Copyright (c) 2007 S.Sam Arun Raj
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
*
14
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
* SUCH DAMAGE.
25
*/
26
27
#include <assert.h>
28
#include <capsicum_helpers.h>
29
#include <err.h>
30
#include <fcntl.h>
31
#include <gelf.h>
32
#include <getopt.h>
33
#include <libelftc.h>
34
#include <stdint.h>
35
#include <stdio.h>
36
#include <stdlib.h>
37
#include <string.h>
38
#include <unistd.h>
39
40
#include <libcasper.h>
41
#include <casper/cap_fileargs.h>
42
43
#include "_elftc.h"
44
45
ELFTC_VCSID("$Id: size.c 3458 2016-05-09 15:01:25Z emaste $");
46
47
#define BUF_SIZE 1024
48
#define ELF_ALIGN(val,x) (((val)+(x)-1) & ~((x)-1))
49
#define SIZE_VERSION_STRING "size 1.0"
50
51
enum return_code {
52
RETURN_OK,
53
RETURN_DATAERR,
54
RETURN_USAGE
55
};
56
57
enum output_style {
58
STYLE_BERKELEY,
59
STYLE_SYSV
60
};
61
62
enum radix_style {
63
RADIX_OCTAL,
64
RADIX_DECIMAL,
65
RADIX_HEX
66
};
67
68
static uint64_t bss_size, data_size, text_size, total_size;
69
static uint64_t bss_size_total, data_size_total, text_size_total;
70
static int show_totals;
71
static int size_option;
72
static enum radix_style radix = RADIX_DECIMAL;
73
static enum output_style style = STYLE_BERKELEY;
74
75
static struct {
76
int row;
77
int col;
78
int *width;
79
char ***tbl;
80
} *tb;
81
82
enum {
83
OPT_FORMAT,
84
OPT_RADIX
85
};
86
87
static struct option size_longopts[] = {
88
{ "format", required_argument, &size_option, OPT_FORMAT },
89
{ "help", no_argument, NULL, 'h' },
90
{ "radix", required_argument, &size_option, OPT_RADIX },
91
{ "totals", no_argument, NULL, 't' },
92
{ "version", no_argument, NULL, 'V' },
93
{ NULL, 0, NULL, 0 }
94
};
95
96
static void berkeley_calc(GElf_Shdr *);
97
static void berkeley_footer(const char *, const char *, const char *);
98
static void berkeley_header(void);
99
static void berkeley_totals(void);
100
static int handle_core(char const *, Elf *elf, GElf_Ehdr *);
101
static void handle_core_note(Elf *, GElf_Ehdr *, GElf_Phdr *, char **);
102
static int handle_elf(int, char const *);
103
static void handle_phdr(Elf *, GElf_Ehdr *, GElf_Phdr *, uint32_t,
104
const char *);
105
static void show_version(void);
106
static void sysv_header(const char *, Elf_Arhdr *);
107
static void sysv_footer(void);
108
static void sysv_calc(Elf *, GElf_Ehdr *, GElf_Shdr *);
109
static void usage(void);
110
static void tbl_new(int);
111
static void tbl_print(const char *, int);
112
static void tbl_print_num(uint64_t, enum radix_style, int);
113
static void tbl_append(void);
114
static void tbl_flush(void);
115
116
/*
117
* size utility using elf(3) and gelf(3) API to list section sizes and
118
* total in elf files. Supports only elf files (core dumps in elf
119
* included) that can be opened by libelf, other formats are not supported.
120
*/
121
int
122
main(int argc, char **argv)
123
{
124
cap_rights_t rights;
125
fileargs_t *fa;
126
int ch, fd, r, rc;
127
const char *fn;
128
char *defaultfn;
129
130
rc = RETURN_OK;
131
132
if (elf_version(EV_CURRENT) == EV_NONE)
133
errx(EXIT_FAILURE, "ELF library initialization failed: %s",
134
elf_errmsg(-1));
135
136
while ((ch = getopt_long(argc, argv, "ABVdhotx", size_longopts,
137
NULL)) != -1)
138
switch((char)ch) {
139
case 'A':
140
style = STYLE_SYSV;
141
break;
142
case 'B':
143
style = STYLE_BERKELEY;
144
break;
145
case 'V':
146
show_version();
147
break;
148
case 'd':
149
radix = RADIX_DECIMAL;
150
break;
151
case 'o':
152
radix = RADIX_OCTAL;
153
break;
154
case 't':
155
show_totals = 1;
156
break;
157
case 'x':
158
radix = RADIX_HEX;
159
break;
160
case 0:
161
switch (size_option) {
162
case OPT_FORMAT:
163
if (*optarg == 's' || *optarg == 'S')
164
style = STYLE_SYSV;
165
else if (*optarg == 'b' || *optarg == 'B')
166
style = STYLE_BERKELEY;
167
else {
168
warnx("unrecognized format \"%s\".",
169
optarg);
170
usage();
171
}
172
break;
173
case OPT_RADIX:
174
r = strtol(optarg, NULL, 10);
175
if (r == 8)
176
radix = RADIX_OCTAL;
177
else if (r == 10)
178
radix = RADIX_DECIMAL;
179
else if (r == 16)
180
radix = RADIX_HEX;
181
else {
182
warnx("unsupported radix \"%s\".",
183
optarg);
184
usage();
185
}
186
break;
187
default:
188
err(EXIT_FAILURE, "Error in option handling.");
189
/*NOTREACHED*/
190
}
191
break;
192
case 'h':
193
case '?':
194
default:
195
usage();
196
/* NOTREACHED */
197
}
198
argc -= optind;
199
argv += optind;
200
201
if (argc == 0) {
202
defaultfn = strdup("a.out");
203
if (defaultfn == NULL)
204
err(EXIT_FAILURE, "strdup");
205
argc = 1;
206
argv = &defaultfn;
207
} else {
208
defaultfn = NULL;
209
}
210
211
cap_rights_init(&rights, CAP_FSTAT, CAP_MMAP_R);
212
fa = fileargs_init(argc, argv, O_RDONLY, 0, &rights, FA_OPEN);
213
if (fa == NULL)
214
err(EXIT_FAILURE, "failed to initialize fileargs");
215
216
caph_cache_catpages();
217
if (caph_limit_stdio() < 0)
218
err(EXIT_FAILURE, "failed to limit stdio rights");
219
if (caph_enter_casper() < 0)
220
err(EXIT_FAILURE, "failed to enter capability mode");
221
222
for (; argc > 0; argc--, argv++) {
223
fn = argv[0];
224
fd = fileargs_open(fa, fn);
225
if (fd < 0) {
226
warn("%s: Failed to open", fn);
227
continue;
228
}
229
rc = handle_elf(fd, fn);
230
if (rc != RETURN_OK)
231
warnx("%s: File format not recognized", fn);
232
}
233
if (style == STYLE_BERKELEY) {
234
if (show_totals)
235
berkeley_totals();
236
tbl_flush();
237
}
238
fileargs_free(fa);
239
free(defaultfn);
240
return (rc);
241
}
242
243
static int
244
xlatetom(Elf *elf, GElf_Ehdr *elfhdr, void *_src, void *_dst,
245
Elf_Type type, size_t size)
246
{
247
Elf_Data src, dst;
248
249
src.d_buf = _src;
250
src.d_type = type;
251
src.d_version = elfhdr->e_version;
252
src.d_size = size;
253
dst.d_buf = _dst;
254
dst.d_version = elfhdr->e_version;
255
dst.d_size = size;
256
return (gelf_xlatetom(elf, &dst, &src, elfhdr->e_ident[EI_DATA]) !=
257
NULL ? 0 : 1);
258
}
259
260
#define NOTE_OFFSET_32(nhdr, namesz, offset) \
261
((char *)nhdr + sizeof(Elf32_Nhdr) + \
262
ELF_ALIGN((int32_t)namesz, 4) + offset)
263
264
#define NOTE_OFFSET_64(nhdr, namesz, offset) \
265
((char *)nhdr + sizeof(Elf32_Nhdr) + \
266
ELF_ALIGN((int32_t)namesz, 8) + offset)
267
268
#define PID32(nhdr, namesz, offset) \
269
(pid_t)*((int *)((uintptr_t)NOTE_OFFSET_32(nhdr, \
270
namesz, offset)));
271
272
#define PID64(nhdr, namesz, offset) \
273
(pid_t)*((int *)((uintptr_t)NOTE_OFFSET_64(nhdr, \
274
namesz, offset)));
275
276
#define NEXT_NOTE(elfhdr, descsz, namesz, offset) do { \
277
if (elfhdr->e_ident[EI_CLASS] == ELFCLASS32) { \
278
offset += ELF_ALIGN((int32_t)descsz, 4) + \
279
sizeof(Elf32_Nhdr) + \
280
ELF_ALIGN((int32_t)namesz, 4); \
281
} else { \
282
offset += ELF_ALIGN((int32_t)descsz, 8) + \
283
sizeof(Elf32_Nhdr) + \
284
ELF_ALIGN((int32_t)namesz, 8); \
285
} \
286
} while (0)
287
288
/*
289
* Parse individual note entries inside a PT_NOTE segment.
290
*/
291
static void
292
handle_core_note(Elf *elf, GElf_Ehdr *elfhdr, GElf_Phdr *phdr,
293
char **cmd_line)
294
{
295
size_t max_size, segment_end;
296
uint64_t raw_size;
297
GElf_Off offset;
298
static pid_t pid;
299
uintptr_t ver;
300
Elf32_Nhdr *nhdr, nhdr_l;
301
static int reg_pseudo = 0, reg2_pseudo = 0 /*, regxfp_pseudo = 0*/;
302
char buf[BUF_SIZE], *data, *name;
303
304
if (elf == NULL || elfhdr == NULL || phdr == NULL)
305
return;
306
307
data = elf_rawfile(elf, &max_size);
308
offset = phdr->p_offset;
309
if (offset >= max_size || phdr->p_filesz > max_size - offset) {
310
warnx("invalid PHDR offset");
311
return;
312
}
313
segment_end = phdr->p_offset + phdr->p_filesz;
314
315
while (data != NULL && offset + sizeof(Elf32_Nhdr) < segment_end) {
316
nhdr = (Elf32_Nhdr *)(uintptr_t)((char*)data + offset);
317
memset(&nhdr_l, 0, sizeof(Elf32_Nhdr));
318
if (xlatetom(elf, elfhdr, &nhdr->n_type, &nhdr_l.n_type,
319
ELF_T_WORD, sizeof(Elf32_Word)) != 0 ||
320
xlatetom(elf, elfhdr, &nhdr->n_descsz, &nhdr_l.n_descsz,
321
ELF_T_WORD, sizeof(Elf32_Word)) != 0 ||
322
xlatetom(elf, elfhdr, &nhdr->n_namesz, &nhdr_l.n_namesz,
323
ELF_T_WORD, sizeof(Elf32_Word)) != 0)
324
break;
325
326
if (offset + sizeof(Elf32_Nhdr) +
327
ELF_ALIGN(nhdr_l.n_namesz, 4) +
328
ELF_ALIGN(nhdr_l.n_descsz, 4) >= segment_end) {
329
warnx("invalid note header");
330
return;
331
}
332
333
name = (char *)((char *)nhdr + sizeof(Elf32_Nhdr));
334
switch (nhdr_l.n_type) {
335
case NT_PRSTATUS: {
336
raw_size = 0;
337
if (elfhdr->e_ident[EI_OSABI] == ELFOSABI_FREEBSD &&
338
nhdr_l.n_namesz == 0x8 &&
339
!strcmp(name,"FreeBSD")) {
340
if (elfhdr->e_ident[EI_CLASS] == ELFCLASS32) {
341
raw_size = (uint64_t)*((uint32_t *)
342
(uintptr_t)(name +
343
ELF_ALIGN((int32_t)
344
nhdr_l.n_namesz, 4) + 8));
345
ver = (uintptr_t)NOTE_OFFSET_32(nhdr,
346
nhdr_l.n_namesz,0);
347
if (*((int *)ver) == 1)
348
pid = PID32(nhdr,
349
nhdr_l.n_namesz, 24);
350
} else {
351
raw_size = *((uint64_t *)(uintptr_t)
352
(name + ELF_ALIGN((int32_t)
353
nhdr_l.n_namesz, 8) + 16));
354
ver = (uintptr_t)NOTE_OFFSET_64(nhdr,
355
nhdr_l.n_namesz,0);
356
if (*((int *)ver) == 1)
357
pid = PID64(nhdr,
358
nhdr_l.n_namesz, 40);
359
}
360
(void)xlatetom(elf, elfhdr, &raw_size,
361
&raw_size, ELF_T_WORD, sizeof(uint64_t));
362
(void)xlatetom(elf, elfhdr, &pid, &pid,
363
ELF_T_WORD, sizeof(pid_t));
364
}
365
366
if (raw_size != 0 && style == STYLE_SYSV) {
367
(void) snprintf(buf, BUF_SIZE, "%s/%d",
368
".reg", pid);
369
tbl_append();
370
tbl_print(buf, 0);
371
tbl_print_num(raw_size, radix, 1);
372
tbl_print_num(0, radix, 2);
373
if (!reg_pseudo) {
374
tbl_append();
375
tbl_print(".reg", 0);
376
tbl_print_num(raw_size, radix, 1);
377
tbl_print_num(0, radix, 2);
378
reg_pseudo = 1;
379
text_size_total += raw_size;
380
}
381
text_size_total += raw_size;
382
}
383
}
384
break;
385
case NT_FPREGSET: /* same as NT_PRFPREG */
386
if (style == STYLE_SYSV) {
387
(void) snprintf(buf, BUF_SIZE,
388
"%s/%d", ".reg2", pid);
389
tbl_append();
390
tbl_print(buf, 0);
391
tbl_print_num(nhdr_l.n_descsz, radix, 1);
392
tbl_print_num(0, radix, 2);
393
if (!reg2_pseudo) {
394
tbl_append();
395
tbl_print(".reg2", 0);
396
tbl_print_num(nhdr_l.n_descsz, radix,
397
1);
398
tbl_print_num(0, radix, 2);
399
reg2_pseudo = 1;
400
text_size_total += nhdr_l.n_descsz;
401
}
402
text_size_total += nhdr_l.n_descsz;
403
}
404
break;
405
#if 0
406
case NT_AUXV:
407
if (style == STYLE_SYSV) {
408
tbl_append();
409
tbl_print(".auxv", 0);
410
tbl_print_num(nhdr_l.n_descsz, radix, 1);
411
tbl_print_num(0, radix, 2);
412
text_size_total += nhdr_l.n_descsz;
413
}
414
break;
415
case NT_PRXFPREG:
416
if (style == STYLE_SYSV) {
417
(void) snprintf(buf, BUF_SIZE, "%s/%d",
418
".reg-xfp", pid);
419
tbl_append();
420
tbl_print(buf, 0);
421
tbl_print_num(nhdr_l.n_descsz, radix, 1);
422
tbl_print_num(0, radix, 2);
423
if (!regxfp_pseudo) {
424
tbl_append();
425
tbl_print(".reg-xfp", 0);
426
tbl_print_num(nhdr_l.n_descsz, radix,
427
1);
428
tbl_print_num(0, radix, 2);
429
regxfp_pseudo = 1;
430
text_size_total += nhdr_l.n_descsz;
431
}
432
text_size_total += nhdr_l.n_descsz;
433
}
434
break;
435
case NT_PSINFO:
436
#endif
437
case NT_PRPSINFO: {
438
/* FreeBSD 64-bit */
439
if (nhdr_l.n_descsz == 0x78 &&
440
!strcmp(name,"FreeBSD")) {
441
*cmd_line = strdup(NOTE_OFFSET_64(nhdr,
442
nhdr_l.n_namesz, 33));
443
/* FreeBSD 32-bit */
444
} else if (nhdr_l.n_descsz == 0x6c &&
445
!strcmp(name,"FreeBSD")) {
446
*cmd_line = strdup(NOTE_OFFSET_32(nhdr,
447
nhdr_l.n_namesz, 25));
448
}
449
/* Strip any trailing spaces */
450
if (*cmd_line != NULL) {
451
char *s;
452
453
s = *cmd_line + strlen(*cmd_line);
454
while (s > *cmd_line) {
455
if (*(s-1) != 0x20) break;
456
s--;
457
}
458
*s = 0;
459
}
460
break;
461
}
462
#if 0
463
case NT_PSTATUS:
464
case NT_LWPSTATUS:
465
#endif
466
default:
467
break;
468
}
469
NEXT_NOTE(elfhdr, nhdr_l.n_descsz, nhdr_l.n_namesz, offset);
470
}
471
}
472
473
/*
474
* Handles program headers except for PT_NOTE, when sysv output style is
475
* chosen, prints out the segment name and length. For berkely output
476
* style only PT_LOAD segments are handled, and text,
477
* data, bss size is calculated for them.
478
*/
479
static void
480
handle_phdr(Elf *elf, GElf_Ehdr *elfhdr, GElf_Phdr *phdr,
481
uint32_t idx, const char *name)
482
{
483
uint64_t addr, size;
484
int split;
485
char buf[BUF_SIZE];
486
487
if (elf == NULL || elfhdr == NULL || phdr == NULL)
488
return;
489
490
split = (phdr->p_memsz > 0) && (phdr->p_filesz > 0) &&
491
(phdr->p_memsz > phdr->p_filesz);
492
493
if (style == STYLE_SYSV) {
494
(void) snprintf(buf, BUF_SIZE,
495
"%s%d%s", name, idx, (split ? "a" : ""));
496
tbl_append();
497
tbl_print(buf, 0);
498
tbl_print_num(phdr->p_filesz, radix, 1);
499
tbl_print_num(phdr->p_vaddr, radix, 2);
500
text_size_total += phdr->p_filesz;
501
if (split) {
502
size = phdr->p_memsz - phdr->p_filesz;
503
addr = phdr->p_vaddr + phdr->p_filesz;
504
(void) snprintf(buf, BUF_SIZE, "%s%d%s", name,
505
idx, "b");
506
text_size_total += phdr->p_memsz - phdr->p_filesz;
507
tbl_append();
508
tbl_print(buf, 0);
509
tbl_print_num(size, radix, 1);
510
tbl_print_num(addr, radix, 2);
511
}
512
} else {
513
if (phdr->p_type != PT_LOAD)
514
return;
515
if ((phdr->p_flags & PF_W) && !(phdr->p_flags & PF_X)) {
516
data_size += phdr->p_filesz;
517
if (split)
518
data_size += phdr->p_memsz - phdr->p_filesz;
519
} else {
520
text_size += phdr->p_filesz;
521
if (split)
522
text_size += phdr->p_memsz - phdr->p_filesz;
523
}
524
}
525
}
526
527
/*
528
* Given a core dump file, this function maps program headers to segments.
529
*/
530
static int
531
handle_core(char const *name, Elf *elf, GElf_Ehdr *elfhdr)
532
{
533
GElf_Phdr phdr;
534
uint32_t i;
535
char *core_cmdline;
536
const char *seg_name;
537
538
if (name == NULL || elf == NULL || elfhdr == NULL)
539
return (RETURN_DATAERR);
540
if (elfhdr->e_shnum != 0 || elfhdr->e_type != ET_CORE)
541
return (RETURN_DATAERR);
542
543
seg_name = core_cmdline = NULL;
544
if (style == STYLE_SYSV)
545
sysv_header(name, NULL);
546
else
547
berkeley_header();
548
549
for (i = 0; i < elfhdr->e_phnum; i++) {
550
if (gelf_getphdr(elf, i, &phdr) != NULL) {
551
if (phdr.p_type == PT_NOTE) {
552
handle_phdr(elf, elfhdr, &phdr, i, "note");
553
handle_core_note(elf, elfhdr, &phdr,
554
&core_cmdline);
555
} else {
556
switch(phdr.p_type) {
557
case PT_NULL:
558
seg_name = "null";
559
break;
560
case PT_LOAD:
561
seg_name = "load";
562
break;
563
case PT_DYNAMIC:
564
seg_name = "dynamic";
565
break;
566
case PT_INTERP:
567
seg_name = "interp";
568
break;
569
case PT_SHLIB:
570
seg_name = "shlib";
571
break;
572
case PT_PHDR:
573
seg_name = "phdr";
574
break;
575
case PT_GNU_EH_FRAME:
576
seg_name = "eh_frame_hdr";
577
break;
578
case PT_GNU_STACK:
579
seg_name = "stack";
580
break;
581
default:
582
seg_name = "segment";
583
}
584
handle_phdr(elf, elfhdr, &phdr, i, seg_name);
585
}
586
}
587
}
588
589
if (style == STYLE_BERKELEY) {
590
if (core_cmdline != NULL) {
591
berkeley_footer(core_cmdline, name,
592
"core file invoked as");
593
} else {
594
berkeley_footer(core_cmdline, name, "core file");
595
}
596
} else {
597
sysv_footer();
598
if (core_cmdline != NULL) {
599
(void) printf(" (core file invoked as %s)\n\n",
600
core_cmdline);
601
} else {
602
(void) printf(" (core file)\n\n");
603
}
604
}
605
free(core_cmdline);
606
return (RETURN_OK);
607
}
608
609
/*
610
* Given an elf object,ar(1) filename, and based on the output style
611
* and radix format the various sections and their length will be printed
612
* or the size of the text, data, bss sections will be printed out.
613
*/
614
static int
615
handle_elf(int fd, const char *name)
616
{
617
GElf_Ehdr elfhdr;
618
GElf_Shdr shdr;
619
Elf *elf, *elf1;
620
Elf_Arhdr *arhdr;
621
Elf_Scn *scn;
622
Elf_Cmd elf_cmd;
623
int exit_code;
624
625
elf_cmd = ELF_C_READ;
626
elf1 = elf_begin(fd, elf_cmd, NULL);
627
while ((elf = elf_begin(fd, elf_cmd, elf1)) != NULL) {
628
arhdr = elf_getarhdr(elf);
629
if (elf_kind(elf) == ELF_K_NONE && arhdr == NULL) {
630
(void) elf_end(elf);
631
(void) elf_end(elf1);
632
(void) close(fd);
633
return (RETURN_DATAERR);
634
}
635
if (elf_kind(elf) != ELF_K_ELF ||
636
(gelf_getehdr(elf, &elfhdr) == NULL)) {
637
elf_cmd = elf_next(elf);
638
(void) elf_end(elf);
639
warnx("%s: File format not recognized",
640
arhdr != NULL ? arhdr->ar_name : name);
641
continue;
642
}
643
/* Core dumps are handled separately */
644
if (elfhdr.e_shnum == 0 && elfhdr.e_type == ET_CORE) {
645
exit_code = handle_core(name, elf, &elfhdr);
646
(void) elf_end(elf);
647
(void) elf_end(elf1);
648
(void) close(fd);
649
return (exit_code);
650
} else {
651
scn = NULL;
652
if (style == STYLE_BERKELEY) {
653
berkeley_header();
654
while ((scn = elf_nextscn(elf, scn)) != NULL) {
655
if (gelf_getshdr(scn, &shdr) != NULL)
656
berkeley_calc(&shdr);
657
}
658
} else {
659
sysv_header(name, arhdr);
660
scn = NULL;
661
while ((scn = elf_nextscn(elf, scn)) != NULL) {
662
if (gelf_getshdr(scn, &shdr) != NULL)
663
sysv_calc(elf, &elfhdr, &shdr);
664
}
665
}
666
if (style == STYLE_BERKELEY) {
667
if (arhdr != NULL) {
668
berkeley_footer(name, arhdr->ar_name,
669
"ex");
670
} else {
671
berkeley_footer(name, NULL, "ex");
672
}
673
} else {
674
sysv_footer();
675
}
676
}
677
elf_cmd = elf_next(elf);
678
(void) elf_end(elf);
679
}
680
(void) elf_end(elf1);
681
(void) close(fd);
682
return (RETURN_OK);
683
}
684
685
/*
686
* Sysv formatting helper functions.
687
*/
688
static void
689
sysv_header(const char *name, Elf_Arhdr *arhdr)
690
{
691
692
text_size_total = 0;
693
if (arhdr != NULL)
694
(void) printf("%s (ex %s):\n", arhdr->ar_name, name);
695
else
696
(void) printf("%s :\n", name);
697
tbl_new(3);
698
tbl_append();
699
tbl_print("section", 0);
700
tbl_print("size", 1);
701
tbl_print("addr", 2);
702
}
703
704
static void
705
sysv_calc(Elf *elf, GElf_Ehdr *elfhdr, GElf_Shdr *shdr)
706
{
707
char *section_name;
708
709
section_name = elf_strptr(elf, elfhdr->e_shstrndx,
710
(size_t) shdr->sh_name);
711
if ((shdr->sh_type == SHT_SYMTAB ||
712
shdr->sh_type == SHT_STRTAB || shdr->sh_type == SHT_RELA ||
713
shdr->sh_type == SHT_REL) && shdr->sh_addr == 0)
714
return;
715
tbl_append();
716
tbl_print(section_name, 0);
717
tbl_print_num(shdr->sh_size, radix, 1);
718
tbl_print_num(shdr->sh_addr, radix, 2);
719
text_size_total += shdr->sh_size;
720
}
721
722
static void
723
sysv_footer(void)
724
{
725
tbl_append();
726
tbl_print("Total", 0);
727
tbl_print_num(text_size_total, radix, 1);
728
tbl_flush();
729
putchar('\n');
730
}
731
732
/*
733
* berkeley style output formatting helper functions.
734
*/
735
static void
736
berkeley_header(void)
737
{
738
static int printed;
739
740
text_size = data_size = bss_size = 0;
741
if (!printed) {
742
tbl_new(6);
743
tbl_append();
744
tbl_print("text", 0);
745
tbl_print("data", 1);
746
tbl_print("bss", 2);
747
if (radix == RADIX_OCTAL)
748
tbl_print("oct", 3);
749
else
750
tbl_print("dec", 3);
751
tbl_print("hex", 4);
752
tbl_print("filename", 5);
753
printed = 1;
754
}
755
}
756
757
static void
758
berkeley_calc(GElf_Shdr *shdr)
759
{
760
if (shdr != NULL) {
761
if (!(shdr->sh_flags & SHF_ALLOC))
762
return;
763
if ((shdr->sh_flags & SHF_ALLOC) &&
764
((shdr->sh_flags & SHF_EXECINSTR) ||
765
!(shdr->sh_flags & SHF_WRITE)))
766
text_size += shdr->sh_size;
767
else if ((shdr->sh_flags & SHF_ALLOC) &&
768
(shdr->sh_flags & SHF_WRITE) &&
769
(shdr->sh_type != SHT_NOBITS))
770
data_size += shdr->sh_size;
771
else
772
bss_size += shdr->sh_size;
773
}
774
}
775
776
static void
777
berkeley_totals(void)
778
{
779
uint64_t grand_total;
780
781
grand_total = text_size_total + data_size_total + bss_size_total;
782
tbl_append();
783
tbl_print_num(text_size_total, radix, 0);
784
tbl_print_num(data_size_total, radix, 1);
785
tbl_print_num(bss_size_total, radix, 2);
786
if (radix == RADIX_OCTAL)
787
tbl_print_num(grand_total, RADIX_OCTAL, 3);
788
else
789
tbl_print_num(grand_total, RADIX_DECIMAL, 3);
790
tbl_print_num(grand_total, RADIX_HEX, 4);
791
}
792
793
static void
794
berkeley_footer(const char *name, const char *ar_name, const char *msg)
795
{
796
char buf[BUF_SIZE];
797
798
total_size = text_size + data_size + bss_size;
799
if (show_totals) {
800
text_size_total += text_size;
801
bss_size_total += bss_size;
802
data_size_total += data_size;
803
}
804
805
tbl_append();
806
tbl_print_num(text_size, radix, 0);
807
tbl_print_num(data_size, radix, 1);
808
tbl_print_num(bss_size, radix, 2);
809
if (radix == RADIX_OCTAL)
810
tbl_print_num(total_size, RADIX_OCTAL, 3);
811
else
812
tbl_print_num(total_size, RADIX_DECIMAL, 3);
813
tbl_print_num(total_size, RADIX_HEX, 4);
814
if (ar_name != NULL && name != NULL)
815
(void) snprintf(buf, BUF_SIZE, "%s (%s %s)", ar_name, msg,
816
name);
817
else if (ar_name != NULL && name == NULL)
818
(void) snprintf(buf, BUF_SIZE, "%s (%s)", ar_name, msg);
819
else
820
(void) snprintf(buf, BUF_SIZE, "%s", name);
821
tbl_print(buf, 5);
822
}
823
824
825
static void
826
tbl_new(int col)
827
{
828
829
assert(tb == NULL);
830
assert(col > 0);
831
if ((tb = calloc(1, sizeof(*tb))) == NULL)
832
err(EXIT_FAILURE, "calloc");
833
if ((tb->tbl = calloc(col, sizeof(*tb->tbl))) == NULL)
834
err(EXIT_FAILURE, "calloc");
835
if ((tb->width = calloc(col, sizeof(*tb->width))) == NULL)
836
err(EXIT_FAILURE, "calloc");
837
tb->col = col;
838
tb->row = 0;
839
}
840
841
static void
842
tbl_print(const char *s, int col)
843
{
844
int len;
845
846
assert(tb != NULL && tb->col > 0 && tb->row > 0 && col < tb->col);
847
assert(s != NULL && tb->tbl[col][tb->row - 1] == NULL);
848
if ((tb->tbl[col][tb->row - 1] = strdup(s)) == NULL)
849
err(EXIT_FAILURE, "strdup");
850
len = strlen(s);
851
if (len > tb->width[col])
852
tb->width[col] = len;
853
}
854
855
static void
856
tbl_print_num(uint64_t num, enum radix_style rad, int col)
857
{
858
char buf[BUF_SIZE];
859
860
(void) snprintf(buf, BUF_SIZE, (rad == RADIX_DECIMAL ? "%ju" :
861
((rad == RADIX_OCTAL) ? "0%jo" : "0x%jx")), (uintmax_t) num);
862
tbl_print(buf, col);
863
}
864
865
static void
866
tbl_append(void)
867
{
868
int i;
869
870
assert(tb != NULL && tb->col > 0);
871
tb->row++;
872
for (i = 0; i < tb->col; i++) {
873
tb->tbl[i] = realloc(tb->tbl[i], sizeof(*tb->tbl[i]) * tb->row);
874
if (tb->tbl[i] == NULL)
875
err(EXIT_FAILURE, "realloc");
876
tb->tbl[i][tb->row - 1] = NULL;
877
}
878
}
879
880
static void
881
tbl_flush(void)
882
{
883
const char *str;
884
int i, j;
885
886
if (tb == NULL)
887
return;
888
889
assert(tb->col > 0);
890
for (i = 0; i < tb->row; i++) {
891
if (style == STYLE_BERKELEY)
892
printf(" ");
893
for (j = 0; j < tb->col; j++) {
894
str = (tb->tbl[j][i] != NULL ? tb->tbl[j][i] : "");
895
if (style == STYLE_SYSV && j == 0)
896
printf("%-*s", tb->width[j], str);
897
else if (style == STYLE_BERKELEY && j == tb->col - 1)
898
printf("%s", str);
899
else
900
printf("%*s", tb->width[j], str);
901
if (j == tb->col -1)
902
putchar('\n');
903
else
904
printf(" ");
905
}
906
}
907
908
for (i = 0; i < tb->col; i++) {
909
for (j = 0; j < tb->row; j++) {
910
if (tb->tbl[i][j])
911
free(tb->tbl[i][j]);
912
}
913
free(tb->tbl[i]);
914
}
915
free(tb->tbl);
916
free(tb->width);
917
free(tb);
918
tb = NULL;
919
}
920
921
#define USAGE_MESSAGE "\
922
Usage: %s [options] file ...\n\
923
Display sizes of ELF sections.\n\n\
924
Options:\n\
925
--format=format Display output in specified format. Supported\n\
926
values are `berkeley' and `sysv'.\n\
927
--help Display this help message and exit.\n\
928
--radix=radix Display numeric values in the specified radix.\n\
929
Supported values are: 8, 10 and 16.\n\
930
--totals Show cumulative totals of section sizes.\n\
931
--version Display a version identifier and exit.\n\
932
-A Equivalent to `--format=sysv'.\n\
933
-B Equivalent to `--format=berkeley'.\n\
934
-V Equivalent to `--version'.\n\
935
-d Equivalent to `--radix=10'.\n\
936
-h Same as option --help.\n\
937
-o Equivalent to `--radix=8'.\n\
938
-t Equivalent to option --totals.\n\
939
-x Equivalent to `--radix=16'.\n"
940
941
static void
942
usage(void)
943
{
944
(void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME());
945
exit(EXIT_FAILURE);
946
}
947
948
static void
949
show_version(void)
950
{
951
(void) printf("%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version());
952
exit(EXIT_SUCCESS);
953
}
954
955