diff options
Diffstat (limited to 'src/cmd/nm/nm.c')
-rw-r--r-- | src/cmd/nm/nm.c | 368 |
1 files changed, 368 insertions, 0 deletions
diff --git a/src/cmd/nm/nm.c b/src/cmd/nm/nm.c new file mode 100644 index 000000000..845b6c773 --- /dev/null +++ b/src/cmd/nm/nm.c @@ -0,0 +1,368 @@ +// Inferno utils/nm/nm.c +// http://code.google.com/p/inferno-os/source/browse/utils/nm/nm.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +/* + * 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 Sflag; +int uflag; +int Tflag; +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 'S': nflag = Sflag = 1; break; + case 'u': uflag = 1; break; + case 't': tflag = 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 name[SARNAME]; + + multifile = 1; + for (offset = Boffset(bp);;offset += size) { + size = nextar(bp, offset, name); + if (size < 0) { + error("phase error on ar header %d", offset); + return; + } + if (size == 0) + return; + if (strcmp(name, symname) == 0) + continue; + obj = objtype(bp, 0); + if (obj < 0) { + // perhaps foreign object + if(strlen(name) > 2 && strcmp(name+strlen(name)-2, ".o") == 0) + return; + error("inconsistent file %s in %s", + name, filename); + return; + } + if (!readar(bp, obj, offset+size, 1)) { + error("invalid symbol reference in file %s", + name); + return; + } + filename = name; + 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) // sort on address (numeric) order + if((*s)->value < (*t)->value) + return -1; + else + return (*s)->value > (*t)->value; + if(sflag) // sort on file order (sequence) + return (*s)->sequence - (*t)->sequence; + 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; + int32 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, j, wid; + Sym *s; + char *cp; + char path[512]; + + qsort(symptr, nsym, sizeof(*symptr), (void*)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, ""); + if(Sflag) { + vlong siz; + + siz = 0; + for(j=i+1; j<nsym; j++) { + if(symptr[j]->type != 'a' && symptr[j]->type != 'p') { + siz = symptr[j]->value - s->value; + break; + } + } + if(siz > 0) + Bprint(&bout, "%*llud ", wid, siz); + } + Bprint(&bout, "%c %s", s->type, cp); + if(tflag && s->gotype) + Bprint(&bout, " %*llux", wid, s->gotype); + Bprint(&bout, "\n"); + } +} + +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"; +} |