123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 |
- /*
- * nm.c -- drive nm
- */
- #include <u.h>
- #include <libc.h>
- #include <ar.h>
- #include <bio.h>
- #include <mach.h>
- enum{
- CHUNK = 256 /* must be power of 2 */
- };
- char *errs; /* exit status */
- char *filename; /* current file */
- char symname[]="__.SYMDEF"; /* table of contents file name */
- int multifile; /* processing multiple files */
- int aflag;
- int gflag;
- int hflag;
- int nflag;
- int sflag;
- int uflag;
- int Tflag;
- Sym **fnames; /* file path translation table */
- Sym **symptr;
- int nsym;
- Biobuf bout;
- int cmp(void*, void*);
- void error(char*, ...);
- void execsyms(int);
- void psym(Sym*, void*);
- void printsyms(Sym**, long);
- void doar(Biobuf*);
- void dofile(Biobuf*);
- void zenter(Sym*);
- void
- usage(void)
- {
- fprint(2, "usage: nm [-aghnsTu] file ...\n");
- exits("usage");
- }
- void
- main(int argc, char *argv[])
- {
- int i;
- Biobuf *bin;
- Binit(&bout, 1, OWRITE);
- argv0 = argv[0];
- ARGBEGIN {
- default: usage();
- case 'a': aflag = 1; break;
- case 'g': gflag = 1; break;
- case 'h': hflag = 1; break;
- case 'n': nflag = 1; break;
- case 's': sflag = 1; break;
- case 'u': uflag = 1; break;
- case 'T': Tflag = 1; break;
- } ARGEND
- if (argc == 0)
- usage();
- if (argc > 1)
- multifile++;
- for(i=0; i<argc; i++){
- filename = argv[i];
- bin = Bopen(filename, OREAD);
- if(bin == 0){
- error("cannot open %s", filename);
- continue;
- }
- if (isar(bin))
- doar(bin);
- else{
- Bseek(bin, 0, 0);
- dofile(bin);
- }
- Bterm(bin);
- }
- exits(errs);
- }
- /*
- * read an archive file,
- * processing the symbols for each intermediate file in it.
- */
- void
- doar(Biobuf *bp)
- {
- int offset, size, obj;
- char membername[SARNAME];
- multifile = 1;
- for (offset = Boffset(bp);;offset += size) {
- size = nextar(bp, offset, membername);
- if (size < 0) {
- error("phase error on ar header %ld", offset);
- return;
- }
- if (size == 0)
- return;
- if (strcmp(membername, symname) == 0)
- continue;
- obj = objtype(bp, 0);
- if (obj < 0) {
- error("inconsistent file %s in %s",
- membername, filename);
- return;
- }
- if (!readar(bp, obj, offset+size, 1)) {
- error("invalid symbol reference in file %s",
- membername);
- return;
- }
- filename = membername;
- nsym=0;
- objtraverse(psym, 0);
- printsyms(symptr, nsym);
- }
- }
- /*
- * process symbols in a file
- */
- void
- dofile(Biobuf *bp)
- {
- int obj;
- obj = objtype(bp, 0);
- if (obj < 0)
- execsyms(Bfildes(bp));
- else
- if (readobj(bp, obj)) {
- nsym = 0;
- objtraverse(psym, 0);
- printsyms(symptr, nsym);
- }
- }
- /*
- * comparison routine for sorting the symbol table
- * this screws up on 'z' records when aflag == 1
- */
- int
- cmp(void *vs, void *vt)
- {
- Sym **s, **t;
- s = vs;
- t = vt;
- if(nflag)
- if((*s)->value < (*t)->value)
- return -1;
- else
- return (*s)->value > (*t)->value;
- return strcmp((*s)->name, (*t)->name);
- }
- /*
- * enter a symbol in the table of filename elements
- */
- void
- zenter(Sym *s)
- {
- static int maxf = 0;
- if (s->value > maxf) {
- maxf = (s->value+CHUNK-1) &~ (CHUNK-1);
- fnames = realloc(fnames, (maxf+1)*sizeof(*fnames));
- if(fnames == 0) {
- error("out of memory", argv0);
- exits("memory");
- }
- }
- fnames[s->value] = s;
- }
- /*
- * get the symbol table from an executable file, if it has one
- */
- void
- execsyms(int fd)
- {
- Fhdr f;
- Sym *s;
- long n;
- seek(fd, 0, 0);
- if (crackhdr(fd, &f) == 0) {
- error("Can't read header for %s", filename);
- return;
- }
- if (syminit(fd, &f) < 0)
- return;
- s = symbase(&n);
- nsym = 0;
- while(n--)
- psym(s++, 0);
- printsyms(symptr, nsym);
- }
- void
- psym(Sym *s, void* p)
- {
- USED(p);
- switch(s->type) {
- case 'T':
- case 'L':
- case 'D':
- case 'B':
- if (uflag)
- return;
- if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
- return;
- break;
- case 'b':
- case 'd':
- case 'l':
- case 't':
- if (uflag || gflag)
- return;
- if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
- return;
- break;
- case 'U':
- if (gflag)
- return;
- break;
- case 'Z':
- if (!aflag)
- return;
- break;
- case 'm':
- case 'f': /* we only see a 'z' when the following is true*/
- if(!aflag || uflag || gflag)
- return;
- if (strcmp(s->name, ".frame"))
- zenter(s);
- break;
- case 'a':
- case 'p':
- case 'z':
- default:
- if(!aflag || uflag || gflag)
- return;
- break;
- }
- symptr = realloc(symptr, (nsym+1)*sizeof(Sym*));
- if (symptr == 0) {
- error("out of memory");
- exits("memory");
- }
- symptr[nsym++] = s;
- }
- void
- printsyms(Sym **symptr, long nsym)
- {
- int i, wid;
- Sym *s;
- char *cp;
- char path[512];
- if(!sflag)
- qsort(symptr, nsym, sizeof(*symptr), cmp);
-
- wid = 0;
- for (i=0; i<nsym; i++) {
- s = symptr[i];
- if (s->value && wid == 0)
- wid = 8;
- else if (s->value >= 0x100000000LL && wid == 8)
- wid = 16;
- }
- for (i=0; i<nsym; i++) {
- s = symptr[i];
- if (multifile && !hflag)
- Bprint(&bout, "%s:", filename);
- if (s->type == 'z') {
- fileelem(fnames, (uchar *) s->name, path, 512);
- cp = path;
- } else
- cp = s->name;
- if (Tflag)
- Bprint(&bout, "%8ux ", s->sig);
- if (s->value || s->type == 'a' || s->type == 'p')
- Bprint(&bout, "%*llux ", wid, s->value);
- else
- Bprint(&bout, "%*s ", wid, "");
- Bprint(&bout, "%c %s\n", s->type, cp);
- }
- }
- void
- error(char *fmt, ...)
- {
- Fmt f;
- char buf[128];
- va_list arg;
- fmtfdinit(&f, 2, buf, sizeof buf);
- fmtprint(&f, "%s: ", argv0);
- va_start(arg, fmt);
- fmtvprint(&f, fmt, arg);
- va_end(arg);
- fmtprint(&f, "\n");
- fmtfdflush(&f);
- errs = "errors";
- }
|