From ca1b8e8285da74915632813aaa5fbe5d5eead882 Mon Sep 17 00:00:00 2001 From: pk Date: Sun, 14 Jan 1996 23:07:11 +0000 Subject: [PATCH] Add capability to read archives (from Thomas Eberhardt; PR#497). --- usr.bin/size/size.1 | 20 +++- usr.bin/size/size.c | 226 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 225 insertions(+), 21 deletions(-) diff --git a/usr.bin/size/size.1 b/usr.bin/size/size.1 index 3e70fe5f2e7f..cad9d12a5fae 100644 --- a/usr.bin/size/size.1 +++ b/usr.bin/size/size.1 @@ -1,4 +1,4 @@ -.\" $NetBSD: size.1,v 1.5 1994/12/21 08:07:20 jtc Exp $ +.\" $NetBSD: size.1,v 1.6 1996/01/14 23:07:11 pk Exp $ .\" .\" Copyright (c) 1990, 1993, 1994 .\" The Regents of the University of California. All rights reserved. @@ -41,19 +41,31 @@ .Nd display object file segment sizes (text, data and bss) .Sh SYNOPSIS .Nm size -.Op Ar object_file ... +.Op Fl w +.Ar .Sh DESCRIPTION .Nm Size displays the text, data and bss segment sizes of the specified -.Ar object_file +.Ar file(s) in bytes (in decimal), and the sum of the three segments (in decimal and hexadecimal). +If a library (archive) is given, +.Nm +displays the segment sizes for each object archive member. If no -.Ar object_file +.Ar file is specified .Nm attempts to report on the file .Pa a.out . +.Bl -tag -width flag +.It Fl w +Warn about non-object archive members. +Normally, +.Nm +will silently ignore all archive members which are not +object files. +.El .Sh SEE ALSO .Xr a.out 5 .Sh HISTORY diff --git a/usr.bin/size/size.c b/usr.bin/size/size.c index 77c5c8b45cf6..676e70555dff 100644 --- a/usr.bin/size/size.c +++ b/usr.bin/size/size.c @@ -1,4 +1,4 @@ -/* $NetBSD: size.c,v 1.6 1994/12/21 08:07:21 jtc Exp $ */ +/* $NetBSD: size.c,v 1.7 1996/01/14 23:07:12 pk Exp $ */ /* * Copyright (c) 1988, 1993 @@ -43,18 +43,26 @@ static char copyright[] = #if 0 static char sccsid[] = "@(#)size.c 8.2 (Berkeley) 12/9/93"; #endif -static char rcsid[] = "$NetBSD: size.c,v 1.6 1994/12/21 08:07:21 jtc Exp $"; +static char rcsid[] = "$NetBSD: size.c,v 1.7 1996/01/14 23:07:12 pk Exp $"; #endif /* not lint */ #include #include #include +#include +#include #include #include #include #include -int show __P((int, char *)); +int ignore_bad_archive_entries = 1; + +int process_file __P((int, char *)); +int show_archive __P((int, char *, FILE *)); +int show_object __P((int, char *, FILE *)); +void *emalloc __P((size_t)); +void *erealloc __P((void *, size_t)); void usage __P((void)); int @@ -64,8 +72,11 @@ main(argc, argv) { int ch, eval; - while ((ch = getopt(argc, argv, "")) != EOF) + while ((ch = getopt(argc, argv, "w")) != EOF) switch(ch) { + case 'w': + ignore_bad_archive_entries = 0; + break; case '?': default: usage(); @@ -76,33 +87,191 @@ main(argc, argv) eval = 0; if (*argv) do { - eval |= show(argc, *argv); + eval |= process_file(argc, *argv); } while (*++argv); else - eval |= show(1, "a.out"); + eval |= process_file(1, "a.out"); exit(eval); } +/* + * process_file() + * show symbols in the file given as an argument. Accepts archive and + * object files as input. + */ int -show(count, name) +process_file(count, fname) + int count; + char *fname; +{ + struct exec exec_head; + FILE *fp; + int retval; + char magic[SARMAG]; + + if (!(fp = fopen(fname, "r"))) { + warnx("cannot read %s", fname); + return(1); + } + + /* + * first check whether this is an object file - read a object + * header, and skip back to the beginning + */ + if (fread((char *)&exec_head, sizeof(exec_head), (size_t)1, fp) != 1) { + warnx("%s: bad format", fname); + (void)fclose(fp); + return(1); + } + rewind(fp); + + /* this could be an archive */ + if (N_BADMAG(exec_head)) { + if (fread(magic, sizeof(magic), (size_t)1, fp) != 1 || + strncmp(magic, ARMAG, SARMAG)) { + warnx("%s: not object file or archive", fname); + (void)fclose(fp); + return(1); + } + retval = show_archive(count, fname, fp); + } else + retval = show_objfile(count, fname, fp); + (void)fclose(fp); + return(retval); +} + +/* + * show_archive() + * show symbols in the given archive file + */ +int +show_archive(count, fname, fp) + int count; + char *fname; + FILE *fp; +{ + struct ar_hdr ar_head; + struct exec exec_head; + int i, rval; + long last_ar_off; + char *p, *name; + int baselen, namelen; + + baselen = strlen(fname) + 3; + namelen = sizeof(ar_head.ar_name); + name = emalloc(baselen + namelen); + + rval = 0; + + /* while there are more entries in the archive */ + while (fread((char *)&ar_head, sizeof(ar_head), (size_t)1, fp) == 1) { + /* bad archive entry - stop processing this archive */ + if (strncmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) { + warnx("%s: bad format archive header", fname); + (void)free(name); + return(1); + } + + /* remember start position of current archive object */ + last_ar_off = ftell(fp); + + /* skip ranlib entries */ + if (!strncmp(ar_head.ar_name, RANLIBMAG, sizeof(RANLIBMAG) - 1)) + goto skip; + + /* + * construct a name of the form "archive.a:obj.o:" for the + * current archive entry if the object name is to be printed + * on each output line + */ + p = name; + if (count > 1) + p += sprintf(p, "%s:", fname); +#ifdef AR_EFMT1 + /* + * BSD 4.4 extended AR format: #1/, with name as the + * first bytes of the file + */ + if ( (ar_head.ar_name[0] == '#') && + (ar_head.ar_name[1] == '1') && + (ar_head.ar_name[2] == '/') && + (isdigit(ar_head.ar_name[3]))) { + + int len = atoi(&ar_head.ar_name[3]); + if (len > namelen) { + p -= (long)name; + name = (char *)erealloc(name, baselen+len); + namelen = len; + p += (long)name; + } + if (fread(p, len, 1, fp) != 1) { + (void)fprintf(stderr, + "nm: %s: premature EOF.\n", name); + (void)free(name); + return 1; + } + p += len; + } else +#endif + for (i = 0; i < sizeof(ar_head.ar_name); ++i) + if (ar_head.ar_name[i] && ar_head.ar_name[i] != ' ') + *p++ = ar_head.ar_name[i]; + *p++ = '\0'; + + /* get and check current object's header */ + if (fread((char *)&exec_head, sizeof(exec_head), + (size_t)1, fp) != 1) { + warnx("%s: premature EOF", name); + (void)free(name); + return(1); + } + + if (N_BADMAG(exec_head)) { + if (!ignore_bad_archive_entries) { + warnx("%s: bad format", name); + rval = 1; + } + } else { + (void)fseek(fp, (long)-sizeof(exec_head), + SEEK_CUR); + rval |= show_objfile(2, name, fp); + } + + /* + * skip to next archive object - it starts at the next + * even byte boundary + */ +#define even(x) (((x) + 1) & ~1) +skip: if (fseek(fp, last_ar_off + even(atol(ar_head.ar_size)), + SEEK_SET)) { + warn("%s", fname); + (void)free(name); + return(1); + } + } + (void)free(name); + return(rval); +} + +int +show_objfile(count, name, fp) int count; char *name; + FILE *fp; { static int first = 1; struct exec head; u_long total; - int fd; - if ((fd = open(name, O_RDONLY, 0)) < 0) { - warn("%s", name); - return (1); + if (fread((char *)&head, sizeof(head), (size_t)1, fp) != 1) { + warnx("%s: cannot read header", name); + return(1); } - if (read(fd, &head, sizeof(head)) != sizeof(head) || N_BADMAG(head)) { - (void)close(fd); - warnx("%s: not in a.out format", name); - return (1); + + if (N_BADMAG(head)) { + warnx("%s: bad format", name); + return(1); } - (void)close(fd); if (first) { first = 0; @@ -117,9 +286,32 @@ show(count, name) return (0); } +void * +emalloc(size) + size_t size; +{ + char *p; + + /* NOSTRICT */ + if (p = malloc(size)) + return(p); + err(1, NULL); +} + +void * +erealloc(p, size) + void *p; + size_t size; +{ + /* NOSTRICT */ + if (p = realloc(p, size)) + return(p); + err(1, NULL); +} + void usage() { - (void)fprintf(stderr, "usage: size [file ...]\n"); + (void)fprintf(stderr, "usage: size [-w] [file ...]\n"); exit(1); }