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> 28*10334649SMark 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 40*10334649SMark Johnston #include <libcasper.h> 41*10334649SMark Johnston #include <casper/cap_fileargs.h> 42*10334649SMark 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 **); 102*10334649SMark 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 122a85fe12eSEd Maste main(int argc, char **argv) 123a85fe12eSEd Maste { 124*10334649SMark Johnston cap_rights_t rights; 125*10334649SMark Johnston fileargs_t *fa; 126*10334649SMark Johnston int ch, fd, r, rc; 127*10334649SMark Johnston const char *fn; 128*10334649SMark 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 201*10334649SMark Johnston if (argc == 0) { 202*10334649SMark Johnston defaultfn = strdup("a.out"); 203*10334649SMark Johnston if (defaultfn == NULL) 204*10334649SMark Johnston err(EXIT_FAILURE, "strdup"); 205*10334649SMark Johnston argc = 1; 206*10334649SMark Johnston argv = &defaultfn; 207*10334649SMark Johnston } else { 208*10334649SMark Johnston defaultfn = NULL; 209*10334649SMark Johnston } 210a85fe12eSEd Maste 211*10334649SMark Johnston cap_rights_init(&rights, CAP_FSTAT, CAP_MMAP_R); 212*10334649SMark Johnston fa = fileargs_init(argc, argv, O_RDONLY, 0, &rights, FA_OPEN); 213*10334649SMark Johnston if (fa == NULL) 214*10334649SMark Johnston err(EXIT_FAILURE, "failed to initialize fileargs"); 215*10334649SMark Johnston 216*10334649SMark Johnston caph_cache_catpages(); 217*10334649SMark Johnston if (caph_limit_stdio() < 0) 218*10334649SMark Johnston err(EXIT_FAILURE, "failed to limit stdio rights"); 219*10334649SMark Johnston if (caph_enter_casper() < 0) 220*10334649SMark Johnston err(EXIT_FAILURE, "failed to enter capability mode"); 221*10334649SMark Johnston 222*10334649SMark Johnston for (; argc > 0; argc--, argv++) { 223*10334649SMark Johnston fn = argv[0]; 224*10334649SMark Johnston fd = fileargs_open(fa, fn); 225*10334649SMark Johnston if (fd < 0) { 226*10334649SMark Johnston warn("%s: Failed to open", fn); 227*10334649SMark Johnston continue; 228*10334649SMark Johnston } 229*10334649SMark Johnston rc = handle_elf(fd, fn); 230a85fe12eSEd Maste if (rc != RETURN_OK) 231*10334649SMark 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 } 238*10334649SMark Johnston fileargs_free(fa); 239*10334649SMark Johnston free(defaultfn); 240a85fe12eSEd Maste return (rc); 241a85fe12eSEd Maste } 242a85fe12eSEd Maste 243a85fe12eSEd Maste static Elf_Data * 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; 256a85fe12eSEd Maste return (gelf_xlatetom(elf, &dst, &src, elfhdr->e_ident[EI_DATA])); 257a85fe12eSEd Maste } 258a85fe12eSEd Maste 259a85fe12eSEd Maste #define NOTE_OFFSET_32(nhdr, namesz, offset) \ 260a85fe12eSEd Maste ((char *)nhdr + sizeof(Elf32_Nhdr) + \ 261a85fe12eSEd Maste ELF_ALIGN((int32_t)namesz, 4) + offset) 262a85fe12eSEd Maste 263a85fe12eSEd Maste #define NOTE_OFFSET_64(nhdr, namesz, offset) \ 264a85fe12eSEd Maste ((char *)nhdr + sizeof(Elf32_Nhdr) + \ 265a85fe12eSEd Maste ELF_ALIGN((int32_t)namesz, 8) + offset) 266a85fe12eSEd Maste 267a85fe12eSEd Maste #define PID32(nhdr, namesz, offset) \ 268a85fe12eSEd Maste (pid_t)*((int *)((uintptr_t)NOTE_OFFSET_32(nhdr, \ 269a85fe12eSEd Maste namesz, offset))); 270a85fe12eSEd Maste 271a85fe12eSEd Maste #define PID64(nhdr, namesz, offset) \ 272a85fe12eSEd Maste (pid_t)*((int *)((uintptr_t)NOTE_OFFSET_64(nhdr, \ 273a85fe12eSEd Maste namesz, offset))); 274a85fe12eSEd Maste 275a85fe12eSEd Maste #define NEXT_NOTE(elfhdr, descsz, namesz, offset) do { \ 276a85fe12eSEd Maste if (elfhdr->e_ident[EI_CLASS] == ELFCLASS32) { \ 277a85fe12eSEd Maste offset += ELF_ALIGN((int32_t)descsz, 4) + \ 278a85fe12eSEd Maste sizeof(Elf32_Nhdr) + \ 279a85fe12eSEd Maste ELF_ALIGN((int32_t)namesz, 4); \ 280a85fe12eSEd Maste } else { \ 281a85fe12eSEd Maste offset += ELF_ALIGN((int32_t)descsz, 8) + \ 282a85fe12eSEd Maste sizeof(Elf32_Nhdr) + \ 283a85fe12eSEd Maste ELF_ALIGN((int32_t)namesz, 8); \ 284a85fe12eSEd Maste } \ 285a85fe12eSEd Maste } while (0) 286a85fe12eSEd Maste 287a85fe12eSEd Maste /* 288a85fe12eSEd Maste * Parse individual note entries inside a PT_NOTE segment. 289a85fe12eSEd Maste */ 290a85fe12eSEd Maste static void 291a85fe12eSEd Maste handle_core_note(Elf *elf, GElf_Ehdr *elfhdr, GElf_Phdr *phdr, 292a85fe12eSEd Maste char **cmd_line) 293a85fe12eSEd Maste { 294b6b6f9ccSEd Maste size_t max_size, segment_end; 295a85fe12eSEd Maste uint64_t raw_size; 296a85fe12eSEd Maste GElf_Off offset; 297a85fe12eSEd Maste static pid_t pid; 298a85fe12eSEd Maste uintptr_t ver; 299a85fe12eSEd Maste Elf32_Nhdr *nhdr, nhdr_l; 300310b1572SEd Maste static int reg_pseudo = 0, reg2_pseudo = 0 /*, regxfp_pseudo = 0*/; 301a85fe12eSEd Maste char buf[BUF_SIZE], *data, *name; 302a85fe12eSEd Maste 303a85fe12eSEd Maste if (elf == NULL || elfhdr == NULL || phdr == NULL) 304a85fe12eSEd Maste return; 305a85fe12eSEd Maste 306a85fe12eSEd Maste data = elf_rawfile(elf, &max_size); 307a85fe12eSEd Maste offset = phdr->p_offset; 308b6b6f9ccSEd Maste if (offset >= max_size || phdr->p_filesz > max_size - offset) { 309b6b6f9ccSEd Maste warnx("invalid PHDR offset"); 310b6b6f9ccSEd Maste return; 311b6b6f9ccSEd Maste } 312b6b6f9ccSEd Maste segment_end = phdr->p_offset + phdr->p_filesz; 313b6b6f9ccSEd Maste 314b6b6f9ccSEd Maste while (data != NULL && offset + sizeof(Elf32_Nhdr) < segment_end) { 315a85fe12eSEd Maste nhdr = (Elf32_Nhdr *)(uintptr_t)((char*)data + offset); 316a85fe12eSEd Maste memset(&nhdr_l, 0, sizeof(Elf32_Nhdr)); 317a85fe12eSEd Maste if (!xlatetom(elf, elfhdr, &nhdr->n_type, &nhdr_l.n_type, 318a85fe12eSEd Maste ELF_T_WORD, sizeof(Elf32_Word)) || 319a85fe12eSEd Maste !xlatetom(elf, elfhdr, &nhdr->n_descsz, &nhdr_l.n_descsz, 320a85fe12eSEd Maste ELF_T_WORD, sizeof(Elf32_Word)) || 321a85fe12eSEd Maste !xlatetom(elf, elfhdr, &nhdr->n_namesz, &nhdr_l.n_namesz, 322a85fe12eSEd Maste ELF_T_WORD, sizeof(Elf32_Word))) 323a85fe12eSEd Maste break; 324a85fe12eSEd Maste 325b6b6f9ccSEd Maste if (offset + sizeof(Elf32_Nhdr) + 326b6b6f9ccSEd Maste ELF_ALIGN(nhdr_l.n_namesz, 4) + 327b6b6f9ccSEd Maste ELF_ALIGN(nhdr_l.n_descsz, 4) >= segment_end) { 328b6b6f9ccSEd Maste warnx("invalid note header"); 329b6b6f9ccSEd Maste return; 330b6b6f9ccSEd Maste } 331b6b6f9ccSEd Maste 332a85fe12eSEd Maste name = (char *)((char *)nhdr + sizeof(Elf32_Nhdr)); 333a85fe12eSEd Maste switch (nhdr_l.n_type) { 334a85fe12eSEd Maste case NT_PRSTATUS: { 335a85fe12eSEd Maste raw_size = 0; 336a85fe12eSEd Maste if (elfhdr->e_ident[EI_OSABI] == ELFOSABI_FREEBSD && 337a85fe12eSEd Maste nhdr_l.n_namesz == 0x8 && 338a85fe12eSEd Maste !strcmp(name,"FreeBSD")) { 339a85fe12eSEd Maste if (elfhdr->e_ident[EI_CLASS] == ELFCLASS32) { 340a85fe12eSEd Maste raw_size = (uint64_t)*((uint32_t *) 341a85fe12eSEd Maste (uintptr_t)(name + 342a85fe12eSEd Maste ELF_ALIGN((int32_t) 343a85fe12eSEd Maste nhdr_l.n_namesz, 4) + 8)); 344a85fe12eSEd Maste ver = (uintptr_t)NOTE_OFFSET_32(nhdr, 345a85fe12eSEd Maste nhdr_l.n_namesz,0); 346a85fe12eSEd Maste if (*((int *)ver) == 1) 347a85fe12eSEd Maste pid = PID32(nhdr, 348a85fe12eSEd Maste nhdr_l.n_namesz, 24); 349a85fe12eSEd Maste } else { 350a85fe12eSEd Maste raw_size = *((uint64_t *)(uintptr_t) 351a85fe12eSEd Maste (name + ELF_ALIGN((int32_t) 352a85fe12eSEd Maste nhdr_l.n_namesz, 8) + 16)); 353a85fe12eSEd Maste ver = (uintptr_t)NOTE_OFFSET_64(nhdr, 354a85fe12eSEd Maste nhdr_l.n_namesz,0); 355a85fe12eSEd Maste if (*((int *)ver) == 1) 356a85fe12eSEd Maste pid = PID64(nhdr, 357a85fe12eSEd Maste nhdr_l.n_namesz, 40); 358a85fe12eSEd Maste } 359a85fe12eSEd Maste xlatetom(elf, elfhdr, &raw_size, &raw_size, 360a85fe12eSEd Maste ELF_T_WORD, sizeof(uint64_t)); 361a85fe12eSEd Maste xlatetom(elf, elfhdr, &pid, &pid, ELF_T_WORD, 362a85fe12eSEd Maste sizeof(pid_t)); 363a85fe12eSEd Maste } 364a85fe12eSEd Maste 365a85fe12eSEd Maste if (raw_size != 0 && style == STYLE_SYSV) { 366a85fe12eSEd Maste (void) snprintf(buf, BUF_SIZE, "%s/%d", 367a85fe12eSEd Maste ".reg", pid); 368a85fe12eSEd Maste tbl_append(); 369a85fe12eSEd Maste tbl_print(buf, 0); 370a85fe12eSEd Maste tbl_print_num(raw_size, radix, 1); 371a85fe12eSEd Maste tbl_print_num(0, radix, 2); 372a85fe12eSEd Maste if (!reg_pseudo) { 373a85fe12eSEd Maste tbl_append(); 374a85fe12eSEd Maste tbl_print(".reg", 0); 375a85fe12eSEd Maste tbl_print_num(raw_size, radix, 1); 376a85fe12eSEd Maste tbl_print_num(0, radix, 2); 377a85fe12eSEd Maste reg_pseudo = 1; 378a85fe12eSEd Maste text_size_total += raw_size; 379a85fe12eSEd Maste } 380a85fe12eSEd Maste text_size_total += raw_size; 381a85fe12eSEd Maste } 382a85fe12eSEd Maste } 383a85fe12eSEd Maste break; 384a85fe12eSEd Maste case NT_FPREGSET: /* same as NT_PRFPREG */ 385a85fe12eSEd Maste if (style == STYLE_SYSV) { 386a85fe12eSEd Maste (void) snprintf(buf, BUF_SIZE, 387a85fe12eSEd Maste "%s/%d", ".reg2", pid); 388a85fe12eSEd Maste tbl_append(); 389a85fe12eSEd Maste tbl_print(buf, 0); 390a85fe12eSEd Maste tbl_print_num(nhdr_l.n_descsz, radix, 1); 391a85fe12eSEd Maste tbl_print_num(0, radix, 2); 392a85fe12eSEd Maste if (!reg2_pseudo) { 393a85fe12eSEd Maste tbl_append(); 394a85fe12eSEd Maste tbl_print(".reg2", 0); 395a85fe12eSEd Maste tbl_print_num(nhdr_l.n_descsz, radix, 396a85fe12eSEd Maste 1); 397a85fe12eSEd Maste tbl_print_num(0, radix, 2); 398a85fe12eSEd Maste reg2_pseudo = 1; 399a85fe12eSEd Maste text_size_total += nhdr_l.n_descsz; 400a85fe12eSEd Maste } 401a85fe12eSEd Maste text_size_total += nhdr_l.n_descsz; 402a85fe12eSEd Maste } 403a85fe12eSEd Maste break; 404310b1572SEd Maste #if 0 405a85fe12eSEd Maste case NT_AUXV: 406a85fe12eSEd Maste if (style == STYLE_SYSV) { 407a85fe12eSEd Maste tbl_append(); 408a85fe12eSEd Maste tbl_print(".auxv", 0); 409a85fe12eSEd Maste tbl_print_num(nhdr_l.n_descsz, radix, 1); 410a85fe12eSEd Maste tbl_print_num(0, radix, 2); 411a85fe12eSEd Maste text_size_total += nhdr_l.n_descsz; 412a85fe12eSEd Maste } 413a85fe12eSEd Maste break; 414a85fe12eSEd Maste case NT_PRXFPREG: 415a85fe12eSEd Maste if (style == STYLE_SYSV) { 416a85fe12eSEd Maste (void) snprintf(buf, BUF_SIZE, "%s/%d", 417a85fe12eSEd Maste ".reg-xfp", pid); 418a85fe12eSEd Maste tbl_append(); 419a85fe12eSEd Maste tbl_print(buf, 0); 420a85fe12eSEd Maste tbl_print_num(nhdr_l.n_descsz, radix, 1); 421a85fe12eSEd Maste tbl_print_num(0, radix, 2); 422a85fe12eSEd Maste if (!regxfp_pseudo) { 423a85fe12eSEd Maste tbl_append(); 424a85fe12eSEd Maste tbl_print(".reg-xfp", 0); 425a85fe12eSEd Maste tbl_print_num(nhdr_l.n_descsz, radix, 426a85fe12eSEd Maste 1); 427a85fe12eSEd Maste tbl_print_num(0, radix, 2); 428a85fe12eSEd Maste regxfp_pseudo = 1; 429a85fe12eSEd Maste text_size_total += nhdr_l.n_descsz; 430a85fe12eSEd Maste } 431a85fe12eSEd Maste text_size_total += nhdr_l.n_descsz; 432a85fe12eSEd Maste } 433a85fe12eSEd Maste break; 434a85fe12eSEd Maste case NT_PSINFO: 435310b1572SEd Maste #endif 436a85fe12eSEd Maste case NT_PRPSINFO: { 437a85fe12eSEd Maste /* FreeBSD 64-bit */ 438a85fe12eSEd Maste if (nhdr_l.n_descsz == 0x78 && 439a85fe12eSEd Maste !strcmp(name,"FreeBSD")) { 440a85fe12eSEd Maste *cmd_line = strdup(NOTE_OFFSET_64(nhdr, 441a85fe12eSEd Maste nhdr_l.n_namesz, 33)); 442a85fe12eSEd Maste /* FreeBSD 32-bit */ 443a85fe12eSEd Maste } else if (nhdr_l.n_descsz == 0x6c && 444a85fe12eSEd Maste !strcmp(name,"FreeBSD")) { 445a85fe12eSEd Maste *cmd_line = strdup(NOTE_OFFSET_32(nhdr, 446a85fe12eSEd Maste nhdr_l.n_namesz, 25)); 447a85fe12eSEd Maste } 448a85fe12eSEd Maste /* Strip any trailing spaces */ 449a85fe12eSEd Maste if (*cmd_line != NULL) { 450a85fe12eSEd Maste char *s; 451a85fe12eSEd Maste 452a85fe12eSEd Maste s = *cmd_line + strlen(*cmd_line); 453a85fe12eSEd Maste while (s > *cmd_line) { 454a85fe12eSEd Maste if (*(s-1) != 0x20) break; 455a85fe12eSEd Maste s--; 456a85fe12eSEd Maste } 457a85fe12eSEd Maste *s = 0; 458a85fe12eSEd Maste } 459a85fe12eSEd Maste break; 460a85fe12eSEd Maste } 461310b1572SEd Maste #if 0 462a85fe12eSEd Maste case NT_PSTATUS: 463a85fe12eSEd Maste case NT_LWPSTATUS: 464310b1572SEd Maste #endif 465a85fe12eSEd Maste default: 466a85fe12eSEd Maste break; 467a85fe12eSEd Maste } 468a85fe12eSEd Maste NEXT_NOTE(elfhdr, nhdr_l.n_descsz, nhdr_l.n_namesz, offset); 469a85fe12eSEd Maste } 470a85fe12eSEd Maste } 471a85fe12eSEd Maste 472a85fe12eSEd Maste /* 473b6b6f9ccSEd Maste * Handles program headers except for PT_NOTE, when sysv output style is 474b6b6f9ccSEd Maste * chosen, prints out the segment name and length. For berkely output 475a85fe12eSEd Maste * style only PT_LOAD segments are handled, and text, 476a85fe12eSEd Maste * data, bss size is calculated for them. 477a85fe12eSEd Maste */ 478a85fe12eSEd Maste static void 479a85fe12eSEd Maste handle_phdr(Elf *elf, GElf_Ehdr *elfhdr, GElf_Phdr *phdr, 480a85fe12eSEd Maste uint32_t idx, const char *name) 481a85fe12eSEd Maste { 482a85fe12eSEd Maste uint64_t addr, size; 483a85fe12eSEd Maste int split; 484a85fe12eSEd Maste char buf[BUF_SIZE]; 485a85fe12eSEd Maste 486a85fe12eSEd Maste if (elf == NULL || elfhdr == NULL || phdr == NULL) 487a85fe12eSEd Maste return; 488a85fe12eSEd Maste 489a85fe12eSEd Maste split = (phdr->p_memsz > 0) && (phdr->p_filesz > 0) && 490a85fe12eSEd Maste (phdr->p_memsz > phdr->p_filesz); 491a85fe12eSEd Maste 492a85fe12eSEd Maste if (style == STYLE_SYSV) { 493a85fe12eSEd Maste (void) snprintf(buf, BUF_SIZE, 494a85fe12eSEd Maste "%s%d%s", name, idx, (split ? "a" : "")); 495a85fe12eSEd Maste tbl_append(); 496a85fe12eSEd Maste tbl_print(buf, 0); 497a85fe12eSEd Maste tbl_print_num(phdr->p_filesz, radix, 1); 498a85fe12eSEd Maste tbl_print_num(phdr->p_vaddr, radix, 2); 499a85fe12eSEd Maste text_size_total += phdr->p_filesz; 500a85fe12eSEd Maste if (split) { 501a85fe12eSEd Maste size = phdr->p_memsz - phdr->p_filesz; 502a85fe12eSEd Maste addr = phdr->p_vaddr + phdr->p_filesz; 503a85fe12eSEd Maste (void) snprintf(buf, BUF_SIZE, "%s%d%s", name, 504a85fe12eSEd Maste idx, "b"); 505a85fe12eSEd Maste text_size_total += phdr->p_memsz - phdr->p_filesz; 506a85fe12eSEd Maste tbl_append(); 507a85fe12eSEd Maste tbl_print(buf, 0); 508a85fe12eSEd Maste tbl_print_num(size, radix, 1); 509a85fe12eSEd Maste tbl_print_num(addr, radix, 2); 510a85fe12eSEd Maste } 511a85fe12eSEd Maste } else { 512a85fe12eSEd Maste if (phdr->p_type != PT_LOAD) 513a85fe12eSEd Maste return; 514a85fe12eSEd Maste if ((phdr->p_flags & PF_W) && !(phdr->p_flags & PF_X)) { 515a85fe12eSEd Maste data_size += phdr->p_filesz; 516a85fe12eSEd Maste if (split) 517a85fe12eSEd Maste data_size += phdr->p_memsz - phdr->p_filesz; 518a85fe12eSEd Maste } else { 519a85fe12eSEd Maste text_size += phdr->p_filesz; 520a85fe12eSEd Maste if (split) 521a85fe12eSEd Maste text_size += phdr->p_memsz - phdr->p_filesz; 522a85fe12eSEd Maste } 523a85fe12eSEd Maste } 524a85fe12eSEd Maste } 525a85fe12eSEd Maste 526a85fe12eSEd Maste /* 527a85fe12eSEd Maste * Given a core dump file, this function maps program headers to segments. 528a85fe12eSEd Maste */ 529a85fe12eSEd Maste static int 530a85fe12eSEd Maste handle_core(char const *name, Elf *elf, GElf_Ehdr *elfhdr) 531a85fe12eSEd Maste { 532a85fe12eSEd Maste GElf_Phdr phdr; 533a85fe12eSEd Maste uint32_t i; 534a85fe12eSEd Maste char *core_cmdline; 535a85fe12eSEd Maste const char *seg_name; 536a85fe12eSEd Maste 537a85fe12eSEd Maste if (name == NULL || elf == NULL || elfhdr == NULL) 538a85fe12eSEd Maste return (RETURN_DATAERR); 539a85fe12eSEd Maste if (elfhdr->e_shnum != 0 || elfhdr->e_type != ET_CORE) 540a85fe12eSEd Maste return (RETURN_DATAERR); 541a85fe12eSEd Maste 542a85fe12eSEd Maste seg_name = core_cmdline = NULL; 543a85fe12eSEd Maste if (style == STYLE_SYSV) 544a85fe12eSEd Maste sysv_header(name, NULL); 545a85fe12eSEd Maste else 546a85fe12eSEd Maste berkeley_header(); 547a85fe12eSEd Maste 548a85fe12eSEd Maste for (i = 0; i < elfhdr->e_phnum; i++) { 549a85fe12eSEd Maste if (gelf_getphdr(elf, i, &phdr) != NULL) { 550a85fe12eSEd Maste if (phdr.p_type == PT_NOTE) { 551a85fe12eSEd Maste handle_phdr(elf, elfhdr, &phdr, i, "note"); 552a85fe12eSEd Maste handle_core_note(elf, elfhdr, &phdr, 553a85fe12eSEd Maste &core_cmdline); 554a85fe12eSEd Maste } else { 555a85fe12eSEd Maste switch(phdr.p_type) { 556a85fe12eSEd Maste case PT_NULL: 557a85fe12eSEd Maste seg_name = "null"; 558a85fe12eSEd Maste break; 559a85fe12eSEd Maste case PT_LOAD: 560a85fe12eSEd Maste seg_name = "load"; 561a85fe12eSEd Maste break; 562a85fe12eSEd Maste case PT_DYNAMIC: 563a85fe12eSEd Maste seg_name = "dynamic"; 564a85fe12eSEd Maste break; 565a85fe12eSEd Maste case PT_INTERP: 566a85fe12eSEd Maste seg_name = "interp"; 567a85fe12eSEd Maste break; 568a85fe12eSEd Maste case PT_SHLIB: 569a85fe12eSEd Maste seg_name = "shlib"; 570a85fe12eSEd Maste break; 571a85fe12eSEd Maste case PT_PHDR: 572a85fe12eSEd Maste seg_name = "phdr"; 573a85fe12eSEd Maste break; 574a85fe12eSEd Maste case PT_GNU_EH_FRAME: 575a85fe12eSEd Maste seg_name = "eh_frame_hdr"; 576a85fe12eSEd Maste break; 577a85fe12eSEd Maste case PT_GNU_STACK: 578a85fe12eSEd Maste seg_name = "stack"; 579a85fe12eSEd Maste break; 580a85fe12eSEd Maste default: 581a85fe12eSEd Maste seg_name = "segment"; 582a85fe12eSEd Maste } 583a85fe12eSEd Maste handle_phdr(elf, elfhdr, &phdr, i, seg_name); 584a85fe12eSEd Maste } 585a85fe12eSEd Maste } 586a85fe12eSEd Maste } 587a85fe12eSEd Maste 588a85fe12eSEd Maste if (style == STYLE_BERKELEY) { 589a85fe12eSEd Maste if (core_cmdline != NULL) { 590a85fe12eSEd Maste berkeley_footer(core_cmdline, name, 591a85fe12eSEd Maste "core file invoked as"); 592a85fe12eSEd Maste } else { 593a85fe12eSEd Maste berkeley_footer(core_cmdline, name, "core file"); 594a85fe12eSEd Maste } 595a85fe12eSEd Maste } else { 596a85fe12eSEd Maste sysv_footer(); 597a85fe12eSEd Maste if (core_cmdline != NULL) { 598a85fe12eSEd Maste (void) printf(" (core file invoked as %s)\n\n", 599a85fe12eSEd Maste core_cmdline); 600a85fe12eSEd Maste } else { 601a85fe12eSEd Maste (void) printf(" (core file)\n\n"); 602a85fe12eSEd Maste } 603a85fe12eSEd Maste } 604a85fe12eSEd Maste free(core_cmdline); 605a85fe12eSEd Maste return (RETURN_OK); 606a85fe12eSEd Maste } 607a85fe12eSEd Maste 608a85fe12eSEd Maste /* 609a85fe12eSEd Maste * Given an elf object,ar(1) filename, and based on the output style 610a85fe12eSEd Maste * and radix format the various sections and their length will be printed 611a85fe12eSEd Maste * or the size of the text, data, bss sections will be printed out. 612a85fe12eSEd Maste */ 613a85fe12eSEd Maste static int 614*10334649SMark Johnston handle_elf(int fd, const char *name) 615a85fe12eSEd Maste { 616a85fe12eSEd Maste GElf_Ehdr elfhdr; 617a85fe12eSEd Maste GElf_Shdr shdr; 618a85fe12eSEd Maste Elf *elf, *elf1; 619a85fe12eSEd Maste Elf_Arhdr *arhdr; 620a85fe12eSEd Maste Elf_Scn *scn; 621a85fe12eSEd Maste Elf_Cmd elf_cmd; 622*10334649SMark Johnston int exit_code; 623a85fe12eSEd Maste 624a85fe12eSEd Maste elf_cmd = ELF_C_READ; 625a85fe12eSEd Maste elf1 = elf_begin(fd, elf_cmd, NULL); 626a85fe12eSEd Maste while ((elf = elf_begin(fd, elf_cmd, elf1)) != NULL) { 627a85fe12eSEd Maste arhdr = elf_getarhdr(elf); 628a85fe12eSEd Maste if (elf_kind(elf) == ELF_K_NONE && arhdr == NULL) { 629a85fe12eSEd Maste (void) elf_end(elf); 630a85fe12eSEd Maste (void) elf_end(elf1); 631a85fe12eSEd Maste (void) close(fd); 632a85fe12eSEd Maste return (RETURN_DATAERR); 633a85fe12eSEd Maste } 634a85fe12eSEd Maste if (elf_kind(elf) != ELF_K_ELF || 635a85fe12eSEd Maste (gelf_getehdr(elf, &elfhdr) == NULL)) { 636a85fe12eSEd Maste elf_cmd = elf_next(elf); 637a85fe12eSEd Maste (void) elf_end(elf); 638a85fe12eSEd Maste warnx("%s: File format not recognized", 639b6b6f9ccSEd Maste arhdr != NULL ? arhdr->ar_name : name); 640a85fe12eSEd Maste continue; 641a85fe12eSEd Maste } 642b00fe64fSEd Maste /* Core dumps are handled separately */ 643a85fe12eSEd Maste if (elfhdr.e_shnum == 0 && elfhdr.e_type == ET_CORE) { 644a85fe12eSEd Maste exit_code = handle_core(name, elf, &elfhdr); 645a85fe12eSEd Maste (void) elf_end(elf); 646a85fe12eSEd Maste (void) elf_end(elf1); 647a85fe12eSEd Maste (void) close(fd); 648a85fe12eSEd Maste return (exit_code); 649a85fe12eSEd Maste } else { 650a85fe12eSEd Maste scn = NULL; 651a85fe12eSEd Maste if (style == STYLE_BERKELEY) { 652a85fe12eSEd Maste berkeley_header(); 653a85fe12eSEd Maste while ((scn = elf_nextscn(elf, scn)) != NULL) { 654a85fe12eSEd Maste if (gelf_getshdr(scn, &shdr) != NULL) 655a85fe12eSEd Maste berkeley_calc(&shdr); 656a85fe12eSEd Maste } 657a85fe12eSEd Maste } else { 658a85fe12eSEd Maste sysv_header(name, arhdr); 659a85fe12eSEd Maste scn = NULL; 660a85fe12eSEd Maste while ((scn = elf_nextscn(elf, scn)) != NULL) { 661a85fe12eSEd Maste if (gelf_getshdr(scn, &shdr) != NULL) 662a85fe12eSEd Maste sysv_calc(elf, &elfhdr, &shdr); 663a85fe12eSEd Maste } 664a85fe12eSEd Maste } 665a85fe12eSEd Maste if (style == STYLE_BERKELEY) { 666a85fe12eSEd Maste if (arhdr != NULL) { 667a85fe12eSEd Maste berkeley_footer(name, arhdr->ar_name, 668a85fe12eSEd Maste "ex"); 669a85fe12eSEd Maste } else { 670a85fe12eSEd Maste berkeley_footer(name, NULL, "ex"); 671a85fe12eSEd Maste } 672a85fe12eSEd Maste } else { 673a85fe12eSEd Maste sysv_footer(); 674a85fe12eSEd Maste } 675a85fe12eSEd Maste } 676a85fe12eSEd Maste elf_cmd = elf_next(elf); 677a85fe12eSEd Maste (void) elf_end(elf); 678a85fe12eSEd Maste } 679a85fe12eSEd Maste (void) elf_end(elf1); 680a85fe12eSEd Maste (void) close(fd); 681a85fe12eSEd Maste return (RETURN_OK); 682a85fe12eSEd Maste } 683a85fe12eSEd Maste 684a85fe12eSEd Maste /* 685a85fe12eSEd Maste * Sysv formatting helper functions. 686a85fe12eSEd Maste */ 687a85fe12eSEd Maste static void 688a85fe12eSEd Maste sysv_header(const char *name, Elf_Arhdr *arhdr) 689a85fe12eSEd Maste { 690a85fe12eSEd Maste 691a85fe12eSEd Maste text_size_total = 0; 692a85fe12eSEd Maste if (arhdr != NULL) 693a85fe12eSEd Maste (void) printf("%s (ex %s):\n", arhdr->ar_name, name); 694a85fe12eSEd Maste else 695a85fe12eSEd Maste (void) printf("%s :\n", name); 696a85fe12eSEd Maste tbl_new(3); 697a85fe12eSEd Maste tbl_append(); 698a85fe12eSEd Maste tbl_print("section", 0); 699a85fe12eSEd Maste tbl_print("size", 1); 700a85fe12eSEd Maste tbl_print("addr", 2); 701a85fe12eSEd Maste } 702a85fe12eSEd Maste 703a85fe12eSEd Maste static void 704a85fe12eSEd Maste sysv_calc(Elf *elf, GElf_Ehdr *elfhdr, GElf_Shdr *shdr) 705a85fe12eSEd Maste { 706a85fe12eSEd Maste char *section_name; 707a85fe12eSEd Maste 708a85fe12eSEd Maste section_name = elf_strptr(elf, elfhdr->e_shstrndx, 709a85fe12eSEd Maste (size_t) shdr->sh_name); 710a85fe12eSEd Maste if ((shdr->sh_type == SHT_SYMTAB || 711a85fe12eSEd Maste shdr->sh_type == SHT_STRTAB || shdr->sh_type == SHT_RELA || 712a85fe12eSEd Maste shdr->sh_type == SHT_REL) && shdr->sh_addr == 0) 713a85fe12eSEd Maste return; 714a85fe12eSEd Maste tbl_append(); 715a85fe12eSEd Maste tbl_print(section_name, 0); 716a85fe12eSEd Maste tbl_print_num(shdr->sh_size, radix, 1); 717a85fe12eSEd Maste tbl_print_num(shdr->sh_addr, radix, 2); 718a85fe12eSEd Maste text_size_total += shdr->sh_size; 719a85fe12eSEd Maste } 720a85fe12eSEd Maste 721a85fe12eSEd Maste static void 722a85fe12eSEd Maste sysv_footer(void) 723a85fe12eSEd Maste { 724a85fe12eSEd Maste tbl_append(); 725a85fe12eSEd Maste tbl_print("Total", 0); 726a85fe12eSEd Maste tbl_print_num(text_size_total, radix, 1); 727a85fe12eSEd Maste tbl_flush(); 728a85fe12eSEd Maste putchar('\n'); 729a85fe12eSEd Maste } 730a85fe12eSEd Maste 731a85fe12eSEd Maste /* 732a85fe12eSEd Maste * berkeley style output formatting helper functions. 733a85fe12eSEd Maste */ 734a85fe12eSEd Maste static void 735a85fe12eSEd Maste berkeley_header(void) 736a85fe12eSEd Maste { 737a85fe12eSEd Maste static int printed; 738a85fe12eSEd Maste 739a85fe12eSEd Maste text_size = data_size = bss_size = 0; 740a85fe12eSEd Maste if (!printed) { 741a85fe12eSEd Maste tbl_new(6); 742a85fe12eSEd Maste tbl_append(); 743a85fe12eSEd Maste tbl_print("text", 0); 744a85fe12eSEd Maste tbl_print("data", 1); 745a85fe12eSEd Maste tbl_print("bss", 2); 746a85fe12eSEd Maste if (radix == RADIX_OCTAL) 747a85fe12eSEd Maste tbl_print("oct", 3); 748a85fe12eSEd Maste else 749a85fe12eSEd Maste tbl_print("dec", 3); 750a85fe12eSEd Maste tbl_print("hex", 4); 751a85fe12eSEd Maste tbl_print("filename", 5); 752a85fe12eSEd Maste printed = 1; 753a85fe12eSEd Maste } 754a85fe12eSEd Maste } 755a85fe12eSEd Maste 756a85fe12eSEd Maste static void 757a85fe12eSEd Maste berkeley_calc(GElf_Shdr *shdr) 758a85fe12eSEd Maste { 759a85fe12eSEd Maste if (shdr != NULL) { 760a85fe12eSEd Maste if (!(shdr->sh_flags & SHF_ALLOC)) 761a85fe12eSEd Maste return; 762a85fe12eSEd Maste if ((shdr->sh_flags & SHF_ALLOC) && 763a85fe12eSEd Maste ((shdr->sh_flags & SHF_EXECINSTR) || 764a85fe12eSEd Maste !(shdr->sh_flags & SHF_WRITE))) 765a85fe12eSEd Maste text_size += shdr->sh_size; 766a85fe12eSEd Maste else if ((shdr->sh_flags & SHF_ALLOC) && 767a85fe12eSEd Maste (shdr->sh_flags & SHF_WRITE) && 768a85fe12eSEd Maste (shdr->sh_type != SHT_NOBITS)) 769a85fe12eSEd Maste data_size += shdr->sh_size; 770a85fe12eSEd Maste else 771a85fe12eSEd Maste bss_size += shdr->sh_size; 772a85fe12eSEd Maste } 773a85fe12eSEd Maste } 774a85fe12eSEd Maste 775a85fe12eSEd Maste static void 776a85fe12eSEd Maste berkeley_totals(void) 777a85fe12eSEd Maste { 778b6b6f9ccSEd Maste uint64_t grand_total; 779a85fe12eSEd Maste 780a85fe12eSEd Maste grand_total = text_size_total + data_size_total + bss_size_total; 781a85fe12eSEd Maste tbl_append(); 782a85fe12eSEd Maste tbl_print_num(text_size_total, radix, 0); 783a85fe12eSEd Maste tbl_print_num(data_size_total, radix, 1); 784a85fe12eSEd Maste tbl_print_num(bss_size_total, radix, 2); 785a85fe12eSEd Maste if (radix == RADIX_OCTAL) 786a85fe12eSEd Maste tbl_print_num(grand_total, RADIX_OCTAL, 3); 787a85fe12eSEd Maste else 788a85fe12eSEd Maste tbl_print_num(grand_total, RADIX_DECIMAL, 3); 789a85fe12eSEd Maste tbl_print_num(grand_total, RADIX_HEX, 4); 790a85fe12eSEd Maste } 791a85fe12eSEd Maste 792a85fe12eSEd Maste static void 793a85fe12eSEd Maste berkeley_footer(const char *name, const char *ar_name, const char *msg) 794a85fe12eSEd Maste { 795a85fe12eSEd Maste char buf[BUF_SIZE]; 796a85fe12eSEd Maste 797a85fe12eSEd Maste total_size = text_size + data_size + bss_size; 798a85fe12eSEd Maste if (show_totals) { 799a85fe12eSEd Maste text_size_total += text_size; 800a85fe12eSEd Maste bss_size_total += bss_size; 801a85fe12eSEd Maste data_size_total += data_size; 802a85fe12eSEd Maste } 803a85fe12eSEd Maste 804a85fe12eSEd Maste tbl_append(); 805a85fe12eSEd Maste tbl_print_num(text_size, radix, 0); 806a85fe12eSEd Maste tbl_print_num(data_size, radix, 1); 807a85fe12eSEd Maste tbl_print_num(bss_size, radix, 2); 808a85fe12eSEd Maste if (radix == RADIX_OCTAL) 809a85fe12eSEd Maste tbl_print_num(total_size, RADIX_OCTAL, 3); 810a85fe12eSEd Maste else 811a85fe12eSEd Maste tbl_print_num(total_size, RADIX_DECIMAL, 3); 812a85fe12eSEd Maste tbl_print_num(total_size, RADIX_HEX, 4); 813a85fe12eSEd Maste if (ar_name != NULL && name != NULL) 814a85fe12eSEd Maste (void) snprintf(buf, BUF_SIZE, "%s (%s %s)", ar_name, msg, 815a85fe12eSEd Maste name); 816a85fe12eSEd Maste else if (ar_name != NULL && name == NULL) 817a85fe12eSEd Maste (void) snprintf(buf, BUF_SIZE, "%s (%s)", ar_name, msg); 818a85fe12eSEd Maste else 819a85fe12eSEd Maste (void) snprintf(buf, BUF_SIZE, "%s", name); 820a85fe12eSEd Maste tbl_print(buf, 5); 821a85fe12eSEd Maste } 822a85fe12eSEd Maste 823a85fe12eSEd Maste 824a85fe12eSEd Maste static void 825a85fe12eSEd Maste tbl_new(int col) 826a85fe12eSEd Maste { 827a85fe12eSEd Maste 828a85fe12eSEd Maste assert(tb == NULL); 829a85fe12eSEd Maste assert(col > 0); 830a85fe12eSEd Maste if ((tb = calloc(1, sizeof(*tb))) == NULL) 831a85fe12eSEd Maste err(EXIT_FAILURE, "calloc"); 832a85fe12eSEd Maste if ((tb->tbl = calloc(col, sizeof(*tb->tbl))) == NULL) 833a85fe12eSEd Maste err(EXIT_FAILURE, "calloc"); 834a85fe12eSEd Maste if ((tb->width = calloc(col, sizeof(*tb->width))) == NULL) 835a85fe12eSEd Maste err(EXIT_FAILURE, "calloc"); 836a85fe12eSEd Maste tb->col = col; 837a85fe12eSEd Maste tb->row = 0; 838a85fe12eSEd Maste } 839a85fe12eSEd Maste 840a85fe12eSEd Maste static void 841a85fe12eSEd Maste tbl_print(const char *s, int col) 842a85fe12eSEd Maste { 843a85fe12eSEd Maste int len; 844a85fe12eSEd Maste 845a85fe12eSEd Maste assert(tb != NULL && tb->col > 0 && tb->row > 0 && col < tb->col); 846a85fe12eSEd Maste assert(s != NULL && tb->tbl[col][tb->row - 1] == NULL); 847a85fe12eSEd Maste if ((tb->tbl[col][tb->row - 1] = strdup(s)) == NULL) 848a85fe12eSEd Maste err(EXIT_FAILURE, "strdup"); 849a85fe12eSEd Maste len = strlen(s); 850a85fe12eSEd Maste if (len > tb->width[col]) 851a85fe12eSEd Maste tb->width[col] = len; 852a85fe12eSEd Maste } 853a85fe12eSEd Maste 854a85fe12eSEd Maste static void 855a85fe12eSEd Maste tbl_print_num(uint64_t num, enum radix_style rad, int col) 856a85fe12eSEd Maste { 857a85fe12eSEd Maste char buf[BUF_SIZE]; 858a85fe12eSEd Maste 859a85fe12eSEd Maste (void) snprintf(buf, BUF_SIZE, (rad == RADIX_DECIMAL ? "%ju" : 860a85fe12eSEd Maste ((rad == RADIX_OCTAL) ? "0%jo" : "0x%jx")), (uintmax_t) num); 861a85fe12eSEd Maste tbl_print(buf, col); 862a85fe12eSEd Maste } 863a85fe12eSEd Maste 864a85fe12eSEd Maste static void 865a85fe12eSEd Maste tbl_append(void) 866a85fe12eSEd Maste { 867a85fe12eSEd Maste int i; 868a85fe12eSEd Maste 869a85fe12eSEd Maste assert(tb != NULL && tb->col > 0); 870a85fe12eSEd Maste tb->row++; 871a85fe12eSEd Maste for (i = 0; i < tb->col; i++) { 872a85fe12eSEd Maste tb->tbl[i] = realloc(tb->tbl[i], sizeof(*tb->tbl[i]) * tb->row); 873a85fe12eSEd Maste if (tb->tbl[i] == NULL) 874a85fe12eSEd Maste err(EXIT_FAILURE, "realloc"); 875a85fe12eSEd Maste tb->tbl[i][tb->row - 1] = NULL; 876a85fe12eSEd Maste } 877a85fe12eSEd Maste } 878a85fe12eSEd Maste 879a85fe12eSEd Maste static void 880a85fe12eSEd Maste tbl_flush(void) 881a85fe12eSEd Maste { 882a85fe12eSEd Maste const char *str; 883a85fe12eSEd Maste int i, j; 884a85fe12eSEd Maste 885a85fe12eSEd Maste if (tb == NULL) 886a85fe12eSEd Maste return; 887a85fe12eSEd Maste 888a85fe12eSEd Maste assert(tb->col > 0); 889a85fe12eSEd Maste for (i = 0; i < tb->row; i++) { 890a85fe12eSEd Maste if (style == STYLE_BERKELEY) 891a85fe12eSEd Maste printf(" "); 892a85fe12eSEd Maste for (j = 0; j < tb->col; j++) { 893a85fe12eSEd Maste str = (tb->tbl[j][i] != NULL ? tb->tbl[j][i] : ""); 894a85fe12eSEd Maste if (style == STYLE_SYSV && j == 0) 895a85fe12eSEd Maste printf("%-*s", tb->width[j], str); 896a85fe12eSEd Maste else if (style == STYLE_BERKELEY && j == tb->col - 1) 897a85fe12eSEd Maste printf("%s", str); 898a85fe12eSEd Maste else 899a85fe12eSEd Maste printf("%*s", tb->width[j], str); 900a85fe12eSEd Maste if (j == tb->col -1) 901a85fe12eSEd Maste putchar('\n'); 902a85fe12eSEd Maste else 903a85fe12eSEd Maste printf(" "); 904a85fe12eSEd Maste } 905a85fe12eSEd Maste } 906a85fe12eSEd Maste 907a85fe12eSEd Maste for (i = 0; i < tb->col; i++) { 908a85fe12eSEd Maste for (j = 0; j < tb->row; j++) { 909a85fe12eSEd Maste if (tb->tbl[i][j]) 910a85fe12eSEd Maste free(tb->tbl[i][j]); 911a85fe12eSEd Maste } 912a85fe12eSEd Maste free(tb->tbl[i]); 913a85fe12eSEd Maste } 914a85fe12eSEd Maste free(tb->tbl); 915a85fe12eSEd Maste free(tb->width); 916a85fe12eSEd Maste free(tb); 917a85fe12eSEd Maste tb = NULL; 918a85fe12eSEd Maste } 919a85fe12eSEd Maste 920a85fe12eSEd Maste #define USAGE_MESSAGE "\ 921a85fe12eSEd Maste Usage: %s [options] file ...\n\ 922a85fe12eSEd Maste Display sizes of ELF sections.\n\n\ 923a85fe12eSEd Maste Options:\n\ 924a85fe12eSEd Maste --format=format Display output in specified format. Supported\n\ 925a85fe12eSEd Maste values are `berkeley' and `sysv'.\n\ 926a85fe12eSEd Maste --help Display this help message and exit.\n\ 927a85fe12eSEd Maste --radix=radix Display numeric values in the specified radix.\n\ 928a85fe12eSEd Maste Supported values are: 8, 10 and 16.\n\ 929a85fe12eSEd Maste --totals Show cumulative totals of section sizes.\n\ 930a85fe12eSEd Maste --version Display a version identifier and exit.\n\ 931a85fe12eSEd Maste -A Equivalent to `--format=sysv'.\n\ 932a85fe12eSEd Maste -B Equivalent to `--format=berkeley'.\n\ 933a85fe12eSEd Maste -V Equivalent to `--version'.\n\ 934a85fe12eSEd Maste -d Equivalent to `--radix=10'.\n\ 935a85fe12eSEd Maste -h Same as option --help.\n\ 936a85fe12eSEd Maste -o Equivalent to `--radix=8'.\n\ 937a85fe12eSEd Maste -t Equivalent to option --totals.\n\ 938a85fe12eSEd Maste -x Equivalent to `--radix=16'.\n" 939a85fe12eSEd Maste 940a85fe12eSEd Maste static void 941a85fe12eSEd Maste usage(void) 942a85fe12eSEd Maste { 943a85fe12eSEd Maste (void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME()); 944a85fe12eSEd Maste exit(EXIT_FAILURE); 945a85fe12eSEd Maste } 946a85fe12eSEd Maste 947a85fe12eSEd Maste static void 948a85fe12eSEd Maste show_version(void) 949a85fe12eSEd Maste { 950a85fe12eSEd Maste (void) printf("%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version()); 951a85fe12eSEd Maste exit(EXIT_SUCCESS); 952a85fe12eSEd Maste } 953