mdoc version three
[unix-history] / usr / src / usr.bin / nm / nm.c
CommitLineData
2fd2f477 1/*
563ceb7b
KB
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Hans Huebner.
7 *
6ecf3d85 8 * %sccs.include.redist.c%
2fd2f477
KB
9 */
10
7ea0db89 11#ifndef lint
563ceb7b
KB
12char copyright[] =
13"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
14 All rights reserved.\n";
15#endif /* not lint */
2fd2f477 16
563ceb7b 17#ifndef lint
9872da10 18static char sccsid[] = "@(#)nm.c 5.8 (Berkeley) %G%";
563ceb7b 19#endif /* not lint */
2fd2f477 20
c0bc0330 21#include <sys/types.h>
9789d1cb 22#include <a.out.h>
c0bc0330 23#include <stab.h>
563ceb7b 24#include <ar.h>
2fd2f477 25#include <ranlib.h>
563ceb7b
KB
26#include <unistd.h>
27#include <errno.h>
28#include <ctype.h>
29#include <stdio.h>
a86379d5 30#include <stdlib.h>
6ebcb998 31#include <string.h>
c0bc0330 32
4bf6a19a
KB
33int ignore_bad_archive_entries = 1;
34int print_only_external_symbols;
35int print_only_undefined_symbols;
36int print_all_symbols;
37int print_file_each_line;
563ceb7b
KB
38int fcount;
39
9872da10
KB
40int rev;
41int fname(), rname(), value();
42int (*sfunc)() = fname;
43
563ceb7b
KB
44/* some macros for symbol type (nlist.n_type) handling */
45#define IS_DEBUGGER_SYMBOL(x) ((x) & N_STAB)
46#define IS_EXTERNAL(x) ((x) & N_EXT)
47#define SYMBOL_TYPE(x) ((x) & (N_TYPE | N_STAB))
48
9872da10
KB
49void *emalloc();
50
563ceb7b
KB
51/*
52 * main()
53 * parse command line, execute process_file() for each file
54 * specified on the command line.
55 */
c0bc0330 56main(argc, argv)
563ceb7b
KB
57 int argc;
58 char **argv;
c0bc0330 59{
563ceb7b
KB
60 extern int optind;
61 int ch, errors;
c0bc0330 62
563ceb7b
KB
63 while ((ch = getopt(argc, argv, "agnopruw")) != EOF) {
64 switch (ch) {
2fd2f477 65 case 'a':
563ceb7b 66 print_all_symbols = 1;
2fd2f477 67 break;
c0bc0330 68 case 'g':
563ceb7b 69 print_only_external_symbols = 1;
2fd2f477
KB
70 break;
71 case 'n':
9872da10 72 sfunc = value;
2fd2f477
KB
73 break;
74 case 'o':
563ceb7b 75 print_file_each_line = 1;
2fd2f477
KB
76 break;
77 case 'p':
9872da10 78 sfunc = NULL;
2fd2f477 79 break;
c0bc0330 80 case 'r':
9872da10 81 rev = 1;
2fd2f477
KB
82 break;
83 case 'u':
563ceb7b
KB
84 print_only_undefined_symbols = 1;
85 break;
86 case 'w':
87 ignore_bad_archive_entries = 0;
2fd2f477
KB
88 break;
89 case '?':
c0bc0330 90 default:
563ceb7b 91 usage();
c0bc0330 92 }
563ceb7b
KB
93 }
94 fcount = argc - optind;
2fd2f477 95 argv += optind;
563ceb7b 96
9872da10
KB
97 if (rev && sfunc == fname)
98 sfunc = rname;
99
563ceb7b
KB
100 if (!fcount)
101 errors = process_file("a.out");
102 else {
103 errors = 0;
104 do {
105 errors |= process_file(*argv);
106 } while (*++argv);
c0bc0330 107 }
563ceb7b 108 exit(errors);
c0bc0330
BJ
109}
110
563ceb7b
KB
111/*
112 * process_file()
113 * show symbols in the file given as an argument. Accepts archive and
114 * object files as input.
115 */
116process_file(fname)
117 char *fname;
c0bc0330 118{
563ceb7b
KB
119 struct exec exec_head;
120 FILE *fp;
121 int retval;
122 char magic[SARMAG];
123
124 if (!(fp = fopen(fname, "r"))) {
125 (void)fprintf(stderr, "nm: cannot read %s.\n", fname);
126 return(1);
127 }
c0bc0330 128
563ceb7b
KB
129 if (fcount > 1)
130 (void)printf("\n%s:\n", fname);
131
2fd2f477 132 /*
563ceb7b
KB
133 * first check whether this is an object file - read a object
134 * header, and skip back to the beginning
2fd2f477 135 */
a86379d5 136 if (fread((char *)&exec_head, sizeof(exec_head), (size_t)1, fp) != 1) {
563ceb7b
KB
137 (void)fprintf(stderr, "nm: %s: bad format.\n", fname);
138 (void)fclose(fp);
139 return(1);
c0bc0330 140 }
563ceb7b
KB
141 rewind(fp);
142
143 /* this could be an archive */
144 if (N_BADMAG(exec_head)) {
a86379d5 145 if (fread(magic, sizeof(magic), (size_t)1, fp) != 1 ||
563ceb7b
KB
146 strncmp(magic, ARMAG, SARMAG)) {
147 (void)fprintf(stderr,
148 "nm: %s: not object file or archive.\n", fname);
149 (void)fclose(fp);
150 return(1);
2fd2f477 151 }
563ceb7b
KB
152 retval = show_archive(fname, fp);
153 } else
154 retval = show_objfile(fname, fp);
155 (void)fclose(fp);
156 return(retval);
157}
158
159/*
160 * show_archive()
161 * show symbols in the given archive file
162 */
163show_archive(fname, fp)
164 char *fname;
165 FILE *fp;
166{
563ceb7b
KB
167 struct ar_hdr ar_head;
168 struct exec exec_head;
a86379d5
KB
169 int i, rval;
170 long last_ar_off;
9872da10 171 char *p, *name;
563ceb7b 172
a86379d5 173 name = emalloc(sizeof(ar_head.ar_name) + strlen(fname) + 3);
563ceb7b
KB
174
175 rval = 0;
176
177 /* while there are more entries in the archive */
a86379d5 178 while (fread((char *)&ar_head, sizeof(ar_head), (size_t)1, fp) == 1) {
563ceb7b
KB
179 /* bad archive entry - stop processing this archive */
180 if (strncmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) {
181 (void)fprintf(stderr,
182 "nm: %s: bad format archive header", fname);
183 (void)free(name);
184 return(1);
185 }
186
7329b8f8
KB
187 /* remember start position of current archive object */
188 last_ar_off = ftell(fp);
189
190 /* skip ranlib entries */
191 if (!strncmp(ar_head.ar_name, RANLIBMAG, sizeof(RANLIBMAG) - 1))
192 goto skip;
193
2fd2f477 194 /*
d737f306 195 * construct a name of the form "archive.a:obj.o:" for the
563ceb7b
KB
196 * current archive entry if the object name is to be printed
197 * on each output line
2fd2f477 198 */
a86379d5
KB
199 p = name;
200 if (print_file_each_line)
201 p += sprintf(p, "%s:", fname);
563ceb7b
KB
202 for (i = 0; i < sizeof(ar_head.ar_name); ++i)
203 if (ar_head.ar_name[i] && ar_head.ar_name[i] != ' ')
204 *p++ = ar_head.ar_name[i];
563ceb7b 205 *p++ = '\0';
c0bc0330 206
563ceb7b 207 /* get and check current object's header */
a86379d5
KB
208 if (fread((char *)&exec_head, sizeof(exec_head),
209 (size_t)1, fp) != 1) {
563ceb7b
KB
210 (void)fprintf(stderr, "nm: %s: premature EOF.\n", name);
211 (void)free(name);
212 return(1);
c0bc0330 213 }
7329b8f8
KB
214
215 if (N_BADMAG(exec_head)) {
216 if (!ignore_bad_archive_entries) {
217 (void)fprintf(stderr,
218 "nm: %s: bad format.\n", name);
219 rval = 1;
2fd2f477 220 }
7329b8f8
KB
221 } else {
222 (void)fseek(fp, (long)-sizeof(exec_head),
223 SEEK_CUR);
224 if (!print_file_each_line)
225 (void)printf("\n%s:\n", name);
226 rval |= show_objfile(name, fp);
227 }
563ceb7b
KB
228
229 /*
a86379d5
KB
230 * skip to next archive object - it starts at the next
231 * even byte boundary
563ceb7b 232 */
a86379d5 233#define even(x) (((x) + 1) & ~1)
7329b8f8 234skip: if (fseek(fp, last_ar_off + even(atol(ar_head.ar_size)),
563ceb7b
KB
235 SEEK_SET)) {
236 (void)fprintf(stderr,
237 "nm: %s: %s\n", fname, strerror(errno));
238 (void)free(name);
239 return(1);
c0bc0330 240 }
563ceb7b
KB
241 }
242 (void)free(name);
243 return(rval);
244}
245
246/*
247 * show_objfile()
248 * show symbols from the object file pointed to by fp. The current
249 * file pointer for fp is expected to be at the beginning of an a.out
250 * header.
251 */
252show_objfile(objname, fp)
253 char *objname;
254 FILE *fp;
255{
a86379d5 256 register struct nlist *names, *np;
563ceb7b
KB
257 register int i, nnames, nrawnames;
258 struct exec head;
259 long stabsize;
9872da10 260 char *stab;
563ceb7b
KB
261
262 /* read a.out header */
a86379d5 263 if (fread((char *)&head, sizeof(head), (size_t)1, fp) != 1) {
563ceb7b
KB
264 (void)fprintf(stderr,
265 "nm: %s: cannot read header.\n", objname);
266 return(1);
267 }
268
269 /*
270 * skip back to the header - the N_-macros return values relative
271 * to the beginning of the a.out header
272 */
273 if (fseek(fp, (long)-sizeof(head), SEEK_CUR)) {
274 (void)fprintf(stderr,
275 "nm: %s: %s\n", objname, strerror(errno));
276 return(1);
277 }
278
279 /* stop if this is no valid object file */
280 if (N_BADMAG(head)) {
281 (void)fprintf(stderr,
282 "nm: %s: bad format.\n", objname);
283 return(1);
284 }
285
286 /* stop if the object file contains no symbol table */
287 if (!head.a_syms) {
288 (void)fprintf(stderr,
289 "nm: %s: no name list.\n", objname);
290 return(1);
291 }
292
293 if (fseek(fp, (long)N_SYMOFF(head), SEEK_CUR)) {
294 (void)fprintf(stderr,
295 "nm: %s: %s\n", objname, strerror(errno));
296 return(1);
297 }
298
299 /* get memory for the symbol table */
9872da10 300 names = emalloc((size_t)head.a_syms);
563ceb7b 301 nrawnames = head.a_syms / sizeof(*names);
a86379d5 302 if (fread((char *)names, (size_t)head.a_syms, (size_t)1, fp) != 1) {
563ceb7b
KB
303 (void)fprintf(stderr,
304 "nm: %s: cannot read symbol table.\n", objname);
305 (void)free((char *)names);
306 return(1);
307 }
308
309 /*
310 * Following the symbol table comes the string table. The first
311 * 4-byte-integer gives the total size of the string table
312 * _including_ the size specification itself.
313 */
a86379d5 314 if (fread((char *)&stabsize, sizeof(stabsize), (size_t)1, fp) != 1) {
563ceb7b
KB
315 (void)fprintf(stderr,
316 "nm: %s: cannot read stab size.\n", objname);
317 (void)free((char *)names);
318 return(1);
319 }
a86379d5 320 stab = emalloc((size_t)stabsize);
563ceb7b
KB
321
322 /*
323 * read the string table offset by 4 - all indices into the string
324 * table include the size specification.
325 */
d737f306 326 stabsize -= 4; /* we already have the size */
a86379d5 327 if (fread(stab + 4, (size_t)stabsize, (size_t)1, fp) != 1) {
563ceb7b
KB
328 (void)fprintf(stderr,
329 "nm: %s: stab truncated..\n", objname);
330 (void)free((char *)names);
331 (void)free(stab);
332 return(1);
333 }
2fd2f477 334
563ceb7b
KB
335 /*
336 * fix up the symbol table and filter out unwanted entries
337 *
338 * common symbols are characterized by a n_type of N_UNDF and a
339 * non-zero n_value -- change n_type to N_COMM for all such
340 * symbols to make life easier later.
341 *
342 * filter out all entries which we don't want to print anyway
343 */
a86379d5
KB
344 for (np = names, i = nnames = 0; i < nrawnames; np++, i++) {
345 if (SYMBOL_TYPE(np->n_type) == N_UNDF && np->n_value)
346 np->n_type = N_COMM | (np->n_type & N_EXT);
347 if (!print_all_symbols && IS_DEBUGGER_SYMBOL(np->n_type))
c0bc0330 348 continue;
a86379d5 349 if (print_only_external_symbols && !IS_EXTERNAL(np->n_type))
563ceb7b
KB
350 continue;
351 if (print_only_undefined_symbols &&
a86379d5 352 SYMBOL_TYPE(np->n_type) != N_UNDF)
2fd2f477 353 continue;
2fd2f477 354
563ceb7b
KB
355 /*
356 * make n_un.n_name a character pointer by adding the string
357 * table's base to n_un.n_strx
358 *
a86379d5 359 * don't mess with zero offsets
563ceb7b 360 */
a86379d5
KB
361 if (np->n_un.n_strx)
362 np->n_un.n_name = stab + np->n_un.n_strx;
563ceb7b 363 else
a86379d5
KB
364 np->n_un.n_name = "";
365 names[nnames++] = *np;
563ceb7b 366 }
2fd2f477 367
563ceb7b 368 /* sort the symbol table if applicable */
9872da10
KB
369 if (sfunc)
370 qsort((char *)names, (size_t)nnames, sizeof(*names), sfunc);
2fd2f477 371
563ceb7b 372 /* print out symbols */
a86379d5
KB
373 for (np = names, i = 0; i < nnames; np++, i++)
374 print_symbol(objname, np);
2fd2f477 375
563ceb7b
KB
376 (void)free((char *)names);
377 (void)free(stab);
378 return(0);
c0bc0330
BJ
379}
380
563ceb7b
KB
381/*
382 * print_symbol()
383 * show one symbol
384 */
385print_symbol(objname, sym)
386 char *objname;
a86379d5 387 register struct nlist *sym;
c0bc0330 388{
563ceb7b
KB
389 char *typestring(), typeletter();
390
391 if (print_file_each_line)
a86379d5 392 (void)printf("%s:", objname);
563ceb7b
KB
393
394 /*
395 * handle undefined-only format seperately (no space is
396 * left for symbol values, no type field is printed)
397 */
398 if (print_only_undefined_symbols) {
a86379d5 399 (void)puts(sym->n_un.n_name);
563ceb7b
KB
400 return;
401 }
402
403 /* print symbol's value */
404 if (SYMBOL_TYPE(sym->n_type) == N_UNDF)
405 (void)printf(" ");
406 else
407 (void)printf("%08lx", sym->n_value);
408
409 /* print type information */
410 if (IS_DEBUGGER_SYMBOL(sym->n_type))
411 (void)printf(" - %02x %04x %5s ", sym->n_other,
412 sym->n_desc&0xffff, typestring(sym->n_type));
413 else
414 (void)printf(" %c ", typeletter(sym->n_type));
415
416 /* print the symbol's name */
a86379d5 417 (void)puts(sym->n_un.n_name);
563ceb7b
KB
418}
419
420/*
421 * typestring()
422 * return the a description string for an STAB entry
423 */
424char *
425typestring(type)
426 register u_char type;
427{
428 switch(type) {
429 case N_BCOMM:
430 return("BCOMM");
431 case N_ECOML:
432 return("ECOML");
433 case N_ECOMM:
434 return("ECOMM");
435 case N_ENTRY:
436 return("ENTRY");
437 case N_FNAME:
438 return("FNAME");
439 case N_FUN:
440 return("FUN");
441 case N_GSYM:
442 return("GSYM");
443 case N_LBRAC:
444 return("LBRAC");
445 case N_LCSYM:
446 return("LCSYM");
447 case N_LENG:
448 return("LENG");
449 case N_LSYM:
450 return("LSYM");
451 case N_PC:
452 return("PC");
453 case N_PSYM:
454 return("PSYM");
455 case N_RBRAC:
456 return("RBRAC");
457 case N_RSYM:
458 return("RSYM");
459 case N_SLINE:
460 return("SLINE");
461 case N_SO:
462 return("SO");
463 case N_SOL:
464 return("SOL");
465 case N_SSYM:
466 return("SSYM");
467 case N_STSYM:
468 return("STSYM");
c0bc0330 469 }
563ceb7b 470 return("???");
c0bc0330
BJ
471}
472
563ceb7b
KB
473/*
474 * typeletter()
475 * return a description letter for the given basic type code of an
476 * symbol table entry. The return value will be upper case for
477 * external, lower case for internal symbols.
478 */
479char
480typeletter(type)
481 u_char type;
c0bc0330 482{
563ceb7b
KB
483 switch(SYMBOL_TYPE(type)) {
484 case N_ABS:
485 return(IS_EXTERNAL(type) ? 'A' : 'a');
486 case N_BSS:
487 return(IS_EXTERNAL(type) ? 'B' : 'b');
488 case N_COMM:
489 return(IS_EXTERNAL(type) ? 'C' : 'c');
490 case N_DATA:
491 return(IS_EXTERNAL(type) ? 'D' : 'd');
492 case N_FN:
493 return(IS_EXTERNAL(type) ? 'F' : 'f');
494 case N_TEXT:
495 return(IS_EXTERNAL(type) ? 'T' : 't');
496 case N_UNDF:
497 return(IS_EXTERNAL(type) ? 'U' : 'u');
c0bc0330 498 }
563ceb7b 499 return('?');
c0bc0330
BJ
500}
501
9872da10 502fname(a0, b0)
a86379d5 503 void *a0, *b0;
c0bc0330 504{
a86379d5
KB
505 struct nlist *a = a0, *b = b0;
506
9872da10 507 return(strcmp(a->n_un.n_name, b->n_un.n_name));
c0bc0330
BJ
508}
509
9872da10
KB
510rname(a0, b0)
511 void *a0, *b0;
512{
513 struct nlist *a = a0, *b = b0;
514
515 return(strcmp(b->n_un.n_name, a->n_un.n_name));
516}
517
518value(a0, b0)
a86379d5 519 void *a0, *b0;
563ceb7b 520{
a86379d5
KB
521 register struct nlist *a = a0, *b = b0;
522
563ceb7b
KB
523 if (SYMBOL_TYPE(a->n_type) == N_UNDF)
524 if (SYMBOL_TYPE(b->n_type) == N_UNDF)
525 return(0);
526 else
527 return(-1);
528 else if (SYMBOL_TYPE(b->n_type) == N_UNDF)
529 return(1);
9872da10
KB
530 if (rev) {
531 if (a->n_value == b->n_value)
532 return(rname(a0, b0));
533 return(b->n_value > a->n_value ? 1 : -1);
534 } else {
535 if (a->n_value == b->n_value)
536 return(fname(a0, b0));
537 return(a->n_value > b->n_value ? 1 : -1);
538 }
563ceb7b 539}
c0bc0330 540
9872da10 541void *
563ceb7b 542emalloc(size)
a86379d5 543 size_t size;
c0bc0330 544{
a86379d5 545 char *p;
563ceb7b
KB
546
547 /* NOSTRICT */
9872da10
KB
548 if (p = malloc(size))
549 return(p);
550 (void)fprintf(stderr, "nm: %s\n", strerror(errno));
551 exit(1);
2fd2f477
KB
552}
553
563ceb7b 554usage()
2fd2f477 555{
a86379d5 556 (void)fprintf(stderr, "usage: nm [-agnopruw] [file ...]\n");
563ceb7b 557 exit(1);
c0bc0330 558}