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