xref: /plan9/sys/src/cmd/nm.c (revision 0c547597109109560d53d0e274a258f0150779c4)
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