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