Blob


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>
10 enum{
11 CHUNK = 256 /* must be power of 2 */
12 };
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;
25 Symbol **fnames; /* file path translation table */
26 Symbol **symptr;
27 int nsym;
28 Biobuf bout;
30 int cmp(void*, void*);
31 void error(char*, ...);
32 void execsyms(int);
33 void psym(Symbol*, void*);
34 void printsyms(Symbol**, long);
35 void doar(Biobuf*);
36 void dofile(Biobuf*);
37 void zenter(Symbol*);
39 void
40 main(int argc, char *argv[])
41 {
42 int i;
43 Biobuf *bin;
45 Binit(&bout, 1, OWRITE);
46 argv0 = argv[0];
47 ARGBEGIN {
48 case 'a': aflag = 1; break;
49 case 'g': gflag = 1; break;
50 case 'h': hflag = 1; break;
51 case 'n': nflag = 1; break;
52 case 's': sflag = 1; break;
53 case 'u': uflag = 1; break;
54 } ARGEND
55 if (argc > 1)
56 multifile++;
57 for(i=0; i<argc; i++){
58 filename = argv[i];
59 bin = Bopen(filename, OREAD);
60 if(bin == 0){
61 error("cannot open %s", filename);
62 continue;
63 }
64 if (isar(bin))
65 doar(bin);
66 else{
67 Bseek(bin, 0, 0);
68 dofile(bin);
69 }
70 Bterm(bin);
71 }
72 exits(errs);
73 }
75 /*
76 * read an archive file,
77 * processing the symbols for each intermediate file in it.
78 */
79 void
80 doar(Biobuf *bp)
81 {
82 int offset, size, obj;
83 char membername[SARNAME];
85 multifile = 1;
86 for (offset = Boffset(bp);;offset += size) {
87 size = nextar(bp, offset, membername);
88 if (size < 0) {
89 error("phase error on ar header %ld", offset);
90 return;
91 }
92 if (size == 0)
93 return;
94 if (strcmp(membername, symname) == 0)
95 continue;
96 obj = objtype(bp, 0);
97 if (obj < 0) {
98 error("inconsistent file %s in %s",
99 membername, filename);
100 return;
102 if (!readar(bp, obj, offset+size, 1)) {
103 error("invalid symbol reference in file %s",
104 membername);
105 return;
107 filename = membername;
108 nsym=0;
109 objtraverse(psym, 0);
110 printsyms(symptr, nsym);
114 /*
115 * process symbols in a file
116 */
117 void
118 dofile(Biobuf *bp)
120 int obj;
122 obj = objtype(bp, 0);
123 if (obj < 0)
124 execsyms(Bfildes(bp));
125 else
126 if (readobj(bp, obj)) {
127 nsym = 0;
128 objtraverse(psym, 0);
129 printsyms(symptr, nsym);
133 /*
134 * comparison routine for sorting the symbol table
135 * this screws up on 'z' records when aflag == 1
136 */
137 int
138 cmp(void *vs, void *vt)
140 Symbol **s, **t;
142 s = vs;
143 t = vt;
144 if(nflag)
145 if((*s)->value < (*t)->value)
146 return -1;
147 else
148 return (*s)->value > (*t)->value;
149 return strcmp((*s)->name, (*t)->name);
151 /*
152 * enter a symbol in the table of filename elements
153 */
154 void
155 zenter(Symbol *s)
157 static int maxf = 0;
159 if (s->value > maxf) {
160 maxf = (s->value+CHUNK-1) &~ (CHUNK-1);
161 fnames = realloc(fnames, (maxf+1)*sizeof(*fnames));
162 if(fnames == 0) {
163 error("out of memory", argv0);
164 exits("memory");
167 fnames[s->value] = s;
170 /*
171 * get the symbol table from an executable file, if it has one
172 */
173 void
174 execsyms(int fd)
176 Fhdr f;
177 Symbol *s;
178 long n;
180 seek(fd, 0, 0);
181 if (crackhdr(fd, &f) == 0) {
182 error("Can't read header for %s", filename);
183 return;
185 if (syminit(fd, &f) < 0)
186 return;
187 s = symbase(&n);
188 nsym = 0;
189 while(n--)
190 psym(s++, 0);
192 printsyms(symptr, nsym);
195 void
196 psym(Symbol *s, void* p)
198 USED(p);
199 switch(s->type) {
200 case 'T':
201 case 'L':
202 case 'D':
203 case 'B':
204 if (uflag)
205 return;
206 if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
207 return;
208 break;
209 case 'b':
210 case 'd':
211 case 'l':
212 case 't':
213 if (uflag || gflag)
214 return;
215 if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
216 return;
217 break;
218 case 'U':
219 if (gflag)
220 return;
221 break;
222 case 'Z':
223 if (!aflag)
224 return;
225 break;
226 case 'm':
227 case 'f': /* we only see a 'z' when the following is true*/
228 if(!aflag || uflag || gflag)
229 return;
230 if (strcmp(s->name, ".frame"))
231 zenter(s);
232 break;
233 case 'a':
234 case 'p':
235 case 'z':
236 default:
237 if(!aflag || uflag || gflag)
238 return;
239 break;
241 symptr = realloc(symptr, (nsym+1)*sizeof(Sym*));
242 if (symptr == 0) {
243 error("out of memory");
244 exits("memory");
246 symptr[nsym++] = s;
249 void
250 printsyms(Symbol **symptr, long nsym)
252 Symbol *s;
253 char *cp;
254 char path[512];
256 if(!sflag)
257 qsort(symptr, nsym, sizeof(*symptr), cmp);
258 while (nsym-- > 0) {
259 s = *symptr++;
260 if (multifile && !hflag)
261 Bprint(&bout, "%s:", filename);
262 if (s->type == 'z') {
263 fileelem(fnames, (uchar *) s->name, path, 512);
264 cp = path;
265 } else
266 cp = s->name;
267 if (s->value || s->type == 'a' || s->type == 'p')
268 Bprint(&bout, "%8lux %c %s\n", s->value, s->type, cp);
269 else
270 Bprint(&bout, " %c %s\n", s->type, cp);
274 void
275 error(char *fmt, ...)
277 Fmt f;
278 char buf[128];
279 va_list arg;
281 fmtfdinit(&f, 2, buf, sizeof buf);
282 fmtprint(&f, "%s: ", argv0);
283 va_start(arg, fmt);
284 fmtvprint(&f, fmt, arg);
285 va_end(arg);
286 fmtprint(&f, "\n");
287 fmtfdflush(&f);
288 errs = "errors";