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