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