diff -Naur src/gnu/usr.bin/binutils/Makefile src1/gnu/usr.bin/binutils/Makefile --- src/gnu/usr.bin/binutils/Makefile Fri Jun 25 13:04:56 2004 +++ src1/gnu/usr.bin/binutils/Makefile Sun Jan 14 05:49:40 2007 @@ -2,6 +2,6 @@ SUBDIR= libiberty libbfd libopcodes libbinutils \ addr2line ar as ld nm objcopy objdump ranlib readelf \ - size strings strip doc + strings strip doc .include diff -Naur src/usr.bin/Makefile src1/usr.bin/Makefile --- src/usr.bin/Makefile Sun Jan 14 05:37:07 2007 +++ src1/usr.bin/Makefile Sun Jan 14 05:50:01 2007 @@ -168,6 +168,7 @@ sed \ shar \ showmount \ + size \ ${_smbutil} \ sockstat \ split \ diff -Naur src/usr.bin/size/Makefile src1/usr.bin/size/Makefile --- src/usr.bin/size/Makefile Thu Jan 1 05:30:00 1970 +++ src1/usr.bin/size/Makefile Sun Jan 14 05:50:12 2007 @@ -0,0 +1,8 @@ +# $FreeBSD: /repoman/r/ncvs/src/usr.bin/size/Makefile,v 1.0 2007/04/25 01:59:27 Sam Exp $ + +PROG= size +WARNS?= 6 +LDADD= -lelf + +.include + diff -Naur src/usr.bin/size/size.1 src1/usr.bin/size/size.1 --- src/usr.bin/size/size.1 Thu Jan 1 05:30:00 1970 +++ src1/usr.bin/size/size.1 Sun Jan 14 05:50:10 2007 @@ -0,0 +1,132 @@ +.\" Copyright (c) 2007 S.Sam Arun Raj +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD: /repoman/r/ncvs/src/usr.bin/size/size.1,v 1.0 2007/04/25 17:58:22 Sam Exp $ +.\" +.Dd March 25, 2007 +.Dt SIZE 1 +.Os +.Sh NAME +.Nm size +.Nd "display section sizes and total size in" +.Tn ELF +files. +.Sh SYNOPSIS +.Nm +.Op Fl Adhotx +.Op Ar +.Sh DESCRIPTION +The +.Nm +utility +lists the size of various sections and total size (if choosen) for each input +.Ar file. +The +.Nm +utility can operate on ELF object, +.Xr ar 1 +archives, and core dumps. +.Pp +If no file name is specified in the input, "a.out" is assumed. +.Pp +The following options are available: +.Bl -tag -width indent +.It Fl A +The output of +.Nm +will resemble output from System V +.Nm . +By default, one line of output is generated for each ELF object or each module +in an archive, if this option is not choosen. +.It Fl t +Shows cumulative totals of section sizes from all objects. Not available when +System V output format +.Fl A +is choosen. +.It Fl d | Fl o | Fl x +The section sizes can be displayed either in decimal, octal or hexadecimal by +choosing one of these options. Totals +.Fl t +are always displayed in two radixes; decimal and hexadecimal for +.Fl d +or +.Fl x +output, or octal and hexadecimal if +.Fl o +is choosen. +.It Fl h +This prints a usage summary and exits. +.El +.Sh EXIT STATUS +.Ex -std +.Sh EXAMPLES +The following are examples of typical usage +of the +.Nm +command: +.Pp +.Dl "$ size /bin/ls" +.Dl "text data bss dec hex filename" +.Dl "20975 540 392 21907 5593 /bin/ls" +.Pp +.Dl "$ size -tx /bin/ls /bin/dd" +.Dl "text data bss dec hex filename" +.Dl "0x51ef 0x21c 0x188 21907 5593 /bin/ls" +.Dl "0x3df5 0x170 0x200 16741 4165 /bin/dd" +.Dl "0x8fe4 0x38c 0x388 38648 96f8 (TOTALS)" +.Sh SEE ALSO +.Xr ar 1 , +.Xr objdump 1 , +.Xr readelf 1 +.Rs +.%A "AT&T Unix Systems Labs" +.%T "System V Application Binary Interface" +.%O http://www.sco.com/developers/gabi/ +.Re +.Sh HISTORY +The +.Nm +utility first appeared in +.At v6. +The last FreeBSD +.Nm +was discontinued in +.Fx v5 , +when i386-only a.out format was dropped in favor of ELF. +.Sh AUTHORS +.An -nosplit +The +.Nm +utility was re-written by +.An S.Sam Arun Raj Aq samarunraj@gmail.com +This manual page was written by +.An S.Sam Arun Raj Aq samarunraj@gmail.com +.Sh LIMITATIONS +Unlike the GNU +.Nm +this doesn't support multiple object file formats, only ELF using the +.Xr elf 3 +and +.Xr gelf 3 +API's. diff -Naur src/usr.bin/size/size.c src1/usr.bin/size/size.c --- src/usr.bin/size/size.c Thu Jan 1 05:30:00 1970 +++ src1/usr.bin/size/size.c Sun Jan 14 06:01:18 2007 @@ -0,0 +1,816 @@ +/*- + * Copyright (c) 2007 S.Sam Arun Raj + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD: src/usr.bin/size/size.c,v 1.0 2007/04/24 17:58:22 Sam Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define BUF_SIZE 40 +#define ELF_ALIGN(val,x) \ + (((val) + (x) - 1) > (val) ? (((val)+(x)-1) & ~((x)-1)) : ~0) + +#ifndef NT_AUXV +#define NT_AUXV 6 +#endif +#ifndef NT_LWPSTATUS +#define NT_LWPSTATUS 16 +#endif +#ifndef NT_PRFPREG +#define NT_PRFPREG 2 +#endif +#ifndef NT_PSTATUS +#define NT_PSTATUS 10 +#endif +#ifndef NT_PSINFO +#define NT_PSINFO 13 +#endif +#ifndef NT_PRXFPREG +#define NT_PRXFPREG 0x46e62b7f +#endif +#ifndef PT_GNU_EH_FRAME +#define PT_GNU_EH_FRAME (PT_LOOS + 0x474e550) +#endif +#ifndef PT_GNU_STACK +#define PT_GNU_STACK (PT_LOOS + 0x474e551) +#endif + +enum output_style { + STYLE_BERKELEY, + STYLE_SYSV +}; + +enum radix_style { + RADIX_OCTAL, + RADIX_DECIMAL, + RADIX_HEX +}; + +size_t sec_name_len; +uint32_t bss_size_total, data_size_total, text_size_total; +uint32_t bss_size, data_size, text_size, total_size; +int show_totals; +enum radix_style radix; +enum output_style style; +const char default_name[] = "a.out"; + +int handle_elf(char const *); +int handle_core(char const *, Elf *elf, GElf_Ehdr *); +void handle_core_note(Elf *, GElf_Ehdr *, GElf_Phdr *, pid_t); +void get_core_cmdline_pid(Elf *, GElf_Ehdr *, GElf_Phdr *, + char **, pid_t *); +void handle_phdr(Elf *, GElf_Ehdr *, GElf_Phdr *, uint32_t, + const char *); +void usage(void); +void print_number(int, uint32_t, enum radix_style, char); +void berkeley_header(void); +void berkeley_footer(const char *, const char *, const char *); +void berkeley_calc(GElf_Shdr *); +void berkeley_totals(void); +void sysv_header(const char *, Elf_Arhdr *); +void sysv_footer(void); +void sysv_calc(Elf *, GElf_Ehdr *, GElf_Shdr *, int); + +/* + * size utility using elf(3) and gelf(3) API to list section sizes and + * total in elf files. Supports only elf files (core dumps in elf + * included) that can be opened by libelf, other formats are not supported. + */ +int +main(int argc, char *argv[]) +{ + int ch, exit_code; + + sec_name_len = 19; + exit_code = EX_OK; + style = STYLE_BERKELEY; + radix = RADIX_DECIMAL; + if (elf_version(EV_CURRENT) == EV_NONE) + errx(EX_SOFTWARE, "ELF library initialization failed: %s", + elf_errmsg(-1)); + + while ((ch = getopt(argc, argv, "Adhotx")) != -1) + switch((char)ch) { + case 'A': + style = STYLE_SYSV; + break; + case 'd': + radix = RADIX_DECIMAL; + break; + case 't': + show_totals = 1; + break; + case 'o': + radix = RADIX_OCTAL; + break; + case 'x': + radix = RADIX_HEX; + break; + case 'h': + case '?': + default: + usage(); + /* NOTREACHED */ + } + argc -= optind; + argv += optind; + + if (!*argv) { + exit_code = handle_elf(default_name); + if (exit_code == EX_SOFTWARE || exit_code == EX_DATAERR) + warnx("%s: File format not recognized", default_name); + if (exit_code == EX_NOINPUT) + warnx("'%s': No such file", default_name); + } + else while (*argv) { + exit_code = handle_elf(*argv); + if (exit_code == EX_SOFTWARE || exit_code == EX_DATAERR) + warnx("%s: File format not recognized", *argv); + if (exit_code == EX_NOINPUT) + warnx("'%s': No such file", *argv); + argv++; + } + if (style == STYLE_BERKELEY) + berkeley_totals(); + return (exit_code); +} + +static Elf_Data * +xlatetom(Elf *elf, GElf_Ehdr *elfhdr, void *_src, void *_dst, + Elf_Type type, size_t size) +{ + Elf_Data src, dst; + + src.d_buf = _src; + src.d_type = type; + src.d_version = elfhdr->e_version; + src.d_size = size; + dst.d_buf = _dst; + dst.d_version = elfhdr->e_version; + dst.d_size = size; + return gelf_xlatetom(elf, &dst, &src, elfhdr->e_ident[EI_DATA]); +} + +#define NOTE_OFFSET_32(nhdr, namesz, offset) \ + ((char *)nhdr + sizeof(Elf32_Nhdr) + \ + ELF_ALIGN((int32_t)namesz, 4) + offset) + +#define NOTE_OFFSET_64(nhdr, namesz, offset) \ + ((char *)nhdr + sizeof(Elf32_Nhdr) + \ + ELF_ALIGN((int32_t)namesz, 8) + offset) + +#define PID32(nhdr, namesz, offset) \ + (pid_t)*((int *)((uintptr_t)NOTE_OFFSET_32(nhdr, \ + namesz, offset))); + +#define PID64(nhdr, namesz, offset) \ + (pid_t)*((int *)((uintptr_t)NOTE_OFFSET_64(nhdr, \ + namesz, offset))); + +#define NEXT_NOTE(elfhdr, descsz, namesz, offset) do { \ + if (elfhdr->e_ident[EI_CLASS] == ELFCLASS32) { \ + offset += ELF_ALIGN((int32_t)descsz, 4) + \ + sizeof(Elf32_Nhdr) + \ + ELF_ALIGN((int32_t)namesz, 4); \ + } else { \ + offset += ELF_ALIGN((int32_t)descsz, 8) + \ + sizeof(Elf32_Nhdr) + \ + ELF_ALIGN((int32_t)namesz, 8); \ + } \ +} while (0) + +/* + * Retrieves the command line and pid from the core file. + */ +void +get_core_cmdline_pid(Elf *elf, GElf_Ehdr *elfhdr, GElf_Phdr *phdr, + char **cmd_line, pid_t *pid) +{ + GElf_Off offset; + size_t max_size; + pid_t p; + Elf32_Nhdr *nhdr, nhdr_l; + uintptr_t addr; + int ver; + char *data, *name; + uint8_t class; + + if (elf == NULL || elfhdr == NULL || phdr == NULL || + pid == NULL || cmd_line == NULL) + return; + + data = elf_rawfile(elf, &max_size); + offset = phdr->p_offset; + while (data != NULL && offset < phdr->p_offset + phdr->p_filesz) { + nhdr = (Elf32_Nhdr *)(uintptr_t)((char*)data + offset); + memset(&nhdr_l, 0, sizeof(Elf32_Nhdr)); + if (!xlatetom(elf, elfhdr, &nhdr->n_type, &nhdr_l.n_type, + ELF_T_WORD, sizeof(Elf32_Word)) || + !xlatetom(elf, elfhdr, &nhdr->n_descsz, &nhdr_l.n_descsz, + ELF_T_WORD, sizeof(Elf32_Word)) || + !xlatetom(elf, elfhdr, &nhdr->n_namesz, &nhdr_l.n_namesz, + ELF_T_WORD, sizeof(Elf32_Word))) + break; + + name = (char *)((char *)nhdr + sizeof(Elf32_Nhdr)); + class = elfhdr->e_ident[EI_CLASS]; + switch (nhdr_l.n_type) { + case NT_PRSTATUS: { + p = 0; + if (elfhdr->e_ident[EI_OSABI] == ELFOSABI_FREEBSD && + nhdr_l.n_namesz == 0x8 && + !strcmp(name,"FreeBSD")) { + if (class == ELFCLASS32) { + addr = (uintptr_t)NOTE_OFFSET_32(nhdr, + nhdr_l.n_namesz,0); + ver = *((int *)addr); + } else { + addr = (uintptr_t)NOTE_OFFSET_64(nhdr, + nhdr_l.n_namesz,0); + ver = *((int *)addr); + } + if (!xlatetom(elf, elfhdr, &ver, + &ver, ELF_T_WORD, sizeof(int))) { + NEXT_NOTE(elfhdr, nhdr_l.n_descsz, + nhdr_l.n_namesz, offset); + continue; + } + if (ver == 1 && class == ELFCLASS32) + p = PID32(nhdr, nhdr_l.n_namesz, 24); + if (ver == 1 && class == ELFCLASS64) + p = PID64(nhdr, nhdr_l.n_namesz, 40); + } + if (xlatetom(elf, elfhdr, &p, &p, ELF_T_WORD, + sizeof(pid_t))) + *pid = p; + } + break; + case NT_PSINFO: + case NT_PRPSINFO: { + /* FreeBSD 64-bit */ + if (nhdr_l.n_descsz == 0x78 && + !strcmp(name,"FreeBSD")) { + *cmd_line = strdup(NOTE_OFFSET_64(nhdr, + nhdr_l.n_namesz, 33)); + /* FreeBSD 32-bit */ + } else if (nhdr_l.n_descsz == 0x6c && + !strcmp(name,"FreeBSD")) { + *cmd_line = strdup(NOTE_OFFSET_32(nhdr, + nhdr_l.n_namesz, 25)); + } + /* Strip any trailing spaces */ + if (*cmd_line != NULL) { + char *s; + + s = *cmd_line + strlen(*cmd_line); + while (s > *cmd_line) { + if (*(s-1) != 0x20) break; + s--; + } + *s = 0; + } + break; + } + default: + break; + } + NEXT_NOTE(elfhdr, nhdr_l.n_descsz, nhdr_l.n_namesz, offset); + } +} + +/* + * Parse individual note entries inside a PT_NOTE segment. + */ +void +handle_core_note(Elf *elf, GElf_Ehdr *elfhdr, GElf_Phdr *phdr, pid_t pid) +{ + size_t max_size; + uint64_t raw_size; + GElf_Off offset; + Elf32_Nhdr *nhdr, nhdr_l; + char buf[BUF_SIZE], *data, *name; + + if (elf == NULL || elfhdr == NULL || phdr == NULL) + return; + + data = elf_rawfile(elf, &max_size); + offset = phdr->p_offset; + raw_size = 0; + while (data != NULL && offset < phdr->p_offset + phdr->p_filesz) { + nhdr = (Elf32_Nhdr *)(uintptr_t)((char*)data + offset); + memset(&nhdr_l, 0, sizeof(Elf32_Nhdr)); + if (!xlatetom(elf, elfhdr, &nhdr->n_type, &nhdr_l.n_type, + ELF_T_WORD, sizeof(Elf32_Word)) || + !xlatetom(elf,elfhdr, &nhdr->n_descsz, &nhdr_l.n_descsz, + ELF_T_WORD, sizeof(Elf32_Word)) || + !xlatetom(elf,elfhdr, &nhdr->n_namesz, &nhdr_l.n_namesz, + ELF_T_WORD, sizeof(Elf32_Word))) + break; + + name = (char *)((char *)nhdr + sizeof(Elf32_Nhdr)); + switch (nhdr_l.n_type) { + case NT_PRSTATUS: { + if (elfhdr->e_ident[EI_OSABI] == ELFOSABI_FREEBSD && + nhdr_l.n_namesz == 0x8 && + !strcmp(name,"FreeBSD")) { + if (elfhdr->e_ident[EI_CLASS] == ELFCLASS32) { + raw_size = (uint64_t)*((uint32_t *) + (uintptr_t)(name + + ELF_ALIGN((int32_t) + nhdr_l.n_namesz, 4) + 8)); + xlatetom(elf, elfhdr, &raw_size, + &raw_size, ELF_T_WORD, + sizeof(uint64_t)); + } else { + raw_size = *((uint64_t *)(uintptr_t) + (name + ELF_ALIGN((int32_t) + nhdr_l.n_namesz, 8) + 16)); + xlatetom(elf, elfhdr, &raw_size, + &raw_size, ELF_T_XWORD, + sizeof(uint64_t)); + } + } + if (raw_size != 0 && style == STYLE_SYSV) { + (void) snprintf(buf, BUF_SIZE, "%s/%d", + ".reg", pid); + (void) printf("%-18s ", buf); + print_number(10, (uint32_t)raw_size, + radix, ' '); + print_number(10, (uint32_t)0, + radix, '\n'); + (void) printf("%-18s ", ".reg"); + print_number(10, (uint32_t)raw_size, + radix, ' '); + print_number(10, (uint32_t)0, radix, '\n'); + text_size_total += raw_size * 2; + } + } + break; + case NT_PRFPREG: /* same as NT_FPREGSET */ + if (style == STYLE_SYSV) { + (void) snprintf(buf, BUF_SIZE, + "%s/%d", ".reg2", pid); + (void) printf("%-18s ", buf); + print_number(10, (uint32_t)nhdr_l.n_descsz, + radix, ' '); + print_number(10, (uint32_t)0, radix, '\n'); + (void) printf("%-18s ", ".reg2"); + print_number(10, (uint32_t)nhdr_l.n_descsz, + radix, ' '); + print_number(10, (uint32_t)0, radix, '\n'); + text_size_total += nhdr_l.n_descsz * 2; + } + break; + case NT_AUXV: + if (style == STYLE_SYSV) { + (void) printf("%-18s ", ".auxv"); + print_number(10, (uint32_t)nhdr_l.n_descsz, + radix, ' '); + print_number(10, (uint32_t)0, radix, '\n'); + text_size_total += nhdr_l.n_descsz; + } + break; + case NT_PRXFPREG: + if (style == STYLE_SYSV) { + (void) snprintf(buf, BUF_SIZE, + "%s/%d", ".reg-xfp", pid); + (void) printf("%-18s ", buf); + print_number(10, (uint32_t)nhdr_l.n_descsz, + radix, ' '); + print_number(10, (uint32_t)0, radix, '\n'); + (void) printf("%-18s ", ".reg-xfp"); + print_number(10, (uint32_t)nhdr_l.n_descsz, + radix, ' '); + print_number(10, (uint32_t)0, radix, '\n'); + text_size_total += nhdr_l.n_descsz * 2; + } + break; + case NT_PSTATUS: + case NT_LWPSTATUS: + default: + break; + } + NEXT_NOTE(elfhdr, nhdr_l.n_descsz, nhdr_l.n_namesz, offset); + } +} + +/* + * Handles program headers except for PT_NOTE, when sysv output stlye is + * choosen, prints out the segment name and length. For berkely output + * style only PT_LOAD segments are handled, and text, + * data, bss size is calculated for them. + */ +void +handle_phdr(Elf *elf, GElf_Ehdr *elfhdr, GElf_Phdr *phdr, + uint32_t idx, const char *name) +{ + uint32_t addr, size; + int split; + char buf[BUF_SIZE]; + + if (elf == NULL || elfhdr == NULL || phdr == NULL) + return; + + size = addr = 0; + split = (phdr->p_memsz > 0) && (phdr->p_filesz > 0) && + (phdr->p_memsz > phdr->p_filesz); + + if (style == STYLE_SYSV) { + (void) snprintf(buf, BUF_SIZE, + "%s%d%s", name, idx, (split ? "a" : "")); + (void) printf("%-18s ", buf); + print_number(10, (uint32_t)phdr->p_filesz, radix, ' '); + print_number(10, (uint32_t)phdr->p_vaddr, radix, '\n'); + text_size_total += phdr->p_filesz; + if (split) { + size = (uint32_t)(phdr->p_memsz - phdr->p_filesz); + addr = (uint32_t)(phdr->p_vaddr + phdr->p_filesz); + (void) snprintf(buf, BUF_SIZE, "%s%d%s", name, + idx, "b"); + text_size_total += phdr->p_memsz - phdr->p_filesz; + (void) printf("%-18s ", buf); + print_number(10, size, radix, ' '); + print_number(10, addr, radix, '\n'); + } + } else { + if (phdr->p_type != PT_LOAD) + return; + if ((phdr->p_flags & PF_R) && ((phdr->p_flags & PF_X) || + !((phdr->p_flags & PF_W))) && (phdr->p_filesz != 0)) { + text_size += phdr->p_filesz; + if (split) + text_size += phdr->p_memsz - phdr->p_filesz; + } else if ((phdr->p_flags & PF_R) && + (phdr->p_flags & PF_W) && (phdr->p_filesz != 0)) { + data_size += phdr->p_filesz; + if (split) + data_size += phdr->p_memsz - phdr->p_filesz; + } else { + bss_size += phdr->p_filesz; + if (split) + bss_size += phdr->p_memsz - phdr->p_filesz; + } + } +} + +/* + * Given a core dump file, this function maps program headers to segments. + */ +int +handle_core(char const *name, Elf *elf, GElf_Ehdr *elfhdr) +{ + GElf_Phdr phdr; + uint32_t i; + pid_t pid; + char *core_cmdline; + const char *seg_name; + + if (name == NULL || elf == NULL || elfhdr == NULL) + return (EX_DATAERR); + if (elfhdr->e_shnum != 0 || elfhdr->e_type != ET_CORE) + return (EX_DATAERR); + + seg_name = core_cmdline = NULL; + pid = 0; + if (style == STYLE_SYSV) + sysv_header(name, NULL); + else + berkeley_header(); + + for (i = 0; i < elfhdr->e_phnum; i++) { + if (gelf_getphdr(elf, i, &phdr) != NULL) { + if (phdr.p_type == PT_NOTE) { + handle_phdr(elf, elfhdr, &phdr, i, "note"); + get_core_cmdline_pid(elf, elfhdr, &phdr, + &core_cmdline, &pid); + handle_core_note(elf, elfhdr, &phdr, pid); + } else { + switch(phdr.p_type) { + case PT_NULL: + seg_name = "null"; + break; + case PT_LOAD: + seg_name = "load"; + break; + case PT_DYNAMIC: + seg_name = "dynamic"; + break; + case PT_INTERP: + seg_name = "interp"; + break; + case PT_SHLIB: + seg_name = "shlib"; + break; + case PT_PHDR: + seg_name = "phdr"; + break; + case PT_GNU_EH_FRAME: + seg_name = "eh_frame_hdr"; + break; + case PT_GNU_STACK: + seg_name = "stack"; + break; + default: + seg_name = "segment"; + } + handle_phdr(elf, elfhdr, &phdr, i, seg_name); + } + } + } + + if (style == STYLE_BERKELEY) { + if (core_cmdline != NULL) { + berkeley_footer(core_cmdline, name, + "core file invoked as"); + } else { + berkeley_footer(core_cmdline, name, "core file"); + } + } else { + sysv_footer(); + if (core_cmdline != NULL) { + (void) printf(" (core file invoked as %s)\n\n", + core_cmdline); + } else { + (void) printf(" (core file)\n\n"); + } + } + free(core_cmdline); + return (EX_OK); +} + +/* + * Given an elf object,ar(1) filename, and based on the output style + * and radix format the various sections and their length will be printed + * or the size of the text, data, bss sections will be printed out. + */ +int +handle_elf(char const *name) +{ + GElf_Ehdr elfhdr; + GElf_Shdr shdr; + Elf *elf, *elf1; + Elf_Arhdr *arhdr; + Elf_Scn *scn; + Elf_Cmd elf_cmd; + int exit_code, fd; + + if (name == NULL) + return (EX_NOINPUT); + + if ((fd = open(name, O_RDONLY, 0)) < 0) + return (EX_NOINPUT); + + elf_cmd = ELF_C_READ; + elf1 = elf_begin(fd, elf_cmd, NULL); + while ((elf = elf_begin(fd, elf_cmd, elf1)) != NULL) { + arhdr = elf_getarhdr(elf); + if (elf_kind(elf) == ELF_K_NONE && arhdr == NULL) { + (void) elf_end(elf); + (void) elf_end(elf1); + (void) close(fd); + return (EX_DATAERR); + } + if (elf_kind(elf) != ELF_K_ELF || + (gelf_getehdr(elf, &elfhdr) == NULL)) { + elf_cmd = elf_next(elf); + (void) elf_end(elf); + warnx("%s: File format not recognized", + arhdr->ar_name); + continue; + } + /* Core dumps are handled seperately */ + if (elfhdr.e_shnum == 0 && elfhdr.e_type == ET_CORE) { + exit_code = handle_core(name, elf, &elfhdr); + (void) elf_end(elf); + (void) elf_end(elf1); + (void) close(fd); + return (exit_code); + } else { + scn = NULL; + if (style == STYLE_BERKELEY) { + berkeley_header(); + while ((scn = elf_nextscn(elf, scn)) != NULL) { + if (gelf_getshdr(scn, &shdr) != NULL) + berkeley_calc(&shdr); + } + } else { + /* + * Perform a dry run to find the length of + * the largest segment name. + */ + while ((scn = elf_nextscn(elf, scn)) != NULL) { + if (gelf_getshdr(scn, &shdr) != NULL) { + sysv_calc(elf, &elfhdr, + &shdr, 1); + } + } + sysv_header(name, arhdr); + scn = NULL; + while ((scn = elf_nextscn(elf, scn)) != NULL) { + if (gelf_getshdr(scn, &shdr) != NULL) + sysv_calc(elf, &elfhdr, + &shdr, 0); + } + } + if (style == STYLE_BERKELEY) { + if (arhdr != NULL) { + berkeley_footer(name, arhdr->ar_name, + "ex"); + } else { + berkeley_footer(name, NULL, "ex"); + } + } else { + sysv_footer(); + } + } + elf_cmd = elf_next(elf); + (void) elf_end(elf); + } + (void) elf_end(elf1); + (void) close(fd); + return (EX_OK); +} + +void +print_number(int width, uint32_t num, enum radix_style rad, char c) +{ + char buffer[BUF_SIZE]; + + (void) snprintf(buffer, BUF_SIZE, (rad == RADIX_DECIMAL ? "%lu" : + ((rad == RADIX_OCTAL) ? "0%lo" : "0x%lx")), + (unsigned long int)num); + (void) printf("%-*s%c", width, buffer, c); +} + +/* + * Sysv formatting helper functions. + */ +void +sysv_header(const char *name, Elf_Arhdr *arhdr) +{ + text_size_total = 0; + if (arhdr != NULL) { + (void) printf("%s (ex %s):\n%-*s%-10s %-10s\n", + arhdr->ar_name, name, (int)sec_name_len, + "section","size","addr"); + } else { + (void) printf("%s :\n%-*s%-10s %-10s\n", + name, (int)sec_name_len, "section", + "size", "addr"); + } +} + +void +sysv_calc(Elf *elf, GElf_Ehdr *elfhdr, GElf_Shdr *shdr, int dry_run) +{ + char *section_name; + + section_name = elf_strptr(elf, elfhdr->e_shstrndx, + (size_t)shdr->sh_name); + if (!dry_run) { + if ((shdr->sh_type == SHT_SYMTAB || + shdr->sh_type == SHT_STRTAB || shdr->sh_type == SHT_RELA || + shdr->sh_type == SHT_REL) && shdr->sh_addr == 0) + return; + (void) printf("%-*s", (int)sec_name_len, section_name); + print_number(10, (uint32_t)shdr->sh_size, radix, ' '); + print_number(10, (uint32_t)shdr->sh_addr, radix, '\n'); + text_size_total += shdr->sh_size; + } else { + if (sec_name_len < strlen(section_name)) + sec_name_len = strlen(section_name) + 3; + } +} + +void +sysv_footer() +{ + (void) printf("%-*s", (int)sec_name_len, "Total"); + print_number(10, text_size_total, radix, '\n'); + (void) printf("\n"); +} + +/* + * berkeley style output formatting helper functions. + */ +void +berkeley_header() +{ + text_size = data_size = bss_size = 0; +} + +void +berkeley_calc(GElf_Shdr *shdr) +{ + if (shdr != NULL) { + if (!(shdr->sh_flags & SHF_ALLOC)) + return; + if ((shdr->sh_flags & SHF_ALLOC) && + ((shdr->sh_flags & SHF_EXECINSTR) || + !(shdr->sh_flags & SHF_WRITE))) + text_size += shdr->sh_size; + else if ((shdr->sh_flags & SHF_ALLOC) && + (shdr->sh_flags & SHF_WRITE) && + (shdr->sh_type != SHT_NOBITS)) + data_size += shdr->sh_size; + else + bss_size += shdr->sh_size; + } +} + +void +berkeley_totals(void) +{ + long unsigned int grand_total; + + if (show_totals) { + grand_total = text_size_total + data_size_total + + bss_size_total; + print_number(10, text_size_total, radix, ' '); + print_number(10, data_size_total, radix, ' '); + print_number(10, bss_size_total, radix, ' '); + if (radix == RADIX_OCTAL) + print_number(10, grand_total, RADIX_OCTAL, ' '); + else + print_number(10, grand_total, RADIX_DECIMAL, ' '); + (void) printf("%-10lx (TOTALS)\n", grand_total); + } +} + +void +berkeley_footer(const char *name, const char *ar_name, const char *msg) +{ + static int header_printed; + const char *col_name; + + if (!header_printed) { + (radix == RADIX_OCTAL) ? (col_name = "oct") : + (col_name = "dec"); + (void) printf("%-10s %-10s %-10s %-10s %-10s filename\n", + "text","data","bss",col_name,"hex"); + header_printed = 1; + } + + total_size = text_size + data_size + bss_size; + if (show_totals) { + text_size_total += text_size; + bss_size_total += bss_size; + data_size_total += data_size; + } + + print_number(10, text_size, radix, ' '); + print_number(10, data_size, radix, ' '); + print_number(10, bss_size, radix, ' '); + if (radix == RADIX_OCTAL) + print_number(10, total_size, RADIX_OCTAL, ' '); + else + print_number(10, total_size, RADIX_DECIMAL, ' '); + (void) printf("%-10lx\t", (long unsigned int)total_size); + if (ar_name != NULL && name != NULL) + (void) printf("%s (%s %s)\n", ar_name, msg, name); + else if (ar_name != NULL && name == NULL) + (void) printf("%s (%s)\n", ar_name, msg); + else + (void) printf("%s\n", name); +} + +void +usage() +{ + (void) fprintf(stderr, "usage: size [-Adhotx] file ...\n"); + exit(EX_USAGE); +}