174a4d8c2SCharles.Forsyth /*
274a4d8c2SCharles.Forsyth * nm.c -- drive nm
374a4d8c2SCharles.Forsyth */
474a4d8c2SCharles.Forsyth #include <lib9.h>
574a4d8c2SCharles.Forsyth #include <ar.h>
674a4d8c2SCharles.Forsyth #include <bio.h>
774a4d8c2SCharles.Forsyth #include <mach.h>
874a4d8c2SCharles.Forsyth
974a4d8c2SCharles.Forsyth enum{
1074a4d8c2SCharles.Forsyth CHUNK = 256 /* must be power of 2 */
1174a4d8c2SCharles.Forsyth };
1274a4d8c2SCharles.Forsyth
1374a4d8c2SCharles.Forsyth char *errs; /* exit status */
1474a4d8c2SCharles.Forsyth char *filename; /* current file */
1574a4d8c2SCharles.Forsyth char symname[]="__.SYMDEF"; /* table of contents file name */
1674a4d8c2SCharles.Forsyth int multifile; /* processing multiple files */
1774a4d8c2SCharles.Forsyth int aflag;
1874a4d8c2SCharles.Forsyth int gflag;
1974a4d8c2SCharles.Forsyth int hflag;
2074a4d8c2SCharles.Forsyth int nflag;
2174a4d8c2SCharles.Forsyth int sflag;
2274a4d8c2SCharles.Forsyth int uflag;
23ce8e0d60Sforsyth int Tflag;
2474a4d8c2SCharles.Forsyth
2574a4d8c2SCharles.Forsyth Sym **fnames; /* file path translation table */
2674a4d8c2SCharles.Forsyth Sym **symptr;
2774a4d8c2SCharles.Forsyth int nsym;
2874a4d8c2SCharles.Forsyth Biobuf bout;
2974a4d8c2SCharles.Forsyth char* argv0;
3074a4d8c2SCharles.Forsyth
3174a4d8c2SCharles.Forsyth void error(char*, ...);
3274a4d8c2SCharles.Forsyth void execsyms(int);
3374a4d8c2SCharles.Forsyth void psym(Sym*, void*);
3474a4d8c2SCharles.Forsyth void printsyms(Sym**, long);
3574a4d8c2SCharles.Forsyth void doar(Biobuf*);
3674a4d8c2SCharles.Forsyth void dofile(Biobuf*);
3774a4d8c2SCharles.Forsyth void zenter(Sym*);
3874a4d8c2SCharles.Forsyth
3974a4d8c2SCharles.Forsyth void
usage(void)40ce8e0d60Sforsyth usage(void)
41ce8e0d60Sforsyth {
42ce8e0d60Sforsyth fprint(2, "usage: nm [-aghnsTu] file ...\n");
43ce8e0d60Sforsyth exits("usage");
44ce8e0d60Sforsyth }
45ce8e0d60Sforsyth
46ce8e0d60Sforsyth void
main(int argc,char * argv[])4774a4d8c2SCharles.Forsyth main(int argc, char *argv[])
4874a4d8c2SCharles.Forsyth {
4974a4d8c2SCharles.Forsyth int i;
5074a4d8c2SCharles.Forsyth Biobuf *bin;
5174a4d8c2SCharles.Forsyth
5274a4d8c2SCharles.Forsyth Binit(&bout, 1, OWRITE);
5374a4d8c2SCharles.Forsyth argv0 = argv[0];
5474a4d8c2SCharles.Forsyth ARGBEGIN {
55ce8e0d60Sforsyth default: usage();
5674a4d8c2SCharles.Forsyth case 'a': aflag = 1; break;
5774a4d8c2SCharles.Forsyth case 'g': gflag = 1; break;
5874a4d8c2SCharles.Forsyth case 'h': hflag = 1; break;
5974a4d8c2SCharles.Forsyth case 'n': nflag = 1; break;
6074a4d8c2SCharles.Forsyth case 's': sflag = 1; break;
6174a4d8c2SCharles.Forsyth case 'u': uflag = 1; break;
62ce8e0d60Sforsyth case 'T': Tflag = 1; break;
6374a4d8c2SCharles.Forsyth } ARGEND
64ce8e0d60Sforsyth if (argc == 0)
65ce8e0d60Sforsyth usage();
6674a4d8c2SCharles.Forsyth if (argc > 1)
6774a4d8c2SCharles.Forsyth multifile++;
6874a4d8c2SCharles.Forsyth for(i=0; i<argc; i++){
6974a4d8c2SCharles.Forsyth filename = argv[i];
7074a4d8c2SCharles.Forsyth bin = Bopen(filename, OREAD);
7174a4d8c2SCharles.Forsyth if(bin == 0){
7274a4d8c2SCharles.Forsyth error("cannot open %s", filename);
7374a4d8c2SCharles.Forsyth continue;
7474a4d8c2SCharles.Forsyth }
7574a4d8c2SCharles.Forsyth if (isar(bin))
7674a4d8c2SCharles.Forsyth doar(bin);
7774a4d8c2SCharles.Forsyth else{
7874a4d8c2SCharles.Forsyth Bseek(bin, 0, 0);
7974a4d8c2SCharles.Forsyth dofile(bin);
8074a4d8c2SCharles.Forsyth }
8174a4d8c2SCharles.Forsyth Bterm(bin);
8274a4d8c2SCharles.Forsyth }
8374a4d8c2SCharles.Forsyth exits(errs);
8474a4d8c2SCharles.Forsyth }
8574a4d8c2SCharles.Forsyth
8674a4d8c2SCharles.Forsyth /*
8774a4d8c2SCharles.Forsyth * read an archive file,
8874a4d8c2SCharles.Forsyth * processing the symbols for each intermediate file in it.
8974a4d8c2SCharles.Forsyth */
9074a4d8c2SCharles.Forsyth void
doar(Biobuf * bp)9174a4d8c2SCharles.Forsyth doar(Biobuf *bp)
9274a4d8c2SCharles.Forsyth {
93ce8e0d60Sforsyth vlong offset;
94ce8e0d60Sforsyth int size, obj;
9574a4d8c2SCharles.Forsyth char membername[SARNAME];
9674a4d8c2SCharles.Forsyth
9774a4d8c2SCharles.Forsyth multifile = 1;
9874a4d8c2SCharles.Forsyth for (offset = Boffset(bp);;offset += size) {
9974a4d8c2SCharles.Forsyth size = nextar(bp, offset, membername);
10074a4d8c2SCharles.Forsyth if (size < 0) {
101ce8e0d60Sforsyth error("phase error on ar header %lld", offset);
10274a4d8c2SCharles.Forsyth return;
10374a4d8c2SCharles.Forsyth }
10474a4d8c2SCharles.Forsyth if (size == 0)
10574a4d8c2SCharles.Forsyth return;
10674a4d8c2SCharles.Forsyth if (strcmp(membername, symname) == 0)
10774a4d8c2SCharles.Forsyth continue;
10874a4d8c2SCharles.Forsyth obj = objtype(bp, 0);
10974a4d8c2SCharles.Forsyth if (obj < 0) {
11074a4d8c2SCharles.Forsyth error("inconsistent file %s in %s",
11174a4d8c2SCharles.Forsyth membername, filename);
11274a4d8c2SCharles.Forsyth return;
11374a4d8c2SCharles.Forsyth }
11474a4d8c2SCharles.Forsyth if (!readar(bp, obj, offset+size, 1)) {
11574a4d8c2SCharles.Forsyth error("invalid symbol reference in file %s",
11674a4d8c2SCharles.Forsyth membername);
11774a4d8c2SCharles.Forsyth return;
11874a4d8c2SCharles.Forsyth }
11974a4d8c2SCharles.Forsyth filename = membername;
12074a4d8c2SCharles.Forsyth nsym=0;
12174a4d8c2SCharles.Forsyth objtraverse(psym, 0);
12274a4d8c2SCharles.Forsyth printsyms(symptr, nsym);
12374a4d8c2SCharles.Forsyth }
12474a4d8c2SCharles.Forsyth }
12574a4d8c2SCharles.Forsyth
12674a4d8c2SCharles.Forsyth /*
12774a4d8c2SCharles.Forsyth * process symbols in a file
12874a4d8c2SCharles.Forsyth */
12974a4d8c2SCharles.Forsyth void
dofile(Biobuf * bp)13074a4d8c2SCharles.Forsyth dofile(Biobuf *bp)
13174a4d8c2SCharles.Forsyth {
13274a4d8c2SCharles.Forsyth int obj;
13374a4d8c2SCharles.Forsyth
13474a4d8c2SCharles.Forsyth obj = objtype(bp, 0);
13574a4d8c2SCharles.Forsyth if (obj < 0)
13674a4d8c2SCharles.Forsyth execsyms(Bfildes(bp));
13774a4d8c2SCharles.Forsyth else
13874a4d8c2SCharles.Forsyth if (readobj(bp, obj)) {
13974a4d8c2SCharles.Forsyth nsym = 0;
14074a4d8c2SCharles.Forsyth objtraverse(psym, 0);
14174a4d8c2SCharles.Forsyth printsyms(symptr, nsym);
14274a4d8c2SCharles.Forsyth }
14374a4d8c2SCharles.Forsyth }
14474a4d8c2SCharles.Forsyth
14574a4d8c2SCharles.Forsyth /*
14674a4d8c2SCharles.Forsyth * comparison routine for sorting the symbol table
14774a4d8c2SCharles.Forsyth * this screws up on 'z' records when aflag == 1
14874a4d8c2SCharles.Forsyth */
14974a4d8c2SCharles.Forsyth int
cmp(void * vs,void * vt)150*45a20ab7Sforsyth cmp(void *vs, void *vt)
15174a4d8c2SCharles.Forsyth {
15274a4d8c2SCharles.Forsyth Sym **s, **t;
15374a4d8c2SCharles.Forsyth
15474a4d8c2SCharles.Forsyth s = (Sym**)vs;
15574a4d8c2SCharles.Forsyth t = (Sym**)vt;
15674a4d8c2SCharles.Forsyth if(nflag)
157ce8e0d60Sforsyth if((*s)->value < (*t)->value)
15874a4d8c2SCharles.Forsyth return -1;
15974a4d8c2SCharles.Forsyth else
160ce8e0d60Sforsyth return (*s)->value > (*t)->value;
16174a4d8c2SCharles.Forsyth return strcmp((*s)->name, (*t)->name);
16274a4d8c2SCharles.Forsyth }
16374a4d8c2SCharles.Forsyth /*
16474a4d8c2SCharles.Forsyth * enter a symbol in the table of filename elements
16574a4d8c2SCharles.Forsyth */
16674a4d8c2SCharles.Forsyth void
zenter(Sym * s)16774a4d8c2SCharles.Forsyth zenter(Sym *s)
16874a4d8c2SCharles.Forsyth {
16974a4d8c2SCharles.Forsyth static int maxf = 0;
17074a4d8c2SCharles.Forsyth
171ce8e0d60Sforsyth if (s->value >= maxf) {
17274a4d8c2SCharles.Forsyth maxf = (s->value+CHUNK-1) &~ (CHUNK-1);
17374a4d8c2SCharles.Forsyth fnames = realloc(fnames, maxf*sizeof(*fnames));
17474a4d8c2SCharles.Forsyth if(fnames == 0) {
17574a4d8c2SCharles.Forsyth error("out of memory", argv0);
17674a4d8c2SCharles.Forsyth exits("memory");
17774a4d8c2SCharles.Forsyth }
17874a4d8c2SCharles.Forsyth }
17974a4d8c2SCharles.Forsyth fnames[s->value] = s;
18074a4d8c2SCharles.Forsyth }
18174a4d8c2SCharles.Forsyth
18274a4d8c2SCharles.Forsyth /*
18374a4d8c2SCharles.Forsyth * get the symbol table from an executable file, if it has one
18474a4d8c2SCharles.Forsyth */
18574a4d8c2SCharles.Forsyth void
execsyms(int fd)18674a4d8c2SCharles.Forsyth execsyms(int fd)
18774a4d8c2SCharles.Forsyth {
18874a4d8c2SCharles.Forsyth Fhdr f;
18974a4d8c2SCharles.Forsyth Sym *s;
19074a4d8c2SCharles.Forsyth long n;
19174a4d8c2SCharles.Forsyth
19274a4d8c2SCharles.Forsyth seek(fd, 0, 0);
19374a4d8c2SCharles.Forsyth if (crackhdr(fd, &f) == 0) {
19474a4d8c2SCharles.Forsyth error("Can't read header for %s", filename);
19574a4d8c2SCharles.Forsyth return;
19674a4d8c2SCharles.Forsyth }
19774a4d8c2SCharles.Forsyth if (syminit(fd, &f) < 0)
19874a4d8c2SCharles.Forsyth return;
19974a4d8c2SCharles.Forsyth s = symbase(&n);
20074a4d8c2SCharles.Forsyth nsym = 0;
20174a4d8c2SCharles.Forsyth while(n--)
20274a4d8c2SCharles.Forsyth psym(s++, 0);
20374a4d8c2SCharles.Forsyth
20474a4d8c2SCharles.Forsyth printsyms(symptr, nsym);
20574a4d8c2SCharles.Forsyth }
20674a4d8c2SCharles.Forsyth
20774a4d8c2SCharles.Forsyth void
psym(Sym * s,void * p)20874a4d8c2SCharles.Forsyth psym(Sym *s, void* p)
20974a4d8c2SCharles.Forsyth {
21074a4d8c2SCharles.Forsyth USED(p);
21174a4d8c2SCharles.Forsyth switch(s->type) {
21274a4d8c2SCharles.Forsyth case 'T':
21374a4d8c2SCharles.Forsyth case 'L':
21474a4d8c2SCharles.Forsyth case 'D':
21574a4d8c2SCharles.Forsyth case 'B':
21674a4d8c2SCharles.Forsyth if (uflag)
21774a4d8c2SCharles.Forsyth return;
21874a4d8c2SCharles.Forsyth if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
21974a4d8c2SCharles.Forsyth return;
22074a4d8c2SCharles.Forsyth break;
22174a4d8c2SCharles.Forsyth case 'b':
22274a4d8c2SCharles.Forsyth case 'd':
22374a4d8c2SCharles.Forsyth case 'l':
22474a4d8c2SCharles.Forsyth case 't':
22574a4d8c2SCharles.Forsyth if (uflag || gflag)
22674a4d8c2SCharles.Forsyth return;
22774a4d8c2SCharles.Forsyth if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
22874a4d8c2SCharles.Forsyth return;
22974a4d8c2SCharles.Forsyth break;
23074a4d8c2SCharles.Forsyth case 'U':
23174a4d8c2SCharles.Forsyth if (gflag)
23274a4d8c2SCharles.Forsyth return;
23374a4d8c2SCharles.Forsyth break;
23474a4d8c2SCharles.Forsyth case 'Z':
23574a4d8c2SCharles.Forsyth if (!aflag)
23674a4d8c2SCharles.Forsyth return;
23774a4d8c2SCharles.Forsyth break;
23874a4d8c2SCharles.Forsyth case 'm':
23974a4d8c2SCharles.Forsyth case 'f': /* we only see a 'z' when the following is true*/
24074a4d8c2SCharles.Forsyth if(!aflag || uflag || gflag)
24174a4d8c2SCharles.Forsyth return;
24274a4d8c2SCharles.Forsyth if (strcmp(s->name, ".frame"))
24374a4d8c2SCharles.Forsyth zenter(s);
24474a4d8c2SCharles.Forsyth break;
24574a4d8c2SCharles.Forsyth case 'a':
24674a4d8c2SCharles.Forsyth case 'p':
24774a4d8c2SCharles.Forsyth case 'z':
24874a4d8c2SCharles.Forsyth default:
24974a4d8c2SCharles.Forsyth if(!aflag || uflag || gflag)
25074a4d8c2SCharles.Forsyth return;
25174a4d8c2SCharles.Forsyth break;
25274a4d8c2SCharles.Forsyth }
25374a4d8c2SCharles.Forsyth symptr = realloc(symptr, (nsym+1)*sizeof(Sym*));
25474a4d8c2SCharles.Forsyth if (symptr == 0) {
25574a4d8c2SCharles.Forsyth error("out of memory");
25674a4d8c2SCharles.Forsyth exits("memory");
25774a4d8c2SCharles.Forsyth }
25874a4d8c2SCharles.Forsyth symptr[nsym++] = s;
25974a4d8c2SCharles.Forsyth }
26074a4d8c2SCharles.Forsyth
26174a4d8c2SCharles.Forsyth void
printsyms(Sym ** symptr,long nsym)26274a4d8c2SCharles.Forsyth printsyms(Sym **symptr, long nsym)
26374a4d8c2SCharles.Forsyth {
26474a4d8c2SCharles.Forsyth Sym *s;
26574a4d8c2SCharles.Forsyth char *cp;
26674a4d8c2SCharles.Forsyth char path[512];
26774a4d8c2SCharles.Forsyth
26874a4d8c2SCharles.Forsyth if(!sflag)
26974a4d8c2SCharles.Forsyth qsort(symptr, nsym, sizeof(*symptr), cmp);
27074a4d8c2SCharles.Forsyth while (nsym-- > 0) {
27174a4d8c2SCharles.Forsyth s = *symptr++;
27274a4d8c2SCharles.Forsyth if (multifile && !hflag)
27374a4d8c2SCharles.Forsyth Bprint(&bout, "%s:", filename);
27474a4d8c2SCharles.Forsyth if (s->type == 'z') {
27574a4d8c2SCharles.Forsyth fileelem(fnames, (uchar *) s->name, path, 512);
27674a4d8c2SCharles.Forsyth cp = path;
27774a4d8c2SCharles.Forsyth } else
27874a4d8c2SCharles.Forsyth cp = s->name;
279ce8e0d60Sforsyth if (Tflag)
280ce8e0d60Sforsyth Bprint(&bout, "%8ux ", s->sig);
28174a4d8c2SCharles.Forsyth if (s->value || s->type == 'a' || s->type == 'p')
282ce8e0d60Sforsyth Bprint(&bout, "%8llux %c %s\n", s->value, s->type, cp);
28374a4d8c2SCharles.Forsyth else
28474a4d8c2SCharles.Forsyth Bprint(&bout, " %c %s\n", s->type, cp);
28574a4d8c2SCharles.Forsyth }
28674a4d8c2SCharles.Forsyth }
28774a4d8c2SCharles.Forsyth
28874a4d8c2SCharles.Forsyth void
error(char * fmt,...)28974a4d8c2SCharles.Forsyth error(char *fmt, ...)
29074a4d8c2SCharles.Forsyth {
29174a4d8c2SCharles.Forsyth char buf[4096], *s;
29274a4d8c2SCharles.Forsyth va_list arg;
29374a4d8c2SCharles.Forsyth
29474a4d8c2SCharles.Forsyth s = buf;
29574a4d8c2SCharles.Forsyth s += sprint(s, "%s: ", argv0);
29674a4d8c2SCharles.Forsyth va_start(arg, fmt);
29774a4d8c2SCharles.Forsyth s = vseprint(s, buf + sizeof(buf) / sizeof(*buf), fmt, arg);
29874a4d8c2SCharles.Forsyth va_end(arg);
29974a4d8c2SCharles.Forsyth *s++ = '\n';
30074a4d8c2SCharles.Forsyth write(2, buf, s - buf);
30174a4d8c2SCharles.Forsyth errs = "errors";
30274a4d8c2SCharles.Forsyth }
303