GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/nm/nm.c Lines: 159 395 40.3 %
Date: 2017-11-07 Branches: 102 336 30.4 %

Line Branch Exec Source
1
/*	$OpenBSD: nm.c,v 1.52 2017/09/12 08:32:44 mpi Exp $	*/
2
/*	$NetBSD: nm.c,v 1.7 1996/01/14 23:04:03 pk Exp $	*/
3
4
/*
5
 * Copyright (c) 1989, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * This code is derived from software contributed to Berkeley by
9
 * Hans Huebner.
10
 *
11
 * Redistribution and use in source and binary forms, with or without
12
 * modification, are permitted provided that the following conditions
13
 * are met:
14
 * 1. Redistributions of source code must retain the above copyright
15
 *    notice, this list of conditions and the following disclaimer.
16
 * 2. Redistributions in binary form must reproduce the above copyright
17
 *    notice, this list of conditions and the following disclaimer in the
18
 *    documentation and/or other materials provided with the distribution.
19
 * 3. Neither the name of the University nor the names of its contributors
20
 *    may be used to endorse or promote products derived from this software
21
 *    without specific prior written permission.
22
 *
23
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33
 * SUCH DAMAGE.
34
 */
35
36
#include <sys/types.h>
37
#include <sys/mman.h>
38
#include <a.out.h>
39
#include <elf_abi.h>
40
#include <ar.h>
41
#include <ranlib.h>
42
#include <unistd.h>
43
#include <err.h>
44
#include <errno.h>
45
#include <ctype.h>
46
#include <link.h>
47
48
#include <stdio.h>
49
#include <stdlib.h>
50
#include <string.h>
51
#include <getopt.h>
52
#include "util.h"
53
#include "elfuncs.h"
54
55
#define	SYMTABMAG	"/ "
56
#define	STRTABMAG	"//"
57
#define	SYM64MAG	"/SYM64/         "
58
59
union hdr {
60
	Elf32_Ehdr elf32;
61
	Elf64_Ehdr elf64;
62
};
63
64
int armap;
65
int demangle;
66
int non_object_warning;
67
int print_only_external_symbols;
68
int print_only_undefined_symbols;
69
int print_all_symbols;
70
int print_file_each_line;
71
int show_extensions;
72
int issize;
73
char posix_fmtstr[6];
74
int posix_output;
75
char posix_radix = 'x';
76
int usemmap = 1;
77
int dynamic_only;
78
79
/* size vars */
80
unsigned long total_text, total_data, total_bss, total_total;
81
int non_object_warning, print_totals;
82
83
int rev;
84
int fname(const void *, const void *);
85
int rname(const void *, const void *);
86
int value(const void *, const void *);
87
char *otherstring(struct xnlist *);
88
int (*sfunc)(const void *, const void *) = fname;
89
char typeletter(struct xnlist *);
90
int mmbr_name(struct ar_hdr *, char **, int, int *, FILE *);
91
int show_symtab(off_t, u_long, const char *, FILE *);
92
int show_symdef(off_t, u_long, const char *, FILE *);
93
94
/* some macros for symbol type (nlist.n_type) handling */
95
#define	IS_EXTERNAL(x)		((x) & N_EXT)
96
#define	SYMBOL_TYPE(x)		((x) & (N_TYPE | N_STAB))
97
98
void	 pipe2cppfilt(void);
99
void	 usage(void);
100
char	*symname(struct xnlist *);
101
int	process_file(int, const char *);
102
int	show_archive(int, const char *, FILE *);
103
int	show_file(int, int, const char *, FILE *fp, off_t, union hdr *);
104
void	print_symbol(const char *, struct xnlist *);
105
106
#define	OPTSTRING_NM	"aABCDegnopPrst:uvw"
107
const struct option longopts_nm[] = {
108
	{ "debug-syms",		no_argument,		0,	'a' },
109
	{ "demangle",		no_argument,		0,	'C' },
110
	{ "dynamic",		no_argument,		0,	'D' },
111
	{ "extern-only",	no_argument,		0,	'g' },
112
/*	{ "line-numbers",	no_argument,		0,	'l' }, */
113
	{ "no-sort",		no_argument,		0,	'p' },
114
	{ "numeric-sort",	no_argument,		0,	'n' },
115
	{ "print-armap",	no_argument,		0,	's' },
116
	{ "print-file-name",	no_argument,		0,	'o' },
117
	{ "reverse-sort",	no_argument,		0,	'r' },
118
/*	{ "size-sort",		no_argument,		&szval,	1 }, */
119
	{ "undefined-only",	no_argument,		0,	'u' },
120
	{ "help",		no_argument,		0,	'?' },
121
	{ NULL }
122
};
123
124
/*
125
 * main()
126
 *	parse command line, execute process_file() for each file
127
 *	specified on the command line.
128
 */
129
int
130
main(int argc, char *argv[])
131
{
132
	extern char *__progname;
133
	extern int optind;
134
	const char *optstr;
135
	const struct option *lopts;
136
	int ch, eval;
137
138
376
	if (pledge("stdio rpath proc exec flock cpath wpath", NULL) == -1)
139
		err(1, "pledge");
140
141
	optstr = OPTSTRING_NM;
142
	lopts = longopts_nm;
143
188
	if (!strcmp(__progname, "size")) {
144
		if (pledge("stdio rpath flock cpath wpath", NULL) == -1)
145
			err(1, "pledge");
146
147
		issize = 1;
148
		optstr = "tw";
149
		lopts = NULL;
150
	}
151
152
556
	while ((ch = getopt_long(argc, argv, optstr, lopts, NULL)) != -1) {
153




736
		switch (ch) {
154
		case 'a':
155
			print_all_symbols = 1;
156
			break;
157
		case 'B':
158
			/* no-op, compat with gnu-nm */
159
			break;
160
		case 'C':
161
5
			demangle = 1;
162
5
			break;
163
		case 'D':
164
			dynamic_only = 1;
165
			break;
166
		case 'e':
167
			show_extensions = 1;
168
			break;
169
		case 'g':
170
180
			print_only_external_symbols = 1;
171
180
			break;
172
		case 'n':
173
		case 'v':
174
			sfunc = value;
175
			break;
176
		case 'A':
177
		case 'o':
178
183
			print_file_each_line = 1;
179
183
			break;
180
		case 'p':
181
			sfunc = NULL;
182
			break;
183
		case 'P':
184
			posix_output = 1;
185
			break;
186
		case 'r':
187
			rev = 1;
188
			break;
189
		case 's':
190
			armap = 1;
191
			break;
192
		case 'u':
193
			print_only_undefined_symbols = 1;
194
			break;
195
		case 'w':
196
			non_object_warning = 1;
197
			break;
198
		case 't':
199
			if (issize) {
200
				print_totals = 1;
201
			} else {
202
				posix_radix = *optarg;
203
				if (strlen(optarg) != 1 ||
204
				    (posix_radix != 'd' && posix_radix != 'o' &&
205
				     posix_radix != 'x'))
206
					usage();
207
			}
208
			break;
209
		case '?':
210
		default:
211
			usage();
212
		}
213
	}
214
215
188
	if (posix_output)
216
		(void)snprintf(posix_fmtstr, sizeof posix_fmtstr, "%%%c %%%c",
217
		    posix_radix, posix_radix);
218
188
	if (demangle)
219
5
		pipe2cppfilt();
220
221
188
	if (pledge("stdio rpath flock cpath wpath", NULL) == -1)
222
		err(1, "pledge");
223
224
188
	argv += optind;
225
188
	argc -= optind;
226
227
188
	if (rev && sfunc == fname)
228
		sfunc = rname;
229
230
	eval = 0;
231
188
	if (*argv)
232
		do {
233
14035
			eval |= process_file(argc, *argv);
234
14035
		} while (*++argv);
235
	else
236
		eval |= process_file(1, "a.out");
237
238
188
	if (issize && print_totals)
239
		printf("\n%lu\t%lu\t%lu\t%lu\t%lx\tTOTAL\n",
240
		    total_text, total_data, total_bss,
241
		    total_total, total_total);
242
	exit(eval);
243
}
244
245
/*
246
 * process_file()
247
 *	show symbols in the file given as an argument.  Accepts archive and
248
 *	object files as input.
249
 */
250
int
251
process_file(int count, const char *fname)
252
{
253
28070
	union hdr exec_head;
254
	FILE *fp;
255
	int retval;
256
	size_t bytes;
257
14035
	char magic[SARMAG];
258
259
14035
	if (!(fp = fopen(fname, "r"))) {
260
		warn("cannot read %s", fname);
261
		return(1);
262
	}
263
264
14035
	if (!issize && count > 1)
265
14027
		(void)printf("\n%s:\n", fname);
266
267
	/*
268
	 * first check whether this is an object file - read a object
269
	 * header, and skip back to the beginning
270
	 */
271
14035
	bzero(&exec_head, sizeof(exec_head));
272
14035
	bytes = fread((char *)&exec_head, 1, sizeof(exec_head), fp);
273
14035
	if (bytes < sizeof(exec_head)) {
274
		if (bytes < sizeof(exec_head.elf32) || IS_ELF(exec_head.elf32)) {
275
			warnx("%s: bad format", fname);
276
			(void)fclose(fp);
277
			return(1);
278
		}
279
	}
280
14035
	rewind(fp);
281
282
	/* this could be an archive */
283


56131
	if (!IS_ELF(exec_head.elf32)) {
284

6
		if (fread(magic, sizeof(magic), (size_t)1, fp) != 1 ||
285
3
		    strncmp(magic, ARMAG, SARMAG)) {
286
			warnx("%s: not object file or archive", fname);
287
			(void)fclose(fp);
288
			return(1);
289
		}
290
3
		retval = show_archive(count, fname, fp);
291
3
	} else
292
14032
		retval = show_file(count, 1, fname, fp, 0, &exec_head);
293
14035
	(void)fclose(fp);
294
14035
	return(retval);
295
14035
}
296
297
char *nametab;
298
299
/*
300
 *
301
 *	given the archive member header -- produce member name
302
 */
303
int
304
mmbr_name(struct ar_hdr *arh, char **name, int baselen, int *namelen, FILE *fp)
305
{
306
228
	char *p = *name + strlen(*name);
307
	long i;
308
309

114
	if (nametab && arh->ar_name[0] == '/') {
310
		int len;
311
312
		i = atol(&arh->ar_name[1]);
313
		len = strlen(&nametab[i]) + 1;
314
		if (len > *namelen) {
315
			p -= (long)*name;
316
			if ((*name = realloc(*name, baselen+len)) == NULL)
317
				err(1, NULL);
318
			*namelen = len;
319
			p += (long)*name;
320
		}
321
		strlcpy(p, &nametab[i], len);
322
		p += len - 1;
323
	} else
324
#ifdef AR_EFMT1
325
	/*
326
	 * BSD 4.4 extended AR format: #1/<namelen>, with name as the
327
	 * first <namelen> bytes of the file
328
	 */
329

114
	if ((arh->ar_name[0] == '#') &&
330
	    (arh->ar_name[1] == '1') &&
331
	    (arh->ar_name[2] == '/') &&
332
	    (isdigit((unsigned char)arh->ar_name[3]))) {
333
		int len = atoi(&arh->ar_name[3]);
334
335
		if (len > *namelen) {
336
			p -= (long)*name;
337
			if ((*name = realloc(*name, baselen+len)) == NULL)
338
				err(1, NULL);
339
			*namelen = len;
340
			p += (long)*name;
341
		}
342
		if (fread(p, len, 1, fp) != 1) {
343
			warnx("%s: premature EOF", *name);
344
			free(*name);
345
			return(1);
346
		}
347
		p += len;
348
	} else
349
#endif
350
3876
	for (i = 0; i < sizeof(arh->ar_name); ++i)
351

3648
		if (arh->ar_name[i] && arh->ar_name[i] != ' ')
352
1167
			*p++ = arh->ar_name[i];
353
114
	*p = '\0';
354
114
	if (p[-1] == '/')
355
114
		*--p = '\0';
356
357
114
	return (0);
358
114
}
359
360
/*
361
 * show_symtab()
362
 *	show archive ranlib index (fs5)
363
 */
364
int
365
show_symtab(off_t off, u_long len, const char *name, FILE *fp)
366
{
367
	struct ar_hdr ar_head;
368
	int *symtab, *ps;
369
	char *strtab, *p;
370
	int num, rval = 0;
371
	int namelen;
372
	off_t restore;
373
374
	restore = ftello(fp);
375
376
	MMAP(symtab, len, PROT_READ, MAP_PRIVATE|MAP_FILE, fileno(fp), off);
377
	if (symtab == MAP_FAILED)
378
		return (1);
379
380
	namelen = sizeof(ar_head.ar_name);
381
	if ((p = malloc(sizeof(ar_head.ar_name))) == NULL) {
382
		warn("%s: malloc", name);
383
		MUNMAP(symtab, len);
384
	}
385
386
	printf("\nArchive index:\n");
387
	num = betoh32(*symtab);
388
	strtab = (char *)(symtab + num + 1);
389
	for (ps = symtab + 1; num--; ps++, strtab += strlen(strtab) + 1) {
390
		if (fseeko(fp, betoh32(*ps), SEEK_SET)) {
391
			warn("%s: fseeko", name);
392
			rval = 1;
393
			break;
394
		}
395
396
		if (fread(&ar_head, sizeof(ar_head), 1, fp) != 1 ||
397
		    memcmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) {
398
			warnx("%s: member fseeko", name);
399
			rval = 1;
400
			break;
401
		}
402
403
		*p = '\0';
404
		if (mmbr_name(&ar_head, &p, 0, &namelen, fp)) {
405
			rval = 1;
406
			break;
407
		}
408
409
		printf("%s in %s\n", strtab, p);
410
	}
411
412
	fseeko(fp, restore, SEEK_SET);
413
414
	free(p);
415
	MUNMAP(symtab, len);
416
	return (rval);
417
}
418
419
/*
420
 * show_symdef()
421
 *	show archive ranlib index (gob)
422
 */
423
int
424
show_symdef(off_t off, u_long len, const char *name, FILE *fp)
425
{
426
	struct ranlib *prn, *eprn;
427
	struct ar_hdr ar_head;
428
	char *symdef;
429
	char *strtab, *p;
430
	u_long size;
431
	int namelen, rval = 0;
432
433
	MMAP(symdef, len, PROT_READ, MAP_PRIVATE|MAP_FILE, fileno(fp), off);
434
	if (symdef == MAP_FAILED)
435
		return (1);
436
	if (usemmap)
437
		(void)madvise(symdef, len, MADV_SEQUENTIAL);
438
439
	namelen = sizeof(ar_head.ar_name);
440
	if ((p = malloc(sizeof(ar_head.ar_name))) == NULL) {
441
		warn("%s: malloc", name);
442
		MUNMAP(symdef, len);
443
		return (1);
444
	}
445
446
	size = *(u_long *)symdef;
447
	prn = (struct ranlib *)(symdef + sizeof(u_long));
448
	eprn = prn + size / sizeof(*prn);
449
	strtab = symdef + sizeof(u_long) + size + sizeof(u_long);
450
451
	printf("\nArchive index:\n");
452
	for (; prn < eprn; prn++) {
453
		if (fseeko(fp, prn->ran_off, SEEK_SET)) {
454
			warn("%s: fseeko", name);
455
			rval = 1;
456
			break;
457
		}
458
459
		if (fread(&ar_head, sizeof(ar_head), 1, fp) != 1 ||
460
		    memcmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) {
461
			warnx("%s: member fseeko", name);
462
			rval = 1;
463
			break;
464
		}
465
466
		*p = '\0';
467
		if (mmbr_name(&ar_head, &p, 0, &namelen, fp)) {
468
			rval = 1;
469
			break;
470
		}
471
472
		printf("%s in %s\n", strtab + prn->ran_un.ran_strx, p);
473
	}
474
475
	free(p);
476
	MUNMAP(symdef, len);
477
	return (rval);
478
}
479
480
/*
481
 * show_archive()
482
 *	show symbols in the given archive file
483
 */
484
int
485
show_archive(int count, const char *fname, FILE *fp)
486
{
487
6
	struct ar_hdr ar_head;
488
3
	union hdr exec_head;
489
	int i, rval;
490
	off_t last_ar_off, foff, symtaboff;
491
3
	char *name;
492
3
	int baselen, namelen;
493
	u_long mmbrlen, symtablen;
494
495
3
	baselen = strlen(fname) + 3;
496
3
	if (posix_output)
497
		baselen += 2;
498
3
	namelen = sizeof(ar_head.ar_name);
499
3
	if ((name = malloc(baselen + namelen)) == NULL)
500
		err(1, NULL);
501
502
	rval = 0;
503
3
	nametab = NULL;
504
	symtaboff = 0;
505
	symtablen = 0;
506
507
	/* while there are more entries in the archive */
508
123
	while (fread(&ar_head, sizeof(ar_head), 1, fp) == 1) {
509
		/* bad archive entry - stop processing this archive */
510
117
		if (memcmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) {
511
			warnx("%s: bad format archive header", fname);
512
			rval = 1;
513
			break;
514
		}
515
516
		/* remember start position of current archive object */
517
117
		last_ar_off = ftello(fp);
518
117
		mmbrlen = atol(ar_head.ar_size);
519
520
234
		if (strncmp(ar_head.ar_name, RANLIBMAG,
521
117
		    sizeof(RANLIBMAG) - 1) == 0) {
522
			if (!issize && armap &&
523
			    show_symdef(last_ar_off, mmbrlen, fname, fp)) {
524
				rval = 1;
525
				break;
526
			}
527
			goto skip;
528
234
		} else if (strncmp(ar_head.ar_name, SYMTABMAG,
529
117
		    sizeof(SYMTABMAG) - 1) == 0) {
530
			/* if nametab hasn't been seen yet -- doit later */
531
3
			if (!nametab) {
532
				symtablen = mmbrlen;
533
				symtaboff = last_ar_off;
534
3
				goto skip;
535
			}
536
537
			/* load the Sys5 long names table */
538
228
		} else if (strncmp(ar_head.ar_name, STRTABMAG,
539
114
		    sizeof(STRTABMAG) - 1) == 0) {
540
			char *p;
541
542
			if ((nametab = malloc(mmbrlen)) == NULL) {
543
				warn("%s: nametab", fname);
544
				rval = 1;
545
				break;
546
			}
547
548
			if (fread(nametab, mmbrlen, (size_t)1, fp) != 1) {
549
				warnx("%s: premature EOF", fname);
550
				rval = 1;
551
				break;
552
			}
553
554
			for (p = nametab, i = mmbrlen; i--; p++)
555
				if (*p == '\n')
556
					*p = '\0';
557
558
			if (issize || !armap || !symtablen || !symtaboff)
559
				goto skip;
560
		}
561
#ifdef __mips64
562
		else if (memcmp(ar_head.ar_name, SYM64MAG,
563
		    sizeof(ar_head.ar_name)) == 0) {
564
			/* IRIX6-compatible archive map */
565
			goto skip;
566
		}
567
#endif
568
569
114
		if (!issize && armap && symtablen && symtaboff) {
570
			if (show_symtab(symtaboff, symtablen, fname, fp)) {
571
				rval = 1;
572
				break;
573
			} else {
574
				symtaboff = 0;
575
				symtablen = 0;
576
			}
577
		}
578
579
		/*
580
		 * construct a name of the form "archive.a:obj.o:" for the
581
		 * current archive entry if the object name is to be printed
582
		 * on each output line
583
		 */
584
114
		*name = '\0';
585
114
		if (posix_output)
586
			snprintf(name, baselen - 1, "%s[", fname);
587
114
		else if (count > 1)
588
			snprintf(name, baselen - 1, "%s:", fname);
589
590
114
		if (mmbr_name(&ar_head, &name, baselen, &namelen, fp)) {
591
			rval = 1;
592
			break;
593
		}
594
595
114
		if (posix_output)
596
			strlcat(name, "]", baselen + namelen);
597
598
114
		foff = ftello(fp);
599
600
		/* get and check current object's header */
601
228
		if (fread((char *)&exec_head, sizeof(exec_head),
602
114
		    (size_t)1, fp) != 1) {
603
			warnx("%s: premature EOF", fname);
604
			rval = 1;
605
			break;
606
		}
607
608
114
		rval |= show_file(2, non_object_warning, name, fp, foff, &exec_head);
609
		/*
610
		 * skip to next archive object - it starts at the next
611
		 * even byte boundary
612
		 */
613
#define even(x) (((x) + 1) & ~1)
614
117
skip:		if (fseeko(fp, last_ar_off + even(mmbrlen), SEEK_SET)) {
615
			warn("%s", fname);
616
			rval = 1;
617
			break;
618
		}
619
	}
620
3
	free(nametab);
621
3
	nametab = NULL;
622
3
	free(name);
623
3
	return(rval);
624
3
}
625
626
char *stab;
627
628
/*
629
 * show_file()
630
 *	show symbols from the object file pointed to by fp.  The current
631
 *	file pointer for fp is expected to be at the beginning of an object
632
 *	file header.
633
 */
634
int
635
show_file(int count, int warn_fmt, const char *name, FILE *fp, off_t foff, union hdr *head)
636
{
637
28292
	u_long text, data, bss, total;
638
14146
	struct xnlist *np, *names, **snames;
639
14146
	int i, nrawnames, nnames;
640
14146
	size_t stabsize;
641
642


56584
	if (IS_ELF(head->elf32) &&
643
14146
	    head->elf32.e_ident[EI_CLASS] == ELFCLASS32 &&
644
	    head->elf32.e_ident[EI_VERSION] == ELF_TARG_VER) {
645
		void *shdr;
646
647
		if (!(shdr = elf32_load_shdrs(name, fp, foff, &head->elf32)))
648
			return (1);
649
650
		i = issize?
651
		    elf32_size(&head->elf32, shdr, &text, &data, &bss) :
652
		    elf32_symload(name, fp, foff, &head->elf32, shdr,
653
			&names, &snames, &stabsize, &nrawnames);
654
		free(shdr);
655
		if (i)
656
			return (i);
657
658



70730
	} else if (IS_ELF(head->elf64) &&
659
14146
	    head->elf64.e_ident[EI_CLASS] == ELFCLASS64 &&
660
14146
	    head->elf64.e_ident[EI_VERSION] == ELF_TARG_VER) {
661
		void *shdr;
662
663
14146
		if (!(shdr = elf64_load_shdrs(name, fp, foff, &head->elf64)))
664
			return (1);
665
666
42438
		i = issize?
667
		    elf64_size(&head->elf64, shdr, &text, &data, &bss) :
668
14146
		    elf64_symload(name, fp, foff, &head->elf64, shdr,
669
			&names, &snames, &stabsize, &nrawnames);
670
14146
		free(shdr);
671
14146
		if (i)
672
			return (i);
673
14146
	} else {
674
		if (warn_fmt)
675
			warnx("%s: bad format", name);
676
		return (1);
677
	}
678
679
14146
	if (issize) {
680
		static int first = 1;
681
682
		if (first) {
683
			first = 0;
684
			printf("text\tdata\tbss\tdec\thex\n");
685
		}
686
687
		total = text + data + bss;
688
		printf("%lu\t%lu\t%lu\t%lu\t%lx",
689
		    text, data, bss, total, total);
690
		if (count > 1)
691
			(void)printf("\t%s", name);
692
693
		total_text += text;
694
		total_data += data;
695
		total_bss += bss;
696
		total_total += total;
697
698
		printf("\n");
699
		return (0);
700
	}
701
	/* else we are nm */
702
703
	/*
704
	 * it seems that string table is sequential
705
	 * relative to the symbol table order
706
	 */
707
14146
	if (sfunc == NULL && usemmap)
708
		(void)madvise(stab, stabsize, MADV_SEQUENTIAL);
709
710
	/*
711
	 * fix up the symbol table and filter out unwanted entries
712
	 *
713
	 * common symbols are characterized by a n_type of N_UNDF and a
714
	 * non-zero n_value -- change n_type to N_COMM for all such
715
	 * symbols to make life easier later.
716
	 *
717
	 * filter out all entries which we don't want to print anyway
718
	 */
719
1277930
	for (np = names, i = nnames = 0; i < nrawnames; np++, i++) {
720
		/*
721
		 * make n_un.n_name a character pointer by adding the string
722
		 * table's base to n_un.n_strx
723
		 *
724
		 * don't mess with zero offsets
725
		 */
726
624819
		if (np->nl.n_un.n_strx)
727
624819
			np->nl.n_un.n_name = stab + np->nl.n_un.n_strx;
728
		else
729
			np->nl.n_un.n_name = "";
730

1233725
		if (print_only_external_symbols && !IS_EXTERNAL(np->nl.n_type))
731
			continue;
732

298347
		if (print_only_undefined_symbols &&
733
		    SYMBOL_TYPE(np->nl.n_type) != N_UNDF)
734
			continue;
735
736
298347
		snames[nnames++] = np;
737
298347
	}
738
739
	/* sort the symbol table if applicable */
740
14146
	if (sfunc)
741
14146
		qsort(snames, (size_t)nnames, sizeof(*snames), sfunc);
742
743
14146
	if (count > 1)
744
14141
		(void)printf("\n%s:\n", name);
745
746
	/* print out symbols */
747
624986
	for (i = 0; i < nnames; i++)
748
298347
		print_symbol(name, snames[i]);
749
750
14146
	free(snames);
751
14146
	free(names);
752
42438
	MUNMAP(stab, stabsize);
753
14146
	return(0);
754
14146
}
755
756
char *
757
symname(struct xnlist *sym)
758
{
759
596694
	return sym->nl.n_un.n_name;
760
}
761
762
/*
763
 * print_symbol()
764
 *	show one symbol
765
 */
766
void
767
print_symbol(const char *name, struct xnlist *sym)
768
{
769
596694
	if (print_file_each_line) {
770
298217
		if (posix_output)
771
			(void)printf("%s: ", name);
772
		else
773
298217
			(void)printf("%s:", name);
774
	}
775
776
298347
	if (posix_output) {
777
		(void)printf("%s %c ", symname(sym), typeletter(sym));
778
		if (SYMBOL_TYPE(sym->nl.n_type) != N_UNDF)
779
			(void)printf(posix_fmtstr, sym->nl.n_value,
780
			    sym->n_size);
781
		(void)printf("\n");
782
	} else {
783
		/*
784
		 * handle undefined-only format especially (no space is
785
		 * left for symbol values, no type field is printed)
786
		 */
787
298347
		if (!print_only_undefined_symbols) {
788
			/* print symbol's value */
789
298347
			if (SYMBOL_TYPE(sym->nl.n_type) == N_UNDF)
790
198536
				(void)printf("        ");
791
			else
792
99811
				(void)printf("%08lx", sym->nl.n_value);
793
794
			/* print type information */
795
596694
			if (show_extensions)
796
298347
				(void)printf(" %c   ", typeletter(sym));
797
			else
798
298347
				(void)printf(" %c ", typeletter(sym));
799
		}
800
801
298347
		(void)puts(symname(sym));
802
	}
803
298347
}
804
805
/*
806
 * typeletter()
807
 *	return a description letter for the given basic type code of an
808
 *	symbol table entry.  The return value will be upper case for
809
 *	external, lower case for internal symbols.
810
 */
811
char
812
typeletter(struct xnlist *np)
813
{
814
596694
	int ext = IS_EXTERNAL(np->nl.n_type);
815
816
298347
	if (np->nl.n_other)
817
15083
		return np->nl.n_other;
818
819


283264
	switch(SYMBOL_TYPE(np->nl.n_type)) {
820
	case N_ABS:
821
		return(ext? 'A' : 'a');
822
	case N_BSS:
823
2989
		return(ext? 'B' : 'b');
824
	case N_COMM:
825
1400
		return(ext? 'C' : 'c');
826
	case N_DATA:
827
7707
		return(ext? 'D' : 'd');
828
	case N_FN:
829
		/* NOTE: N_FN == N_WARNING,
830
		 * in this case, the N_EXT bit is to considered as
831
		 * part of the symbol's type itself.
832
		 */
833
13567
		return(ext? 'F' : 'W');
834
	case N_TEXT:
835
59077
		return(ext? 'T' : 't');
836
	case N_SIZE:
837
		return(ext? 'S' : 's');
838
	case N_UNDF:
839
198524
		return(ext? 'U' : 'u');
840
	}
841
	return('?');
842
298347
}
843
844
int
845
fname(const void *a0, const void *b0)
846
{
847
2793912
	struct xnlist * const *a = a0, * const *b = b0;
848
849
1396956
	return(strcmp((*a)->nl.n_un.n_name, (*b)->nl.n_un.n_name));
850
}
851
852
int
853
rname(const void *a0, const void *b0)
854
{
855
	struct xnlist * const *a = a0, * const *b = b0;
856
857
	return(strcmp((*b)->nl.n_un.n_name, (*a)->nl.n_un.n_name));
858
}
859
860
int
861
value(const void *a0, const void *b0)
862
{
863
	struct xnlist * const *a = a0, * const *b = b0;
864
865
	if (SYMBOL_TYPE((*a)->nl.n_type) == N_UNDF)
866
		if (SYMBOL_TYPE((*b)->nl.n_type) == N_UNDF)
867
			return(0);
868
		else
869
			return(-1);
870
	else if (SYMBOL_TYPE((*b)->nl.n_type) == N_UNDF)
871
		return(1);
872
	if (rev) {
873
		if ((*a)->nl.n_value == (*b)->nl.n_value)
874
			return(rname(a0, b0));
875
		return((*b)->nl.n_value > (*a)->nl.n_value ? 1 : -1);
876
	} else {
877
		if ((*a)->nl.n_value == (*b)->nl.n_value)
878
			return(fname(a0, b0));
879
		return((*a)->nl.n_value > (*b)->nl.n_value ? 1 : -1);
880
	}
881
}
882
883
#define CPPFILT	"/usr/bin/c++filt"
884
885
void
886
pipe2cppfilt(void)
887
{
888
10
	int pip[2];
889
5
	char *argv[2];
890
891
5
	argv[0] = "c++filt";
892
5
	argv[1] = NULL;
893
894
5
	if (pipe(pip) == -1)
895
		err(1, "pipe");
896
5
	switch(fork()) {
897
	case -1:
898
		err(1, "fork");
899
	default:
900
		dup2(pip[0], 0);
901
		close(pip[0]);
902
		close(pip[1]);
903
		execve(CPPFILT, argv, NULL);
904
		err(1, "execve");
905
	case 0:
906
5
		dup2(pip[1], 1);
907
5
		close(pip[1]);
908
5
		close(pip[0]);
909
	}
910
5
}
911
912
void
913
usage(void)
914
{
915
	extern char *__progname;
916
917
	if (issize)
918
		fprintf(stderr, "usage: %s [-tw] [file ...]\n", __progname);
919
	else
920
		fprintf(stderr, "usage: %s [-AaCDegnoPprsuw] [-t d|o|x] [file ...]\n",
921
		    __progname);
922
	exit(1);
923
}