Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 25 Mar 2007 18:52:39 +0530
From:      "Sam Arun Raj Seeniraj" <samarunraj@gmail.com>
To:        current@freebsd.org
Subject:   Resurrecting old FreeBSD size with a rewrite using libelf
Message-ID:  <4fd6fc030703250622g36ddd5f9r833fb4440958a249@mail.gmail.com>

next in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
Hello there,

This patch is to resurrect the old FreeBSD size with a rewrite using
libelf. Currently supports elf objects, ar(1) archives and core dumps
in elf.

Can handle ELF of various architectures using libelf but doesn't
support any other object file formats unlike the GNU size. The cmdline
parameters as similar to the GNU size minus the long formats. The
output will be also be similar save for difference in indentation.

This is my first patch to FreeBSD & new to the code style, recent
convert from Windows :). Looking for a public review.

Tested by doing,
- make universe
- Comparing output of GNU size versus this against a vast number of
elf objects from different architectures.
- core dumps from i386,amd64 and sparc64 - These were the only ones I
could lay my hands on.

(NOTE: Will disable GNU size)
Apply against,
  /usr in -current as "patch -p0 < size.diff"


Cheers,
-Sam Arun Raj
samarunraj@gmail.com

[-- Attachment #2 --]
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 <bsd.subdir.mk>
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 <bsd.prog.mk>
+
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 <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/size/size.c,v 1.0 2007/04/24 17:58:22 Sam Exp $");
+
+#include <err.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include <libelf.h>
+#include <gelf.h>
+
+#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);
+}

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4fd6fc030703250622g36ddd5f9r833fb4440958a249>