1 /* $OpenBSD: nm.c,v 1.56 2024/05/21 05:00:48 jsg 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.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 int (*sfunc)(const void *, const void *) = fname;
88 char typeletter(struct xnlist *);
89 int mmbr_name(struct ar_hdr *, char **, int, int *, FILE *);
90 int show_symtab(off_t, u_long, const char *, FILE *);
91 int show_symdef(off_t, u_long, const char *, FILE *);
92
93 /* some macros for symbol type (nlist.n_type) handling */
94 #define IS_EXTERNAL(x) ((x) & N_EXT)
95 #define SYMBOL_TYPE(x) ((x) & (N_TYPE | N_STAB))
96
97 void pipe2cppfilt(void);
98 void usage(void);
99 char *symname(struct xnlist *);
100 int process_file(int, const char *);
101 int show_archive(int, const char *, FILE *);
102 int show_file(int, int, const char *, FILE *fp, off_t, union hdr *);
103 void print_symbol(const char *, struct xnlist *);
104
105 #define OPTSTRING_NM "aABCDegnopPrst:uvw"
106 const struct option longopts_nm[] = {
107 { "debug-syms", no_argument, 0, 'a' },
108 { "demangle", no_argument, 0, 'C' },
109 { "dynamic", no_argument, 0, 'D' },
110 { "extern-only", no_argument, 0, 'g' },
111 /* { "line-numbers", no_argument, 0, 'l' }, */
112 { "no-sort", no_argument, 0, 'p' },
113 { "numeric-sort", no_argument, 0, 'n' },
114 { "print-armap", no_argument, 0, 's' },
115 { "print-file-name", no_argument, 0, 'o' },
116 { "reverse-sort", no_argument, 0, 'r' },
117 /* { "size-sort", no_argument, &szval, 1 }, */
118 { "undefined-only", no_argument, 0, 'u' },
119 { "help", no_argument, 0, '?' },
120 { NULL }
121 };
122
123 /*
124 * main()
125 * parse command line, execute process_file() for each file
126 * specified on the command line.
127 */
128 int
main(int argc,char * argv[])129 main(int argc, char *argv[])
130 {
131 extern char *__progname;
132 extern int optind;
133 const char *optstr;
134 const struct option *lopts;
135 int ch, eval;
136
137 if (pledge("stdio rpath proc exec", NULL) == -1)
138 err(1, "pledge");
139
140 optstr = OPTSTRING_NM;
141 lopts = longopts_nm;
142 if (!strcmp(__progname, "size")) {
143 if (pledge("stdio rpath", NULL) == -1)
144 err(1, "pledge");
145
146 issize = 1;
147 optstr = "tw";
148 lopts = NULL;
149 }
150
151 while ((ch = getopt_long(argc, argv, optstr, lopts, NULL)) != -1) {
152 switch (ch) {
153 case 'a':
154 print_all_symbols = 1;
155 break;
156 case 'B':
157 /* no-op, compat with gnu-nm */
158 break;
159 case 'C':
160 demangle = 1;
161 break;
162 case 'D':
163 dynamic_only = 1;
164 break;
165 case 'e':
166 show_extensions = 1;
167 break;
168 case 'g':
169 print_only_external_symbols = 1;
170 break;
171 case 'n':
172 case 'v':
173 sfunc = value;
174 break;
175 case 'A':
176 case 'o':
177 print_file_each_line = 1;
178 break;
179 case 'p':
180 sfunc = NULL;
181 break;
182 case 'P':
183 posix_output = 1;
184 break;
185 case 'r':
186 rev = 1;
187 break;
188 case 's':
189 armap = 1;
190 break;
191 case 'u':
192 print_only_undefined_symbols = 1;
193 break;
194 case 'w':
195 non_object_warning = 1;
196 break;
197 case 't':
198 if (issize) {
199 print_totals = 1;
200 } else {
201 posix_radix = *optarg;
202 if (strlen(optarg) != 1 ||
203 (posix_radix != 'd' && posix_radix != 'o' &&
204 posix_radix != 'x'))
205 usage();
206 }
207 break;
208 default:
209 usage();
210 }
211 }
212
213 if (posix_output)
214 (void)snprintf(posix_fmtstr, sizeof posix_fmtstr, "%%%c %%%c",
215 posix_radix, posix_radix);
216 if (demangle)
217 pipe2cppfilt();
218
219 if (pledge("stdio rpath", NULL) == -1)
220 err(1, "pledge");
221
222 argv += optind;
223 argc -= optind;
224
225 if (rev && sfunc == fname)
226 sfunc = rname;
227
228 eval = 0;
229 if (*argv)
230 do {
231 eval |= process_file(argc, *argv);
232 } while (*++argv);
233 else
234 eval |= process_file(1, "a.out");
235
236 if (issize && print_totals)
237 printf("\n%lu\t%lu\t%lu\t%lu\t%lx\tTOTAL\n",
238 total_text, total_data, total_bss,
239 total_total, total_total);
240 exit(eval);
241 }
242
243 /*
244 * process_file()
245 * show symbols in the file given as an argument. Accepts archive and
246 * object files as input.
247 */
248 int
process_file(int count,const char * fname)249 process_file(int count, const char *fname)
250 {
251 union hdr exec_head;
252 FILE *fp;
253 int retval;
254 size_t bytes;
255 char magic[SARMAG];
256
257 if (!(fp = fopen(fname, "r"))) {
258 warn("cannot read %s", fname);
259 return(1);
260 }
261
262 if (!issize && count > 1)
263 (void)printf("\n%s:\n", fname);
264
265 /*
266 * first check whether this is an object file - read a object
267 * header, and skip back to the beginning
268 */
269 bzero(&exec_head, sizeof(exec_head));
270 bytes = fread((char *)&exec_head, 1, sizeof(exec_head), fp);
271 if (bytes < sizeof(exec_head)) {
272 if (bytes < sizeof(exec_head.elf32) || IS_ELF(exec_head.elf32)) {
273 warnx("%s: bad format", fname);
274 (void)fclose(fp);
275 return(1);
276 }
277 }
278 rewind(fp);
279
280 /* this could be an archive */
281 if (!IS_ELF(exec_head.elf32)) {
282 if (fread(magic, sizeof(magic), (size_t)1, fp) != 1 ||
283 strncmp(magic, ARMAG, SARMAG)) {
284 warnx("%s: not object file or archive", fname);
285 (void)fclose(fp);
286 return(1);
287 }
288 retval = show_archive(count, fname, fp);
289 } else
290 retval = show_file(count, 1, fname, fp, 0, &exec_head);
291 (void)fclose(fp);
292 return(retval);
293 }
294
295 char *nametab;
296
297 /*
298 *
299 * given the archive member header -- produce member name
300 */
301 int
mmbr_name(struct ar_hdr * arh,char ** name,int baselen,int * namelen,FILE * fp)302 mmbr_name(struct ar_hdr *arh, char **name, int baselen, int *namelen, FILE *fp)
303 {
304 char *p = *name + strlen(*name);
305 long i;
306
307 if (nametab && arh->ar_name[0] == '/') {
308 int len;
309
310 i = atol(&arh->ar_name[1]);
311 len = strlen(&nametab[i]) + 1;
312 if (len > *namelen) {
313 p -= (long)*name;
314 if ((*name = realloc(*name, baselen+len)) == NULL)
315 err(1, NULL);
316 *namelen = len;
317 p += (long)*name;
318 }
319 strlcpy(p, &nametab[i], len);
320 p += len - 1;
321 } else
322 #ifdef AR_EFMT1
323 /*
324 * BSD 4.4 extended AR format: #1/<namelen>, with name as the
325 * first <namelen> bytes of the file
326 */
327 if ((arh->ar_name[0] == '#') &&
328 (arh->ar_name[1] == '1') &&
329 (arh->ar_name[2] == '/') &&
330 (isdigit((unsigned char)arh->ar_name[3]))) {
331 int len = atoi(&arh->ar_name[3]);
332
333 if (len > *namelen) {
334 p -= (long)*name;
335 if ((*name = realloc(*name, baselen+len)) == NULL)
336 err(1, NULL);
337 *namelen = len;
338 p += (long)*name;
339 }
340 if (fread(p, len, 1, fp) != 1) {
341 warnx("%s: premature EOF", *name);
342 free(*name);
343 return(1);
344 }
345 p += len;
346 } else
347 #endif
348 for (i = 0; i < sizeof(arh->ar_name); ++i)
349 if (arh->ar_name[i] && arh->ar_name[i] != ' ')
350 *p++ = arh->ar_name[i];
351 *p = '\0';
352 if (p[-1] == '/')
353 *--p = '\0';
354
355 return (0);
356 }
357
358 /*
359 * show_symtab()
360 * show archive ranlib index (fs5)
361 */
362 int
show_symtab(off_t off,u_long len,const char * name,FILE * fp)363 show_symtab(off_t off, u_long len, const char *name, FILE *fp)
364 {
365 struct ar_hdr ar_head;
366 int *symtab, *ps;
367 char *strtab, *p;
368 int num, rval = 0;
369 int namelen;
370 off_t restore;
371
372 restore = ftello(fp);
373
374 MMAP(symtab, len, PROT_READ, MAP_PRIVATE|MAP_FILE, fileno(fp), off);
375 if (symtab == MAP_FAILED)
376 return (1);
377
378 namelen = sizeof(ar_head.ar_name);
379 if ((p = malloc(sizeof(ar_head.ar_name))) == NULL) {
380 warn("%s: malloc", name);
381 MUNMAP(symtab, len);
382 return (1);
383 }
384
385 printf("\nArchive index:\n");
386 num = betoh32(*symtab);
387 strtab = (char *)(symtab + num + 1);
388 for (ps = symtab + 1; num--; ps++, strtab += strlen(strtab) + 1) {
389 if (fseeko(fp, betoh32(*ps), SEEK_SET)) {
390 warn("%s: fseeko", name);
391 rval = 1;
392 break;
393 }
394
395 if (fread(&ar_head, sizeof(ar_head), 1, fp) != 1 ||
396 memcmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) {
397 warnx("%s: member fseeko", name);
398 rval = 1;
399 break;
400 }
401
402 *p = '\0';
403 if (mmbr_name(&ar_head, &p, 0, &namelen, fp)) {
404 rval = 1;
405 break;
406 }
407
408 printf("%s in %s\n", strtab, p);
409 }
410
411 fseeko(fp, restore, SEEK_SET);
412
413 free(p);
414 MUNMAP(symtab, len);
415 return (rval);
416 }
417
418 /*
419 * show_symdef()
420 * show archive ranlib index (gob)
421 */
422 int
show_symdef(off_t off,u_long len,const char * name,FILE * fp)423 show_symdef(off_t off, u_long len, const char *name, FILE *fp)
424 {
425 struct ranlib *prn, *eprn;
426 struct ar_hdr ar_head;
427 char *symdef;
428 char *strtab, *p;
429 u_long size;
430 int namelen, rval = 0;
431
432 MMAP(symdef, len, PROT_READ, MAP_PRIVATE|MAP_FILE, fileno(fp), off);
433 if (symdef == MAP_FAILED)
434 return (1);
435 if (usemmap)
436 (void)madvise(symdef, len, MADV_SEQUENTIAL);
437
438 namelen = sizeof(ar_head.ar_name);
439 if ((p = malloc(sizeof(ar_head.ar_name))) == NULL) {
440 warn("%s: malloc", name);
441 MUNMAP(symdef, len);
442 return (1);
443 }
444
445 size = *(u_long *)symdef;
446 prn = (struct ranlib *)(symdef + sizeof(u_long));
447 eprn = prn + size / sizeof(*prn);
448 strtab = symdef + sizeof(u_long) + size + sizeof(u_long);
449
450 printf("\nArchive index:\n");
451 for (; prn < eprn; prn++) {
452 if (fseeko(fp, prn->ran_off, SEEK_SET)) {
453 warn("%s: fseeko", name);
454 rval = 1;
455 break;
456 }
457
458 if (fread(&ar_head, sizeof(ar_head), 1, fp) != 1 ||
459 memcmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) {
460 warnx("%s: member fseeko", name);
461 rval = 1;
462 break;
463 }
464
465 *p = '\0';
466 if (mmbr_name(&ar_head, &p, 0, &namelen, fp)) {
467 rval = 1;
468 break;
469 }
470
471 printf("%s in %s\n", strtab + prn->ran_un.ran_strx, p);
472 }
473
474 free(p);
475 MUNMAP(symdef, len);
476 return (rval);
477 }
478
479 /*
480 * show_archive()
481 * show symbols in the given archive file
482 */
483 int
show_archive(int count,const char * fname,FILE * fp)484 show_archive(int count, const char *fname, FILE *fp)
485 {
486 struct ar_hdr ar_head;
487 union hdr exec_head;
488 int i, rval;
489 off_t last_ar_off, foff, symtaboff;
490 char *name;
491 int baselen, namelen;
492 u_long mmbrlen, symtablen;
493
494 baselen = strlen(fname) + 3;
495 if (posix_output)
496 baselen += 2;
497 namelen = sizeof(ar_head.ar_name);
498 if ((name = malloc(baselen + namelen)) == NULL)
499 err(1, NULL);
500
501 rval = 0;
502 nametab = NULL;
503 symtaboff = 0;
504 symtablen = 0;
505
506 /* while there are more entries in the archive */
507 while (fread(&ar_head, sizeof(ar_head), 1, fp) == 1) {
508 /* bad archive entry - stop processing this archive */
509 if (memcmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) {
510 warnx("%s: bad format archive header", fname);
511 rval = 1;
512 break;
513 }
514
515 /* remember start position of current archive object */
516 last_ar_off = ftello(fp);
517 mmbrlen = atol(ar_head.ar_size);
518
519 if (strncmp(ar_head.ar_name, RANLIBMAG,
520 sizeof(RANLIBMAG) - 1) == 0) {
521 if (!issize && armap &&
522 show_symdef(last_ar_off, mmbrlen, fname, fp)) {
523 rval = 1;
524 break;
525 }
526 goto skip;
527 } else if (strncmp(ar_head.ar_name, SYMTABMAG,
528 sizeof(SYMTABMAG) - 1) == 0) {
529 /* if nametab hasn't been seen yet -- doit later */
530 if (!nametab) {
531 symtablen = mmbrlen;
532 symtaboff = last_ar_off;
533 goto skip;
534 }
535
536 /* load the Sys5 long names table */
537 } else if (strncmp(ar_head.ar_name, STRTABMAG,
538 sizeof(STRTABMAG) - 1) == 0) {
539 char *p;
540
541 if ((nametab = malloc(mmbrlen)) == NULL) {
542 warn("%s: nametab", fname);
543 rval = 1;
544 break;
545 }
546
547 if (fread(nametab, mmbrlen, (size_t)1, fp) != 1) {
548 warnx("%s: premature EOF", fname);
549 rval = 1;
550 break;
551 }
552
553 for (p = nametab, i = mmbrlen; i--; p++)
554 if (*p == '\n')
555 *p = '\0';
556
557 if (issize || !armap || !symtablen || !symtaboff)
558 goto skip;
559 }
560 #ifdef __mips64
561 else if (memcmp(ar_head.ar_name, SYM64MAG,
562 sizeof(ar_head.ar_name)) == 0) {
563 /* IRIX6-compatible archive map */
564 goto skip;
565 }
566 #endif
567
568 if (!issize && armap && symtablen && symtaboff) {
569 if (show_symtab(symtaboff, symtablen, fname, fp)) {
570 rval = 1;
571 break;
572 } else {
573 symtaboff = 0;
574 symtablen = 0;
575 }
576 }
577
578 /*
579 * construct a name of the form "archive.a:obj.o:" for the
580 * current archive entry if the object name is to be printed
581 * on each output line
582 */
583 *name = '\0';
584 if (posix_output)
585 snprintf(name, baselen - 1, "%s[", fname);
586 else if (count > 1)
587 snprintf(name, baselen - 1, "%s:", fname);
588
589 if (mmbr_name(&ar_head, &name, baselen, &namelen, fp)) {
590 rval = 1;
591 break;
592 }
593
594 if (posix_output)
595 strlcat(name, "]", baselen + namelen);
596
597 foff = ftello(fp);
598
599 /* get and check current object's header */
600 if (fread((char *)&exec_head, sizeof(exec_head),
601 (size_t)1, fp) != 1) {
602 warnx("%s: premature EOF", fname);
603 rval = 1;
604 break;
605 }
606
607 rval |= show_file(2, non_object_warning, name, fp, foff, &exec_head);
608 /*
609 * skip to next archive object - it starts at the next
610 * even byte boundary
611 */
612 #define even(x) (((x) + 1) & ~1)
613 skip: if (fseeko(fp, last_ar_off + even(mmbrlen), SEEK_SET)) {
614 warn("%s", fname);
615 rval = 1;
616 break;
617 }
618 }
619 free(nametab);
620 nametab = NULL;
621 free(name);
622 return(rval);
623 }
624
625 char *stab;
626
627 /*
628 * show_file()
629 * show symbols from the object file pointed to by fp. The current
630 * file pointer for fp is expected to be at the beginning of an object
631 * file header.
632 */
633 int
show_file(int count,int warn_fmt,const char * name,FILE * fp,off_t foff,union hdr * head)634 show_file(int count, int warn_fmt, const char *name, FILE *fp, off_t foff, union hdr *head)
635 {
636 u_long text, data, bss, total;
637 struct xnlist *np, *names, **snames;
638 int i, nrawnames, nnames;
639 size_t stabsize;
640
641 if (IS_ELF(head->elf32) &&
642 head->elf32.e_ident[EI_CLASS] == ELFCLASS32 &&
643 head->elf32.e_ident[EI_VERSION] == ELF_TARG_VER) {
644 void *shdr;
645
646 if (!(shdr = elf32_load_shdrs(name, fp, foff, &head->elf32)))
647 return (1);
648
649 i = issize?
650 elf32_size(&head->elf32, shdr, &text, &data, &bss) :
651 elf32_symload(name, fp, foff, &head->elf32, shdr,
652 &names, &snames, &stabsize, &nrawnames);
653 free(shdr);
654 if (i)
655 return (i);
656
657 } else if (IS_ELF(head->elf64) &&
658 head->elf64.e_ident[EI_CLASS] == ELFCLASS64 &&
659 head->elf64.e_ident[EI_VERSION] == ELF_TARG_VER) {
660 void *shdr;
661
662 if (!(shdr = elf64_load_shdrs(name, fp, foff, &head->elf64)))
663 return (1);
664
665 i = issize?
666 elf64_size(&head->elf64, shdr, &text, &data, &bss) :
667 elf64_symload(name, fp, foff, &head->elf64, shdr,
668 &names, &snames, &stabsize, &nrawnames);
669 free(shdr);
670 if (i)
671 return (i);
672 } else {
673 if (warn_fmt)
674 warnx("%s: bad format", name);
675 return (1);
676 }
677
678 if (issize) {
679 static int first = 1;
680
681 if (first) {
682 first = 0;
683 printf("text\tdata\tbss\tdec\thex\n");
684 }
685
686 total = text + data + bss;
687 printf("%lu\t%lu\t%lu\t%lu\t%lx",
688 text, data, bss, total, total);
689 if (count > 1)
690 (void)printf("\t%s", name);
691
692 total_text += text;
693 total_data += data;
694 total_bss += bss;
695 total_total += total;
696
697 printf("\n");
698 return (0);
699 }
700 /* else we are nm */
701
702 /*
703 * it seems that string table is sequential
704 * relative to the symbol table order
705 */
706 if (sfunc == NULL && usemmap)
707 (void)madvise(stab, stabsize, MADV_SEQUENTIAL);
708
709 /*
710 * fix up the symbol table and filter out unwanted entries
711 *
712 * common symbols are characterized by a n_type of N_UNDF and a
713 * non-zero n_value -- change n_type to N_COMM for all such
714 * symbols to make life easier later.
715 *
716 * filter out all entries which we don't want to print anyway
717 */
718 for (np = names, i = nnames = 0; i < nrawnames; np++, i++) {
719 /*
720 * make n_un.n_name a character pointer by adding the string
721 * table's base to n_un.n_strx
722 *
723 * don't mess with zero offsets
724 */
725 if (np->nl.n_un.n_strx)
726 np->nl.n_un.n_name = stab + np->nl.n_un.n_strx;
727 else
728 np->nl.n_un.n_name = "";
729 if (print_only_external_symbols && !IS_EXTERNAL(np->nl.n_type))
730 continue;
731 if (print_only_undefined_symbols &&
732 SYMBOL_TYPE(np->nl.n_type) != N_UNDF)
733 continue;
734
735 snames[nnames++] = np;
736 }
737
738 /* sort the symbol table if applicable */
739 if (sfunc)
740 qsort(snames, (size_t)nnames, sizeof(*snames), sfunc);
741
742 if (count > 1)
743 (void)printf("\n%s:\n", name);
744
745 /* print out symbols */
746 for (i = 0; i < nnames; i++)
747 print_symbol(name, snames[i]);
748
749 free(snames);
750 free(names);
751 MUNMAP(stab, stabsize);
752 return(0);
753 }
754
755 char *
symname(struct xnlist * sym)756 symname(struct xnlist *sym)
757 {
758 return sym->nl.n_un.n_name;
759 }
760
761 /*
762 * print_symbol()
763 * show one symbol
764 */
765 void
print_symbol(const char * name,struct xnlist * sym)766 print_symbol(const char *name, struct xnlist *sym)
767 {
768 if (print_file_each_line) {
769 if (posix_output)
770 (void)printf("%s: ", name);
771 else
772 (void)printf("%s:", name);
773 }
774
775 if (posix_output) {
776 (void)printf("%s %c ", symname(sym), typeletter(sym));
777 if (SYMBOL_TYPE(sym->nl.n_type) != N_UNDF)
778 (void)printf(posix_fmtstr, sym->nl.n_value,
779 sym->n_size);
780 (void)printf("\n");
781 } else {
782 /*
783 * handle undefined-only format especially (no space is
784 * left for symbol values, no type field is printed)
785 */
786 if (!print_only_undefined_symbols) {
787 /* print symbol's value */
788 if (SYMBOL_TYPE(sym->nl.n_type) == N_UNDF)
789 (void)printf(" ");
790 else
791 (void)printf("%08lx", sym->nl.n_value);
792
793 /* print type information */
794 if (show_extensions)
795 (void)printf(" %c ", typeletter(sym));
796 else
797 (void)printf(" %c ", typeletter(sym));
798 }
799
800 (void)puts(symname(sym));
801 }
802 }
803
804 /*
805 * typeletter()
806 * return a description letter for the given basic type code of an
807 * symbol table entry. The return value will be upper case for
808 * external, lower case for internal symbols.
809 */
810 char
typeletter(struct xnlist * np)811 typeletter(struct xnlist *np)
812 {
813 int ext = IS_EXTERNAL(np->nl.n_type);
814
815 if (np->nl.n_other)
816 return np->nl.n_other;
817
818 switch(SYMBOL_TYPE(np->nl.n_type)) {
819 case N_ABS:
820 return(ext? 'A' : 'a');
821 case N_BSS:
822 return(ext? 'B' : 'b');
823 case N_COMM:
824 return(ext? 'C' : 'c');
825 case N_DATA:
826 return(ext? 'D' : 'd');
827 case N_FN:
828 /* NOTE: N_FN == N_WARNING,
829 * in this case, the N_EXT bit is to considered as
830 * part of the symbol's type itself.
831 */
832 return(ext? 'F' : 'W');
833 case N_TEXT:
834 return(ext? 'T' : 't');
835 case N_SIZE:
836 return(ext? 'S' : 's');
837 case N_UNDF:
838 return(ext? 'U' : 'u');
839 }
840 return('?');
841 }
842
843 int
fname(const void * a0,const void * b0)844 fname(const void *a0, const void *b0)
845 {
846 struct xnlist * const *a = a0, * const *b = b0;
847
848 return(strcmp((*a)->nl.n_un.n_name, (*b)->nl.n_un.n_name));
849 }
850
851 int
rname(const void * a0,const void * b0)852 rname(const void *a0, const void *b0)
853 {
854 struct xnlist * const *a = a0, * const *b = b0;
855
856 return(strcmp((*b)->nl.n_un.n_name, (*a)->nl.n_un.n_name));
857 }
858
859 int
value(const void * a0,const void * b0)860 value(const void *a0, const void *b0)
861 {
862 struct xnlist * const *a = a0, * const *b = b0;
863
864 if (SYMBOL_TYPE((*a)->nl.n_type) == N_UNDF)
865 if (SYMBOL_TYPE((*b)->nl.n_type) == N_UNDF)
866 return(0);
867 else
868 return(-1);
869 else if (SYMBOL_TYPE((*b)->nl.n_type) == N_UNDF)
870 return(1);
871 if (rev) {
872 if ((*a)->nl.n_value == (*b)->nl.n_value)
873 return(rname(a0, b0));
874 return((*b)->nl.n_value > (*a)->nl.n_value ? 1 : -1);
875 } else {
876 if ((*a)->nl.n_value == (*b)->nl.n_value)
877 return(fname(a0, b0));
878 return((*a)->nl.n_value > (*b)->nl.n_value ? 1 : -1);
879 }
880 }
881
882 #define CPPFILT "/usr/bin/c++filt"
883
884 void
pipe2cppfilt(void)885 pipe2cppfilt(void)
886 {
887 int pip[2];
888 char *argv[2];
889
890 argv[0] = "c++filt";
891 argv[1] = NULL;
892
893 if (pipe(pip) == -1)
894 err(1, "pipe");
895 switch(fork()) {
896 case -1:
897 err(1, "fork");
898 default:
899 dup2(pip[0], 0);
900 close(pip[0]);
901 close(pip[1]);
902 execve(CPPFILT, argv, NULL);
903 err(1, "execve");
904 case 0:
905 dup2(pip[1], 1);
906 close(pip[1]);
907 close(pip[0]);
908 }
909 }
910
911 void
usage(void)912 usage(void)
913 {
914 extern char *__progname;
915
916 if (issize)
917 fprintf(stderr, "usage: %s [-tw] [file ...]\n", __progname);
918 else
919 fprintf(stderr, "usage: %s [-AaCDegnoPprsuw] [-t d|o|x] [file ...]\n",
920 __progname);
921 exit(1);
922 }
923