431 lines
11 KiB
Plaintext
431 lines
11 KiB
Plaintext
/*
|
|
* This version of nm will use a disk file, rather than trying to store
|
|
* the entire symbol table in memory. Useful for some sites.
|
|
*
|
|
* 11/25/90 - The ASCII version of archives has been implemented, but this
|
|
* program was NOT updated. the normal version of 'nm' not only handles
|
|
* .a files correctly but can even process /unix. so this program is of even
|
|
* less value than before, this program is extremely slow even for cases
|
|
* which the regular 'nm' works well.
|
|
*/
|
|
|
|
/*
|
|
* print symbol tables for
|
|
* object or archive files
|
|
*
|
|
* nm [-fgoprun] [name ...]
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <ar.h>
|
|
#include <a.out.h>
|
|
#include <stdio.h>
|
|
#include <signal.h>
|
|
#include <ctype.h>
|
|
#include <fcntl.h>
|
|
#include <sys/file.h>
|
|
|
|
struct nnlist { /* symbol table entry */
|
|
char n_name[8]; /* symbol name */
|
|
char nn_type; /* type flag */
|
|
char nn_ovno;
|
|
unsigned int n_value; /* value */
|
|
};
|
|
#define SYMFILE "/tmp/nm.sym.XXXXXX"
|
|
#define SELECT arch_flg ? arp.ar_name : *argv
|
|
int numsort_flg;
|
|
int undef_flg;
|
|
int revsort_flg = 1;
|
|
int globl_flg;
|
|
int nosort_flg;
|
|
int arch_flg;
|
|
int prep_flg;
|
|
int file_flg;
|
|
struct ar_hdr arp;
|
|
struct exec exp;
|
|
FILE *fi;
|
|
long off;
|
|
long ftell();
|
|
char *malloc();
|
|
char *realloc();
|
|
char *mktemp();
|
|
int symfile = -1;
|
|
char *symfname;
|
|
long lseek();
|
|
long save_sym();
|
|
struct nnlist *get_sym();
|
|
int cleanup();
|
|
|
|
main(argc, argv)
|
|
char **argv;
|
|
{
|
|
int narg;
|
|
int compare();
|
|
int fcompare();
|
|
|
|
signal(SIGINT,cleanup);
|
|
signal(SIGHUP,cleanup);
|
|
signal(SIGTERM,cleanup);
|
|
signal(SIGQUIT,cleanup);
|
|
|
|
if (--argc>0 && argv[1][0]=='-' && argv[1][1]!=0) {
|
|
argv++;
|
|
while (*++*argv) switch (**argv) {
|
|
case 'n': /* sort numerically */
|
|
numsort_flg++;
|
|
continue;
|
|
|
|
case 'g': /* globl symbols only */
|
|
globl_flg++;
|
|
continue;
|
|
|
|
case 'u': /* undefined symbols only */
|
|
undef_flg++;
|
|
continue;
|
|
|
|
case 'r': /* sort in reverse order */
|
|
revsort_flg = -1;
|
|
continue;
|
|
|
|
case 'p': /* don't sort -- symbol table order */
|
|
nosort_flg++;
|
|
continue;
|
|
|
|
case 'o': /* prepend a name to each line */
|
|
prep_flg++;
|
|
continue;
|
|
|
|
case 'f': /* use a file insted of memory - slow */
|
|
file_flg++;
|
|
continue;
|
|
|
|
default: /* oops */
|
|
fprintf(stderr, "nm: invalid argument -%c\n", *argv[0]);
|
|
cleanup(1);
|
|
}
|
|
argc--;
|
|
}
|
|
if (argc == 0) {
|
|
argc = 1;
|
|
argv[1] = "a.out";
|
|
}
|
|
narg = argc;
|
|
while(argc--) {
|
|
fi = fopen(*++argv,"r");
|
|
if (fi == NULL) {
|
|
fprintf(stderr, "nm: cannot open %s\n", *argv);
|
|
continue;
|
|
}
|
|
off = sizeof(exp.a_magic);
|
|
fread((char *)&exp, 1, sizeof(exp.a_magic), fi); /* get magic no. */
|
|
if (exp.a_magic == ARMAG)
|
|
arch_flg++;
|
|
else if (N_BADMAG(exp)) {
|
|
fprintf(stderr, "nm: %s-- bad format\n", *argv);
|
|
continue;
|
|
}
|
|
fseek(fi, 0L, L_SET);
|
|
if (arch_flg) {
|
|
(void) nextel(fi);
|
|
if (narg > 1)
|
|
printf("\n%s:\n", *argv);
|
|
}
|
|
do {
|
|
long o;
|
|
register i, n, c;
|
|
struct nnlist sym;
|
|
struct nnlist *symp = NULL;
|
|
long *idxsymfile = NULL;
|
|
unsigned ovsizes[1 + NOVL];
|
|
|
|
fread((char *)&exp, 1, sizeof(struct exec), fi);
|
|
if (N_BADMAG(exp)) /* archive element not in */
|
|
continue; /* proper format - skip it */
|
|
if (exp.a_magic == A_MAGIC5 || exp.a_magic == A_MAGIC6) {
|
|
fread((char *)ovsizes, 1, sizeof ovsizes, fi);
|
|
o = 0L;
|
|
for (i = 1; i <= NOVL; i++)
|
|
o += (long) ovsizes[i];
|
|
fseek(fi, o, L_INCR);
|
|
}
|
|
o = (long)exp.a_text + exp.a_data;
|
|
if ((exp.a_flag & 01) == 0)
|
|
o *= 2;
|
|
fseek(fi, o, L_INCR);
|
|
if (file_flg)
|
|
set_sym();
|
|
i = 0;
|
|
while (fread((char *)&sym, sizeof(sym), 1, fi) == 1) {
|
|
if (globl_flg && (sym.nn_type&N_EXT)==0)
|
|
continue;
|
|
switch (sym.nn_type&N_TYPE) {
|
|
case N_UNDF:
|
|
c = 'u';
|
|
if (sym.n_value)
|
|
c = 'c';
|
|
break;
|
|
|
|
default:
|
|
case N_ABS:
|
|
c = 'a';
|
|
break;
|
|
|
|
case N_TEXT:
|
|
c = 't';
|
|
break;
|
|
|
|
case N_DATA:
|
|
c = 'd';
|
|
break;
|
|
|
|
case N_BSS:
|
|
c = 'b';
|
|
break;
|
|
|
|
case N_FN:
|
|
c = 'f';
|
|
break;
|
|
}
|
|
if (undef_flg && c!='u')
|
|
continue;
|
|
if (sym.nn_type&N_EXT)
|
|
c = toupper(c);
|
|
sym.nn_type = c;
|
|
if (file_flg) {
|
|
if (idxsymfile==NULL)
|
|
idxsymfile = (long *)malloc(sizeof(long));
|
|
else
|
|
idxsymfile = (long *)realloc(idxsymfile, (i+1)*sizeof(long));
|
|
} else {
|
|
if (symp==NULL)
|
|
symp = (struct nnlist *)malloc(sizeof(struct nnlist));
|
|
else
|
|
symp = (struct nnlist *)realloc(symp, (i+1)*sizeof(struct nnlist));
|
|
}
|
|
if (file_flg) {
|
|
if (idxsymfile == NULL) {
|
|
fprintf(stderr, "nm: out of memory on %s\n", *argv);
|
|
cleanup(2);
|
|
}
|
|
} else {
|
|
if (symp == NULL) {
|
|
fprintf(stderr, "nm: try using the '-f' option.\n");
|
|
cleanup(2);
|
|
}
|
|
}
|
|
if (file_flg)
|
|
idxsymfile[i++] = save_sym(&sym);
|
|
else
|
|
symp[i++] = sym;
|
|
}
|
|
if (i == 0) {
|
|
fprintf(stderr, "nm: %s-- no name list\n", SELECT);
|
|
continue;
|
|
}
|
|
if (nosort_flg==0)
|
|
if (file_flg)
|
|
qsort(idxsymfile, i, sizeof(long), fcompare);
|
|
else
|
|
qsort(symp, i, sizeof(struct nnlist), compare);
|
|
if ((arch_flg || narg>1) && prep_flg==0)
|
|
printf("\n%s:\n", SELECT);
|
|
for (n=0; n<i; n++) {
|
|
struct nnlist *tt;
|
|
if (prep_flg) {
|
|
if (arch_flg)
|
|
printf("%s:", *argv);
|
|
printf("%s:", SELECT);
|
|
}
|
|
if (file_flg) {
|
|
tt = get_sym(idxsymfile[n]);
|
|
c = tt->nn_type;
|
|
} else
|
|
c = symp[n].nn_type;
|
|
if (!undef_flg) {
|
|
if (c=='u' || c=='U')
|
|
printf(" ");
|
|
else {
|
|
if (file_flg)
|
|
printf("%08x", tt->n_value);
|
|
else
|
|
printf("%08x", symp[n].n_value);
|
|
}
|
|
printf(" %c ", c);
|
|
}
|
|
if (file_flg) {
|
|
if (tt->nn_ovno)
|
|
printf("%-8.8s %d", tt->n_name,
|
|
tt->nn_ovno);
|
|
else
|
|
printf("%.8s", tt->n_name);
|
|
} else {
|
|
if (symp[n].nn_ovno)
|
|
printf("%-8.8s %d", symp[n].n_name,
|
|
symp[n].nn_ovno);
|
|
else
|
|
printf("%.8s", symp[n].n_name);
|
|
}
|
|
printf("\n");
|
|
if (file_flg)
|
|
free(tt);
|
|
}
|
|
if (file_flg)
|
|
if (idxsymfile)
|
|
free((char *)idxsymfile);
|
|
else
|
|
if (symp)
|
|
free((char *)symp);
|
|
} while(arch_flg && nextel(fi));
|
|
fclose(fi);
|
|
}
|
|
cleanup(0);
|
|
}
|
|
|
|
compare(p1, p2)
|
|
register struct nnlist *p1, *p2;
|
|
{
|
|
register i;
|
|
|
|
if (numsort_flg) {
|
|
if (p1->n_value > p2->n_value)
|
|
return(revsort_flg);
|
|
if (p1->n_value < p2->n_value)
|
|
return(-revsort_flg);
|
|
}
|
|
for(i=0; i<sizeof(p1->n_name); i++)
|
|
if (p1->n_name[i] != p2->n_name[i]) {
|
|
if (p1->n_name[i] > p2->n_name[i])
|
|
return(revsort_flg);
|
|
else
|
|
return(-revsort_flg);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
nextel(af)
|
|
register FILE *af;
|
|
{
|
|
register r;
|
|
|
|
fseek(af, off, L_SET);
|
|
r = fread((char *)&arp, 1, sizeof(struct ar_hdr), af); /* read archive header */
|
|
if (r <= 0)
|
|
return(0);
|
|
if (arp.ar_size & 1)
|
|
++arp.ar_size;
|
|
off = ftell(af) + arp.ar_size; /* offset to next element */
|
|
return(1);
|
|
}
|
|
|
|
fcompare(fi1, fi2)
|
|
register long *fi1, *fi2;
|
|
{
|
|
register i;
|
|
register struct nnlist *p1, *p2;
|
|
|
|
p1 = get_sym(*fi1);
|
|
p2 = get_sym(*fi2);
|
|
if (numsort_flg) {
|
|
if (p1->n_value > p2->n_value) {
|
|
free((char *)p1);
|
|
free((char *)p2);
|
|
return(revsort_flg);
|
|
}
|
|
if (p1->n_value < p2->n_value) {
|
|
free((char *)p1);
|
|
free((char *)p2);
|
|
return(-revsort_flg);
|
|
}
|
|
}
|
|
for(i=0; i<sizeof(p1->n_name); i++)
|
|
if (p1->n_name[i] != p2->n_name[i]) {
|
|
if (p1->n_name[i] > p2->n_name[i]) {
|
|
free((char *)p1);
|
|
free((char *)p2);
|
|
return(revsort_flg);
|
|
} else {
|
|
free((char *)p1);
|
|
free((char *)p2);
|
|
return(-revsort_flg);
|
|
}
|
|
}
|
|
free((char *)p1);
|
|
free((char *)p2);
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* Save a symbol in symfile
|
|
*/
|
|
|
|
long
|
|
save_sym(sym)
|
|
struct nlist *sym;
|
|
{
|
|
long ret_val;
|
|
|
|
if ((ret_val = lseek(symfile,0L,L_INCR)) < 0) {
|
|
perror("lseek:save_sym");
|
|
cleanup(1);
|
|
}
|
|
|
|
if (write(symfile,sym,sizeof(struct nlist)) < 0) {
|
|
perror("write:save_sym");
|
|
cleanup(1);
|
|
}
|
|
return(ret_val);
|
|
}
|
|
|
|
/*
|
|
* Retrieve a symbol from symfile
|
|
*/
|
|
|
|
struct nnlist *
|
|
get_sym(offset)
|
|
long offset;
|
|
{
|
|
struct nnlist *temp;
|
|
|
|
if(lseek(symfile,offset,L_SET) < 0) {
|
|
perror("lseek:get_sym");
|
|
cleanup(1);
|
|
}
|
|
|
|
temp = (struct nnlist *) malloc(sizeof(struct nnlist));
|
|
if(read(symfile,temp,sizeof(struct nnlist)) != sizeof (struct nnlist)) {
|
|
perror("read:get_sym");
|
|
cleanup(1);
|
|
}
|
|
|
|
return(temp);
|
|
}
|
|
|
|
/*
|
|
* Open The symfile
|
|
*/
|
|
|
|
set_sym()
|
|
{
|
|
if (symfile != -1)
|
|
close(symfile);
|
|
else
|
|
symfname = mktemp(SYMFILE);
|
|
if ((symfile = open(symfname,O_CREAT|O_RDWR|O_TRUNC,0666)) < 0) {
|
|
perror("open:symfile");
|
|
cleanup(1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Cleanup Routine
|
|
*/
|
|
|
|
int
|
|
cleanup(n)
|
|
int n;
|
|
{
|
|
if (file_flg)
|
|
unlink(symfname);
|
|
exit(n);
|
|
}
|