1 /* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Hans Huebner. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 static char copyright[] = 13 "@(#) Copyright (c) 1989, 1993\n\ 14 The Regents of the University of California. All rights reserved.\n"; 15 #endif /* not lint */ 16 17 #ifndef lint 18 static char sccsid[] = "@(#)nm.c 8.1 (Berkeley) 06/06/93"; 19 #endif /* not lint */ 20 21 #include <sys/types.h> 22 #include <a.out.h> 23 #include <stab.h> 24 #include <ar.h> 25 #include <ranlib.h> 26 #include <unistd.h> 27 #include <errno.h> 28 #include <ctype.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 33 int ignore_bad_archive_entries = 1; 34 int print_only_external_symbols; 35 int print_only_undefined_symbols; 36 int print_all_symbols; 37 int print_file_each_line; 38 int fcount; 39 40 int rev; 41 int fname(), rname(), value(); 42 int (*sfunc)() = fname; 43 44 /* some macros for symbol type (nlist.n_type) handling */ 45 #define IS_DEBUGGER_SYMBOL(x) ((x) & N_STAB) 46 #define IS_EXTERNAL(x) ((x) & N_EXT) 47 #define SYMBOL_TYPE(x) ((x) & (N_TYPE | N_STAB)) 48 49 void *emalloc(); 50 51 /* 52 * main() 53 * parse command line, execute process_file() for each file 54 * specified on the command line. 55 */ 56 main(argc, argv) 57 int argc; 58 char **argv; 59 { 60 extern int optind; 61 int ch, errors; 62 63 while ((ch = getopt(argc, argv, "agnopruw")) != EOF) { 64 switch (ch) { 65 case 'a': 66 print_all_symbols = 1; 67 break; 68 case 'g': 69 print_only_external_symbols = 1; 70 break; 71 case 'n': 72 sfunc = value; 73 break; 74 case 'o': 75 print_file_each_line = 1; 76 break; 77 case 'p': 78 sfunc = NULL; 79 break; 80 case 'r': 81 rev = 1; 82 break; 83 case 'u': 84 print_only_undefined_symbols = 1; 85 break; 86 case 'w': 87 ignore_bad_archive_entries = 0; 88 break; 89 case '?': 90 default: 91 usage(); 92 } 93 } 94 fcount = argc - optind; 95 argv += optind; 96 97 if (rev && sfunc == fname) 98 sfunc = rname; 99 100 if (!fcount) 101 errors = process_file("a.out"); 102 else { 103 errors = 0; 104 do { 105 errors |= process_file(*argv); 106 } while (*++argv); 107 } 108 exit(errors); 109 } 110 111 /* 112 * process_file() 113 * show symbols in the file given as an argument. Accepts archive and 114 * object files as input. 115 */ 116 process_file(fname) 117 char *fname; 118 { 119 struct exec exec_head; 120 FILE *fp; 121 int retval; 122 char magic[SARMAG]; 123 124 if (!(fp = fopen(fname, "r"))) { 125 (void)fprintf(stderr, "nm: cannot read %s.\n", fname); 126 return(1); 127 } 128 129 if (fcount > 1) 130 (void)printf("\n%s:\n", fname); 131 132 /* 133 * first check whether this is an object file - read a object 134 * header, and skip back to the beginning 135 */ 136 if (fread((char *)&exec_head, sizeof(exec_head), (size_t)1, fp) != 1) { 137 (void)fprintf(stderr, "nm: %s: bad format.\n", fname); 138 (void)fclose(fp); 139 return(1); 140 } 141 rewind(fp); 142 143 /* this could be an archive */ 144 if (N_BADMAG(exec_head)) { 145 if (fread(magic, sizeof(magic), (size_t)1, fp) != 1 || 146 strncmp(magic, ARMAG, SARMAG)) { 147 (void)fprintf(stderr, 148 "nm: %s: not object file or archive.\n", fname); 149 (void)fclose(fp); 150 return(1); 151 } 152 retval = show_archive(fname, fp); 153 } else 154 retval = show_objfile(fname, fp); 155 (void)fclose(fp); 156 return(retval); 157 } 158 159 /* 160 * show_archive() 161 * show symbols in the given archive file 162 */ 163 show_archive(fname, fp) 164 char *fname; 165 FILE *fp; 166 { 167 struct ar_hdr ar_head; 168 struct exec exec_head; 169 int i, rval; 170 long last_ar_off; 171 char *p, *name; 172 173 name = emalloc(sizeof(ar_head.ar_name) + strlen(fname) + 3); 174 175 rval = 0; 176 177 /* while there are more entries in the archive */ 178 while (fread((char *)&ar_head, sizeof(ar_head), (size_t)1, fp) == 1) { 179 /* bad archive entry - stop processing this archive */ 180 if (strncmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) { 181 (void)fprintf(stderr, 182 "nm: %s: bad format archive header", fname); 183 (void)free(name); 184 return(1); 185 } 186 187 /* remember start position of current archive object */ 188 last_ar_off = ftell(fp); 189 190 /* skip ranlib entries */ 191 if (!strncmp(ar_head.ar_name, RANLIBMAG, sizeof(RANLIBMAG) - 1)) 192 goto skip; 193 194 /* 195 * construct a name of the form "archive.a:obj.o:" for the 196 * current archive entry if the object name is to be printed 197 * on each output line 198 */ 199 p = name; 200 if (print_file_each_line) 201 p += sprintf(p, "%s:", fname); 202 for (i = 0; i < sizeof(ar_head.ar_name); ++i) 203 if (ar_head.ar_name[i] && ar_head.ar_name[i] != ' ') 204 *p++ = ar_head.ar_name[i]; 205 *p++ = '\0'; 206 207 /* get and check current object's header */ 208 if (fread((char *)&exec_head, sizeof(exec_head), 209 (size_t)1, fp) != 1) { 210 (void)fprintf(stderr, "nm: %s: premature EOF.\n", name); 211 (void)free(name); 212 return(1); 213 } 214 215 if (N_BADMAG(exec_head)) { 216 if (!ignore_bad_archive_entries) { 217 (void)fprintf(stderr, 218 "nm: %s: bad format.\n", name); 219 rval = 1; 220 } 221 } else { 222 (void)fseek(fp, (long)-sizeof(exec_head), 223 SEEK_CUR); 224 if (!print_file_each_line) 225 (void)printf("\n%s:\n", name); 226 rval |= show_objfile(name, fp); 227 } 228 229 /* 230 * skip to next archive object - it starts at the next 231 * even byte boundary 232 */ 233 #define even(x) (((x) + 1) & ~1) 234 skip: if (fseek(fp, last_ar_off + even(atol(ar_head.ar_size)), 235 SEEK_SET)) { 236 (void)fprintf(stderr, 237 "nm: %s: %s\n", fname, strerror(errno)); 238 (void)free(name); 239 return(1); 240 } 241 } 242 (void)free(name); 243 return(rval); 244 } 245 246 /* 247 * show_objfile() 248 * show symbols from the object file pointed to by fp. The current 249 * file pointer for fp is expected to be at the beginning of an a.out 250 * header. 251 */ 252 show_objfile(objname, fp) 253 char *objname; 254 FILE *fp; 255 { 256 register struct nlist *names, *np; 257 register int i, nnames, nrawnames; 258 struct exec head; 259 long stabsize; 260 char *stab; 261 262 /* read a.out header */ 263 if (fread((char *)&head, sizeof(head), (size_t)1, fp) != 1) { 264 (void)fprintf(stderr, 265 "nm: %s: cannot read header.\n", objname); 266 return(1); 267 } 268 269 /* 270 * skip back to the header - the N_-macros return values relative 271 * to the beginning of the a.out header 272 */ 273 if (fseek(fp, (long)-sizeof(head), SEEK_CUR)) { 274 (void)fprintf(stderr, 275 "nm: %s: %s\n", objname, strerror(errno)); 276 return(1); 277 } 278 279 /* stop if this is no valid object file */ 280 if (N_BADMAG(head)) { 281 (void)fprintf(stderr, 282 "nm: %s: bad format.\n", objname); 283 return(1); 284 } 285 286 /* stop if the object file contains no symbol table */ 287 if (!head.a_syms) { 288 (void)fprintf(stderr, 289 "nm: %s: no name list.\n", objname); 290 return(1); 291 } 292 293 if (fseek(fp, (long)N_SYMOFF(head), SEEK_CUR)) { 294 (void)fprintf(stderr, 295 "nm: %s: %s\n", objname, strerror(errno)); 296 return(1); 297 } 298 299 /* get memory for the symbol table */ 300 names = emalloc((size_t)head.a_syms); 301 nrawnames = head.a_syms / sizeof(*names); 302 if (fread((char *)names, (size_t)head.a_syms, (size_t)1, fp) != 1) { 303 (void)fprintf(stderr, 304 "nm: %s: cannot read symbol table.\n", objname); 305 (void)free((char *)names); 306 return(1); 307 } 308 309 /* 310 * Following the symbol table comes the string table. The first 311 * 4-byte-integer gives the total size of the string table 312 * _including_ the size specification itself. 313 */ 314 if (fread((char *)&stabsize, sizeof(stabsize), (size_t)1, fp) != 1) { 315 (void)fprintf(stderr, 316 "nm: %s: cannot read stab size.\n", objname); 317 (void)free((char *)names); 318 return(1); 319 } 320 stab = emalloc((size_t)stabsize); 321 322 /* 323 * read the string table offset by 4 - all indices into the string 324 * table include the size specification. 325 */ 326 stabsize -= 4; /* we already have the size */ 327 if (fread(stab + 4, (size_t)stabsize, (size_t)1, fp) != 1) { 328 (void)fprintf(stderr, 329 "nm: %s: stab truncated..\n", objname); 330 (void)free((char *)names); 331 (void)free(stab); 332 return(1); 333 } 334 335 /* 336 * fix up the symbol table and filter out unwanted entries 337 * 338 * common symbols are characterized by a n_type of N_UNDF and a 339 * non-zero n_value -- change n_type to N_COMM for all such 340 * symbols to make life easier later. 341 * 342 * filter out all entries which we don't want to print anyway 343 */ 344 for (np = names, i = nnames = 0; i < nrawnames; np++, i++) { 345 if (SYMBOL_TYPE(np->n_type) == N_UNDF && np->n_value) 346 np->n_type = N_COMM | (np->n_type & N_EXT); 347 if (!print_all_symbols && IS_DEBUGGER_SYMBOL(np->n_type)) 348 continue; 349 if (print_only_external_symbols && !IS_EXTERNAL(np->n_type)) 350 continue; 351 if (print_only_undefined_symbols && 352 SYMBOL_TYPE(np->n_type) != N_UNDF) 353 continue; 354 355 /* 356 * make n_un.n_name a character pointer by adding the string 357 * table's base to n_un.n_strx 358 * 359 * don't mess with zero offsets 360 */ 361 if (np->n_un.n_strx) 362 np->n_un.n_name = stab + np->n_un.n_strx; 363 else 364 np->n_un.n_name = ""; 365 names[nnames++] = *np; 366 } 367 368 /* sort the symbol table if applicable */ 369 if (sfunc) 370 qsort((char *)names, (size_t)nnames, sizeof(*names), sfunc); 371 372 /* print out symbols */ 373 for (np = names, i = 0; i < nnames; np++, i++) 374 print_symbol(objname, np); 375 376 (void)free((char *)names); 377 (void)free(stab); 378 return(0); 379 } 380 381 /* 382 * print_symbol() 383 * show one symbol 384 */ 385 print_symbol(objname, sym) 386 char *objname; 387 register struct nlist *sym; 388 { 389 char *typestring(), typeletter(); 390 391 if (print_file_each_line) 392 (void)printf("%s:", objname); 393 394 /* 395 * handle undefined-only format seperately (no space is 396 * left for symbol values, no type field is printed) 397 */ 398 if (print_only_undefined_symbols) { 399 (void)puts(sym->n_un.n_name); 400 return; 401 } 402 403 /* print symbol's value */ 404 if (SYMBOL_TYPE(sym->n_type) == N_UNDF) 405 (void)printf(" "); 406 else 407 (void)printf("%08lx", sym->n_value); 408 409 /* print type information */ 410 if (IS_DEBUGGER_SYMBOL(sym->n_type)) 411 (void)printf(" - %02x %04x %5s ", sym->n_other, 412 sym->n_desc&0xffff, typestring(sym->n_type)); 413 else 414 (void)printf(" %c ", typeletter(sym->n_type)); 415 416 /* print the symbol's name */ 417 (void)puts(sym->n_un.n_name); 418 } 419 420 /* 421 * typestring() 422 * return the a description string for an STAB entry 423 */ 424 char * 425 typestring(type) 426 register u_char type; 427 { 428 switch(type) { 429 case N_BCOMM: 430 return("BCOMM"); 431 case N_ECOML: 432 return("ECOML"); 433 case N_ECOMM: 434 return("ECOMM"); 435 case N_ENTRY: 436 return("ENTRY"); 437 case N_FNAME: 438 return("FNAME"); 439 case N_FUN: 440 return("FUN"); 441 case N_GSYM: 442 return("GSYM"); 443 case N_LBRAC: 444 return("LBRAC"); 445 case N_LCSYM: 446 return("LCSYM"); 447 case N_LENG: 448 return("LENG"); 449 case N_LSYM: 450 return("LSYM"); 451 case N_PC: 452 return("PC"); 453 case N_PSYM: 454 return("PSYM"); 455 case N_RBRAC: 456 return("RBRAC"); 457 case N_RSYM: 458 return("RSYM"); 459 case N_SLINE: 460 return("SLINE"); 461 case N_SO: 462 return("SO"); 463 case N_SOL: 464 return("SOL"); 465 case N_SSYM: 466 return("SSYM"); 467 case N_STSYM: 468 return("STSYM"); 469 } 470 return("???"); 471 } 472 473 /* 474 * typeletter() 475 * return a description letter for the given basic type code of an 476 * symbol table entry. The return value will be upper case for 477 * external, lower case for internal symbols. 478 */ 479 char 480 typeletter(type) 481 u_char type; 482 { 483 switch(SYMBOL_TYPE(type)) { 484 case N_ABS: 485 return(IS_EXTERNAL(type) ? 'A' : 'a'); 486 case N_BSS: 487 return(IS_EXTERNAL(type) ? 'B' : 'b'); 488 case N_COMM: 489 return(IS_EXTERNAL(type) ? 'C' : 'c'); 490 case N_DATA: 491 return(IS_EXTERNAL(type) ? 'D' : 'd'); 492 case N_FN: 493 return(IS_EXTERNAL(type) ? 'F' : 'f'); 494 case N_TEXT: 495 return(IS_EXTERNAL(type) ? 'T' : 't'); 496 case N_UNDF: 497 return(IS_EXTERNAL(type) ? 'U' : 'u'); 498 } 499 return('?'); 500 } 501 502 fname(a0, b0) 503 void *a0, *b0; 504 { 505 struct nlist *a = a0, *b = b0; 506 507 return(strcmp(a->n_un.n_name, b->n_un.n_name)); 508 } 509 510 rname(a0, b0) 511 void *a0, *b0; 512 { 513 struct nlist *a = a0, *b = b0; 514 515 return(strcmp(b->n_un.n_name, a->n_un.n_name)); 516 } 517 518 value(a0, b0) 519 void *a0, *b0; 520 { 521 register struct nlist *a = a0, *b = b0; 522 523 if (SYMBOL_TYPE(a->n_type) == N_UNDF) 524 if (SYMBOL_TYPE(b->n_type) == N_UNDF) 525 return(0); 526 else 527 return(-1); 528 else if (SYMBOL_TYPE(b->n_type) == N_UNDF) 529 return(1); 530 if (rev) { 531 if (a->n_value == b->n_value) 532 return(rname(a0, b0)); 533 return(b->n_value > a->n_value ? 1 : -1); 534 } else { 535 if (a->n_value == b->n_value) 536 return(fname(a0, b0)); 537 return(a->n_value > b->n_value ? 1 : -1); 538 } 539 } 540 541 void * 542 emalloc(size) 543 size_t size; 544 { 545 char *p; 546 547 /* NOSTRICT */ 548 if (p = malloc(size)) 549 return(p); 550 (void)fprintf(stderr, "nm: %s\n", strerror(errno)); 551 exit(1); 552 } 553 554 usage() 555 { 556 (void)fprintf(stderr, "usage: nm [-agnopruw] [file ...]\n"); 557 exit(1); 558 } 559