130855Sbostic /* 239109Sbostic * Copyright (c) 1989 The Regents of the University of California. 339109Sbostic * All rights reserved. 439109Sbostic * 539109Sbostic * This code is derived from software contributed to Berkeley by 639109Sbostic * Hans Huebner. 739109Sbostic * 842689Sbostic * %sccs.include.redist.c% 930855Sbostic */ 1030855Sbostic 1112672Ssam #ifndef lint 1239109Sbostic char copyright[] = 1339109Sbostic "@(#) Copyright (c) 1989 The Regents of the University of California.\n\ 1439109Sbostic All rights reserved.\n"; 1539109Sbostic #endif /* not lint */ 1630855Sbostic 1739109Sbostic #ifndef lint 18*46550Sbostic static char sccsid[] = "@(#)nm.c 5.7 (Berkeley) 02/22/91"; 1939109Sbostic #endif /* not lint */ 2030855Sbostic 21619Sbill #include <sys/types.h> 22653Sbill #include <a.out.h> 23619Sbill #include <stab.h> 2439109Sbostic #include <ar.h> 2530855Sbostic #include <ranlib.h> 2639109Sbostic #include <unistd.h> 2739109Sbostic #include <errno.h> 2839109Sbostic #include <ctype.h> 2939109Sbostic #include <stdio.h> 3042452Sbostic #include <stdlib.h> 3142034Sbostic #include <string.h> 32619Sbill 3340272Sbostic int ignore_bad_archive_entries = 1; 3440272Sbostic int print_only_external_symbols; 3540272Sbostic int print_only_undefined_symbols; 3640272Sbostic int print_all_symbols; 3740272Sbostic int print_file_each_line; 3840272Sbostic int cmp_value(), cmp_name(); 3940272Sbostic int (*sort_func)() = cmp_name; 4040272Sbostic 4139109Sbostic enum { FORWARD, BACKWARD } sort_direction = FORWARD; 4239109Sbostic int fcount; 4330855Sbostic 4439109Sbostic /* some macros for symbol type (nlist.n_type) handling */ 4539109Sbostic #define IS_DEBUGGER_SYMBOL(x) ((x) & N_STAB) 4639109Sbostic #define IS_EXTERNAL(x) ((x) & N_EXT) 4739109Sbostic #define SYMBOL_TYPE(x) ((x) & (N_TYPE | N_STAB)) 4830855Sbostic 4939109Sbostic /* 5039109Sbostic * main() 5139109Sbostic * parse command line, execute process_file() for each file 5239109Sbostic * specified on the command line. 5339109Sbostic */ 54619Sbill main(argc, argv) 5539109Sbostic int argc; 5639109Sbostic char **argv; 57619Sbill { 5839109Sbostic extern int optind; 5939109Sbostic int ch, errors; 60619Sbill 6139109Sbostic while ((ch = getopt(argc, argv, "agnopruw")) != EOF) { 6239109Sbostic switch (ch) { 6330855Sbostic case 'a': 6439109Sbostic print_all_symbols = 1; 6530855Sbostic break; 6630855Sbostic case 'g': 6739109Sbostic print_only_external_symbols = 1; 6830855Sbostic break; 69619Sbill case 'n': 7039109Sbostic sort_func = cmp_value; 7130855Sbostic break; 7230855Sbostic case 'o': 7339109Sbostic print_file_each_line = 1; 7430855Sbostic break; 7530855Sbostic case 'p': 7639109Sbostic sort_func = NULL; 7730855Sbostic break; 78619Sbill case 'r': 7939109Sbostic sort_direction = BACKWARD; 8030855Sbostic break; 8130855Sbostic case 'u': 8239109Sbostic print_only_undefined_symbols = 1; 8330855Sbostic break; 8439109Sbostic case 'w': 8539109Sbostic ignore_bad_archive_entries = 0; 8639109Sbostic break; 8730855Sbostic case '?': 88619Sbill default: 8939109Sbostic usage(); 90619Sbill } 9139109Sbostic } 9239109Sbostic fcount = argc - optind; 9330855Sbostic argv += optind; 9439109Sbostic 9539109Sbostic if (!fcount) 9639109Sbostic errors = process_file("a.out"); 9739109Sbostic else { 9839109Sbostic errors = 0; 9939109Sbostic do { 10039109Sbostic errors |= process_file(*argv); 10139109Sbostic } while (*++argv); 102619Sbill } 10339109Sbostic exit(errors); 104619Sbill } 105619Sbill 10639109Sbostic /* 10739109Sbostic * process_file() 10839109Sbostic * show symbols in the file given as an argument. Accepts archive and 10939109Sbostic * object files as input. 11039109Sbostic */ 11139109Sbostic process_file(fname) 11239109Sbostic char *fname; 113619Sbill { 11439109Sbostic struct exec exec_head; 11539109Sbostic FILE *fp; 11639109Sbostic int retval; 11739109Sbostic char magic[SARMAG]; 11839109Sbostic 11939109Sbostic if (!(fp = fopen(fname, "r"))) { 12039109Sbostic (void)fprintf(stderr, "nm: cannot read %s.\n", fname); 12139109Sbostic return(1); 12239109Sbostic } 123619Sbill 12439109Sbostic if (fcount > 1) 12539109Sbostic (void)printf("\n%s:\n", fname); 12639109Sbostic 12730855Sbostic /* 12839109Sbostic * first check whether this is an object file - read a object 12939109Sbostic * header, and skip back to the beginning 13030855Sbostic */ 13142452Sbostic if (fread((char *)&exec_head, sizeof(exec_head), (size_t)1, fp) != 1) { 13239109Sbostic (void)fprintf(stderr, "nm: %s: bad format.\n", fname); 13339109Sbostic (void)fclose(fp); 13439109Sbostic return(1); 135619Sbill } 13639109Sbostic rewind(fp); 13739109Sbostic 13839109Sbostic /* this could be an archive */ 13939109Sbostic if (N_BADMAG(exec_head)) { 14042452Sbostic if (fread(magic, sizeof(magic), (size_t)1, fp) != 1 || 14139109Sbostic strncmp(magic, ARMAG, SARMAG)) { 14239109Sbostic (void)fprintf(stderr, 14339109Sbostic "nm: %s: not object file or archive.\n", fname); 14439109Sbostic (void)fclose(fp); 14539109Sbostic return(1); 14630855Sbostic } 14739109Sbostic retval = show_archive(fname, fp); 14839109Sbostic } else 14939109Sbostic retval = show_objfile(fname, fp); 15039109Sbostic (void)fclose(fp); 15139109Sbostic return(retval); 15239109Sbostic } 15339109Sbostic 15439109Sbostic /* 15539109Sbostic * show_archive() 15639109Sbostic * show symbols in the given archive file 15739109Sbostic */ 15839109Sbostic show_archive(fname, fp) 15939109Sbostic char *fname; 16039109Sbostic FILE *fp; 16139109Sbostic { 16239109Sbostic struct ar_hdr ar_head; 16339109Sbostic struct exec exec_head; 16442452Sbostic int i, rval; 16542452Sbostic long last_ar_off; 16639109Sbostic char *p, *name, *emalloc(); 16739109Sbostic long atol(); 16839109Sbostic 16942452Sbostic name = emalloc(sizeof(ar_head.ar_name) + strlen(fname) + 3); 17039109Sbostic 17139109Sbostic rval = 0; 17239109Sbostic 17339109Sbostic /* while there are more entries in the archive */ 17442452Sbostic while (fread((char *)&ar_head, sizeof(ar_head), (size_t)1, fp) == 1) { 17539109Sbostic /* bad archive entry - stop processing this archive */ 17639109Sbostic if (strncmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) { 17739109Sbostic (void)fprintf(stderr, 17839109Sbostic "nm: %s: bad format archive header", fname); 17939109Sbostic (void)free(name); 18039109Sbostic return(1); 18139109Sbostic } 18239109Sbostic 183*46550Sbostic /* remember start position of current archive object */ 184*46550Sbostic last_ar_off = ftell(fp); 185*46550Sbostic 186*46550Sbostic /* skip ranlib entries */ 187*46550Sbostic if (!strncmp(ar_head.ar_name, RANLIBMAG, sizeof(RANLIBMAG) - 1)) 188*46550Sbostic goto skip; 189*46550Sbostic 19030855Sbostic /* 19139143Sbostic * construct a name of the form "archive.a:obj.o:" for the 19239109Sbostic * current archive entry if the object name is to be printed 19339109Sbostic * on each output line 19430855Sbostic */ 19542452Sbostic p = name; 19642452Sbostic if (print_file_each_line) 19742452Sbostic p += sprintf(p, "%s:", fname); 19839109Sbostic for (i = 0; i < sizeof(ar_head.ar_name); ++i) 19939109Sbostic if (ar_head.ar_name[i] && ar_head.ar_name[i] != ' ') 20039109Sbostic *p++ = ar_head.ar_name[i]; 20139109Sbostic *p++ = '\0'; 20230855Sbostic 20339109Sbostic /* get and check current object's header */ 20442452Sbostic if (fread((char *)&exec_head, sizeof(exec_head), 20542452Sbostic (size_t)1, fp) != 1) { 20639109Sbostic (void)fprintf(stderr, "nm: %s: premature EOF.\n", name); 20739109Sbostic (void)free(name); 20839109Sbostic return(1); 209619Sbill } 210*46550Sbostic 211*46550Sbostic if (N_BADMAG(exec_head)) { 212*46550Sbostic if (!ignore_bad_archive_entries) { 213*46550Sbostic (void)fprintf(stderr, 214*46550Sbostic "nm: %s: bad format.\n", name); 215*46550Sbostic rval = 1; 21639109Sbostic } 217*46550Sbostic } else { 218*46550Sbostic (void)fseek(fp, (long)-sizeof(exec_head), 219*46550Sbostic SEEK_CUR); 220*46550Sbostic if (!print_file_each_line) 221*46550Sbostic (void)printf("\n%s:\n", name); 222*46550Sbostic rval |= show_objfile(name, fp); 223*46550Sbostic } 22430855Sbostic 22539109Sbostic /* 22642452Sbostic * skip to next archive object - it starts at the next 22742452Sbostic * even byte boundary 22839109Sbostic */ 22942452Sbostic #define even(x) (((x) + 1) & ~1) 230*46550Sbostic skip: if (fseek(fp, last_ar_off + even(atol(ar_head.ar_size)), 23139109Sbostic SEEK_SET)) { 23239109Sbostic (void)fprintf(stderr, 23339109Sbostic "nm: %s: %s\n", fname, strerror(errno)); 23439109Sbostic (void)free(name); 23539109Sbostic return(1); 23630855Sbostic } 23739109Sbostic } 23839109Sbostic (void)free(name); 23939109Sbostic return(rval); 24039109Sbostic } 24130855Sbostic 24239109Sbostic /* 24339109Sbostic * show_objfile() 24439109Sbostic * show symbols from the object file pointed to by fp. The current 24539109Sbostic * file pointer for fp is expected to be at the beginning of an a.out 24639109Sbostic * header. 24739109Sbostic */ 24839109Sbostic show_objfile(objname, fp) 24939109Sbostic char *objname; 25039109Sbostic FILE *fp; 25139109Sbostic { 25242452Sbostic register struct nlist *names, *np; 25339109Sbostic register int i, nnames, nrawnames; 25439109Sbostic struct exec head; 25539109Sbostic long stabsize; 25639109Sbostic char *stab, *emalloc(); 25739109Sbostic 25839109Sbostic /* read a.out header */ 25942452Sbostic if (fread((char *)&head, sizeof(head), (size_t)1, fp) != 1) { 26039109Sbostic (void)fprintf(stderr, 26139109Sbostic "nm: %s: cannot read header.\n", objname); 26239109Sbostic return(1); 26339109Sbostic } 26439109Sbostic 26539109Sbostic /* 26639109Sbostic * skip back to the header - the N_-macros return values relative 26739109Sbostic * to the beginning of the a.out header 26839109Sbostic */ 26939109Sbostic if (fseek(fp, (long)-sizeof(head), SEEK_CUR)) { 27039109Sbostic (void)fprintf(stderr, 27139109Sbostic "nm: %s: %s\n", objname, strerror(errno)); 27239109Sbostic return(1); 27339109Sbostic } 27439109Sbostic 27539109Sbostic /* stop if this is no valid object file */ 27639109Sbostic if (N_BADMAG(head)) { 27739109Sbostic (void)fprintf(stderr, 27839109Sbostic "nm: %s: bad format.\n", objname); 27939109Sbostic return(1); 28039109Sbostic } 28139109Sbostic 28239109Sbostic /* stop if the object file contains no symbol table */ 28339109Sbostic if (!head.a_syms) { 28439109Sbostic (void)fprintf(stderr, 28539109Sbostic "nm: %s: no name list.\n", objname); 28639109Sbostic return(1); 28739109Sbostic } 28839109Sbostic 28939109Sbostic if (fseek(fp, (long)N_SYMOFF(head), SEEK_CUR)) { 29039109Sbostic (void)fprintf(stderr, 29139109Sbostic "nm: %s: %s\n", objname, strerror(errno)); 29239109Sbostic return(1); 29339109Sbostic } 29439109Sbostic 29539109Sbostic /* get memory for the symbol table */ 29642452Sbostic names = (struct nlist *)emalloc((size_t)head.a_syms); 29739109Sbostic nrawnames = head.a_syms / sizeof(*names); 29842452Sbostic if (fread((char *)names, (size_t)head.a_syms, (size_t)1, fp) != 1) { 29939109Sbostic (void)fprintf(stderr, 30039109Sbostic "nm: %s: cannot read symbol table.\n", objname); 30139109Sbostic (void)free((char *)names); 30239109Sbostic return(1); 30339109Sbostic } 30439109Sbostic 30539109Sbostic /* 30639109Sbostic * Following the symbol table comes the string table. The first 30739109Sbostic * 4-byte-integer gives the total size of the string table 30839109Sbostic * _including_ the size specification itself. 30939109Sbostic */ 31042452Sbostic if (fread((char *)&stabsize, sizeof(stabsize), (size_t)1, fp) != 1) { 31139109Sbostic (void)fprintf(stderr, 31239109Sbostic "nm: %s: cannot read stab size.\n", objname); 31339109Sbostic (void)free((char *)names); 31439109Sbostic return(1); 31539109Sbostic } 31642452Sbostic stab = emalloc((size_t)stabsize); 31739109Sbostic 31839109Sbostic /* 31939109Sbostic * read the string table offset by 4 - all indices into the string 32039109Sbostic * table include the size specification. 32139109Sbostic */ 32239143Sbostic stabsize -= 4; /* we already have the size */ 32342452Sbostic if (fread(stab + 4, (size_t)stabsize, (size_t)1, fp) != 1) { 32439109Sbostic (void)fprintf(stderr, 32539109Sbostic "nm: %s: stab truncated..\n", objname); 32639109Sbostic (void)free((char *)names); 32739109Sbostic (void)free(stab); 32839109Sbostic return(1); 32939109Sbostic } 33039109Sbostic 33139109Sbostic /* 33239109Sbostic * fix up the symbol table and filter out unwanted entries 33339109Sbostic * 33439109Sbostic * common symbols are characterized by a n_type of N_UNDF and a 33539109Sbostic * non-zero n_value -- change n_type to N_COMM for all such 33639109Sbostic * symbols to make life easier later. 33739109Sbostic * 33839109Sbostic * filter out all entries which we don't want to print anyway 33939109Sbostic */ 34042452Sbostic for (np = names, i = nnames = 0; i < nrawnames; np++, i++) { 34142452Sbostic if (SYMBOL_TYPE(np->n_type) == N_UNDF && np->n_value) 34242452Sbostic np->n_type = N_COMM | (np->n_type & N_EXT); 34342452Sbostic if (!print_all_symbols && IS_DEBUGGER_SYMBOL(np->n_type)) 34430855Sbostic continue; 34542452Sbostic if (print_only_external_symbols && !IS_EXTERNAL(np->n_type)) 346619Sbill continue; 34739109Sbostic if (print_only_undefined_symbols && 34842452Sbostic SYMBOL_TYPE(np->n_type) != N_UNDF) 34939109Sbostic continue; 35030855Sbostic 35139109Sbostic /* 35239109Sbostic * make n_un.n_name a character pointer by adding the string 35339109Sbostic * table's base to n_un.n_strx 35439109Sbostic * 35542452Sbostic * don't mess with zero offsets 35639109Sbostic */ 35742452Sbostic if (np->n_un.n_strx) 35842452Sbostic np->n_un.n_name = stab + np->n_un.n_strx; 35939109Sbostic else 36042452Sbostic np->n_un.n_name = ""; 36142452Sbostic names[nnames++] = *np; 36239109Sbostic } 36330855Sbostic 36439109Sbostic /* sort the symbol table if applicable */ 36539109Sbostic if (sort_func) 36642452Sbostic qsort((char *)names, (size_t)nnames, sizeof(*names), sort_func); 36730855Sbostic 36839109Sbostic /* print out symbols */ 36942452Sbostic for (np = names, i = 0; i < nnames; np++, i++) 37042452Sbostic print_symbol(objname, np); 37130855Sbostic 37239109Sbostic (void)free((char *)names); 37339109Sbostic (void)free(stab); 37439109Sbostic return(0); 375619Sbill } 376619Sbill 37739109Sbostic /* 37839109Sbostic * print_symbol() 37939109Sbostic * show one symbol 38039109Sbostic */ 38139109Sbostic print_symbol(objname, sym) 38239109Sbostic char *objname; 38342452Sbostic register struct nlist *sym; 384619Sbill { 38539109Sbostic char *typestring(), typeletter(); 386619Sbill 38739109Sbostic if (print_file_each_line) 38842452Sbostic (void)printf("%s:", objname); 38939109Sbostic 39039109Sbostic /* 39139109Sbostic * handle undefined-only format seperately (no space is 39239109Sbostic * left for symbol values, no type field is printed) 39339109Sbostic */ 39439109Sbostic if (print_only_undefined_symbols) { 39542452Sbostic (void)puts(sym->n_un.n_name); 39639109Sbostic return; 397619Sbill } 39839109Sbostic 39939109Sbostic /* print symbol's value */ 40039109Sbostic if (SYMBOL_TYPE(sym->n_type) == N_UNDF) 40139109Sbostic (void)printf(" "); 40239109Sbostic else 40339109Sbostic (void)printf("%08lx", sym->n_value); 40439109Sbostic 40539109Sbostic /* print type information */ 40639109Sbostic if (IS_DEBUGGER_SYMBOL(sym->n_type)) 40739109Sbostic (void)printf(" - %02x %04x %5s ", sym->n_other, 40839109Sbostic sym->n_desc&0xffff, typestring(sym->n_type)); 40939109Sbostic else 41039109Sbostic (void)printf(" %c ", typeletter(sym->n_type)); 41139109Sbostic 41239109Sbostic /* print the symbol's name */ 41342452Sbostic (void)puts(sym->n_un.n_name); 414619Sbill } 415619Sbill 41639109Sbostic /* 41739109Sbostic * typestring() 41839109Sbostic * return the a description string for an STAB entry 41939109Sbostic */ 42039109Sbostic char * 42139109Sbostic typestring(type) 42239109Sbostic register u_char type; 423619Sbill { 42439109Sbostic switch(type) { 42539109Sbostic case N_BCOMM: 42639109Sbostic return("BCOMM"); 42739109Sbostic case N_ECOML: 42839109Sbostic return("ECOML"); 42939109Sbostic case N_ECOMM: 43039109Sbostic return("ECOMM"); 43139109Sbostic case N_ENTRY: 43239109Sbostic return("ENTRY"); 43339109Sbostic case N_FNAME: 43439109Sbostic return("FNAME"); 43539109Sbostic case N_FUN: 43639109Sbostic return("FUN"); 43739109Sbostic case N_GSYM: 43839109Sbostic return("GSYM"); 43939109Sbostic case N_LBRAC: 44039109Sbostic return("LBRAC"); 44139109Sbostic case N_LCSYM: 44239109Sbostic return("LCSYM"); 44339109Sbostic case N_LENG: 44439109Sbostic return("LENG"); 44539109Sbostic case N_LSYM: 44639109Sbostic return("LSYM"); 44739109Sbostic case N_PC: 44839109Sbostic return("PC"); 44939109Sbostic case N_PSYM: 45039109Sbostic return("PSYM"); 45139109Sbostic case N_RBRAC: 45239109Sbostic return("RBRAC"); 45339109Sbostic case N_RSYM: 45439109Sbostic return("RSYM"); 45539109Sbostic case N_SLINE: 45639109Sbostic return("SLINE"); 45739109Sbostic case N_SO: 45839109Sbostic return("SO"); 45939109Sbostic case N_SOL: 46039109Sbostic return("SOL"); 46139109Sbostic case N_SSYM: 46239109Sbostic return("SSYM"); 46339109Sbostic case N_STSYM: 46439109Sbostic return("STSYM"); 465619Sbill } 46639109Sbostic return("???"); 467619Sbill } 468619Sbill 46939109Sbostic /* 47039109Sbostic * typeletter() 47139109Sbostic * return a description letter for the given basic type code of an 47239109Sbostic * symbol table entry. The return value will be upper case for 47339109Sbostic * external, lower case for internal symbols. 47439109Sbostic */ 47539109Sbostic char 47639109Sbostic typeletter(type) 47739109Sbostic u_char type; 478619Sbill { 47939109Sbostic switch(SYMBOL_TYPE(type)) { 48039109Sbostic case N_ABS: 48139109Sbostic return(IS_EXTERNAL(type) ? 'A' : 'a'); 48239109Sbostic case N_BSS: 48339109Sbostic return(IS_EXTERNAL(type) ? 'B' : 'b'); 48439109Sbostic case N_COMM: 48539109Sbostic return(IS_EXTERNAL(type) ? 'C' : 'c'); 48639109Sbostic case N_DATA: 48739109Sbostic return(IS_EXTERNAL(type) ? 'D' : 'd'); 48839109Sbostic case N_FN: 48939109Sbostic return(IS_EXTERNAL(type) ? 'F' : 'f'); 49039109Sbostic case N_TEXT: 49139109Sbostic return(IS_EXTERNAL(type) ? 'T' : 't'); 49239109Sbostic case N_UNDF: 49339109Sbostic return(IS_EXTERNAL(type) ? 'U' : 'u'); 49439109Sbostic } 49539109Sbostic return('?'); 49639109Sbostic } 497619Sbill 49839109Sbostic /* 49939109Sbostic * cmp_name() 50039109Sbostic * compare two symbols by their names 50139109Sbostic */ 50242452Sbostic cmp_name(a0, b0) 50342452Sbostic void *a0, *b0; 50439109Sbostic { 50542452Sbostic struct nlist *a = a0, *b = b0; 50642452Sbostic 50739109Sbostic return(sort_direction == FORWARD ? 50839109Sbostic strcmp(a->n_un.n_name, b->n_un.n_name) : 50939109Sbostic strcmp(b->n_un.n_name, a->n_un.n_name)); 510619Sbill } 511619Sbill 51239109Sbostic /* 51339109Sbostic * cmp_value() 51439109Sbostic * compare two symbols by their values 51539109Sbostic */ 51642452Sbostic cmp_value(a0, b0) 51742452Sbostic void *a0, *b0; 51839109Sbostic { 51942452Sbostic register struct nlist *a = a0, *b = b0; 52042452Sbostic 52139109Sbostic if (SYMBOL_TYPE(a->n_type) == N_UNDF) 52239109Sbostic if (SYMBOL_TYPE(b->n_type) == N_UNDF) 52339109Sbostic return(0); 52439109Sbostic else 52539109Sbostic return(-1); 52639109Sbostic else if (SYMBOL_TYPE(b->n_type) == N_UNDF) 52739109Sbostic return(1); 52839109Sbostic if (a->n_value == b->n_value) 52942452Sbostic return(cmp_name((void *)a, (void *)b)); 53039109Sbostic return(sort_direction == FORWARD ? a->n_value > b->n_value : 53139109Sbostic a->n_value < b->n_value); 53239109Sbostic } 533619Sbill 534619Sbill char * 53539109Sbostic emalloc(size) 53642452Sbostic size_t size; 537619Sbill { 53842452Sbostic char *p; 539619Sbill 54039109Sbostic /* NOSTRICT */ 54139109Sbostic if (!(p = malloc(size))) { 54239109Sbostic (void)fprintf(stderr, "nm: no more memory.\n"); 54339109Sbostic exit(1); 54439109Sbostic } 54539109Sbostic return(p); 546619Sbill } 54730855Sbostic 54839109Sbostic usage() 54930855Sbostic { 55042452Sbostic (void)fprintf(stderr, "usage: nm [-agnopruw] [file ...]\n"); 55139109Sbostic exit(1); 55230855Sbostic } 553