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 * 8*42689Sbostic * %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*42689Sbostic static char sccsid[] = "@(#)nm.c 5.6 (Berkeley) 06/01/90"; 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 18330855Sbostic /* 18439143Sbostic * construct a name of the form "archive.a:obj.o:" for the 18539109Sbostic * current archive entry if the object name is to be printed 18639109Sbostic * on each output line 18730855Sbostic */ 18842452Sbostic p = name; 18942452Sbostic if (print_file_each_line) 19042452Sbostic p += sprintf(p, "%s:", fname); 19139109Sbostic for (i = 0; i < sizeof(ar_head.ar_name); ++i) 19239109Sbostic if (ar_head.ar_name[i] && ar_head.ar_name[i] != ' ') 19339109Sbostic *p++ = ar_head.ar_name[i]; 19439109Sbostic *p++ = '\0'; 19530855Sbostic 19639109Sbostic /* remember start position of current archive object */ 19739109Sbostic last_ar_off = ftell(fp); 19830855Sbostic 19939109Sbostic /* get and check current object's header */ 20042452Sbostic if (fread((char *)&exec_head, sizeof(exec_head), 20142452Sbostic (size_t)1, fp) != 1) { 20239109Sbostic (void)fprintf(stderr, "nm: %s: premature EOF.\n", name); 20339109Sbostic (void)free(name); 20439109Sbostic return(1); 205619Sbill } 20639109Sbostic if (strcmp(name, RANLIBMAG)) 20739109Sbostic if (N_BADMAG(exec_head)) { 20839109Sbostic if (!ignore_bad_archive_entries) { 20939109Sbostic (void)fprintf(stderr, 21039109Sbostic "nm: %s: bad format.\n", name); 21139109Sbostic rval = 1; 21239109Sbostic } 21339109Sbostic } else { 21439109Sbostic (void)fseek(fp, (long)-sizeof(exec_head), 21539109Sbostic SEEK_CUR); 21639109Sbostic if (!print_file_each_line) 21739109Sbostic (void)printf("\n%s:\n", name); 21839109Sbostic rval |= show_objfile(name, fp); 21939109Sbostic } 22030855Sbostic 22139109Sbostic /* 22242452Sbostic * skip to next archive object - it starts at the next 22342452Sbostic * even byte boundary 22439109Sbostic */ 22542452Sbostic #define even(x) (((x) + 1) & ~1) 22642452Sbostic if (fseek(fp, last_ar_off + even(atol(ar_head.ar_size)), 22739109Sbostic SEEK_SET)) { 22839109Sbostic (void)fprintf(stderr, 22939109Sbostic "nm: %s: %s\n", fname, strerror(errno)); 23039109Sbostic (void)free(name); 23139109Sbostic return(1); 23230855Sbostic } 23339109Sbostic } 23439109Sbostic (void)free(name); 23539109Sbostic return(rval); 23639109Sbostic } 23730855Sbostic 23839109Sbostic /* 23939109Sbostic * show_objfile() 24039109Sbostic * show symbols from the object file pointed to by fp. The current 24139109Sbostic * file pointer for fp is expected to be at the beginning of an a.out 24239109Sbostic * header. 24339109Sbostic */ 24439109Sbostic show_objfile(objname, fp) 24539109Sbostic char *objname; 24639109Sbostic FILE *fp; 24739109Sbostic { 24842452Sbostic register struct nlist *names, *np; 24939109Sbostic register int i, nnames, nrawnames; 25039109Sbostic struct exec head; 25139109Sbostic long stabsize; 25239109Sbostic char *stab, *emalloc(); 25339109Sbostic 25439109Sbostic /* read a.out header */ 25542452Sbostic if (fread((char *)&head, sizeof(head), (size_t)1, fp) != 1) { 25639109Sbostic (void)fprintf(stderr, 25739109Sbostic "nm: %s: cannot read header.\n", objname); 25839109Sbostic return(1); 25939109Sbostic } 26039109Sbostic 26139109Sbostic /* 26239109Sbostic * skip back to the header - the N_-macros return values relative 26339109Sbostic * to the beginning of the a.out header 26439109Sbostic */ 26539109Sbostic if (fseek(fp, (long)-sizeof(head), SEEK_CUR)) { 26639109Sbostic (void)fprintf(stderr, 26739109Sbostic "nm: %s: %s\n", objname, strerror(errno)); 26839109Sbostic return(1); 26939109Sbostic } 27039109Sbostic 27139109Sbostic /* stop if this is no valid object file */ 27239109Sbostic if (N_BADMAG(head)) { 27339109Sbostic (void)fprintf(stderr, 27439109Sbostic "nm: %s: bad format.\n", objname); 27539109Sbostic return(1); 27639109Sbostic } 27739109Sbostic 27839109Sbostic /* stop if the object file contains no symbol table */ 27939109Sbostic if (!head.a_syms) { 28039109Sbostic (void)fprintf(stderr, 28139109Sbostic "nm: %s: no name list.\n", objname); 28239109Sbostic return(1); 28339109Sbostic } 28439109Sbostic 28539109Sbostic if (fseek(fp, (long)N_SYMOFF(head), SEEK_CUR)) { 28639109Sbostic (void)fprintf(stderr, 28739109Sbostic "nm: %s: %s\n", objname, strerror(errno)); 28839109Sbostic return(1); 28939109Sbostic } 29039109Sbostic 29139109Sbostic /* get memory for the symbol table */ 29242452Sbostic names = (struct nlist *)emalloc((size_t)head.a_syms); 29339109Sbostic nrawnames = head.a_syms / sizeof(*names); 29442452Sbostic if (fread((char *)names, (size_t)head.a_syms, (size_t)1, fp) != 1) { 29539109Sbostic (void)fprintf(stderr, 29639109Sbostic "nm: %s: cannot read symbol table.\n", objname); 29739109Sbostic (void)free((char *)names); 29839109Sbostic return(1); 29939109Sbostic } 30039109Sbostic 30139109Sbostic /* 30239109Sbostic * Following the symbol table comes the string table. The first 30339109Sbostic * 4-byte-integer gives the total size of the string table 30439109Sbostic * _including_ the size specification itself. 30539109Sbostic */ 30642452Sbostic if (fread((char *)&stabsize, sizeof(stabsize), (size_t)1, fp) != 1) { 30739109Sbostic (void)fprintf(stderr, 30839109Sbostic "nm: %s: cannot read stab size.\n", objname); 30939109Sbostic (void)free((char *)names); 31039109Sbostic return(1); 31139109Sbostic } 31242452Sbostic stab = emalloc((size_t)stabsize); 31339109Sbostic 31439109Sbostic /* 31539109Sbostic * read the string table offset by 4 - all indices into the string 31639109Sbostic * table include the size specification. 31739109Sbostic */ 31839143Sbostic stabsize -= 4; /* we already have the size */ 31942452Sbostic if (fread(stab + 4, (size_t)stabsize, (size_t)1, fp) != 1) { 32039109Sbostic (void)fprintf(stderr, 32139109Sbostic "nm: %s: stab truncated..\n", objname); 32239109Sbostic (void)free((char *)names); 32339109Sbostic (void)free(stab); 32439109Sbostic return(1); 32539109Sbostic } 32639109Sbostic 32739109Sbostic /* 32839109Sbostic * fix up the symbol table and filter out unwanted entries 32939109Sbostic * 33039109Sbostic * common symbols are characterized by a n_type of N_UNDF and a 33139109Sbostic * non-zero n_value -- change n_type to N_COMM for all such 33239109Sbostic * symbols to make life easier later. 33339109Sbostic * 33439109Sbostic * filter out all entries which we don't want to print anyway 33539109Sbostic */ 33642452Sbostic for (np = names, i = nnames = 0; i < nrawnames; np++, i++) { 33742452Sbostic if (SYMBOL_TYPE(np->n_type) == N_UNDF && np->n_value) 33842452Sbostic np->n_type = N_COMM | (np->n_type & N_EXT); 33942452Sbostic if (!print_all_symbols && IS_DEBUGGER_SYMBOL(np->n_type)) 34030855Sbostic continue; 34142452Sbostic if (print_only_external_symbols && !IS_EXTERNAL(np->n_type)) 342619Sbill continue; 34339109Sbostic if (print_only_undefined_symbols && 34442452Sbostic SYMBOL_TYPE(np->n_type) != N_UNDF) 34539109Sbostic continue; 34630855Sbostic 34739109Sbostic /* 34839109Sbostic * make n_un.n_name a character pointer by adding the string 34939109Sbostic * table's base to n_un.n_strx 35039109Sbostic * 35142452Sbostic * don't mess with zero offsets 35239109Sbostic */ 35342452Sbostic if (np->n_un.n_strx) 35442452Sbostic np->n_un.n_name = stab + np->n_un.n_strx; 35539109Sbostic else 35642452Sbostic np->n_un.n_name = ""; 35742452Sbostic names[nnames++] = *np; 35839109Sbostic } 35930855Sbostic 36039109Sbostic /* sort the symbol table if applicable */ 36139109Sbostic if (sort_func) 36242452Sbostic qsort((char *)names, (size_t)nnames, sizeof(*names), sort_func); 36330855Sbostic 36439109Sbostic /* print out symbols */ 36542452Sbostic for (np = names, i = 0; i < nnames; np++, i++) 36642452Sbostic print_symbol(objname, np); 36730855Sbostic 36839109Sbostic (void)free((char *)names); 36939109Sbostic (void)free(stab); 37039109Sbostic return(0); 371619Sbill } 372619Sbill 37339109Sbostic /* 37439109Sbostic * print_symbol() 37539109Sbostic * show one symbol 37639109Sbostic */ 37739109Sbostic print_symbol(objname, sym) 37839109Sbostic char *objname; 37942452Sbostic register struct nlist *sym; 380619Sbill { 38139109Sbostic char *typestring(), typeletter(); 382619Sbill 38339109Sbostic if (print_file_each_line) 38442452Sbostic (void)printf("%s:", objname); 38539109Sbostic 38639109Sbostic /* 38739109Sbostic * handle undefined-only format seperately (no space is 38839109Sbostic * left for symbol values, no type field is printed) 38939109Sbostic */ 39039109Sbostic if (print_only_undefined_symbols) { 39142452Sbostic (void)puts(sym->n_un.n_name); 39239109Sbostic return; 393619Sbill } 39439109Sbostic 39539109Sbostic /* print symbol's value */ 39639109Sbostic if (SYMBOL_TYPE(sym->n_type) == N_UNDF) 39739109Sbostic (void)printf(" "); 39839109Sbostic else 39939109Sbostic (void)printf("%08lx", sym->n_value); 40039109Sbostic 40139109Sbostic /* print type information */ 40239109Sbostic if (IS_DEBUGGER_SYMBOL(sym->n_type)) 40339109Sbostic (void)printf(" - %02x %04x %5s ", sym->n_other, 40439109Sbostic sym->n_desc&0xffff, typestring(sym->n_type)); 40539109Sbostic else 40639109Sbostic (void)printf(" %c ", typeletter(sym->n_type)); 40739109Sbostic 40839109Sbostic /* print the symbol's name */ 40942452Sbostic (void)puts(sym->n_un.n_name); 410619Sbill } 411619Sbill 41239109Sbostic /* 41339109Sbostic * typestring() 41439109Sbostic * return the a description string for an STAB entry 41539109Sbostic */ 41639109Sbostic char * 41739109Sbostic typestring(type) 41839109Sbostic register u_char type; 419619Sbill { 42039109Sbostic switch(type) { 42139109Sbostic case N_BCOMM: 42239109Sbostic return("BCOMM"); 42339109Sbostic case N_ECOML: 42439109Sbostic return("ECOML"); 42539109Sbostic case N_ECOMM: 42639109Sbostic return("ECOMM"); 42739109Sbostic case N_ENTRY: 42839109Sbostic return("ENTRY"); 42939109Sbostic case N_FNAME: 43039109Sbostic return("FNAME"); 43139109Sbostic case N_FUN: 43239109Sbostic return("FUN"); 43339109Sbostic case N_GSYM: 43439109Sbostic return("GSYM"); 43539109Sbostic case N_LBRAC: 43639109Sbostic return("LBRAC"); 43739109Sbostic case N_LCSYM: 43839109Sbostic return("LCSYM"); 43939109Sbostic case N_LENG: 44039109Sbostic return("LENG"); 44139109Sbostic case N_LSYM: 44239109Sbostic return("LSYM"); 44339109Sbostic case N_PC: 44439109Sbostic return("PC"); 44539109Sbostic case N_PSYM: 44639109Sbostic return("PSYM"); 44739109Sbostic case N_RBRAC: 44839109Sbostic return("RBRAC"); 44939109Sbostic case N_RSYM: 45039109Sbostic return("RSYM"); 45139109Sbostic case N_SLINE: 45239109Sbostic return("SLINE"); 45339109Sbostic case N_SO: 45439109Sbostic return("SO"); 45539109Sbostic case N_SOL: 45639109Sbostic return("SOL"); 45739109Sbostic case N_SSYM: 45839109Sbostic return("SSYM"); 45939109Sbostic case N_STSYM: 46039109Sbostic return("STSYM"); 461619Sbill } 46239109Sbostic return("???"); 463619Sbill } 464619Sbill 46539109Sbostic /* 46639109Sbostic * typeletter() 46739109Sbostic * return a description letter for the given basic type code of an 46839109Sbostic * symbol table entry. The return value will be upper case for 46939109Sbostic * external, lower case for internal symbols. 47039109Sbostic */ 47139109Sbostic char 47239109Sbostic typeletter(type) 47339109Sbostic u_char type; 474619Sbill { 47539109Sbostic switch(SYMBOL_TYPE(type)) { 47639109Sbostic case N_ABS: 47739109Sbostic return(IS_EXTERNAL(type) ? 'A' : 'a'); 47839109Sbostic case N_BSS: 47939109Sbostic return(IS_EXTERNAL(type) ? 'B' : 'b'); 48039109Sbostic case N_COMM: 48139109Sbostic return(IS_EXTERNAL(type) ? 'C' : 'c'); 48239109Sbostic case N_DATA: 48339109Sbostic return(IS_EXTERNAL(type) ? 'D' : 'd'); 48439109Sbostic case N_FN: 48539109Sbostic return(IS_EXTERNAL(type) ? 'F' : 'f'); 48639109Sbostic case N_TEXT: 48739109Sbostic return(IS_EXTERNAL(type) ? 'T' : 't'); 48839109Sbostic case N_UNDF: 48939109Sbostic return(IS_EXTERNAL(type) ? 'U' : 'u'); 49039109Sbostic } 49139109Sbostic return('?'); 49239109Sbostic } 493619Sbill 49439109Sbostic /* 49539109Sbostic * cmp_name() 49639109Sbostic * compare two symbols by their names 49739109Sbostic */ 49842452Sbostic cmp_name(a0, b0) 49942452Sbostic void *a0, *b0; 50039109Sbostic { 50142452Sbostic struct nlist *a = a0, *b = b0; 50242452Sbostic 50339109Sbostic return(sort_direction == FORWARD ? 50439109Sbostic strcmp(a->n_un.n_name, b->n_un.n_name) : 50539109Sbostic strcmp(b->n_un.n_name, a->n_un.n_name)); 506619Sbill } 507619Sbill 50839109Sbostic /* 50939109Sbostic * cmp_value() 51039109Sbostic * compare two symbols by their values 51139109Sbostic */ 51242452Sbostic cmp_value(a0, b0) 51342452Sbostic void *a0, *b0; 51439109Sbostic { 51542452Sbostic register struct nlist *a = a0, *b = b0; 51642452Sbostic 51739109Sbostic if (SYMBOL_TYPE(a->n_type) == N_UNDF) 51839109Sbostic if (SYMBOL_TYPE(b->n_type) == N_UNDF) 51939109Sbostic return(0); 52039109Sbostic else 52139109Sbostic return(-1); 52239109Sbostic else if (SYMBOL_TYPE(b->n_type) == N_UNDF) 52339109Sbostic return(1); 52439109Sbostic if (a->n_value == b->n_value) 52542452Sbostic return(cmp_name((void *)a, (void *)b)); 52639109Sbostic return(sort_direction == FORWARD ? a->n_value > b->n_value : 52739109Sbostic a->n_value < b->n_value); 52839109Sbostic } 529619Sbill 530619Sbill char * 53139109Sbostic emalloc(size) 53242452Sbostic size_t size; 533619Sbill { 53442452Sbostic char *p; 535619Sbill 53639109Sbostic /* NOSTRICT */ 53739109Sbostic if (!(p = malloc(size))) { 53839109Sbostic (void)fprintf(stderr, "nm: no more memory.\n"); 53939109Sbostic exit(1); 54039109Sbostic } 54139109Sbostic return(p); 542619Sbill } 54330855Sbostic 54439109Sbostic usage() 54530855Sbostic { 54642452Sbostic (void)fprintf(stderr, "usage: nm [-agnopruw] [file ...]\n"); 54739109Sbostic exit(1); 54830855Sbostic } 549