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: