xref: /inferno-os/utils/nm/nm.c (revision 45a20ab721a513710138340faff3d59a31c3e01e)
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