V9/jerq/sgs/3nm.c

Compare this file to the similar file:
Show the results in this format:

#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++;
	}
}