Subject: bin/497: size(1) doesn't know about archive libraries
To: None <gnats-admin@sun-lamp.cs.berkeley.edu>
From: None <thomas@mathematik.uni-Bremen.de>
List: netbsd-bugs
Date: 09/25/1994 09:05:04
>Number: 497
>Category: bin
>Synopsis: size(1) doesn't know about archive libraries
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: gnats-admin (Utility Bug People)
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Sun Sep 25 09:05:03 1994
>Originator: Thomas Eberhardt
>Organization:
CeVis, University of Bremen, Germany
>Release:
>Environment:
System: NetBSD ed209 1.0_BETA NetBSD 1.0_BETA (ED209) #1: Sun Sep 25 13:33:28 MET 1994 root@:/usr/src/sys/arch/i386/compile/ED209 i386
Machine: i386
>Description:
size(1) isn't able to handle archive libraries. Since nm(1) knows
about them size(1) should also IMHO.
>How-To-Repeat:
>Fix:
The code to handle archives in the following patch is extracted from the
nm(1) sources.
*** usr.bin/size/size.1- Fri Jan 14 11:25:46 1994
--- usr.bin/size/size.1 Sun Sep 25 16:49:47 1994
***************
*** 40,58 ****
.Nd display object file segment sizes (text, data and bss)
.Sh SYNOPSIS
.Nm size
! .Op Ar object_file ...
.Sh DESCRIPTION
.Nm Size
displays the text, data and bss segment sizes of the specified
! .Ar object_file
in bytes (in decimal), and the sum of the three segments (in
decimal and hexadecimal).
If no
! .Ar object_file
is specified
.Nm
attempts to report on the file
.Pa a.out .
.Sh SEE ALSO
.Xr a.out 5
.Sh HISTORY
--- 40,70 ----
.Nd display object file segment sizes (text, data and bss)
.Sh SYNOPSIS
.Nm size
! .Op Fl w
! .Ar
.Sh DESCRIPTION
.Nm Size
displays the text, data and bss segment sizes of the specified
! .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 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
*** usr.bin/size/size.c- Fri Dec 17 08:17:43 1993
--- usr.bin/size/size.c Sun Sep 25 16:48:53 1994
***************
*** 46,59 ****
#include <sys/file.h>
#include <errno.h>
#include <a.out.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
! void err __P((const char *, ...));
! int show __P((int, char *));
! void usage __P((void));
int
main(argc, argv)
--- 46,67 ----
#include <sys/file.h>
#include <errno.h>
#include <a.out.h>
+ #include <ar.h>
+ #include <ranlib.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+ #include <err.h>
! int ignore_bad_archive_entries = 1;
!
! int process_file __P((int, char *));
! int show_archive __P((int, char *, FILE *));
! int show_objfile __P((int, char *, FILE *));
! void *emalloc __P((size_t));
! void *erealloc __P((void *, size_t));
! void usage __P((void));
int
main(argc, argv)
***************
*** 62,69 ****
{
int ch, eval;
! while ((ch = getopt(argc, argv, "")) != EOF)
switch(ch) {
case '?':
default:
usage();
--- 70,80 ----
{
int ch, eval;
! while ((ch = getopt(argc, argv, "w")) != EOF)
switch(ch) {
+ case 'w':
+ ignore_bad_archive_entries = 0;
+ break;
case '?':
default:
usage();
***************
*** 74,106 ****
eval = 0;
if (*argv)
do {
! eval |= show(argc, *argv);
} while (*++argv);
else
! eval |= show(1, "a.out");
exit(eval);
}
int
! show(count, name)
int count;
! char *name;
{
static int first = 1;
struct exec head;
u_long total;
- int fd;
! if ((fd = open(name, O_RDONLY, 0)) < 0) {
! err("%s: %s", name, strerror(errno));
! return (1);
! }
! if (read(fd, &head, sizeof(head)) != sizeof(head) || N_BADMAG(head)) {
! err("%s: not in a.out format", name);
! (void)close(fd);
! return (1);
}
- (void)close(fd);
if (first) {
first = 0;
--- 85,282 ----
eval = 0;
if (*argv)
do {
! eval |= process_file(argc, *argv);
} while (*++argv);
else
! eval |= process_file(1, "a.out");
exit(eval);
}
+ /*
+ * process_file()
+ * show segment sizes in the file given as an argument. Accepts archive
+ * and object files as input.
+ */
+ int
+ 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 segment sizes 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 we were invoked with more than one
! * file argument
! */
! p = name;
! if (count > 1)
! p += sprintf(p, "%s:", fname);
! #ifdef AR_EFMT1
! /*
! * BSD 4.4 extended AR format: #1/<namelen>, with name as the
! * first <namelen> 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 -= (int)name;
! name = (char *)erealloc(name, baselen+len);
! namelen = len;
! p += (int)name;
! }
! if (fread(p, len, 1, fp) != 1) {
! warnx("%s: premature EOF", 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);
! }
!
! /*
! * show_objfile()
! * show segment sizes from the object file pointed to by fp. The current
! * file pointer for fp is expected to be at the beginning of an a.out
! * header.
! */
! int
! show_objfile(count, objname, fp)
! int count;
! char *objname;
! FILE *fp;
{
static int first = 1;
struct exec head;
u_long total;
! /* read a.out header */
! if (fread((char *)&head, sizeof(head), (size_t)1, fp) != 1) {
! warnx("%s: cannot read header", objname);
! return(1);
! }
!
! /* stop if this is no valid object file */
! if (N_BADMAG(head)) {
! warnx("%s: bad format", objname);
! return(1);
}
if (first) {
first = 0;
***************
*** 110,150 ****
(void)printf("%lu\t%lu\t%lu\t%lu\t%lx", head.a_text, head.a_data,
head.a_bss, total, total);
if (count > 1)
! (void)printf("\t%s", name);
(void)printf("\n");
return (0);
}
! void
! usage()
{
! (void)fprintf(stderr, "usage: size [file ...]\n");
! exit(1);
}
! #if __STDC__
! #include <stdarg.h>
! #else
! #include <varargs.h>
! #endif
void
! #if __STDC__
! err(const char *fmt, ...)
! #else
! err(fmt, va_alist)
! char *fmt;
! va_dcl
! #endif
{
! va_list ap;
! #if __STDC__
! va_start(ap, fmt);
! #else
! va_start(ap);
! #endif
! (void)fprintf(stderr, "size: ");
! (void)vfprintf(stderr, fmt, ap);
! va_end(ap);
! (void)fprintf(stderr, "\n");
}
--- 286,324 ----
(void)printf("%lu\t%lu\t%lu\t%lu\t%lx", head.a_text, head.a_data,
head.a_bss, total, total);
if (count > 1)
! (void)printf("\t%s", objname);
(void)printf("\n");
return (0);
}
! void *
! emalloc(size)
! size_t size;
{
! char *p;
!
! /* NOSTRICT */
! if (p = malloc(size))
! return(p);
! err(1, NULL);
! /* NOTREACHED */
}
! void *
! erealloc(p, size)
! void *p;
! size_t size;
! {
! /* NOSTRICT */
! if (p = realloc(p, size))
! return(p);
! err(1, NULL);
! /* NOTREACHED */
! }
void
! usage()
{
! (void)fprintf(stderr, "usage: size [-w] [file ...]\n");
! exit(1);
}
>Audit-Trail:
>Unformatted: