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