xref: /inferno-os/utils/nm/nm.c (revision 2b69dba5038ffd0b59cf30a4c44bce549e5097f8)
1 /*
2  * nm.c -- drive nm
3  */
4 #include <lib9.h>
5 #include <ar.h>
6 #include <bio.h>
7 #include <mach.h>
8 
9 enum{
10 	CHUNK	=	256	/* must be power of 2 */
11 };
12 
13 char	*errs;			/* exit status */
14 char	*filename;		/* current file */
15 char	symname[]="__.SYMDEF";	/* table of contents file name */
16 int	multifile;		/* processing multiple files */
17 int	aflag;
18 int	gflag;
19 int	hflag;
20 int	nflag;
21 int	sflag;
22 int	uflag;
23 int	Tflag;
24 
25 Sym	**fnames;		/* file path translation table */
26 Sym	**symptr;
27 int	nsym;
28 Biobuf	bout;
29 char*	argv0;
30 
31 void	error(char*, ...);
32 void	execsyms(int);
33 void	psym(Sym*, void*);
34 void	printsyms(Sym**, long);
35 void	doar(Biobuf*);
36 void	dofile(Biobuf*);
37 void	zenter(Sym*);
38 
39 void
40 usage(void)
41 {
42 	fprint(2, "usage: nm [-aghnsTu] file ...\n");
43 	exits("usage");
44 }
45 
46 void
47 main(int argc, char *argv[])
48 {
49 	int i;
50 	Biobuf	*bin;
51 
52 	Binit(&bout, 1, OWRITE);
53 	argv0 = argv[0];
54 	ARGBEGIN {
55 	default:	usage();
56 	case 'a':	aflag = 1; break;
57 	case 'g':	gflag = 1; break;
58 	case 'h':	hflag = 1; break;
59 	case 'n':	nflag = 1; break;
60 	case 's':	sflag = 1; break;
61 	case 'u':	uflag = 1; break;
62 	case 'T':	Tflag = 1; break;
63 	} ARGEND
64 	if (argc == 0)
65 		usage();
66 	if (argc > 1)
67 		multifile++;
68 	for(i=0; i<argc; i++){
69 		filename = argv[i];
70 		bin = Bopen(filename, OREAD);
71 		if(bin == 0){
72 			error("cannot open %s", filename);
73 			continue;
74 		}
75 		if (isar(bin))
76 			doar(bin);
77 		else{
78 			Bseek(bin, 0, 0);
79 			dofile(bin);
80 		}
81 		Bterm(bin);
82 	}
83 	exits(errs);
84 }
85 
86 /*
87  * read an archive file,
88  * processing the symbols for each intermediate file in it.
89  */
90 void
91 doar(Biobuf *bp)
92 {
93 	vlong offset;
94 	int size, obj;
95 	char membername[SARNAME];
96 
97 	multifile = 1;
98 	for (offset = Boffset(bp);;offset += size) {
99 		size = nextar(bp, offset, membername);
100 		if (size < 0) {
101 			error("phase error on ar header %lld", offset);
102 			return;
103 		}
104 		if (size == 0)
105 			return;
106 		if (strcmp(membername, symname) == 0)
107 			continue;
108 		obj = objtype(bp, 0);
109 		if (obj < 0) {
110 			error("inconsistent file %s in %s",
111 					membername, filename);
112 			return;
113 		}
114 		if (!readar(bp, obj, offset+size, 1)) {
115 			error("invalid symbol reference in file %s",
116 					membername);
117 			return;
118 		}
119 		filename = membername;
120 		nsym=0;
121 		objtraverse(psym, 0);
122 		printsyms(symptr, nsym);
123 	}
124 }
125 
126 /*
127  * process symbols in a file
128  */
129 void
130 dofile(Biobuf *bp)
131 {
132 	int obj;
133 
134 	obj = objtype(bp, 0);
135 	if (obj < 0)
136 		execsyms(Bfildes(bp));
137 	else
138 	if (readobj(bp, obj)) {
139 		nsym = 0;
140 		objtraverse(psym, 0);
141 		printsyms(symptr, nsym);
142 	}
143 }
144 
145 /*
146  * comparison routine for sorting the symbol table
147  *	this screws up on 'z' records when aflag == 1
148  */
149 int
150 cmp(const void *vs, const void *vt)
151 {
152 	Sym **s, **t;
153 
154 	s = (Sym**)vs;
155 	t = (Sym**)vt;
156 	if(nflag)
157 		if((*s)->value < (*t)->value)
158 			return -1;
159 		else
160 			return (*s)->value > (*t)->value;
161 	return strcmp((*s)->name, (*t)->name);
162 }
163 /*
164  * enter a symbol in the table of filename elements
165  */
166 void
167 zenter(Sym *s)
168 {
169 	static int maxf = 0;
170 
171 	if (s->value >= maxf) {
172 		maxf = (s->value+CHUNK-1) &~ (CHUNK-1);
173 		fnames = realloc(fnames, maxf*sizeof(*fnames));
174 		if(fnames == 0) {
175 			error("out of memory", argv0);
176 			exits("memory");
177 		}
178 	}
179 	fnames[s->value] = s;
180 }
181 
182 /*
183  * get the symbol table from an executable file, if it has one
184  */
185 void
186 execsyms(int fd)
187 {
188 	Fhdr f;
189 	Sym *s;
190 	long n;
191 
192 	seek(fd, 0, 0);
193 	if (crackhdr(fd, &f) == 0) {
194 		error("Can't read header for %s", filename);
195 		return;
196 	}
197 	if (syminit(fd, &f) < 0)
198 		return;
199 	s = symbase(&n);
200 	nsym = 0;
201 	while(n--)
202 		psym(s++, 0);
203 
204 	printsyms(symptr, nsym);
205 }
206 
207 void
208 psym(Sym *s, void* p)
209 {
210 	USED(p);
211 	switch(s->type) {
212 	case 'T':
213 	case 'L':
214 	case 'D':
215 	case 'B':
216 		if (uflag)
217 			return;
218 		if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
219 			return;
220 		break;
221 	case 'b':
222 	case 'd':
223 	case 'l':
224 	case 't':
225 		if (uflag || gflag)
226 			return;
227 		if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
228 			return;
229 		break;
230 	case 'U':
231 		if (gflag)
232 			return;
233 		break;
234 	case 'Z':
235 		if (!aflag)
236 			return;
237 		break;
238 	case 'm':
239 	case 'f':	/* we only see a 'z' when the following is true*/
240 		if(!aflag || uflag || gflag)
241 			return;
242 		if (strcmp(s->name, ".frame"))
243 			zenter(s);
244 		break;
245 	case 'a':
246 	case 'p':
247 	case 'z':
248 	default:
249 		if(!aflag || uflag || gflag)
250 			return;
251 		break;
252 	}
253 	symptr = realloc(symptr, (nsym+1)*sizeof(Sym*));
254 	if (symptr == 0) {
255 		error("out of memory");
256 		exits("memory");
257 	}
258 	symptr[nsym++] = s;
259 }
260 
261 void
262 printsyms(Sym **symptr, long nsym)
263 {
264 	Sym *s;
265 	char *cp;
266 	char path[512];
267 
268 	if(!sflag)
269 		qsort(symptr, nsym, sizeof(*symptr), cmp);
270 	while (nsym-- > 0) {
271 		s = *symptr++;
272 		if (multifile && !hflag)
273 			Bprint(&bout, "%s:", filename);
274 		if (s->type == 'z') {
275 			fileelem(fnames, (uchar *) s->name, path, 512);
276 			cp = path;
277 		} else
278 			cp = s->name;
279 		if (Tflag)
280 			Bprint(&bout, "%8ux ", s->sig);
281 		if (s->value || s->type == 'a' || s->type == 'p')
282 			Bprint(&bout, "%8llux %c %s\n", s->value, s->type, cp);
283 		else
284 			Bprint(&bout, "         %c %s\n", s->type, cp);
285 	}
286 }
287 
288 void
289 error(char *fmt, ...)
290 {
291 	char buf[4096], *s;
292 	va_list arg;
293 
294 	s = buf;
295 	s += sprint(s, "%s: ", argv0);
296 	va_start(arg, fmt);
297 	s = vseprint(s, buf + sizeof(buf) / sizeof(*buf), fmt, arg);
298 	va_end(arg);
299 	*s++ = '\n';
300 	write(2, buf, s - buf);
301 	errs = "errors";
302 }
303