]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/nm.c
upas/fs: remove imap lastread debounding
[plan9front.git] / sys / src / cmd / nm.c
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
41 usage(void)
42 {
43         fprint(2, "usage: nm [-aghnsTu] file ...\n");
44         exits("usage");
45 }
46
47 void
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
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
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(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
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
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         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
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 }