version 1.19, 2003/06/10 22:20:51 |
version 1.20, 2003/09/30 19:00:14 |
|
|
*/ |
*/ |
|
|
#ifndef lint |
#ifndef lint |
static char copyright[] = |
static const char copyright[] = |
"@(#) Copyright (c) 1988, 1993\n\ |
"@(#) Copyright (c) 1988, 1993\n\ |
The Regents of the University of California. All rights reserved.\n"; |
The Regents of the University of California. All rights reserved.\n"; |
#endif /* not lint */ |
#endif /* not lint */ |
|
|
#if 0 |
#if 0 |
static char sccsid[] = "@(#)size.c 8.2 (Berkeley) 12/9/93"; |
static char sccsid[] = "@(#)size.c 8.2 (Berkeley) 12/9/93"; |
#endif |
#endif |
static char rcsid[] = "$OpenBSD$"; |
static const char rcsid[] = "$OpenBSD$"; |
#endif /* not lint */ |
#endif /* not lint */ |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
#include <sys/file.h> |
#include <sys/file.h> |
|
#include <elf_abi.h> |
#include <a.out.h> |
#include <a.out.h> |
#include <ar.h> |
#include <ar.h> |
#include <ranlib.h> |
#include <ranlib.h> |
|
|
#define MID_MACHINE MID_MACHINE_OVERRIDE |
#define MID_MACHINE MID_MACHINE_OVERRIDE |
#endif |
#endif |
|
|
|
#define STRTABMAG "//" |
|
|
|
union hdr { |
|
struct exec aout; |
|
Elf_Ehdr elf; |
|
}; |
|
|
unsigned long total_text, total_data, total_bss, total_total; |
unsigned long total_text, total_data, total_bss, total_total; |
int ignore_bad_archive_entries = 1; |
int non_object_warning, print_totals; |
int print_totals = 0; |
|
|
|
int process_file(int, char *); |
int process_file(int, char *); |
int show_archive(int, char *, FILE *); |
int show_archive(int, char *, FILE *); |
int show_objfile(int, char *, FILE *); |
int show_file(int, int, char *, FILE *, off_t, union hdr *); |
void usage(void); |
void usage(void); |
|
|
int |
int |
|
|
while ((ch = getopt(argc, argv, "wt")) != -1) |
while ((ch = getopt(argc, argv, "wt")) != -1) |
switch(ch) { |
switch(ch) { |
case 'w': |
case 'w': |
ignore_bad_archive_entries = 0; |
non_object_warning = 1; |
break; |
break; |
case 't': |
case 't': |
print_totals = 1; |
print_totals = 1; |
|
|
int |
int |
process_file(int count, char *fname) |
process_file(int count, char *fname) |
{ |
{ |
struct exec exec_head; |
union hdr exec_head; |
FILE *fp; |
FILE *fp; |
int retval; |
int retval; |
char magic[SARMAG]; |
char magic[SARMAG]; |
|
|
rewind(fp); |
rewind(fp); |
|
|
/* this could be an archive */ |
/* this could be an archive */ |
if (N_BADMAG(exec_head)) { |
if (!IS_ELF(exec_head.elf) && N_BADMAG(exec_head.aout)) { |
if (fread(magic, sizeof(magic), (size_t)1, fp) != 1 || |
if (fread(magic, sizeof(magic), (size_t)1, fp) != 1 || |
strncmp(magic, ARMAG, SARMAG)) { |
strncmp(magic, ARMAG, SARMAG)) { |
warnx("%s: not object file or archive", fname); |
warnx("%s: not object file or archive", fname); |
|
|
} |
} |
retval = show_archive(count, fname, fp); |
retval = show_archive(count, fname, fp); |
} else |
} else |
retval = show_objfile(count, fname, fp); |
retval = show_file(count, 1, fname, fp, 0, &exec_head); |
(void)fclose(fp); |
(void)fclose(fp); |
return(retval); |
return(retval); |
} |
} |
|
|
show_archive(int count, char *fname, FILE *fp) |
show_archive(int count, char *fname, FILE *fp) |
{ |
{ |
struct ar_hdr ar_head; |
struct ar_hdr ar_head; |
struct exec exec_head; |
union hdr exec_head; |
int i, rval; |
int i, rval; |
long last_ar_off; |
off_t last_ar_off, foff; |
char *p, *name; |
char *p, *name, *strtab; |
int baselen, namelen; |
int baselen, namelen; |
|
|
baselen = strlen(fname) + 3; |
baselen = strlen(fname) + 3; |
|
|
err(1, NULL); |
err(1, NULL); |
|
|
rval = 0; |
rval = 0; |
|
strtab = NULL; |
|
|
/* while there are more entries in the archive */ |
/* while there are more entries in the archive */ |
while (fread((char *)&ar_head, sizeof(ar_head), (size_t)1, fp) == 1) { |
while (fread((char *)&ar_head, sizeof(ar_head), (size_t)1, fp) == 1) { |
/* bad archive entry - stop processing this archive */ |
/* bad archive entry - stop processing this archive */ |
if (strncmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) { |
if (strncmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) { |
warnx("%s: bad format archive header", fname); |
warnx("%s: bad format archive header", fname); |
(void)free(name); |
free(name); |
|
free(strtab); |
return(1); |
return(1); |
} |
} |
|
|
/* remember start position of current archive object */ |
/* remember start position of current archive object */ |
last_ar_off = ftell(fp); |
last_ar_off = ftello(fp); |
|
|
/* skip ranlib entries */ |
/* skip ranlib entries */ |
if (!strncmp(ar_head.ar_name, RANLIBMAG, sizeof(RANLIBMAG) - 1)) |
if (!strncmp(ar_head.ar_name, RANLIBMAG, sizeof(RANLIBMAG) - 1)) |
goto skip; |
goto skip; |
|
|
|
/* load the Sys5 long names table */ |
|
if (!strncmp(ar_head.ar_name, STRTABMAG, |
|
sizeof(STRTABMAG) - 1)) { |
|
|
|
i = atol(ar_head.ar_size); |
|
if ((strtab = malloc(i)) == NULL) { |
|
warn("%s: strtab", name); |
|
free(name); |
|
return(1); |
|
} |
|
|
|
if (fread(strtab, i, (size_t)1, fp) != 1) { |
|
warnx("%s: premature EOF", name); |
|
free(strtab); |
|
free(name); |
|
return(1); |
|
} |
|
|
|
for (p = strtab; i--; p++) |
|
if (*p == '\n') |
|
*p = '\0'; |
|
goto skip; |
|
} |
|
|
/* |
/* |
* construct a name of the form "archive.a:obj.o:" for the |
* construct a name of the form "archive.a:obj.o:" for the |
* current archive entry if the object name is to be printed |
* current archive entry if the object name is to be printed |
|
|
snprintf(name, baselen - 1, "%s:", fname); |
snprintf(name, baselen - 1, "%s:", fname); |
p += strlen(name); |
p += strlen(name); |
} |
} |
|
|
|
if (strtab && ar_head.ar_name[0] == '/') { |
|
int len; |
|
|
|
i = atol(&ar_head.ar_name[1]); |
|
len = strlen(&strtab[i]); |
|
if (len > namelen) { |
|
p -= (long)name; |
|
if ((name = realloc(name, baselen+len)) == NULL) |
|
err(1, NULL); |
|
namelen = len; |
|
p += (long)name; |
|
} |
|
strlcpy(p, &strtab[i], len); |
|
p += len; |
|
} else |
#ifdef AR_EFMT1 |
#ifdef AR_EFMT1 |
/* |
/* |
* BSD 4.4 extended AR format: #1/<namelen>, with name as the |
* BSD 4.4 extended AR format: #1/<namelen>, with name as the |
|
|
} |
} |
if (fread(p, len, 1, fp) != 1) { |
if (fread(p, len, 1, fp) != 1) { |
warnx("%s: premature EOF", name); |
warnx("%s: premature EOF", name); |
(void)free(name); |
free(name); |
return(1); |
return(1); |
} |
} |
p += len; |
p += len; |
|
|
for (i = 0; i < sizeof(ar_head.ar_name); ++i) |
for (i = 0; i < sizeof(ar_head.ar_name); ++i) |
if (ar_head.ar_name[i] && ar_head.ar_name[i] != ' ') |
if (ar_head.ar_name[i] && ar_head.ar_name[i] != ' ') |
*p++ = ar_head.ar_name[i]; |
*p++ = ar_head.ar_name[i]; |
*p++ = '\0'; |
*p = '\0'; |
|
if (p[-1] == '/') |
|
*--p = '\0'; |
|
|
|
foff = ftello(fp); |
|
|
/* get and check current object's header */ |
/* get and check current object's header */ |
if (fread((char *)&exec_head, sizeof(exec_head), |
if (fread((char *)&exec_head, sizeof(exec_head), |
(size_t)1, fp) != 1) { |
(size_t)1, fp) != 1) { |
warnx("%s: premature EOF", name); |
warnx("%s: premature EOF", name); |
(void)free(name); |
free(name); |
return(1); |
return(1); |
} |
} |
|
|
if (BAD_OBJECT(exec_head)) { |
rval |= show_file(2, non_object_warning, name, fp, foff, &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 |
* skip to next archive object - it starts at the next |
* even byte boundary |
* even byte boundary |
*/ |
*/ |
#define even(x) (((x) + 1) & ~1) |
#define even(x) (((x) + 1) & ~1) |
skip: if (fseek(fp, last_ar_off + even(atol(ar_head.ar_size)), |
skip: if (fseeko(fp, last_ar_off + even(atol(ar_head.ar_size)), |
SEEK_SET)) { |
SEEK_SET)) { |
warn("%s", fname); |
warn("%s", fname); |
(void)free(name); |
free(name); |
return(1); |
return(1); |
} |
} |
} |
} |
(void)free(name); |
free(name); |
return(rval); |
return(rval); |
} |
} |
|
|
int |
int |
show_objfile(int count, char *name, FILE *fp) |
show_file(int count, int warn_fmt, char *name, FILE *fp, off_t foff, union hdr *head) |
{ |
{ |
static int first = 1; |
static int first = 1; |
struct exec head; |
Elf_Shdr *shdr; |
u_long total; |
u_long text, data, bss, total; |
|
int i; |
|
|
if (fread((char *)&head, sizeof(head), (size_t)1, fp) != 1) { |
if (IS_ELF(head->elf) && |
warnx("%s: cannot read header", name); |
head->elf.e_ident[EI_CLASS] == ELF_TARG_CLASS && |
return(1); |
head->elf.e_ident[EI_DATA] == ELF_TARG_DATA && |
} |
head->elf.e_ident[EI_VERSION] == ELF_TARG_VER && |
|
head->elf.e_machine == ELF_TARG_MACH && |
|
head->elf.e_version == ELF_TARG_VER) { |
|
|
if (BAD_OBJECT(head)) { |
if ((shdr = malloc(head->elf.e_shentsize * |
warnx("%s: bad format", name); |
head->elf.e_shnum)) == NULL) { |
return(1); |
warn("%s: malloc shdr", name); |
} |
return (1); |
|
} |
|
|
fix_header_order(&head); |
if (fseeko(fp, foff + head->elf.e_shoff, SEEK_SET)) { |
|
warn("%s: fseeko", name); |
|
free(shdr); |
|
return (1); |
|
} |
|
|
|
if (fread(shdr, head->elf.e_shentsize, head->elf.e_shnum, |
|
fp) != head->elf.e_shnum) { |
|
warnx("%s: premature EOF", name); |
|
free(shdr); |
|
return(1); |
|
} |
|
|
|
text = data = bss = 0; |
|
for (i = 0; i < head->elf.e_shnum; i++) { |
|
if (!(shdr[i].sh_flags & SHF_ALLOC)) |
|
; |
|
else if (shdr[i].sh_flags & SHF_EXECINSTR || |
|
!(shdr[i].sh_flags & SHF_WRITE)) |
|
text += shdr[i].sh_size; |
|
else if (shdr[i].sh_type == SHT_NOBITS) |
|
bss += shdr[i].sh_size; |
|
else |
|
data += shdr[i].sh_size; |
|
} |
|
free(shdr); |
|
|
|
} else if (BAD_OBJECT(head->aout)) { |
|
if (warn_fmt) |
|
warnx("%s: bad format", name); |
|
return (1); |
|
} else { |
|
fix_header_order(&head->aout); |
|
|
|
text = head->aout.a_text; |
|
data = head->aout.a_data; |
|
bss = head->aout.a_bss; |
|
} |
|
|
if (first) { |
if (first) { |
first = 0; |
first = 0; |
(void)printf("text\tdata\tbss\tdec\thex\n"); |
(void)printf("text\tdata\tbss\tdec\thex\n"); |
} |
} |
total = head.a_text + head.a_data + head.a_bss; |
|
(void)printf("%lu\t%lu\t%lu\t%lu\t%lx", (unsigned long)head.a_text, |
total = text + data + bss; |
(unsigned long)head.a_data, (unsigned long)head.a_bss, total, total); |
(void)printf("%lu\t%lu\t%lu\t%lu\t%lx", text, data, bss, total, total); |
if (count > 1) |
if (count > 1) |
(void)printf("\t%s", name); |
(void)printf("\t%s", name); |
|
|
total_text += head.a_text; |
total_text += text; |
total_data += head.a_data; |
total_data += data; |
total_bss += head.a_bss; |
total_bss += bss; |
total_total += total; |
total_total += total; |
|
|
(void)printf("\n"); |
(void)printf("\n"); |