nm.c (4945B)
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 25 Symbol **fnames; /* file path translation table */ 26 Symbol **symptr; 27 int nsym; 28 Biobuf bout; 29 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*); 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", 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", 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; 101 } 102 if (!readar(bp, obj, offset+size, 1)) { 103 error("invalid symbol reference in file %s", 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(void *vs, void *vt) 139 { 140 Symbol **s, **t; 141 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); 150 } 151 /* 152 * enter a symbol in the table of filename elements 153 */ 154 void 155 zenter(Symbol *s) 156 { 157 static int maxf = 0; 158 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"); 165 } 166 } 167 fnames[s->value] = s; 168 } 169 170 /* 171 * get the symbol table from an executable file, if it has one 172 */ 173 void 174 execsyms(int fd) 175 { 176 Fhdr f; 177 Symbol *s; 178 long n; 179 180 seek(fd, 0, 0); 181 if (crackhdr(fd, &f) == 0) { 182 error("Can't read header for %s", filename); 183 return; 184 } 185 if (syminit(fd, &f) < 0) 186 return; 187 s = symbase(&n); 188 nsym = 0; 189 while(n--) 190 psym(s++, 0); 191 192 printsyms(symptr, nsym); 193 } 194 195 void 196 psym(Symbol *s, void* p) 197 { 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; 240 } 241 symptr = realloc(symptr, (nsym+1)*sizeof(Sym*)); 242 if (symptr == 0) { 243 error("out of memory"); 244 exits("memory"); 245 } 246 symptr[nsym++] = s; 247 } 248 249 void 250 printsyms(Symbol **symptr, long nsym) 251 { 252 Symbol *s; 253 char *cp; 254 char path[512]; 255 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); 271 } 272 } 273 274 void 275 error(char *fmt, ...) 276 { 277 Fmt f; 278 char buf[128]; 279 va_list arg; 280 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"; 289 }