1*30855Sbostic /* 2*30855Sbostic * Copyright (c) 1987 Regents of the University of California. 3*30855Sbostic * All rights reserved. The Berkeley software License Agreement 4*30855Sbostic * specifies the terms and conditions for redistribution. 5*30855Sbostic */ 6*30855Sbostic 712672Ssam #ifndef lint 8*30855Sbostic static char sccsid[] = "@(#)nm.c 4.8 04/07/87"; 912672Ssam #endif 10*30855Sbostic 11619Sbill /* 12619Sbill * nm - print name list; VAX string table version 13619Sbill */ 14*30855Sbostic 15619Sbill #include <sys/types.h> 16*30855Sbostic #include <sys/file.h> 17653Sbill #include <ar.h> 18619Sbill #include <stdio.h> 19619Sbill #include <ctype.h> 20653Sbill #include <a.out.h> 21619Sbill #include <stab.h> 22*30855Sbostic #include <ranlib.h> 23619Sbill 24*30855Sbostic #define OARMAG 0177545 /* OLD archive magic number */ 25*30855Sbostic #define SELECT (archive ? archdr.ar_name : *xargv) 26619Sbill 27*30855Sbostic #define YES 1 28*30855Sbostic #define NO 0 29*30855Sbostic 30*30855Sbostic #define u_strx n_un.n_strx 31*30855Sbostic #define u_name n_un.n_name 32*30855Sbostic 33*30855Sbostic typedef struct nlist NLIST; 34*30855Sbostic 35*30855Sbostic union { /* exec header, or magic string from library */ 36*30855Sbostic char mag_armag[SARMAG + 1]; 37619Sbill struct exec mag_exp; 38619Sbill } mag_un; 39619Sbill 40*30855Sbostic struct ar_hdr archdr; /* archive file header structure */ 41*30855Sbostic FILE *fi; /* input file stream */ 42*30855Sbostic off_t off; /* offset into file */ 43*30855Sbostic int aflg, /* print debugger symbols */ 44*30855Sbostic gflg, /* print only global (external symbols */ 45*30855Sbostic nflg, /* sort numerically, not alphabetically */ 46*30855Sbostic oflg, /* prepend element name to each output line */ 47*30855Sbostic pflg, /* don't sort */ 48*30855Sbostic rflg = 1, /* how to sort */ 49*30855Sbostic uflg, /* print only undefined symbols */ 50*30855Sbostic narg, /* global number of arguments */ 51*30855Sbostic errs, /* global error flag */ 52*30855Sbostic archive; /* if file is an archive */ 53*30855Sbostic char **xargv; /* global pointer to file name */ 54*30855Sbostic 55619Sbill main(argc, argv) 56*30855Sbostic int argc; 57*30855Sbostic char **argv; 58619Sbill { 59*30855Sbostic extern int optind; 60*30855Sbostic int ch; /* getopts char */ 61619Sbill 62*30855Sbostic while ((ch = getopt(argc, argv, "agnopru")) != EOF) 63*30855Sbostic switch((char)ch) { 64*30855Sbostic case 'a': 65*30855Sbostic aflg = YES; 66*30855Sbostic break; 67*30855Sbostic case 'g': 68*30855Sbostic gflg = YES; 69*30855Sbostic break; 70619Sbill case 'n': 71*30855Sbostic nflg = YES; 72*30855Sbostic break; 73*30855Sbostic case 'o': 74*30855Sbostic oflg = YES; 75*30855Sbostic break; 76*30855Sbostic case 'p': 77*30855Sbostic pflg = YES; 78*30855Sbostic break; 79619Sbill case 'r': 80619Sbill rflg = -1; 81*30855Sbostic break; 82*30855Sbostic case 'u': 83*30855Sbostic uflg = YES; 84*30855Sbostic break; 85*30855Sbostic case '?': 86619Sbill default: 87*30855Sbostic fputs("usage: nm [-agnopru] [file ...]\n", stderr); 88619Sbill exit(2); 89619Sbill } 90*30855Sbostic argc -= optind; 91*30855Sbostic argv += optind; 92*30855Sbostic if (!argc) { 93619Sbill argc = 1; 94*30855Sbostic argv[0] = "a.out"; 95619Sbill } 96619Sbill narg = argc; 97*30855Sbostic for (xargv = argv; argc--; ++xargv) 98*30855Sbostic if (fi = fopen(*xargv, "r")) { 99*30855Sbostic namelist(); 100*30855Sbostic (void)fclose(fi); 101*30855Sbostic } 102*30855Sbostic else 103*30855Sbostic error(NO, "cannot open"); 104619Sbill exit(errs); 105619Sbill } 106619Sbill 107619Sbill namelist() 108619Sbill { 109*30855Sbostic register NLIST *N, **L; 110*30855Sbostic register int symcount, nsyms; 111*30855Sbostic static NLIST *symp, **list; 112*30855Sbostic static int lastnsyms = -1, 113*30855Sbostic laststrsiz = -1; 114*30855Sbostic static char *strp; 115*30855Sbostic off_t strsiz; 116*30855Sbostic long lseek(); 117*30855Sbostic int compare(); 118*30855Sbostic char *malloc(), *realloc(); 119619Sbill 120*30855Sbostic /* 121*30855Sbostic * read first few bytes, determine if an archive, 122*30855Sbostic * or executable; if executable, check magic number 123*30855Sbostic */ 124*30855Sbostic /*NOSTRICT*/ 125*30855Sbostic if (!fread((char *)&mag_un, sizeof(mag_un), 1, fi)) { 126*30855Sbostic error(NO, "unable to read file"); 127619Sbill return; 128619Sbill } 129619Sbill if (mag_un.mag_exp.a_magic == OARMAG) { 130*30855Sbostic error(NO, "old archive"); 131*30855Sbostic return; 132619Sbill } 133*30855Sbostic if (bcmp(mag_un.mag_armag, ARMAG, SARMAG)) { 134*30855Sbostic if (N_BADMAG(mag_un.mag_exp)) { 135*30855Sbostic error(NO, "bad format"); 136*30855Sbostic return; 137*30855Sbostic } 138*30855Sbostic archive = NO; 139*30855Sbostic rewind(fi); 140619Sbill } 141*30855Sbostic else { 142*30855Sbostic /* 143*30855Sbostic * if archive, skip first entry 144*30855Sbostic * if ranlib'd, skip second entry 145*30855Sbostic */ 146*30855Sbostic off = SARMAG; /* see nextel() */ 147*30855Sbostic (void)nextel(); 148*30855Sbostic if (!strcmp(RANLIBMAG, archdr.ar_name)) 149*30855Sbostic (void)nextel(); 150619Sbill if (narg > 1) 151619Sbill printf("\n%s:\n", *xargv); 152*30855Sbostic archive = YES; 153619Sbill } 154*30855Sbostic 155619Sbill do { 156*30855Sbostic /* check for bad magic number */ 157*30855Sbostic /*NOSTRICT*/ 158*30855Sbostic if (!fread((char *)&mag_un.mag_exp, sizeof(struct exec), 1, fi)) { 159*30855Sbostic error(NO, "unable to read magic number"); 160*30855Sbostic return; 161*30855Sbostic } 162619Sbill if (N_BADMAG(mag_un.mag_exp)) 163619Sbill continue; 164*30855Sbostic 165*30855Sbostic /* calculate number of symbols in object */ 166*30855Sbostic if (!(nsyms = mag_un.mag_exp.a_syms / sizeof(NLIST))) { 167*30855Sbostic error(NO, "no name list"); 168619Sbill continue; 169619Sbill } 170*30855Sbostic 171*30855Sbostic /* seek to and read symbols */ 172*30855Sbostic (void)fseek(fi, (long)(N_SYMOFF(mag_un.mag_exp) - sizeof(struct exec)), L_INCR); 173*30855Sbostic if (!symp || nsyms > lastnsyms) { 174*30855Sbostic if (!symp) { 175*30855Sbostic /*NOSTRICT*/ 176*30855Sbostic symp = (NLIST *)malloc((u_int)(nsyms * sizeof(NLIST))); 177*30855Sbostic /*NOSTRICT*/ 178*30855Sbostic list = (NLIST **)malloc((u_int)(nsyms * sizeof(NLIST *))); 179*30855Sbostic } 180*30855Sbostic else { 181*30855Sbostic /*NOSTRICT*/ 182*30855Sbostic symp = (NLIST *)realloc((char *)symp, (u_int)(nsyms * sizeof(NLIST))); 183*30855Sbostic /*NOSTRICT*/ 184*30855Sbostic list = (NLIST **)realloc((char *)list, (u_int)(nsyms * sizeof(NLIST *))); 185*30855Sbostic } 186*30855Sbostic if (!symp || !list) 187*30855Sbostic error(YES, "out of memory"); 188*30855Sbostic lastnsyms = nsyms; 189*30855Sbostic } 190*30855Sbostic /*NOSTRICT*/ 191*30855Sbostic if (fread((char *)symp, sizeof(NLIST), nsyms, fi) != nsyms) { 192*30855Sbostic error(NO, "bad symbol table"); 19317424Sralph continue; 19417424Sralph } 195*30855Sbostic 196*30855Sbostic /* read number of strings, string table */ 197*30855Sbostic /*NOSTRICT*/ 198*30855Sbostic if (!fread((char *)&strsiz, sizeof(strsiz), 1, fi)) { 199*30855Sbostic error(NO, "no string table (old format .o?)"); 200*30855Sbostic continue; 201619Sbill } 202*30855Sbostic if (!strp || strsiz > laststrsiz) { 203*30855Sbostic strp = strp ? realloc(strp, (u_int)strsiz) : malloc((u_int)strsiz); 204*30855Sbostic if (!strp) 205*30855Sbostic error(YES, "out of memory"); 206*30855Sbostic laststrsiz = strsiz; 207*30855Sbostic } 208*30855Sbostic if (!fread(strp + sizeof(strsiz), 1, (int)(strsiz - sizeof(strsiz)), fi)) { 209*30855Sbostic error(NO, "no string table (old format .o?)"); 210619Sbill continue; 211619Sbill } 212*30855Sbostic 213*30855Sbostic for (symcount = nsyms, L = list, N = symp;--nsyms >= 0;++N) 214*30855Sbostic if (!(N->n_type & N_EXT) && gflg || N->n_type & N_STAB && (!aflg || gflg || uflg)) 215*30855Sbostic --symcount; 216*30855Sbostic else { 217*30855Sbostic N->u_name = N->u_strx ? strp + N->u_strx : ""; 218*30855Sbostic *L++ = N; 219*30855Sbostic } 220*30855Sbostic 221*30855Sbostic if (!pflg) 222*30855Sbostic qsort(list, symcount, sizeof(NLIST *), compare); 223*30855Sbostic 224*30855Sbostic if ((archive || narg > 1) && !oflg) 225619Sbill printf("\n%s:\n", SELECT); 226*30855Sbostic 227*30855Sbostic psyms(list, symcount); 228*30855Sbostic } while(archive && nextel()); 229619Sbill } 230619Sbill 231*30855Sbostic psyms(list, nsyms) 232*30855Sbostic NLIST **list; 233*30855Sbostic register int nsyms; 234619Sbill { 235*30855Sbostic register NLIST *L; 236*30855Sbostic register u_char type; 237*30855Sbostic char *stab(); 238619Sbill 239*30855Sbostic while (nsyms--) { 240*30855Sbostic L = *list++; 241*30855Sbostic type = L->n_type; 242*30855Sbostic if (type & N_STAB) { 243619Sbill if (oflg) { 244619Sbill if (archive) 245619Sbill printf("%s:", *xargv); 246619Sbill printf("%s:", SELECT); 247619Sbill } 248*30855Sbostic printf("%08x - %02x %04x %5.5s %s\n", (int)L->n_value, L->n_other & 0xff, L->n_desc & 0xffff, stab(L->n_type), L->u_name); 249619Sbill continue; 250619Sbill } 251*30855Sbostic switch (type & N_TYPE) { 252619Sbill case N_UNDF: 253*30855Sbostic type = L->n_value ? 'c' : 'u'; 254619Sbill break; 255619Sbill case N_ABS: 256*30855Sbostic type = 'a'; 257619Sbill break; 258619Sbill case N_TEXT: 259*30855Sbostic type = 't'; 260619Sbill break; 261619Sbill case N_DATA: 262*30855Sbostic type = 'd'; 263619Sbill break; 264619Sbill case N_BSS: 265*30855Sbostic type = 'b'; 266619Sbill break; 267*30855Sbostic case N_FN: 268*30855Sbostic type = 'f'; 269*30855Sbostic break; 27028296Skarels default: 271*30855Sbostic type = '?'; 272619Sbill break; 273619Sbill } 274*30855Sbostic if (uflg && type != 'u') 275619Sbill continue; 276619Sbill if (oflg) { 277619Sbill if (archive) 278619Sbill printf("%s:", *xargv); 279619Sbill printf("%s:", SELECT); 280619Sbill } 281*30855Sbostic if (L->n_type & N_EXT) 282*30855Sbostic type = toupper(type); 283619Sbill if (!uflg) { 284*30855Sbostic if (type == 'u' || type == 'U') 285*30855Sbostic fputs(" ", stdout); 286619Sbill else 287*30855Sbostic printf(N_FORMAT, (int)L->n_value); 288*30855Sbostic printf(" %c ", (char)type); 289619Sbill } 290*30855Sbostic puts(L->u_name); 291619Sbill } 292619Sbill } 293619Sbill 294619Sbill compare(p1, p2) 295*30855Sbostic NLIST **p1, **p2; 296619Sbill { 297619Sbill if (nflg) { 298*30855Sbostic if ((*p1)->n_value > (*p2)->n_value) 299619Sbill return(rflg); 300*30855Sbostic if ((*p1)->n_value < (*p2)->n_value) 301619Sbill return(-rflg); 302619Sbill } 303*30855Sbostic return(rflg * strcmp((*p1)->u_name, (*p2)->u_name)); 304619Sbill } 305619Sbill 306*30855Sbostic nextel() 307619Sbill { 308*30855Sbostic register char *cp; 309*30855Sbostic long arsize, 310*30855Sbostic lseek(); 311619Sbill 312*30855Sbostic (void)fseek(fi, off, L_SET); 313*30855Sbostic /*NOSTRICT*/ 314*30855Sbostic if (!fread((char *)&archdr, sizeof(struct ar_hdr), 1, fi)) 315619Sbill return(0); 316*30855Sbostic for (cp = archdr.ar_name; cp < &archdr.ar_name[sizeof(archdr.ar_name)]; ++cp) 317*30855Sbostic if (*cp == ' ') { 318619Sbill *cp = '\0'; 319*30855Sbostic break; 320*30855Sbostic } 321619Sbill arsize = atol(archdr.ar_size); 322619Sbill if (arsize & 1) 323619Sbill ++arsize; 324*30855Sbostic off = ftell(fi) + arsize; /* beginning of next element */ 325619Sbill return(1); 326619Sbill } 327619Sbill 328619Sbill struct stabnames { 329619Sbill int st_value; 330619Sbill char *st_name; 331619Sbill } stabnames[] ={ 332*30855Sbostic N_GSYM, "GSYM", 333*30855Sbostic N_FNAME, "FNAME", 334*30855Sbostic N_FUN, "FUN", 335*30855Sbostic N_STSYM, "STSYM", 336*30855Sbostic N_LCSYM, "LCSYM", 337*30855Sbostic N_RSYM, "RSYM", 338*30855Sbostic N_SLINE, "SLINE", 339*30855Sbostic N_SSYM, "SSYM", 340*30855Sbostic N_SO, "SO", 341*30855Sbostic N_LSYM, "LSYM", 342*30855Sbostic N_SOL, "SOL", 343*30855Sbostic N_PSYM, "PSYM", 344*30855Sbostic N_ENTRY, "ENTRY", 345*30855Sbostic N_LBRAC, "LBRAC", 346*30855Sbostic N_RBRAC, "RBRAC", 347*30855Sbostic N_BCOMM, "BCOMM", 348*30855Sbostic N_ECOMM, "ECOMM", 349*30855Sbostic N_ECOML, "ECOML", 350*30855Sbostic N_LENG, "LENG", 351*30855Sbostic N_PC, "PC", 352*30855Sbostic 0, 0 353619Sbill }; 354619Sbill 355619Sbill char * 356619Sbill stab(val) 357*30855Sbostic register u_char val; 358619Sbill { 359*30855Sbostic register struct stabnames *sp; 360*30855Sbostic static char prbuf[5]; 361619Sbill 362*30855Sbostic for (sp = stabnames; sp->st_value; ++sp) 363619Sbill if (sp->st_value == val) 364*30855Sbostic return(sp->st_name); 365*30855Sbostic (void)sprintf(prbuf, "%02x", (int)val); 366*30855Sbostic return(prbuf); 367619Sbill } 368*30855Sbostic 369*30855Sbostic error(doexit, msg) 370*30855Sbostic int doexit; 371*30855Sbostic char *msg; 372*30855Sbostic { 373*30855Sbostic fprintf(stderr, "nm: %s:", *xargv); 374*30855Sbostic if (archive) 375*30855Sbostic fprintf(stderr, "(%s): %s\n", archdr.ar_name, msg); 376*30855Sbostic else 377*30855Sbostic fprintf(stderr, " %s\n", msg); 378*30855Sbostic if (doexit) 379*30855Sbostic exit(2); 380*30855Sbostic errs = 1; 381*30855Sbostic } 382