github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/nm/nm.c (about) 1 // Inferno utils/nm/nm.c 2 // http://code.google.com/p/inferno-os/source/browse/utils/nm/nm.c 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 6 // Portions Copyright © 1997-1999 Vita Nuova Limited 7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) 8 // Portions Copyright © 2004,2006 Bruce Ellis 9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others 11 // Portions Copyright © 2009 The Go Authors. All rights reserved. 12 // 13 // Permission is hereby granted, free of charge, to any person obtaining a copy 14 // of this software and associated documentation files (the "Software"), to deal 15 // in the Software without restriction, including without limitation the rights 16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 // copies of the Software, and to permit persons to whom the Software is 18 // furnished to do so, subject to the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be included in 21 // all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 // THE SOFTWARE. 30 31 /* 32 * nm.c -- drive nm 33 */ 34 #include <u.h> 35 #include <libc.h> 36 #include <ar.h> 37 #include <bio.h> 38 #include <mach.h> 39 40 enum{ 41 CHUNK = 256 /* must be power of 2 */ 42 }; 43 44 char *errs; /* exit status */ 45 char *filename; /* current file */ 46 char symname[]="__.GOSYMDEF"; /* table of contents file name */ 47 int multifile; /* processing multiple files */ 48 int aflag; 49 int gflag; 50 int hflag; 51 int nflag; 52 int sflag; 53 int Sflag; 54 int uflag; 55 int Tflag; 56 int tflag; 57 58 Sym **fnames; /* file path translation table */ 59 Sym **symptr; 60 int nsym; 61 Biobuf bout; 62 63 int cmp(void*, void*); 64 void error(char*, ...); 65 void execsyms(int); 66 void psym(Sym*, void*); 67 void printsyms(Sym**, long); 68 void doar(Biobuf*); 69 void dofile(Biobuf*); 70 void zenter(Sym*); 71 72 void 73 usage(void) 74 { 75 fprint(2, "usage: nm [-aghnsTu] file ...\n"); 76 exits("usage"); 77 } 78 79 void 80 main(int argc, char *argv[]) 81 { 82 int i; 83 Biobuf *bin; 84 85 Binit(&bout, 1, OWRITE); 86 argv0 = argv[0]; 87 ARGBEGIN { 88 default: usage(); 89 case 'a': aflag = 1; break; 90 case 'g': gflag = 1; break; 91 case 'h': hflag = 1; break; 92 case 'n': nflag = 1; break; 93 case 's': sflag = 1; break; 94 case 'S': nflag = Sflag = 1; break; 95 case 'u': uflag = 1; break; 96 case 't': tflag = 1; break; 97 case 'T': Tflag = 1; break; 98 } ARGEND 99 if (argc == 0) 100 usage(); 101 if (argc > 1) 102 multifile++; 103 for(i=0; i<argc; i++){ 104 filename = argv[i]; 105 bin = Bopen(filename, OREAD); 106 if(bin == 0){ 107 error("cannot open %s", filename); 108 continue; 109 } 110 if (isar(bin)) 111 doar(bin); 112 else{ 113 Bseek(bin, 0, 0); 114 dofile(bin); 115 } 116 Bterm(bin); 117 } 118 exits(errs); 119 } 120 121 /* 122 * read an archive file, 123 * processing the symbols for each intermediate file in it. 124 */ 125 void 126 doar(Biobuf *bp) 127 { 128 int offset, size, obj; 129 char name[SARNAME]; 130 131 multifile = 1; 132 for (offset = Boffset(bp);;offset += size) { 133 size = nextar(bp, offset, name); 134 if (size < 0) { 135 error("phase error on ar header %d", offset); 136 return; 137 } 138 if (size == 0) 139 return; 140 if (strcmp(name, symname) == 0) 141 continue; 142 obj = objtype(bp, 0); 143 if (obj < 0) { 144 // perhaps foreign object 145 if(strlen(name) > 2 && strcmp(name+strlen(name)-2, ".o") == 0) 146 return; 147 error("inconsistent file %s in %s", 148 name, filename); 149 return; 150 } 151 if (!readar(bp, obj, offset+size, 1)) { 152 error("invalid symbol reference in file %s", 153 name); 154 return; 155 } 156 filename = name; 157 nsym=0; 158 objtraverse(psym, 0); 159 printsyms(symptr, nsym); 160 } 161 } 162 163 /* 164 * process symbols in a file 165 */ 166 void 167 dofile(Biobuf *bp) 168 { 169 int obj; 170 171 obj = objtype(bp, 0); 172 if (obj < 0) 173 execsyms(Bfildes(bp)); 174 else 175 if (readobj(bp, obj)) { 176 nsym = 0; 177 objtraverse(psym, 0); 178 printsyms(symptr, nsym); 179 } 180 } 181 182 /* 183 * comparison routine for sorting the symbol table 184 * this screws up on 'z' records when aflag == 1 185 */ 186 int 187 cmp(void *vs, void *vt) 188 { 189 Sym **s, **t; 190 191 s = vs; 192 t = vt; 193 if(nflag) // sort on address (numeric) order 194 if((*s)->value < (*t)->value) 195 return -1; 196 else 197 return (*s)->value > (*t)->value; 198 if(sflag) // sort on file order (sequence) 199 return (*s)->sequence - (*t)->sequence; 200 return strcmp((*s)->name, (*t)->name); 201 } 202 /* 203 * enter a symbol in the table of filename elements 204 */ 205 void 206 zenter(Sym *s) 207 { 208 static int maxf = 0; 209 210 if (s->value > maxf) { 211 maxf = (s->value+CHUNK-1) &~ (CHUNK-1); 212 fnames = realloc(fnames, (maxf+1)*sizeof(*fnames)); 213 if(fnames == 0) { 214 error("out of memory", argv0); 215 exits("memory"); 216 } 217 } 218 fnames[s->value] = s; 219 } 220 221 /* 222 * get the symbol table from an executable file, if it has one 223 */ 224 void 225 execsyms(int fd) 226 { 227 Fhdr f; 228 Sym *s; 229 int32 n; 230 231 seek(fd, 0, 0); 232 if (crackhdr(fd, &f) == 0) { 233 error("Can't read header for %s", filename); 234 return; 235 } 236 if (syminit(fd, &f) < 0) 237 return; 238 s = symbase(&n); 239 nsym = 0; 240 while(n--) 241 psym(s++, 0); 242 243 printsyms(symptr, nsym); 244 } 245 246 void 247 psym(Sym *s, void* p) 248 { 249 USED(p); 250 switch(s->type) { 251 case 'T': 252 case 'L': 253 case 'D': 254 case 'B': 255 if (uflag) 256 return; 257 if (!aflag && ((s->name[0] == '.' || s->name[0] == '$'))) 258 return; 259 break; 260 case 'b': 261 case 'd': 262 case 'l': 263 case 't': 264 if (uflag || gflag) 265 return; 266 if (!aflag && ((s->name[0] == '.' || s->name[0] == '$'))) 267 return; 268 break; 269 case 'U': 270 if (gflag) 271 return; 272 break; 273 case 'Z': 274 if (!aflag) 275 return; 276 break; 277 case 'm': 278 if(!aflag || uflag || gflag) 279 return; 280 break; 281 case 'f': /* we only see a 'z' when the following is true*/ 282 if(!aflag || uflag || gflag) 283 return; 284 zenter(s); 285 break; 286 case 'a': 287 case 'p': 288 case 'z': 289 default: 290 if(!aflag || uflag || gflag) 291 return; 292 break; 293 } 294 symptr = realloc(symptr, (nsym+1)*sizeof(Sym*)); 295 if (symptr == 0) { 296 error("out of memory"); 297 exits("memory"); 298 } 299 symptr[nsym++] = s; 300 } 301 302 void 303 printsyms(Sym **symptr, long nsym) 304 { 305 int i, j, wid; 306 Sym *s; 307 char *cp; 308 char path[512]; 309 310 qsort(symptr, nsym, sizeof(*symptr), (void*)cmp); 311 312 wid = 0; 313 for (i=0; i<nsym; i++) { 314 s = symptr[i]; 315 if (s->value && wid == 0) 316 wid = 8; 317 else if (s->value >= 0x100000000LL && wid == 8) 318 wid = 16; 319 } 320 for (i=0; i<nsym; i++) { 321 s = symptr[i]; 322 if (multifile && !hflag) 323 Bprint(&bout, "%s:", filename); 324 if (s->type == 'z') { 325 fileelem(fnames, (uchar *) s->name, path, 512); 326 cp = path; 327 } else 328 cp = s->name; 329 if (Tflag) 330 Bprint(&bout, "%8ux ", s->sig); 331 if (s->value || s->type == 'a' || s->type == 'p') 332 Bprint(&bout, "%*llux ", wid, s->value); 333 else 334 Bprint(&bout, "%*s ", wid, ""); 335 if(Sflag) { 336 vlong siz; 337 338 siz = 0; 339 for(j=i+1; j<nsym; j++) { 340 if(symptr[j]->type != 'a' && symptr[j]->type != 'p') { 341 siz = symptr[j]->value - s->value; 342 break; 343 } 344 } 345 if(siz > 0) 346 Bprint(&bout, "%*llud ", wid, siz); 347 } 348 Bprint(&bout, "%c %s", s->type, cp); 349 if(tflag && s->gotype) 350 Bprint(&bout, " %*llux", wid, s->gotype); 351 Bprint(&bout, "\n"); 352 } 353 } 354 355 void 356 error(char *fmt, ...) 357 { 358 Fmt f; 359 char buf[128]; 360 va_list arg; 361 362 fmtfdinit(&f, 2, buf, sizeof buf); 363 fmtprint(&f, "%s: ", argv0); 364 va_start(arg, fmt); 365 fmtvprint(&f, fmt, arg); 366 va_end(arg); 367 fmtprint(&f, "\n"); 368 fmtfdflush(&f); 369 errs = "errors"; 370 }