13e12c5d1SDavid du Colombier /*
23e12c5d1SDavid du Colombier * nm.c -- drive nm
33e12c5d1SDavid du Colombier */
43e12c5d1SDavid du Colombier #include <u.h>
53e12c5d1SDavid du Colombier #include <libc.h>
63e12c5d1SDavid du Colombier #include <ar.h>
73e12c5d1SDavid du Colombier #include <bio.h>
8bd389b36SDavid du Colombier #include <mach.h>
93e12c5d1SDavid du Colombier
10bd389b36SDavid du Colombier enum{
11bd389b36SDavid du Colombier CHUNK = 256 /* must be power of 2 */
12bd389b36SDavid du Colombier };
133e12c5d1SDavid du Colombier
14bd389b36SDavid du Colombier char *errs; /* exit status */
15bd389b36SDavid du Colombier char *filename; /* current file */
16bd389b36SDavid du Colombier char symname[]="__.SYMDEF"; /* table of contents file name */
177dd7cddfSDavid du Colombier int multifile; /* processing multiple files */
187dd7cddfSDavid du Colombier int aflag;
197dd7cddfSDavid du Colombier int gflag;
207dd7cddfSDavid du Colombier int hflag;
217dd7cddfSDavid du Colombier int nflag;
227dd7cddfSDavid du Colombier int sflag;
237dd7cddfSDavid du Colombier int uflag;
24*0c547597SDavid du Colombier int Tflag;
25bd389b36SDavid du Colombier
263e12c5d1SDavid du Colombier Sym **fnames; /* file path translation table */
27219b2ee8SDavid du Colombier Sym **symptr;
28219b2ee8SDavid du Colombier int nsym;
29bd389b36SDavid du Colombier Biobuf bout;
303e12c5d1SDavid du Colombier
317dd7cddfSDavid du Colombier int cmp(void*, void*);
327dd7cddfSDavid du Colombier void error(char*, ...);
337dd7cddfSDavid du Colombier void execsyms(int);
347dd7cddfSDavid du Colombier void psym(Sym*, void*);
357dd7cddfSDavid du Colombier void printsyms(Sym**, long);
367dd7cddfSDavid du Colombier void doar(Biobuf*);
377dd7cddfSDavid du Colombier void dofile(Biobuf*);
387dd7cddfSDavid du Colombier void zenter(Sym*);
393e12c5d1SDavid du Colombier
403e12c5d1SDavid du Colombier void
usage(void)41*0c547597SDavid du Colombier usage(void)
42*0c547597SDavid du Colombier {
43*0c547597SDavid du Colombier fprint(2, "usage: nm [-aghnsTu] file ...\n");
44*0c547597SDavid du Colombier exits("usage");
45*0c547597SDavid du Colombier }
46*0c547597SDavid du Colombier
47*0c547597SDavid du Colombier void
main(int argc,char * argv[])483e12c5d1SDavid du Colombier main(int argc, char *argv[])
493e12c5d1SDavid du Colombier {
50bd389b36SDavid du Colombier int i;
51bd389b36SDavid du Colombier Biobuf *bin;
523e12c5d1SDavid du Colombier
53bd389b36SDavid du Colombier Binit(&bout, 1, OWRITE);
543e12c5d1SDavid du Colombier argv0 = argv[0];
553e12c5d1SDavid du Colombier ARGBEGIN {
56*0c547597SDavid du Colombier default: usage();
573e12c5d1SDavid du Colombier case 'a': aflag = 1; break;
583e12c5d1SDavid du Colombier case 'g': gflag = 1; break;
593e12c5d1SDavid du Colombier case 'h': hflag = 1; break;
603e12c5d1SDavid du Colombier case 'n': nflag = 1; break;
613e12c5d1SDavid du Colombier case 's': sflag = 1; break;
623e12c5d1SDavid du Colombier case 'u': uflag = 1; break;
63*0c547597SDavid du Colombier case 'T': Tflag = 1; break;
643e12c5d1SDavid du Colombier } ARGEND
65*0c547597SDavid du Colombier if (argc == 0)
66*0c547597SDavid du Colombier usage();
67bd389b36SDavid du Colombier if (argc > 1)
68bd389b36SDavid du Colombier multifile++;
693e12c5d1SDavid du Colombier for(i=0; i<argc; i++){
70bd389b36SDavid du Colombier filename = argv[i];
71bd389b36SDavid du Colombier bin = Bopen(filename, OREAD);
72bd389b36SDavid du Colombier if(bin == 0){
737dd7cddfSDavid du Colombier error("cannot open %s", filename);
743e12c5d1SDavid du Colombier continue;
753e12c5d1SDavid du Colombier }
76bd389b36SDavid du Colombier if (isar(bin))
77bd389b36SDavid du Colombier doar(bin);
783e12c5d1SDavid du Colombier else{
79bd389b36SDavid du Colombier Bseek(bin, 0, 0);
80bd389b36SDavid du Colombier dofile(bin);
813e12c5d1SDavid du Colombier }
82219b2ee8SDavid du Colombier Bterm(bin);
833e12c5d1SDavid du Colombier }
843e12c5d1SDavid du Colombier exits(errs);
853e12c5d1SDavid du Colombier }
863e12c5d1SDavid du Colombier
873e12c5d1SDavid du Colombier /*
883e12c5d1SDavid du Colombier * read an archive file,
893e12c5d1SDavid du Colombier * processing the symbols for each intermediate file in it.
903e12c5d1SDavid du Colombier */
913e12c5d1SDavid du Colombier void
doar(Biobuf * bp)92bd389b36SDavid du Colombier doar(Biobuf *bp)
933e12c5d1SDavid du Colombier {
94bd389b36SDavid du Colombier int offset, size, obj;
95219b2ee8SDavid du Colombier char membername[SARNAME];
96bd389b36SDavid du Colombier
973e12c5d1SDavid du Colombier multifile = 1;
987dd7cddfSDavid du Colombier for (offset = Boffset(bp);;offset += size) {
99bd389b36SDavid du Colombier size = nextar(bp, offset, membername);
100bd389b36SDavid du Colombier if (size < 0) {
1017dd7cddfSDavid du Colombier error("phase error on ar header %ld", offset);
102bd389b36SDavid du Colombier return;
103bd389b36SDavid du Colombier }
104bd389b36SDavid du Colombier if (size == 0)
105bd389b36SDavid du Colombier return;
106bd389b36SDavid du Colombier if (strcmp(membername, symname) == 0)
107bd389b36SDavid du Colombier continue;
108219b2ee8SDavid du Colombier obj = objtype(bp, 0);
109bd389b36SDavid du Colombier if (obj < 0) {
1107dd7cddfSDavid du Colombier error("inconsistent file %s in %s",
111bd389b36SDavid du Colombier membername, filename);
112bd389b36SDavid du Colombier return;
113bd389b36SDavid du Colombier }
114219b2ee8SDavid du Colombier if (!readar(bp, obj, offset+size, 1)) {
1157dd7cddfSDavid du Colombier error("invalid symbol reference in file %s",
116bd389b36SDavid du Colombier membername);
117bd389b36SDavid du Colombier return;
118bd389b36SDavid du Colombier }
119bd389b36SDavid du Colombier filename = membername;
120219b2ee8SDavid du Colombier nsym=0;
121219b2ee8SDavid du Colombier objtraverse(psym, 0);
122219b2ee8SDavid du Colombier printsyms(symptr, nsym);
123bd389b36SDavid du Colombier }
1243e12c5d1SDavid du Colombier }
1253e12c5d1SDavid du Colombier
1263e12c5d1SDavid du Colombier /*
1273e12c5d1SDavid du Colombier * process symbols in a file
1283e12c5d1SDavid du Colombier */
1293e12c5d1SDavid du Colombier void
dofile(Biobuf * bp)130bd389b36SDavid du Colombier dofile(Biobuf *bp)
1313e12c5d1SDavid du Colombier {
132bd389b36SDavid du Colombier int obj;
133bd389b36SDavid du Colombier
134219b2ee8SDavid du Colombier obj = objtype(bp, 0);
135bd389b36SDavid du Colombier if (obj < 0)
136219b2ee8SDavid du Colombier execsyms(Bfildes(bp));
137219b2ee8SDavid du Colombier else
138bd389b36SDavid du Colombier if (readobj(bp, obj)) {
139219b2ee8SDavid du Colombier nsym = 0;
140219b2ee8SDavid du Colombier objtraverse(psym, 0);
141219b2ee8SDavid du Colombier printsyms(symptr, nsym);
142bd389b36SDavid du Colombier }
1433e12c5d1SDavid du Colombier }
1443e12c5d1SDavid du Colombier
1453e12c5d1SDavid du Colombier /*
1463e12c5d1SDavid du Colombier * comparison routine for sorting the symbol table
1473e12c5d1SDavid du Colombier * this screws up on 'z' records when aflag == 1
1483e12c5d1SDavid du Colombier */
1493e12c5d1SDavid du Colombier int
cmp(void * vs,void * vt)1507dd7cddfSDavid du Colombier cmp(void *vs, void *vt)
1513e12c5d1SDavid du Colombier {
1527dd7cddfSDavid du Colombier Sym **s, **t;
1537dd7cddfSDavid du Colombier
1547dd7cddfSDavid du Colombier s = vs;
1557dd7cddfSDavid du Colombier t = vt;
1563e12c5d1SDavid du Colombier if(nflag)
1573e12c5d1SDavid du Colombier if((*s)->value < (*t)->value)
1583e12c5d1SDavid du Colombier return -1;
1593e12c5d1SDavid du Colombier else
1603e12c5d1SDavid du Colombier return (*s)->value > (*t)->value;
1613e12c5d1SDavid du Colombier return strcmp((*s)->name, (*t)->name);
1623e12c5d1SDavid du Colombier }
1633e12c5d1SDavid du Colombier /*
1643e12c5d1SDavid du Colombier * enter a symbol in the table of filename elements
1653e12c5d1SDavid du Colombier */
1663e12c5d1SDavid du Colombier void
zenter(Sym * s)1673e12c5d1SDavid du Colombier zenter(Sym *s)
1683e12c5d1SDavid du Colombier {
1693e12c5d1SDavid du Colombier static int maxf = 0;
1703e12c5d1SDavid du Colombier
1713e12c5d1SDavid du Colombier if (s->value > maxf) {
172bd389b36SDavid du Colombier maxf = (s->value+CHUNK-1) &~ (CHUNK-1);
1732e976735SDavid du Colombier fnames = realloc(fnames, (maxf+1)*sizeof(*fnames));
1743e12c5d1SDavid du Colombier if(fnames == 0) {
1757dd7cddfSDavid du Colombier error("out of memory", argv0);
1763e12c5d1SDavid du Colombier exits("memory");
1773e12c5d1SDavid du Colombier }
1783e12c5d1SDavid du Colombier }
1793e12c5d1SDavid du Colombier fnames[s->value] = s;
1803e12c5d1SDavid du Colombier }
1813e12c5d1SDavid du Colombier
1823e12c5d1SDavid du Colombier /*
1833e12c5d1SDavid du Colombier * get the symbol table from an executable file, if it has one
1843e12c5d1SDavid du Colombier */
1853e12c5d1SDavid du Colombier void
execsyms(int fd)186219b2ee8SDavid du Colombier execsyms(int fd)
1873e12c5d1SDavid du Colombier {
1883e12c5d1SDavid du Colombier Fhdr f;
1893e12c5d1SDavid du Colombier Sym *s;
190219b2ee8SDavid du Colombier long n;
1913e12c5d1SDavid du Colombier
192219b2ee8SDavid du Colombier seek(fd, 0, 0);
193219b2ee8SDavid du Colombier if (crackhdr(fd, &f) == 0) {
1947dd7cddfSDavid du Colombier error("Can't read header for %s", filename);
1953e12c5d1SDavid du Colombier return;
1963e12c5d1SDavid du Colombier }
197219b2ee8SDavid du Colombier if (syminit(fd, &f) < 0)
1983e12c5d1SDavid du Colombier return;
199219b2ee8SDavid du Colombier s = symbase(&n);
200219b2ee8SDavid du Colombier nsym = 0;
201219b2ee8SDavid du Colombier while(n--)
202219b2ee8SDavid du Colombier psym(s++, 0);
203219b2ee8SDavid du Colombier
204219b2ee8SDavid du Colombier printsyms(symptr, nsym);
2053e12c5d1SDavid du Colombier }
2063e12c5d1SDavid du Colombier
2073e12c5d1SDavid du Colombier void
psym(Sym * s,void * p)208219b2ee8SDavid du Colombier psym(Sym *s, void* p)
2093e12c5d1SDavid du Colombier {
210219b2ee8SDavid du Colombier USED(p);
2113e12c5d1SDavid du Colombier switch(s->type) {
2123e12c5d1SDavid du Colombier case 'T':
2133e12c5d1SDavid du Colombier case 'L':
2143e12c5d1SDavid du Colombier case 'D':
2153e12c5d1SDavid du Colombier case 'B':
216219b2ee8SDavid du Colombier if (uflag)
217219b2ee8SDavid du Colombier return;
218219b2ee8SDavid du Colombier if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
219219b2ee8SDavid du Colombier return;
2203e12c5d1SDavid du Colombier break;
2213e12c5d1SDavid du Colombier case 'b':
2223e12c5d1SDavid du Colombier case 'd':
2233e12c5d1SDavid du Colombier case 'l':
2243e12c5d1SDavid du Colombier case 't':
225219b2ee8SDavid du Colombier if (uflag || gflag)
226219b2ee8SDavid du Colombier return;
227219b2ee8SDavid du Colombier if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
228219b2ee8SDavid du Colombier return;
2293e12c5d1SDavid du Colombier break;
2303e12c5d1SDavid du Colombier case 'U':
231219b2ee8SDavid du Colombier if (gflag)
232219b2ee8SDavid du Colombier return;
2333e12c5d1SDavid du Colombier break;
2343e12c5d1SDavid du Colombier case 'Z':
235219b2ee8SDavid du Colombier if (!aflag)
236219b2ee8SDavid du Colombier return;
2373e12c5d1SDavid du Colombier break;
238219b2ee8SDavid du Colombier case 'm':
2393e12c5d1SDavid du Colombier case 'f': /* we only see a 'z' when the following is true*/
240219b2ee8SDavid du Colombier if(!aflag || uflag || gflag)
241219b2ee8SDavid du Colombier return;
2423e12c5d1SDavid du Colombier if (strcmp(s->name, ".frame"))
2433e12c5d1SDavid du Colombier zenter(s);
2443e12c5d1SDavid du Colombier break;
2453e12c5d1SDavid du Colombier case 'a':
2463e12c5d1SDavid du Colombier case 'p':
2473e12c5d1SDavid du Colombier case 'z':
2483e12c5d1SDavid du Colombier default:
249219b2ee8SDavid du Colombier if(!aflag || uflag || gflag)
250219b2ee8SDavid du Colombier return;
2513e12c5d1SDavid du Colombier break;
2523e12c5d1SDavid du Colombier }
253219b2ee8SDavid du Colombier symptr = realloc(symptr, (nsym+1)*sizeof(Sym*));
254219b2ee8SDavid du Colombier if (symptr == 0) {
2557dd7cddfSDavid du Colombier error("out of memory");
256219b2ee8SDavid du Colombier exits("memory");
2573e12c5d1SDavid du Colombier }
258219b2ee8SDavid du Colombier symptr[nsym++] = s;
2593e12c5d1SDavid du Colombier }
2603e12c5d1SDavid du Colombier
2613e12c5d1SDavid du Colombier void
printsyms(Sym ** symptr,long nsym)2627dd7cddfSDavid du Colombier printsyms(Sym **symptr, long nsym)
2633e12c5d1SDavid du Colombier {
264*0c547597SDavid du Colombier int i, wid;
2653e12c5d1SDavid du Colombier Sym *s;
2663e12c5d1SDavid du Colombier char *cp;
2673e12c5d1SDavid du Colombier char path[512];
2683e12c5d1SDavid du Colombier
269219b2ee8SDavid du Colombier if(!sflag)
270219b2ee8SDavid du Colombier qsort(symptr, nsym, sizeof(*symptr), cmp);
271*0c547597SDavid du Colombier
272*0c547597SDavid du Colombier wid = 0;
273*0c547597SDavid du Colombier for (i=0; i<nsym; i++) {
274*0c547597SDavid du Colombier s = symptr[i];
275*0c547597SDavid du Colombier if (s->value && wid == 0)
276*0c547597SDavid du Colombier wid = 8;
277*0c547597SDavid du Colombier else if (s->value >= 0x100000000LL && wid == 8)
278*0c547597SDavid du Colombier wid = 16;
279*0c547597SDavid du Colombier }
280*0c547597SDavid du Colombier for (i=0; i<nsym; i++) {
281*0c547597SDavid du Colombier s = symptr[i];
2823e12c5d1SDavid du Colombier if (multifile && !hflag)
283bd389b36SDavid du Colombier Bprint(&bout, "%s:", filename);
2843e12c5d1SDavid du Colombier if (s->type == 'z') {
2853e12c5d1SDavid du Colombier fileelem(fnames, (uchar *) s->name, path, 512);
2863e12c5d1SDavid du Colombier cp = path;
2873e12c5d1SDavid du Colombier } else
2883e12c5d1SDavid du Colombier cp = s->name;
289*0c547597SDavid du Colombier if (Tflag)
290*0c547597SDavid du Colombier Bprint(&bout, "%8ux ", s->sig);
2913e12c5d1SDavid du Colombier if (s->value || s->type == 'a' || s->type == 'p')
292*0c547597SDavid du Colombier Bprint(&bout, "%*llux ", wid, s->value);
2933e12c5d1SDavid du Colombier else
294*0c547597SDavid du Colombier Bprint(&bout, "%*s ", wid, "");
295bd389b36SDavid du Colombier Bprint(&bout, "%c %s\n", s->type, cp);
2963e12c5d1SDavid du Colombier }
2973e12c5d1SDavid du Colombier }
2983e12c5d1SDavid du Colombier
2993e12c5d1SDavid du Colombier void
error(char * fmt,...)3003e12c5d1SDavid du Colombier error(char *fmt, ...)
3013e12c5d1SDavid du Colombier {
3029a747e4fSDavid du Colombier Fmt f;
3039a747e4fSDavid du Colombier char buf[128];
3047dd7cddfSDavid du Colombier va_list arg;
3053e12c5d1SDavid du Colombier
3069a747e4fSDavid du Colombier fmtfdinit(&f, 2, buf, sizeof buf);
3079a747e4fSDavid du Colombier fmtprint(&f, "%s: ", argv0);
3087dd7cddfSDavid du Colombier va_start(arg, fmt);
3099a747e4fSDavid du Colombier fmtvprint(&f, fmt, arg);
3107dd7cddfSDavid du Colombier va_end(arg);
3119a747e4fSDavid du Colombier fmtprint(&f, "\n");
3129a747e4fSDavid du Colombier fmtfdflush(&f);
3133e12c5d1SDavid du Colombier errs = "errors";
3143e12c5d1SDavid du Colombier }
315