/* * 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 #include #include #include #include #include #include #include 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; case N_REG: c = 'r'; 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; nnn_type; } else c = symp[n].nn_type; if (!undef_flg) { if (c=='u' || c=='U') printf(" "); else { if (file_flg) printf(N_FORMAT, tt->n_value); else printf(N_FORMAT, 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; in_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; in_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); }