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 aflag, 19 gflag, 20 hflag, 21 nflag, 22 sflag, 23 uflag; 24 25 Sym **fnames; /* file path translation table */ 26 Sym **symptr; 27 int nsym; 28 Biobuf bout; 29 30 int cmp(Sym **, Sym **); 31 void error(char*, ...), 32 execsyms(int), 33 psym(Sym*, void*), 34 printsyms(Sym**, long), 35 doar(Biobuf*), 36 dofile(Biobuf*), 37 zenter(Sym*); 38 39 void 40 main(int argc, char *argv[]) 41 { 42 int i; 43 Biobuf *bin; 44 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\n", 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 } 74 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]; 84 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\n", 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\n", 99 membername, filename); 100 return; 101 } 102 if (!readar(bp, obj, offset+size, 1)) { 103 error("invalid symbol reference in file %s\n", 104 membername); 105 return; 106 } 107 filename = membername; 108 nsym=0; 109 objtraverse(psym, 0); 110 printsyms(symptr, nsym); 111 } 112 } 113 114 /* 115 * process symbols in a file 116 */ 117 void 118 dofile(Biobuf *bp) 119 { 120 int obj; 121 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); 130 } 131 } 132 133 /* 134 * comparison routine for sorting the symbol table 135 * this screws up on 'z' records when aflag == 1 136 */ 137 int 138 cmp(Sym **s, Sym **t) 139 { 140 if(nflag) 141 if((*s)->value < (*t)->value) 142 return -1; 143 else 144 return (*s)->value > (*t)->value; 145 return strcmp((*s)->name, (*t)->name); 146 } 147 /* 148 * enter a symbol in the table of filename elements 149 */ 150 void 151 zenter(Sym *s) 152 { 153 static int maxf = 0; 154 155 if (s->value > maxf) { 156 maxf = (s->value+CHUNK-1) &~ (CHUNK-1); 157 fnames = realloc(fnames, maxf*sizeof(*fnames)); 158 if(fnames == 0) { 159 error("out of memory\n", argv0); 160 exits("memory"); 161 } 162 } 163 fnames[s->value] = s; 164 } 165 166 /* 167 * get the symbol table from an executable file, if it has one 168 */ 169 void 170 execsyms(int fd) 171 { 172 Fhdr f; 173 Sym *s; 174 long n; 175 176 seek(fd, 0, 0); 177 if (crackhdr(fd, &f) == 0) { 178 error("Can't read header for %s\n", filename); 179 return; 180 } 181 if (syminit(fd, &f) < 0) 182 return; 183 s = symbase(&n); 184 nsym = 0; 185 while(n--) 186 psym(s++, 0); 187 188 printsyms(symptr, nsym); 189 } 190 191 void 192 psym(Sym *s, void* p) 193 { 194 USED(p); 195 switch(s->type) { 196 case 'T': 197 case 'L': 198 case 'D': 199 case 'B': 200 if (uflag) 201 return; 202 if (!aflag && ((s->name[0] == '.' || s->name[0] == '$'))) 203 return; 204 break; 205 case 'b': 206 case 'd': 207 case 'l': 208 case 't': 209 if (uflag || gflag) 210 return; 211 if (!aflag && ((s->name[0] == '.' || s->name[0] == '$'))) 212 return; 213 break; 214 case 'U': 215 if (gflag) 216 return; 217 break; 218 case 'Z': 219 if (!aflag) 220 return; 221 break; 222 case 'm': 223 case 'f': /* we only see a 'z' when the following is true*/ 224 if(!aflag || uflag || gflag) 225 return; 226 if (strcmp(s->name, ".frame")) 227 zenter(s); 228 break; 229 case 'a': 230 case 'p': 231 case 'z': 232 default: 233 if(!aflag || uflag || gflag) 234 return; 235 break; 236 } 237 symptr = realloc(symptr, (nsym+1)*sizeof(Sym*)); 238 if (symptr == 0) { 239 error("out of memory\n"); 240 exits("memory"); 241 } 242 symptr[nsym++] = s; 243 } 244 245 void 246 printsyms(Sym **symptr, int nsym) 247 { 248 Sym *s; 249 char *cp; 250 char path[512]; 251 252 if(!sflag) 253 qsort(symptr, nsym, sizeof(*symptr), cmp); 254 while (nsym-- > 0) { 255 s = *symptr++; 256 if (multifile && !hflag) 257 Bprint(&bout, "%s:", filename); 258 if (s->type == 'z') { 259 fileelem(fnames, (uchar *) s->name, path, 512); 260 cp = path; 261 } else 262 cp = s->name; 263 if (s->value || s->type == 'a' || s->type == 'p') 264 Bprint(&bout, "%8lux %c %s\n", s->value, s->type, cp); 265 else 266 Bprint(&bout, " %c %s\n", s->type, cp); 267 } 268 } 269 270 void 271 error(char *fmt, ...) 272 { 273 char buf[4096], *s; 274 275 s = buf; 276 s += sprint(s, "%s: ", argv0); 277 s = doprint(s, buf + sizeof(buf) / sizeof(*buf), fmt, &fmt + 1); 278 *s++ = '\n'; 279 write(2, buf, s - buf); 280 errs = "errors"; 281 } 282