1 /* 2 * Copyright (c) 1987 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #ifndef lint 8 static char sccsid[] = "@(#)nm.c 4.8 04/07/87"; 9 #endif 10 11 /* 12 * nm - print name list; VAX string table version 13 */ 14 15 #include <sys/types.h> 16 #include <sys/file.h> 17 #include <ar.h> 18 #include <stdio.h> 19 #include <ctype.h> 20 #include <a.out.h> 21 #include <stab.h> 22 #include <ranlib.h> 23 24 #define OARMAG 0177545 /* OLD archive magic number */ 25 #define SELECT (archive ? archdr.ar_name : *xargv) 26 27 #define YES 1 28 #define NO 0 29 30 #define u_strx n_un.n_strx 31 #define u_name n_un.n_name 32 33 typedef struct nlist NLIST; 34 35 union { /* exec header, or magic string from library */ 36 char mag_armag[SARMAG + 1]; 37 struct exec mag_exp; 38 } mag_un; 39 40 struct ar_hdr archdr; /* archive file header structure */ 41 FILE *fi; /* input file stream */ 42 off_t off; /* offset into file */ 43 int aflg, /* print debugger symbols */ 44 gflg, /* print only global (external symbols */ 45 nflg, /* sort numerically, not alphabetically */ 46 oflg, /* prepend element name to each output line */ 47 pflg, /* don't sort */ 48 rflg = 1, /* how to sort */ 49 uflg, /* print only undefined symbols */ 50 narg, /* global number of arguments */ 51 errs, /* global error flag */ 52 archive; /* if file is an archive */ 53 char **xargv; /* global pointer to file name */ 54 55 main(argc, argv) 56 int argc; 57 char **argv; 58 { 59 extern int optind; 60 int ch; /* getopts char */ 61 62 while ((ch = getopt(argc, argv, "agnopru")) != EOF) 63 switch((char)ch) { 64 case 'a': 65 aflg = YES; 66 break; 67 case 'g': 68 gflg = YES; 69 break; 70 case 'n': 71 nflg = YES; 72 break; 73 case 'o': 74 oflg = YES; 75 break; 76 case 'p': 77 pflg = YES; 78 break; 79 case 'r': 80 rflg = -1; 81 break; 82 case 'u': 83 uflg = YES; 84 break; 85 case '?': 86 default: 87 fputs("usage: nm [-agnopru] [file ...]\n", stderr); 88 exit(2); 89 } 90 argc -= optind; 91 argv += optind; 92 if (!argc) { 93 argc = 1; 94 argv[0] = "a.out"; 95 } 96 narg = argc; 97 for (xargv = argv; argc--; ++xargv) 98 if (fi = fopen(*xargv, "r")) { 99 namelist(); 100 (void)fclose(fi); 101 } 102 else 103 error(NO, "cannot open"); 104 exit(errs); 105 } 106 107 namelist() 108 { 109 register NLIST *N, **L; 110 register int symcount, nsyms; 111 static NLIST *symp, **list; 112 static int lastnsyms = -1, 113 laststrsiz = -1; 114 static char *strp; 115 off_t strsiz; 116 long lseek(); 117 int compare(); 118 char *malloc(), *realloc(); 119 120 /* 121 * read first few bytes, determine if an archive, 122 * or executable; if executable, check magic number 123 */ 124 /*NOSTRICT*/ 125 if (!fread((char *)&mag_un, sizeof(mag_un), 1, fi)) { 126 error(NO, "unable to read file"); 127 return; 128 } 129 if (mag_un.mag_exp.a_magic == OARMAG) { 130 error(NO, "old archive"); 131 return; 132 } 133 if (bcmp(mag_un.mag_armag, ARMAG, SARMAG)) { 134 if (N_BADMAG(mag_un.mag_exp)) { 135 error(NO, "bad format"); 136 return; 137 } 138 archive = NO; 139 rewind(fi); 140 } 141 else { 142 /* 143 * if archive, skip first entry 144 * if ranlib'd, skip second entry 145 */ 146 off = SARMAG; /* see nextel() */ 147 (void)nextel(); 148 if (!strcmp(RANLIBMAG, archdr.ar_name)) 149 (void)nextel(); 150 if (narg > 1) 151 printf("\n%s:\n", *xargv); 152 archive = YES; 153 } 154 155 do { 156 /* check for bad magic number */ 157 /*NOSTRICT*/ 158 if (!fread((char *)&mag_un.mag_exp, sizeof(struct exec), 1, fi)) { 159 error(NO, "unable to read magic number"); 160 return; 161 } 162 if (N_BADMAG(mag_un.mag_exp)) 163 continue; 164 165 /* calculate number of symbols in object */ 166 if (!(nsyms = mag_un.mag_exp.a_syms / sizeof(NLIST))) { 167 error(NO, "no name list"); 168 continue; 169 } 170 171 /* seek to and read symbols */ 172 (void)fseek(fi, (long)(N_SYMOFF(mag_un.mag_exp) - sizeof(struct exec)), L_INCR); 173 if (!symp || nsyms > lastnsyms) { 174 if (!symp) { 175 /*NOSTRICT*/ 176 symp = (NLIST *)malloc((u_int)(nsyms * sizeof(NLIST))); 177 /*NOSTRICT*/ 178 list = (NLIST **)malloc((u_int)(nsyms * sizeof(NLIST *))); 179 } 180 else { 181 /*NOSTRICT*/ 182 symp = (NLIST *)realloc((char *)symp, (u_int)(nsyms * sizeof(NLIST))); 183 /*NOSTRICT*/ 184 list = (NLIST **)realloc((char *)list, (u_int)(nsyms * sizeof(NLIST *))); 185 } 186 if (!symp || !list) 187 error(YES, "out of memory"); 188 lastnsyms = nsyms; 189 } 190 /*NOSTRICT*/ 191 if (fread((char *)symp, sizeof(NLIST), nsyms, fi) != nsyms) { 192 error(NO, "bad symbol table"); 193 continue; 194 } 195 196 /* read number of strings, string table */ 197 /*NOSTRICT*/ 198 if (!fread((char *)&strsiz, sizeof(strsiz), 1, fi)) { 199 error(NO, "no string table (old format .o?)"); 200 continue; 201 } 202 if (!strp || strsiz > laststrsiz) { 203 strp = strp ? realloc(strp, (u_int)strsiz) : malloc((u_int)strsiz); 204 if (!strp) 205 error(YES, "out of memory"); 206 laststrsiz = strsiz; 207 } 208 if (!fread(strp + sizeof(strsiz), 1, (int)(strsiz - sizeof(strsiz)), fi)) { 209 error(NO, "no string table (old format .o?)"); 210 continue; 211 } 212 213 for (symcount = nsyms, L = list, N = symp;--nsyms >= 0;++N) 214 if (!(N->n_type & N_EXT) && gflg || N->n_type & N_STAB && (!aflg || gflg || uflg)) 215 --symcount; 216 else { 217 N->u_name = N->u_strx ? strp + N->u_strx : ""; 218 *L++ = N; 219 } 220 221 if (!pflg) 222 qsort(list, symcount, sizeof(NLIST *), compare); 223 224 if ((archive || narg > 1) && !oflg) 225 printf("\n%s:\n", SELECT); 226 227 psyms(list, symcount); 228 } while(archive && nextel()); 229 } 230 231 psyms(list, nsyms) 232 NLIST **list; 233 register int nsyms; 234 { 235 register NLIST *L; 236 register u_char type; 237 char *stab(); 238 239 while (nsyms--) { 240 L = *list++; 241 type = L->n_type; 242 if (type & N_STAB) { 243 if (oflg) { 244 if (archive) 245 printf("%s:", *xargv); 246 printf("%s:", SELECT); 247 } 248 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); 249 continue; 250 } 251 switch (type & N_TYPE) { 252 case N_UNDF: 253 type = L->n_value ? 'c' : 'u'; 254 break; 255 case N_ABS: 256 type = 'a'; 257 break; 258 case N_TEXT: 259 type = 't'; 260 break; 261 case N_DATA: 262 type = 'd'; 263 break; 264 case N_BSS: 265 type = 'b'; 266 break; 267 case N_FN: 268 type = 'f'; 269 break; 270 default: 271 type = '?'; 272 break; 273 } 274 if (uflg && type != 'u') 275 continue; 276 if (oflg) { 277 if (archive) 278 printf("%s:", *xargv); 279 printf("%s:", SELECT); 280 } 281 if (L->n_type & N_EXT) 282 type = toupper(type); 283 if (!uflg) { 284 if (type == 'u' || type == 'U') 285 fputs(" ", stdout); 286 else 287 printf(N_FORMAT, (int)L->n_value); 288 printf(" %c ", (char)type); 289 } 290 puts(L->u_name); 291 } 292 } 293 294 compare(p1, p2) 295 NLIST **p1, **p2; 296 { 297 if (nflg) { 298 if ((*p1)->n_value > (*p2)->n_value) 299 return(rflg); 300 if ((*p1)->n_value < (*p2)->n_value) 301 return(-rflg); 302 } 303 return(rflg * strcmp((*p1)->u_name, (*p2)->u_name)); 304 } 305 306 nextel() 307 { 308 register char *cp; 309 long arsize, 310 lseek(); 311 312 (void)fseek(fi, off, L_SET); 313 /*NOSTRICT*/ 314 if (!fread((char *)&archdr, sizeof(struct ar_hdr), 1, fi)) 315 return(0); 316 for (cp = archdr.ar_name; cp < &archdr.ar_name[sizeof(archdr.ar_name)]; ++cp) 317 if (*cp == ' ') { 318 *cp = '\0'; 319 break; 320 } 321 arsize = atol(archdr.ar_size); 322 if (arsize & 1) 323 ++arsize; 324 off = ftell(fi) + arsize; /* beginning of next element */ 325 return(1); 326 } 327 328 struct stabnames { 329 int st_value; 330 char *st_name; 331 } stabnames[] ={ 332 N_GSYM, "GSYM", 333 N_FNAME, "FNAME", 334 N_FUN, "FUN", 335 N_STSYM, "STSYM", 336 N_LCSYM, "LCSYM", 337 N_RSYM, "RSYM", 338 N_SLINE, "SLINE", 339 N_SSYM, "SSYM", 340 N_SO, "SO", 341 N_LSYM, "LSYM", 342 N_SOL, "SOL", 343 N_PSYM, "PSYM", 344 N_ENTRY, "ENTRY", 345 N_LBRAC, "LBRAC", 346 N_RBRAC, "RBRAC", 347 N_BCOMM, "BCOMM", 348 N_ECOMM, "ECOMM", 349 N_ECOML, "ECOML", 350 N_LENG, "LENG", 351 N_PC, "PC", 352 0, 0 353 }; 354 355 char * 356 stab(val) 357 register u_char val; 358 { 359 register struct stabnames *sp; 360 static char prbuf[5]; 361 362 for (sp = stabnames; sp->st_value; ++sp) 363 if (sp->st_value == val) 364 return(sp->st_name); 365 (void)sprintf(prbuf, "%02x", (int)val); 366 return(prbuf); 367 } 368 369 error(doexit, msg) 370 int doexit; 371 char *msg; 372 { 373 fprintf(stderr, "nm: %s:", *xargv); 374 if (archive) 375 fprintf(stderr, "(%s): %s\n", archdr.ar_name, msg); 376 else 377 fprintf(stderr, " %s\n", msg); 378 if (doexit) 379 exit(2); 380 errs = 1; 381 } 382