xref: /plan9/sys/src/cmd/nm.c (revision 0c547597109109560d53d0e274a258f0150779c4)
1 /*
2  * nm.c -- drive nm
3  */
4 #include <u.h>
5 #include <libc.h>
6 #include <ar.h>
7 #include <bio.h>
8 #include <mach.h>
9 
10 enum{
11 	CHUNK	=	256	/* must be power of 2 */
12 };
13 
14 char	*errs;			/* exit status */
15 char	*filename;		/* current file */
16 char	symname[]="__.SYMDEF";	/* table of contents file name */
17 int	multifile;		/* processing multiple files */
18 int	aflag;
19 int	gflag;
20 int	hflag;
21 int	nflag;
22 int	sflag;
23 int	uflag;
24 int	Tflag;
25 
26 Sym	**fnames;		/* file path translation table */
27 Sym	**symptr;
28 int	nsym;
29 Biobuf	bout;
30 
31 int	cmp(void*, void*);
32 void	error(char*, ...);
33 void	execsyms(int);
34 void	psym(Sym*, void*);
35 void	printsyms(Sym**, long);
36 void	doar(Biobuf*);
37 void	dofile(Biobuf*);
38 void	zenter(Sym*);
39 
40 void
usage(void)41 usage(void)
42 {
43 	fprint(2, "usage: nm [-aghnsTu] file ...\n");
44 	exits("usage");
45 }
46 
47 void
main(int argc,char * argv[])48 main(int argc, char *argv[])
49 {
50 	int i;
51 	Biobuf	*bin;
52 
53 	Binit(&bout, 1, OWRITE);
54 	argv0 = argv[0];
55 	ARGBEGIN {
56 	default:	usage();
57 	case 'a':	aflag = 1; break;
58 	case 'g':	gflag = 1; break;
59 	case 'h':	hflag = 1; break;
60 	case 'n':	nflag = 1; break;
61 	case 's':	sflag = 1; break;
62 	case 'u':	uflag = 1; break;
63 	case 'T':	Tflag = 1; break;
64 	} ARGEND
65 	if (argc == 0)
66 		usage();
67 	if (argc > 1)
68 		multifile++;
69 	for(i=0; i<argc; i++){
70 		filename = argv[i];
71 		bin = Bopen(filename, OREAD);
72 		if(bin == 0){
73 			error("cannot open %s", filename);
74 			continue;
75 		}
76 		if (isar(bin))
77 			doar(bin);
78 		else{
79 			Bseek(bin, 0, 0);
80 			dofile(bin);
81 		}
82 		Bterm(bin);
83 	}
84 	exits(errs);
85 }
86 
87 /*
88  * read an archive file,
89  * processing the symbols for each intermediate file in it.
90  */
91 void
doar(Biobuf * bp)92 doar(Biobuf *bp)
93 {
94 	int offset, 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 %ld", 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
dofile(Biobuf * bp)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
cmp(void * vs,void * vt)150 cmp(void *vs, void *vt)
151 {
152 	Sym **s, **t;
153 
154 	s = vs;
155 	t = 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
zenter(Sym * s)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+1)*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
execsyms(int fd)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
psym(Sym * s,void * p)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
printsyms(Sym ** symptr,long nsym)262 printsyms(Sym **symptr, long nsym)
263 {
264 	int i, wid;
265 	Sym *s;
266 	char *cp;
267 	char path[512];
268 
269 	if(!sflag)
270 		qsort(symptr, nsym, sizeof(*symptr), cmp);
271 
272 	wid = 0;
273 	for (i=0; i<nsym; i++) {
274 		s = symptr[i];
275 		if (s->value && wid == 0)
276 			wid = 8;
277 		else if (s->value >= 0x100000000LL && wid == 8)
278 			wid = 16;
279 	}
280 	for (i=0; i<nsym; i++) {
281 		s = symptr[i];
282 		if (multifile && !hflag)
283 			Bprint(&bout, "%s:", filename);
284 		if (s->type == 'z') {
285 			fileelem(fnames, (uchar *) s->name, path, 512);
286 			cp = path;
287 		} else
288 			cp = s->name;
289 		if (Tflag)
290 			Bprint(&bout, "%8ux ", s->sig);
291 		if (s->value || s->type == 'a' || s->type == 'p')
292 			Bprint(&bout, "%*llux ", wid, s->value);
293 		else
294 			Bprint(&bout, "%*s ", wid, "");
295 		Bprint(&bout, "%c %s\n", s->type, cp);
296 	}
297 }
298 
299 void
error(char * fmt,...)300 error(char *fmt, ...)
301 {
302 	Fmt f;
303 	char buf[128];
304 	va_list arg;
305 
306 	fmtfdinit(&f, 2, buf, sizeof buf);
307 	fmtprint(&f, "%s: ", argv0);
308 	va_start(arg, fmt);
309 	fmtvprint(&f, fmt, arg);
310 	va_end(arg);
311 	fmtprint(&f, "\n");
312 	fmtfdflush(&f);
313 	errs = "errors";
314 }
315