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