V9/jerq/sgs/3nm.c
#include <sys/types.h>
#include <stdio.h>
#include <ctype.h>
#include <sys/stat.h>
#include "filehdr.h"
#include "aouthdr.h"
#include "scnhdr.h"
#include "storclass.h"
#include "syms.h"
/* global */
int nflg, gflg, uflg, rflg, pflg, oflg, aflg;
#define SYMINC(sp,n) (struct syment *)(((u_int)sp)+(n)*SYMESZ)
#define AUXINC(ap,n) (struct auxent *)(((u_int)ap)+(n)*SYMESZ)
char section[256]; /* section types ('T', 'D', 'B', or '?') */
struct symbol {
char *name;
u_long value;
char sclass;
};
/* predeclared */
struct symbol *dosymtab();
char *dofile();
char *namelist();
main(argc, argv)
char **argv;
{
int errs;
char *rv;
int printname;
rflg = 1;
if (--argc>0 && argv[1][0]=='-' && argv[1][1]!=0) {
argv++;
while (*++*argv) switch (**argv) {
case 'n':
nflg = 1;
continue;
case 'g':
gflg = 1;
continue;
case 'u':
uflg = 1;
continue;
case 'r':
rflg = -1;
continue;
case 'p':
pflg = 1;
continue;
case 'o':
oflg = 1;
continue;
case 'a':
aflg = 1;
continue;
default:
fprintf(stderr, "nm: invalid argument -%c\n",
*argv[0]);
exit(2);
}
argc--;
}
if (argc == 0) {
argc = 1;
argv[1] = "a.out";
}
printname = argc > 1 && !oflg;
while (argc--) {
if (printname)
printf("%s:\n", argv[1]);
if ((rv = dofile(argv[1])) != NULL) {
errs++;
fprintf(stderr, "nm: %s (%s)\n", rv, argv[1]);
}
argv++;
}
exit(errs);
}
char *
dofile(file)
char *file;
{
int fd;
char *rv;
if ((fd = open(file, 0)) < 0)
return "can't open";
rv = namelist(file, fd);
close(fd);
return rv;
}
char *
namelist(file, fd)
char *file;
int fd;
{
struct filehdr fh;
struct aouthdr ah;
struct syment *syms;
struct symbol *symtab;
struct scnhdr sh;
char *strings;
struct stat sbuf;
unsigned int nel, i, size;
/* get file length */
if (fstat(fd, &sbuf) < 0)
return "problem stating";
/* get file header and a.out header */
if (read(fd, &fh, sizeof(fh)) != sizeof(fh))
return "problem reading";
if (read(fd, &ah, sizeof(ah)) != sizeof(ah))
return "error reading a.out header";
if (fh.f_magic != FBOMAGIC)
return "bad magic";
/* read and classify section headers */
for (i = 1; i <= fh.f_nscns; i++) {
if (read(fd, &sh, sizeof(sh)) != sizeof(sh))
return "error reading section header";
if (strncmp(sh.s_name, _TEXT, sizeof(sh.s_name)) == 0)
section[i] = 'T';
else if (strncmp(sh.s_name, _DATA, sizeof(sh.s_name)) == 0)
section[i] = 'D';
else if (strncmp(sh.s_name, _BSS, sizeof(sh.s_name)) == 0)
section[i] = 'B';
else
section[i] = 'O';
}
/* read in the symbols */
size = fh.f_nsyms*SYMESZ;
if (lseek(fd, fh.f_symptr, 0) < 0)
return "problem seeking ";
syms = (struct syment *)malloc(size);
if (syms == NULL)
return "not enough memory";
if (read(fd, syms, size) != size) {
free(syms);
return "problem reading";
}
/* read in string table */
size = sbuf.st_size - size - fh.f_symptr;
strings = (char *)malloc(size);
if (strings == NULL) {
free(syms);
return "not enough memory";
}
if (read(fd, strings, size) != size) {
free(syms); free(strings);
return "problem reading";
}
/* create symbol table */
symtab = dosymtab(syms, strings, fh.f_nsyms, &nel);
if (symtab == NULL) {
free(syms); free(strings);
return "not enough memory";
}
/* sort it */
if (!pflg) {
int ncompare(), scompare();
if (nflg)
qsort(symtab, nel, sizeof(struct symbol), ncompare);
else
qsort(symtab, nel, sizeof(struct symbol), scompare);
}
/* print out symbols */
doprint(file, symtab, nel);
free(syms);
free(strings);
free(symtab);
return NULL;
}
struct symbol *
dosymtab(syms, strings, nsyms, np)
struct syment *syms;
char *strings;
unsigned int nsyms;
unsigned int *np;
{
struct symbol *symtab, *stp;
struct syment *sp;
int nel=0;
/* build table */
stp = symtab = (struct symbol *)malloc(nsyms*sizeof(struct symbol));
if (symtab == NULL)
return NULL;
for (sp = syms; sp < SYMINC(syms,nsyms); sp=SYMINC(sp, sp->n_numaux+1)) {
switch(sp->n_sclass) {
case C_REG: case C_REGPARM:
if (!aflg || uflg || gflg) continue;
stp->sclass = 'r';
break;
case C_AUTO: case C_MOS: case C_ARG:
case C_MOU: case C_MOE: case C_FIELD:
if (!aflg || uflg || gflg) continue;
stp->sclass = 'a';
break;
case C_EXT:
stp->sclass = class(sp);
if (uflg && stp->sclass != 'U') continue;
break;
case C_STAT: case C_HIDDEN:
if (uflg || gflg) continue;
stp->sclass = tolower(class(sp));
break;
case C_USTATIC:
if (!aflg || gflg) continue;
stp->sclass = 'u';
break;
case C_LABEL: case C_BLOCK: case C_FCN:
if (!aflg || uflg || gflg) continue;
stp->sclass = tolower(class(*symtab));
break;
case C_ULABEL:
if ((!aflg && !uflg) || gflg) continue;
stp->sclass = 'u';
break;
case C_EXTDEF:
if (uflg) continue;
stp->sclass = class(*symtab);
break;
case C_NULL: case C_STRTAG:
case C_UNTAG: case C_TPDEF: case C_ENTAG: case C_EOS:
if (!aflg || uflg || gflg) continue;
stp->sclass = 'a';
break;
case C_FILE:
if (uflg) continue;
stp->sclass = 'f';
if (sp->n_numaux > 0) {
struct auxent *ap;
ap = AUXINC(sp, 1);
stp->name = ap->x_file.x_fname;
ap->x_file.x_fname[sizeof(ap->x_file.x_fname)] = 0;
}
break;
default:
continue;
}
stp->value = sp->n_value;
if (stp->sclass != 'f') {
if (sp->n_zeroes == 0) {
/* long name */
stp->name = strings + sp->n_offset;
} else {
/* short name */
stp->name = sp->n_name;
sp->n_name[sizeof(sp->n_name)] = '\0';
}
if (*(stp->name) == '.') continue;
}
stp++;
}
*np = stp - symtab;
return symtab;
}
ncompare(s1, s2)
struct symbol *s1, *s2;
{
return rflg*(s1->value - s2->value);
}
scompare(s1, s2)
struct symbol *s1, *s2;
{
return rflg*strcmp(s1->name, s2->name);
}
class(sp)
struct syment *sp;
{
if (sp->n_scnum == 0) {
if (sp->n_value == 0)
return 'U';
else
return 'C';
}else if (sp->n_scnum == -1)
return 'A';
return section[sp->n_scnum];
}
doprint(file, sp, nel)
char *file;
struct symbol *sp;
int nel;
{
while (nel-- > 0) {
if (oflg)
printf("%s:%08x %c %s\n", file, sp->value, sp->sclass,
sp->name);
else
printf("%08x %c %s\n", sp->value, sp->sclass, sp->name);
sp++;
}
}