blob: 969c6d355524601aaade24857f66129cbf1dea07 [file] [log] [blame]
Brian Silverman86497922018-02-10 19:28:39 -05001/* Print symbol information from ELF file in human-readable form.
2 Copyright (C) 2000-2008, 2009, 2011, 2012, 2014, 2015 Red Hat, Inc.
3 This file is part of elfutils.
4 Written by Ulrich Drepper <drepper@redhat.com>, 2000.
5
6 This file is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 elfutils is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18
19#ifdef HAVE_CONFIG_H
20# include <config.h>
21#endif
22
23#include <ar.h>
24#include <argp.h>
25#include <assert.h>
26#include <ctype.h>
27#include <dwarf.h>
28#include <errno.h>
29#include <error.h>
30#include <fcntl.h>
31#include <gelf.h>
32#include <inttypes.h>
33#include <libdw.h>
34#include <libintl.h>
35#include <locale.h>
36#include <obstack.h>
37#include <search.h>
38#include <stdbool.h>
39#include <stdio.h>
40#include <stdio_ext.h>
41#include <stdlib.h>
42#include <string.h>
43#include <unistd.h>
44
45#include <libeu.h>
46#include <system.h>
47#include <color.h>
48#include <printversion.h>
49#include "../libebl/libeblP.h"
50#include "../libdwfl/libdwflP.h"
51
52
53/* Name and version of program. */
54ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
55
56/* Bug report address. */
57ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
58
59
60/* Values for the parameters which have no short form. */
61#define OPT_DEFINED 0x100
62#define OPT_MARK_SPECIAL 0x101
63
64/* Definitions of arguments for argp functions. */
65static const struct argp_option options[] =
66{
67 { NULL, 0, NULL, 0, N_("Output selection:"), 0 },
68 { "debug-syms", 'a', NULL, 0, N_("Display debugger-only symbols"), 0 },
69 { "defined-only", OPT_DEFINED, NULL, 0, N_("Display only defined symbols"),
70 0 },
71 { "dynamic", 'D', NULL, 0,
72 N_("Display dynamic symbols instead of normal symbols"), 0 },
73 { "extern-only", 'g', NULL, 0, N_("Display only external symbols"), 0 },
74 { "undefined-only", 'u', NULL, 0, N_("Display only undefined symbols"), 0 },
75 { "print-armap", 's', NULL, 0,
76 N_("Include index for symbols from archive members"), 0 },
77
78 { NULL, 0, NULL, 0, N_("Output format:"), 0 },
79 { "print-file-name", 'A', NULL, 0,
80 N_("Print name of the input file before every symbol"), 0 },
81 { NULL, 'o', NULL, OPTION_HIDDEN, "Same as -A", 0 },
82 { "format", 'f', "FORMAT", 0,
83 N_("Use the output format FORMAT. FORMAT can be `bsd', `sysv' or `posix'. The default is `sysv'"),
84 0 },
85 { NULL, 'B', NULL, 0, N_("Same as --format=bsd"), 0 },
86 { "portability", 'P', NULL, 0, N_("Same as --format=posix"), 0 },
87 { "radix", 't', "RADIX", 0, N_("Use RADIX for printing symbol values"), 0 },
88 { "mark-special", OPT_MARK_SPECIAL, NULL, 0, N_("Mark special symbols"), 0 },
89 { "mark-weak", OPT_MARK_SPECIAL, NULL, OPTION_HIDDEN, "", 0 },
90 { "print-size", 'S', NULL, 0, N_("Print size of defined symbols"), 0 },
91
92 { NULL, 0, NULL, 0, N_("Output options:"), 0 },
93 { "numeric-sort", 'n', NULL, 0, N_("Sort symbols numerically by address"),
94 0 },
95 { "no-sort", 'p', NULL, 0, N_("Do not sort the symbols"), 0 },
96 { "reverse-sort", 'r', NULL, 0, N_("Reverse the sense of the sort"), 0 },
97#ifdef USE_DEMANGLE
98 { "demangle", 'C', NULL, 0,
99 N_("Decode low-level symbol names into source code names"), 0 },
100#endif
101 { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 },
102 { NULL, 0, NULL, 0, NULL, 0 }
103};
104
105/* Short description of program. */
106static const char doc[] = N_("List symbols from FILEs (a.out by default).");
107
108/* Strings for arguments in help texts. */
109static const char args_doc[] = N_("[FILE...]");
110
111/* Prototype for option handler. */
112static error_t parse_opt (int key, char *arg, struct argp_state *state);
113
114/* Parser children. */
115static struct argp_child argp_children[] =
116 {
117 { &color_argp, 0, N_("Output formatting"), 2 },
118 { NULL, 0, NULL, 0}
119 };
120
121/* Data structure to communicate with argp functions. */
122static struct argp argp =
123{
124 options, parse_opt, args_doc, doc, argp_children, NULL, NULL
125};
126
127
128/* Print symbols in file named FNAME. */
129static int process_file (const char *fname, bool more_than_one);
130
131/* Handle content of archive. */
132static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
133 const char *suffix);
134
135/* Handle ELF file. */
136static int handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
137 const char *suffix);
138
139
140#define INTERNAL_ERROR(fname) \
141 error (EXIT_FAILURE, 0, gettext ("%s: INTERNAL ERROR %d (%s): %s"), \
142 fname, __LINE__, PACKAGE_VERSION, elf_errmsg (-1))
143
144
145/* Internal representation of symbols. */
146typedef struct GElf_SymX
147{
148 GElf_Sym sym;
149 Elf32_Word xndx;
150 char *where;
151} GElf_SymX;
152
153
154/* User-selectable options. */
155
156/* The selected output format. */
157static enum
158{
159 format_sysv = 0,
160 format_bsd,
161 format_posix
162} format;
163
164/* Print defined, undefined, or both? */
165static bool hide_undefined;
166static bool hide_defined;
167
168/* Print local symbols also? */
169static bool hide_local;
170
171/* Nonzero if full filename should precede every symbol. */
172static bool print_file_name;
173
174/* If true print size of defined symbols in BSD format. */
175static bool print_size;
176
177/* If true print archive index. */
178static bool print_armap;
179
180/* If true reverse sorting. */
181static bool reverse_sort;
182
183#ifdef USE_DEMANGLE
184/* If true demangle symbols. */
185static bool demangle;
186#endif
187
188/* Type of the section we are printing. */
189static GElf_Word symsec_type = SHT_SYMTAB;
190
191/* Sorting selection. */
192static enum
193{
194 sort_name = 0,
195 sort_numeric,
196 sort_nosort
197} sort;
198
199/* Radix for printed numbers. */
200static enum
201{
202 radix_hex = 0,
203 radix_decimal,
204 radix_octal
205} radix;
206
207/* If nonzero mark special symbols:
208 - weak symbols are distinguished from global symbols by adding
209 a `*' after the identifying letter for the symbol class and type.
210 - TLS symbols are distinguished from normal symbols by adding
211 a '@' after the identifying letter for the symbol class and type. */
212static bool mark_special;
213
214
215int
216main (int argc, char *argv[])
217{
218 int remaining;
219 int result = 0;
220
221 /* We use no threads here which can interfere with handling a stream. */
222 (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);
223 (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
224 (void) __fsetlocking (stderr, FSETLOCKING_BYCALLER);
225
226 /* Set locale. */
227 (void) setlocale (LC_ALL, "");
228
229 /* Make sure the message catalog can be found. */
230 (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
231
232 /* Initialize the message catalog. */
233 (void) textdomain (PACKAGE_TARNAME);
234
235 /* Parse and process arguments. */
236 (void) argp_parse (&argp, argc, argv, 0, &remaining, NULL);
237
238 /* Tell the library which version we are expecting. */
239 (void) elf_version (EV_CURRENT);
240
241 if (remaining == argc)
242 /* The user didn't specify a name so we use a.out. */
243 result = process_file ("a.out", false);
244 else
245 {
246 /* Process all the remaining files. */
247 const bool more_than_one = remaining + 1 < argc;
248
249 do
250 result |= process_file (argv[remaining], more_than_one);
251 while (++remaining < argc);
252 }
253
254 return result;
255}
256
257
258/* Handle program arguments. */
259static error_t
260parse_opt (int key, char *arg,
261 struct argp_state *state __attribute__ ((unused)))
262{
263 switch (key)
264 {
265 case 'a':
266 /* XXX */
267 break;
268
269#ifdef USE_DEMANGLE
270 case 'C':
271 demangle = true;
272 break;
273#endif
274
275 case 'f':
276 if (strcmp (arg, "bsd") == 0)
277 format = format_bsd;
278 else if (strcmp (arg, "posix") == 0)
279 format = format_posix;
280 else
281 /* Be bug compatible. The BFD implementation also defaulted to
282 using the SysV format if nothing else matches. */
283 format = format_sysv;
284 break;
285
286 case 'g':
287 hide_local = true;
288 break;
289
290 case 'n':
291 sort = sort_numeric;
292 break;
293
294 case 'p':
295 sort = sort_nosort;
296 break;
297
298 case 't':
299 if (strcmp (arg, "10") == 0 || strcmp (arg, "d") == 0)
300 radix = radix_decimal;
301 else if (strcmp (arg, "8") == 0 || strcmp (arg, "o") == 0)
302 radix = radix_octal;
303 else
304 radix = radix_hex;
305 break;
306
307 case 'u':
308 hide_undefined = false;
309 hide_defined = true;
310 break;
311
312 case 'A':
313 case 'o':
314 print_file_name = true;
315 break;
316
317 case 'B':
318 format = format_bsd;
319 break;
320
321 case 'D':
322 symsec_type = SHT_DYNSYM;
323 break;
324
325 case 'P':
326 format = format_posix;
327 break;
328
329 case OPT_DEFINED:
330 hide_undefined = true;
331 hide_defined = false;
332 break;
333
334 case OPT_MARK_SPECIAL:
335 mark_special = true;
336 break;
337
338 case 'S':
339 print_size = true;
340 break;
341
342 case 's':
343 print_armap = true;
344 break;
345
346 case 'r':
347 reverse_sort = true;
348 break;
349
350 default:
351 return ARGP_ERR_UNKNOWN;
352 }
353 return 0;
354}
355
356
357/* Open the file and determine the type. */
358static int
359process_file (const char *fname, bool more_than_one)
360{
361 /* Open the file. */
362 int fd = open (fname, O_RDONLY);
363 if (fd == -1)
364 {
365 error (0, errno, gettext ("cannot open '%s'"), fname);
366 return 1;
367 }
368
369 /* Now get the ELF descriptor. */
370 Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
371 if (elf != NULL)
372 {
373 if (elf_kind (elf) == ELF_K_ELF)
374 {
375 int result = handle_elf (fd, elf, more_than_one ? "" : NULL,
376 fname, NULL);
377
378 if (elf_end (elf) != 0)
379 INTERNAL_ERROR (fname);
380
381 if (close (fd) != 0)
382 error (EXIT_FAILURE, errno, gettext ("while closing '%s'"), fname);
383
384 return result;
385 }
386 else if (elf_kind (elf) == ELF_K_AR)
387 {
388 int result = handle_ar (fd, elf, NULL, fname, NULL);
389
390 if (elf_end (elf) != 0)
391 INTERNAL_ERROR (fname);
392
393 if (close (fd) != 0)
394 error (EXIT_FAILURE, errno, gettext ("while closing '%s'"), fname);
395
396 return result;
397 }
398
399 /* We cannot handle this type. Close the descriptor anyway. */
400 if (elf_end (elf) != 0)
401 INTERNAL_ERROR (fname);
402 }
403
404 error (0, 0, gettext ("%s: File format not recognized"), fname);
405
406 return 1;
407}
408
409
410static int
411handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
412 const char *suffix)
413{
414 size_t fname_len = strlen (fname) + 1;
415 size_t prefix_len = prefix != NULL ? strlen (prefix) : 0;
416 char new_prefix[prefix_len + fname_len + 2];
417 size_t suffix_len = suffix != NULL ? strlen (suffix) : 0;
418 char new_suffix[suffix_len + 2];
419 Elf *subelf;
420 Elf_Cmd cmd = ELF_C_READ_MMAP;
421 int result = 0;
422
423 char *cp = new_prefix;
424 if (prefix != NULL)
425 cp = stpcpy (cp, prefix);
426 cp = stpcpy (cp, fname);
427 stpcpy (cp, "[");
428
429 cp = new_suffix;
430 if (suffix != NULL)
431 cp = stpcpy (cp, suffix);
432 stpcpy (cp, "]");
433
434 /* First print the archive index if this is wanted. */
435 if (print_armap)
436 {
437 Elf_Arsym *arsym = elf_getarsym (elf, NULL);
438
439 if (arsym != NULL)
440 {
441 Elf_Arhdr *arhdr = NULL;
442 size_t arhdr_off = 0; /* Note: 0 is no valid offset. */
443
444 fputs_unlocked (gettext("\nArchive index:\n"), stdout);
445
446 while (arsym->as_off != 0)
447 {
448 if (arhdr_off != arsym->as_off
449 && (elf_rand (elf, arsym->as_off) != arsym->as_off
450 || (subelf = elf_begin (fd, cmd, elf)) == NULL
451 || (arhdr = elf_getarhdr (subelf)) == NULL))
452 {
453 error (0, 0, gettext ("invalid offset %zu for symbol %s"),
454 arsym->as_off, arsym->as_name);
455 break;
456 }
457
458 printf (gettext ("%s in %s\n"), arsym->as_name, arhdr->ar_name);
459
460 ++arsym;
461 }
462
463 if (elf_rand (elf, SARMAG) != SARMAG)
464 {
465 error (0, 0,
466 gettext ("cannot reset archive offset to beginning"));
467 return 1;
468 }
469 }
470 }
471
472 /* Process all the files contained in the archive. */
473 while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
474 {
475 /* The the header for this element. */
476 Elf_Arhdr *arhdr = elf_getarhdr (subelf);
477
478 /* Skip over the index entries. */
479 if (strcmp (arhdr->ar_name, "/") != 0
480 && strcmp (arhdr->ar_name, "//") != 0
481 && strcmp (arhdr->ar_name, "/SYM64/") != 0)
482 {
483 if (elf_kind (subelf) == ELF_K_ELF)
484 result |= handle_elf (fd, subelf, new_prefix, arhdr->ar_name,
485 new_suffix);
486 else if (elf_kind (subelf) == ELF_K_AR)
487 result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name,
488 new_suffix);
489 else
490 {
491 error (0, 0, gettext ("%s%s%s: file format not recognized"),
492 new_prefix, arhdr->ar_name, new_suffix);
493 result = 1;
494 }
495 }
496
497 /* Get next archive element. */
498 cmd = elf_next (subelf);
499 if (elf_end (subelf) != 0)
500 INTERNAL_ERROR (fname);
501 }
502
503 return result;
504}
505
506
507/* Mapping of radix and binary class to length. */
508static const int length_map[2][3] =
509{
510 [ELFCLASS32 - 1] =
511 {
512 [radix_hex] = 8,
513 [radix_decimal] = 10,
514 [radix_octal] = 11
515 },
516 [ELFCLASS64 - 1] =
517 {
518 [radix_hex] = 16,
519 [radix_decimal] = 20,
520 [radix_octal] = 22
521 }
522};
523
524
525static int
526global_compare (const void *p1, const void *p2)
527{
528 const Dwarf_Global *g1 = (const Dwarf_Global *) p1;
529 const Dwarf_Global *g2 = (const Dwarf_Global *) p2;
530
531 return strcmp (g1->name, g2->name);
532}
533
534
535static void *global_root;
536
537
538static int
539get_global (Dwarf *dbg __attribute__ ((unused)), Dwarf_Global *global,
540 void *arg __attribute__ ((unused)))
541{
542 tsearch (memcpy (xmalloc (sizeof (Dwarf_Global)), global,
543 sizeof (Dwarf_Global)),
544 &global_root, global_compare);
545
546 return DWARF_CB_OK;
547}
548
549
550struct local_name
551{
552 const char *name;
553 const char *file;
554 Dwarf_Word lineno;
555 Dwarf_Addr lowpc;
556 Dwarf_Addr highpc;
557};
558
559
560static int
561local_compare (const void *p1, const void *p2)
562{
563 struct local_name *g1 = (struct local_name *) p1;
564 struct local_name *g2 = (struct local_name *) p2;
565 int result;
566
567 result = strcmp (g1->name, g2->name);
568 if (result == 0)
569 {
570 if (g1->lowpc <= g2->lowpc && g1->highpc >= g2->highpc)
571 {
572 /* g2 is contained in g1. Update the data. */
573 g2->lowpc = g1->lowpc;
574 g2->highpc = g1->highpc;
575 result = 0;
576 }
577 else if (g2->lowpc <= g1->lowpc && g2->highpc >= g1->highpc)
578 {
579 /* g1 is contained in g2. Update the data. */
580 g1->lowpc = g2->lowpc;
581 g1->highpc = g2->highpc;
582 result = 0;
583 }
584 else
585 result = g1->lowpc < g2->lowpc ? -1 : 1;
586 }
587
588 return result;
589}
590
591
592static int
593get_var_range (Dwarf_Die *die, Dwarf_Word *lowpc, Dwarf_Word *highpc)
594{
595 Dwarf_Attribute locattr_mem;
596 Dwarf_Attribute *locattr = dwarf_attr (die, DW_AT_location, &locattr_mem);
597 if (locattr == NULL)
598 return 1;
599
600 Dwarf_Op *loc;
601 size_t nloc;
602 if (dwarf_getlocation (locattr, &loc, &nloc) != 0)
603 return 1;
604
605 /* Interpret the location expressions. */
606 // XXX For now just the simple one:
607 if (nloc == 1 && loc[0].atom == DW_OP_addr)
608 {
609 *lowpc = *highpc = loc[0].number;
610 return 0;
611 }
612
613 return 1;
614}
615
616
617
618static void *local_root;
619
620
621static void
622get_local_names (Dwarf *dbg)
623{
624 Dwarf_Off offset = 0;
625 Dwarf_Off old_offset;
626 size_t hsize;
627
628 while (dwarf_nextcu (dbg, old_offset = offset, &offset, &hsize, NULL, NULL,
629 NULL) == 0)
630 {
631 Dwarf_Die cudie_mem;
632 Dwarf_Die *cudie = dwarf_offdie (dbg, old_offset + hsize, &cudie_mem);
633
634 /* If we cannot get the CU DIE there is no need to go on with
635 this CU. */
636 if (cudie == NULL)
637 continue;
638 /* This better be a CU DIE. */
639 if (dwarf_tag (cudie) != DW_TAG_compile_unit)
640 continue;
641
642 /* Get the line information. */
643 Dwarf_Files *files;
644 size_t nfiles;
645 if (dwarf_getsrcfiles (cudie, &files, &nfiles) != 0)
646 continue;
647
648 Dwarf_Die die_mem;
649 Dwarf_Die *die = &die_mem;
650 if (dwarf_child (cudie, die) == 0)
651 /* Iterate over all immediate children of the CU DIE. */
652 do
653 {
654 int tag = dwarf_tag (die);
655 if (tag != DW_TAG_subprogram && tag != DW_TAG_variable)
656 continue;
657
658 /* We are interested in five attributes: name, decl_file,
659 decl_line, low_pc, and high_pc. */
660 Dwarf_Attribute attr_mem;
661 Dwarf_Attribute *attr = dwarf_attr (die, DW_AT_name, &attr_mem);
662 const char *name = dwarf_formstring (attr);
663 if (name == NULL)
664 continue;
665
666 Dwarf_Word fileidx;
667 attr = dwarf_attr (die, DW_AT_decl_file, &attr_mem);
668 if (dwarf_formudata (attr, &fileidx) != 0 || fileidx >= nfiles)
669 continue;
670
671 Dwarf_Word lineno;
672 attr = dwarf_attr (die, DW_AT_decl_line, &attr_mem);
673 if (dwarf_formudata (attr, &lineno) != 0 || lineno == 0)
674 continue;
675
676 Dwarf_Addr lowpc;
677 Dwarf_Addr highpc;
678 if (tag == DW_TAG_subprogram)
679 {
680 if (dwarf_lowpc (die, &lowpc) != 0
681 || dwarf_highpc (die, &highpc) != 0)
682 continue;
683 }
684 else
685 {
686 if (get_var_range (die, &lowpc, &highpc) != 0)
687 continue;
688 }
689
690 /* We have all the information. Create a record. */
691 struct local_name *newp
692 = (struct local_name *) xmalloc (sizeof (*newp));
693 newp->name = name;
694 newp->file = dwarf_filesrc (files, fileidx, NULL, NULL);
695 newp->lineno = lineno;
696 newp->lowpc = lowpc;
697 newp->highpc = highpc;
698
699 /* Check whether a similar local_name is already in the
700 cache. That should not happen. But if it does, we
701 don't want to leak memory. */
702 struct local_name **tres = tsearch (newp, &local_root,
703 local_compare);
704 if (tres == NULL)
705 error (EXIT_FAILURE, errno,
706 gettext ("cannot create search tree"));
707 else if (*tres != newp)
708 free (newp);
709 }
710 while (dwarf_siblingof (die, die) == 0);
711 }
712}
713
714/* Do elf_strptr, but return a backup string and never NULL. */
715static const char *
716sym_name (Elf *elf, GElf_Word strndx, GElf_Word st_name, char buf[], size_t n)
717{
718 const char *symstr = elf_strptr (elf, strndx, st_name);
719 if (symstr == NULL)
720 {
721 snprintf (buf, n, "[invalid st_name %#" PRIx32 "]", st_name);
722 symstr = buf;
723 }
724 return symstr;
725}
726
727/* Show symbols in SysV format. */
728static void
729show_symbols_sysv (Ebl *ebl, GElf_Word strndx, const char *fullname,
730 GElf_SymX *syms, size_t nsyms, int longest_name,
731 int longest_where)
732{
733 size_t shnum;
734 if (elf_getshdrnum (ebl->elf, &shnum) < 0)
735 INTERNAL_ERROR (fullname);
736
737 bool scnnames_malloced = shnum * sizeof (const char *) > 128 * 1024;
738 const char **scnnames;
739 if (scnnames_malloced)
740 scnnames = (const char **) xmalloc (sizeof (const char *) * shnum);
741 else
742 scnnames = (const char **) alloca (sizeof (const char *) * shnum);
743 /* Get the section header string table index. */
744 size_t shstrndx;
745 if (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0)
746 error (EXIT_FAILURE, 0,
747 gettext ("cannot get section header string table index"));
748
749 /* Cache the section names. */
750 Elf_Scn *scn = NULL;
751 size_t cnt = 1;
752 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
753 {
754 GElf_Shdr shdr_mem;
755
756 assert (elf_ndxscn (scn) == cnt);
757 cnt++;
758
759 char *name = elf_strptr (ebl->elf, shstrndx,
760 gelf_getshdr (scn, &shdr_mem)->sh_name);
761 if (unlikely (name == NULL))
762 {
763 const size_t bufsz = sizeof "[invalid sh_name 0x12345678]";
764 name = alloca (bufsz);
765 snprintf (name, bufsz, "[invalid sh_name %#" PRIx32 "]",
766 gelf_getshdr (scn, &shdr_mem)->sh_name);
767 }
768 scnnames[elf_ndxscn (scn)] = name;
769 }
770
771 int digits = length_map[gelf_getclass (ebl->elf) - 1][radix];
772
773 /* We always print this prolog. */
774 printf (gettext ("\n\nSymbols from %s:\n\n"), fullname);
775
776 /* The header line. */
777 printf (gettext ("%*s%-*s %-*s Class Type %-*s %*s Section\n\n"),
778 print_file_name ? (int) strlen (fullname) + 1: 0, "",
779 longest_name, sgettext ("sysv|Name"),
780 /* TRANS: the "sysv|" parts makes the string unique. */
781 digits, sgettext ("sysv|Value"),
782 /* TRANS: the "sysv|" parts makes the string unique. */
783 digits, sgettext ("sysv|Size"),
784 /* TRANS: the "sysv|" parts makes the string unique. */
785 longest_where, sgettext ("sysv|Line"));
786
787#ifdef USE_DEMANGLE
788 size_t demangle_buffer_len = 0;
789 char *demangle_buffer = NULL;
790#endif
791
792 /* Iterate over all symbols. */
793 for (cnt = 1; cnt < nsyms; ++cnt)
794 {
795 /* In this format SECTION entries are not printed. */
796 if (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_SECTION)
797 continue;
798
799 char symstrbuf[50];
800 const char *symstr = sym_name (ebl->elf, strndx, syms[cnt].sym.st_name,
801 symstrbuf, sizeof symstrbuf);
802
803#ifdef USE_DEMANGLE
804 /* Demangle if necessary. Require GNU v3 ABI by the "_Z" prefix. */
805 if (demangle && symstr[0] == '_' && symstr[1] == 'Z')
806 {
807 int status = -1;
808 char *dmsymstr = __cxa_demangle (symstr, demangle_buffer,
809 &demangle_buffer_len, &status);
810
811 if (status == 0)
812 symstr = dmsymstr;
813 }
814#endif
815
816 char symbindbuf[50];
817 char symtypebuf[50];
818 char secnamebuf[1024];
819 char addressbuf[(64 + 2) / 3 + 1];
820 char sizebuf[(64 + 2) / 3 + 1];
821
822 /* If we have to precede the line with the file name. */
823 if (print_file_name)
824 {
825 fputs_unlocked (fullname, stdout);
826 putchar_unlocked (':');
827 }
828
829 /* Covert the address. */
830 if (syms[cnt].sym.st_shndx == SHN_UNDEF)
831 addressbuf[0] = sizebuf[0] = '\0';
832 else
833 {
834 snprintf (addressbuf, sizeof (addressbuf),
835 (radix == radix_hex ? "%0*" PRIx64
836 : (radix == radix_decimal ? "%0*" PRId64
837 : "%0*" PRIo64)),
838 digits, syms[cnt].sym.st_value);
839 snprintf (sizebuf, sizeof (sizebuf),
840 (radix == radix_hex ? "%0*" PRIx64
841 : (radix == radix_decimal ? "%0*" PRId64
842 : "%0*" PRIo64)),
843 digits, syms[cnt].sym.st_size);
844 }
845
846 /* Print the actual string. */
847 printf ("%-*s|%s|%-6s|%-8s|%s|%*s|%s\n",
848 longest_name, symstr, addressbuf,
849 ebl_symbol_binding_name (ebl,
850 GELF_ST_BIND (syms[cnt].sym.st_info),
851 symbindbuf, sizeof (symbindbuf)),
852 ebl_symbol_type_name (ebl, GELF_ST_TYPE (syms[cnt].sym.st_info),
853 symtypebuf, sizeof (symtypebuf)),
854 sizebuf, longest_where, syms[cnt].where,
855 ebl_section_name (ebl, syms[cnt].sym.st_shndx, syms[cnt].xndx,
856 secnamebuf, sizeof (secnamebuf), scnnames,
857 shnum));
858 }
859
860#ifdef USE_DEMANGLE
861 free (demangle_buffer);
862#endif
863
864 if (scnnames_malloced)
865 free (scnnames);
866}
867
868
869static char
870class_type_char (Elf *elf, const GElf_Ehdr *ehdr, GElf_Sym *sym)
871{
872 int local_p = GELF_ST_BIND (sym->st_info) == STB_LOCAL;
873
874 /* XXX Add support for architecture specific types and classes. */
875 if (sym->st_shndx == SHN_ABS)
876 return local_p ? 'a' : 'A';
877
878 if (sym->st_shndx == SHN_UNDEF)
879 /* Undefined symbols must be global. */
880 return 'U';
881
882 char result = "NDTSFBD "[GELF_ST_TYPE (sym->st_info)];
883
884 if (result == 'D')
885 {
886 /* Special handling: unique data symbols. */
887 if (ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX
888 && GELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE)
889 result = 'u';
890 else
891 {
892 GElf_Shdr shdr_mem;
893 GElf_Shdr *shdr = gelf_getshdr (elf_getscn (elf, sym->st_shndx),
894 &shdr_mem);
895 if (shdr != NULL)
896 {
897 if ((shdr->sh_flags & SHF_WRITE) == 0)
898 result = 'R';
899 else if (shdr->sh_type == SHT_NOBITS)
900 result = 'B';
901 }
902 }
903 }
904
905 return local_p ? tolower (result) : result;
906}
907
908
909static void
910show_symbols_bsd (Elf *elf, const GElf_Ehdr *ehdr, GElf_Word strndx,
911 const char *prefix, const char *fname, const char *fullname,
912 GElf_SymX *syms, size_t nsyms)
913{
914 int digits = length_map[gelf_getclass (elf) - 1][radix];
915
916 if (prefix != NULL && ! print_file_name)
917 printf ("\n%s:\n", fname);
918
919#ifdef USE_DEMANGLE
920 size_t demangle_buffer_len = 0;
921 char *demangle_buffer = NULL;
922#endif
923
924 /* Iterate over all symbols. */
925 for (size_t cnt = 0; cnt < nsyms; ++cnt)
926 {
927 char symstrbuf[50];
928 const char *symstr = sym_name (elf, strndx, syms[cnt].sym.st_name,
929 symstrbuf, sizeof symstrbuf);
930
931 /* Printing entries with a zero-length name makes the output
932 not very well parseable. Since these entries don't carry
933 much information we leave them out. */
934 if (symstr[0] == '\0')
935 continue;
936
937 /* We do not print the entries for files. */
938 if (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_FILE)
939 continue;
940
941#ifdef USE_DEMANGLE
942 /* Demangle if necessary. Require GNU v3 ABI by the "_Z" prefix. */
943 if (demangle && symstr[0] == '_' && symstr[1] == 'Z')
944 {
945 int status = -1;
946 char *dmsymstr = __cxa_demangle (symstr, demangle_buffer,
947 &demangle_buffer_len, &status);
948
949 if (status == 0)
950 symstr = dmsymstr;
951 }
952#endif
953
954 /* If we have to precede the line with the file name. */
955 if (print_file_name)
956 {
957 fputs_unlocked (fullname, stdout);
958 putchar_unlocked (':');
959 }
960
961 bool is_tls = GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_TLS;
962 bool is_weak = GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK;
963 const char *marker = (mark_special
964 ? (is_tls ? "@" : (is_weak ? "*" : " ")) : "");
965
966 if (syms[cnt].sym.st_shndx == SHN_UNDEF)
967 {
968 const char *color = "";
969 if (color_mode)
970 {
971 if (is_tls)
972 color = color_undef_tls;
973 else if (is_weak)
974 color = color_undef_weak;
975 else
976 color = color_undef;
977 }
978
979 printf ("%*s %sU%s %s", digits, "", color, marker, symstr);
980 }
981 else
982 {
983 const char *color = "";
984 if (color_mode)
985 {
986 if (is_tls)
987 color = color_tls;
988 else if (is_weak)
989 color = color_weak;
990 else
991 color = color_symbol;
992 }
993 if (print_size && syms[cnt].sym.st_size != 0)
994 {
995#define HEXFMT "%6$s%2$0*1$" PRIx64 "%8$s %10$0*9$" PRIx64 " %7$s%3$c%4$s %5$s"
996#define DECFMT "%6$s%2$*1$" PRId64 "%8$s %10$*9$" PRId64 " %7$s%3$c%4$s %5$s"
997#define OCTFMT "%6$s%2$0*1$" PRIo64 "%8$s %10$0*9$" PRIo64 " %7$s%3$c%4$s %5$s"
998 printf ((radix == radix_hex ? HEXFMT
999 : (radix == radix_decimal ? DECFMT : OCTFMT)),
1000 digits, syms[cnt].sym.st_value,
1001 class_type_char (elf, ehdr, &syms[cnt].sym), marker,
1002 symstr,
1003 color_mode ? color_address : "",
1004 color,
1005 color_mode ? color_off : "",
1006 digits, (uint64_t) syms[cnt].sym.st_size);
1007#undef HEXFMT
1008#undef DECFMT
1009#undef OCTFMT
1010 }
1011 else
1012 {
1013#define HEXFMT "%6$s%2$0*1$" PRIx64 "%8$s %7$s%3$c%4$s %5$s"
1014#define DECFMT "%6$s%2$*1$" PRId64 "%8$s %7$s%3$c%4$s %5$s"
1015#define OCTFMT "%6$s%2$0*1$" PRIo64 "%8$s %7$s%3$c%4$s %5$s"
1016 printf ((radix == radix_hex ? HEXFMT
1017 : (radix == radix_decimal ? DECFMT : OCTFMT)),
1018 digits, syms[cnt].sym.st_value,
1019 class_type_char (elf, ehdr, &syms[cnt].sym), marker,
1020 symstr,
1021 color_mode ? color_address : "",
1022 color,
1023 color_mode ? color_off : "");
1024#undef HEXFMT
1025#undef DECFMT
1026#undef OCTFMT
1027 }
1028 }
1029
1030 if (color_mode)
1031 fputs_unlocked (color_off, stdout);
1032 putchar_unlocked ('\n');
1033 }
1034
1035#ifdef USE_DEMANGLE
1036 free (demangle_buffer);
1037#endif
1038}
1039
1040
1041static void
1042show_symbols_posix (Elf *elf, const GElf_Ehdr *ehdr, GElf_Word strndx,
1043 const char *prefix, const char *fullname, GElf_SymX *syms,
1044 size_t nsyms)
1045{
1046 if (prefix != NULL && ! print_file_name)
1047 printf ("%s:\n", fullname);
1048
1049 int digits = length_map[gelf_getclass (elf) - 1][radix];
1050
1051#ifdef USE_DEMANGLE
1052 size_t demangle_buffer_len = 0;
1053 char *demangle_buffer = NULL;
1054#endif
1055
1056 /* Iterate over all symbols. */
1057 for (size_t cnt = 0; cnt < nsyms; ++cnt)
1058 {
1059 char symstrbuf[50];
1060 const char *symstr = sym_name (elf, strndx, syms[cnt].sym.st_name,
1061 symstrbuf, sizeof symstrbuf);
1062
1063 /* Printing entries with a zero-length name makes the output
1064 not very well parseable. Since these entries don't carry
1065 much information we leave them out. */
1066 if (symstr[0] == '\0')
1067 continue;
1068
1069#ifdef USE_DEMANGLE
1070 /* Demangle if necessary. Require GNU v3 ABI by the "_Z" prefix. */
1071 if (demangle && symstr[0] == '_' && symstr[1] == 'Z')
1072 {
1073 int status = -1;
1074 char *dmsymstr = __cxa_demangle (symstr, demangle_buffer,
1075 &demangle_buffer_len, &status);
1076
1077 if (status == 0)
1078 symstr = dmsymstr;
1079 }
1080#endif
1081
1082 /* If we have to precede the line with the file name. */
1083 if (print_file_name)
1084 {
1085 fputs_unlocked (fullname, stdout);
1086 putchar_unlocked (':');
1087 putchar_unlocked (' ');
1088 }
1089
1090 printf ((radix == radix_hex
1091 ? "%s %c%s %0*" PRIx64 " %0*" PRIx64 "\n"
1092 : (radix == radix_decimal
1093 ? "%s %c%s %*" PRId64 " %*" PRId64 "\n"
1094 : "%s %c%s %0*" PRIo64 " %0*" PRIo64 "\n")),
1095 symstr,
1096 class_type_char (elf, ehdr, &syms[cnt].sym),
1097 mark_special
1098 ? (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_TLS
1099 ? "@"
1100 : (GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK
1101 ? "*" : " "))
1102 : "",
1103 digits, syms[cnt].sym.st_value,
1104 digits, syms[cnt].sym.st_size);
1105 }
1106
1107#ifdef USE_DEMANGLE
1108 free (demangle_buffer);
1109#endif
1110}
1111
1112
1113/* Maximum size of memory we allocate on the stack. */
1114#define MAX_STACK_ALLOC 65536
1115
1116static int
1117sort_by_address (const void *p1, const void *p2)
1118{
1119 GElf_SymX *s1 = (GElf_SymX *) p1;
1120 GElf_SymX *s2 = (GElf_SymX *) p2;
1121
1122 int result = (s1->sym.st_value < s2->sym.st_value
1123 ? -1 : (s1->sym.st_value == s2->sym.st_value ? 0 : 1));
1124
1125 return reverse_sort ? -result : result;
1126}
1127
1128static Elf_Data *sort_by_name_strtab;
1129
1130static int
1131sort_by_name (const void *p1, const void *p2)
1132{
1133 GElf_SymX *s1 = (GElf_SymX *) p1;
1134 GElf_SymX *s2 = (GElf_SymX *) p2;
1135
1136 const char *n1 = sort_by_name_strtab->d_buf + s1->sym.st_name;
1137 const char *n2 = sort_by_name_strtab->d_buf + s2->sym.st_name;
1138
1139 int result = strcmp (n1, n2);
1140
1141 return reverse_sort ? -result : result;
1142}
1143
1144/* Stub libdwfl callback, only the ELF handle already open is ever
1145 used. Only used for finding the alternate debug file if the Dwarf
1146 comes from the main file. We are not interested in separate
1147 debuginfo. */
1148static int
1149find_no_debuginfo (Dwfl_Module *mod,
1150 void **userdata,
1151 const char *modname,
1152 Dwarf_Addr base,
1153 const char *file_name,
1154 const char *debuglink_file,
1155 GElf_Word debuglink_crc,
1156 char **debuginfo_file_name)
1157{
1158 Dwarf_Addr dwbias;
1159 dwfl_module_info (mod, NULL, NULL, NULL, &dwbias, NULL, NULL, NULL);
1160
1161 /* We are only interested if the Dwarf has been setup on the main
1162 elf file but is only missing the alternate debug link. If dwbias
1163 hasn't even been setup, this is searching for separate debuginfo
1164 for the main elf. We don't care in that case. */
1165 if (dwbias == (Dwarf_Addr) -1)
1166 return -1;
1167
1168 return dwfl_standard_find_debuginfo (mod, userdata, modname, base,
1169 file_name, debuglink_file,
1170 debuglink_crc, debuginfo_file_name);
1171}
1172
1173/* Get the Dwarf for the module/file we want. */
1174struct getdbg
1175{
1176 const char *name;
1177 Dwarf **dbg;
1178};
1179
1180static int
1181getdbg_dwflmod (Dwfl_Module *dwflmod,
1182 void **userdata __attribute__ ((unused)),
1183 const char *name,
1184 Dwarf_Addr base __attribute__ ((unused)),
1185 void *arg)
1186{
1187 struct getdbg *get = (struct getdbg *) arg;
1188 if (get != NULL && get->name != NULL && strcmp (get->name, name) == 0)
1189 {
1190 Dwarf_Addr bias;
1191 *get->dbg = dwfl_module_getdwarf (dwflmod, &bias);
1192 return DWARF_CB_ABORT;
1193 }
1194
1195 return DWARF_CB_OK;
1196}
1197
1198static void
1199show_symbols (int fd, Ebl *ebl, GElf_Ehdr *ehdr,
1200 Elf_Scn *scn, Elf_Scn *xndxscn,
1201 GElf_Shdr *shdr, const char *prefix, const char *fname,
1202 const char *fullname)
1203{
1204 /* Get the section header string table index. */
1205 size_t shstrndx;
1206 if (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0)
1207 error (EXIT_FAILURE, 0,
1208 gettext ("cannot get section header string table index"));
1209
1210 /* The section is that large. */
1211 size_t size = shdr->sh_size;
1212 /* One entry is this large. */
1213 size_t entsize = shdr->sh_entsize;
1214
1215 /* Consistency checks. */
1216 if (entsize == 0
1217 || entsize != gelf_fsize (ebl->elf, ELF_T_SYM, 1, EV_CURRENT))
1218 error (0, 0,
1219 gettext ("%s: entry size in section %zd `%s' is not what we expect"),
1220 fullname, elf_ndxscn (scn),
1221 elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
1222 else if (size % entsize != 0)
1223 error (0, 0,
1224 gettext ("%s: size of section %zd `%s' is not multiple of entry size"),
1225 fullname, elf_ndxscn (scn),
1226 elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
1227
1228 /* Compute number of entries. Handle buggy entsize values. */
1229 size_t nentries = size / (entsize ?: 1);
1230
1231
1232#define obstack_chunk_alloc xmalloc
1233#define obstack_chunk_free free
1234 struct obstack whereob;
1235 obstack_init (&whereob);
1236
1237 /* Get a DWARF debugging descriptor. It's no problem if this isn't
1238 possible. We just won't print any line number information. */
1239 Dwarf *dbg = NULL;
1240 Dwfl *dwfl = NULL;
1241 if (format == format_sysv)
1242 {
1243 if (ehdr->e_type != ET_REL)
1244 dbg = dwarf_begin_elf (ebl->elf, DWARF_C_READ, NULL);
1245 else
1246 {
1247 /* Abuse libdwfl to do the relocations for us. This is just
1248 for the ET_REL file containing Dwarf, so no need for
1249 fancy lookups. */
1250
1251 /* Duplicate an fd for dwfl_report_offline to swallow. */
1252 int dwfl_fd = dup (fd);
1253 if (likely (dwfl_fd >= 0))
1254 {
1255 static const Dwfl_Callbacks callbacks =
1256 {
1257 .section_address = dwfl_offline_section_address,
1258 .find_debuginfo = find_no_debuginfo
1259 };
1260 dwfl = dwfl_begin (&callbacks);
1261 if (likely (dwfl != NULL))
1262 {
1263 /* Let 0 be the logical address of the file (or
1264 first in archive). */
1265 dwfl->offline_next_address = 0;
1266 if (dwfl_report_offline (dwfl, fname, fname, dwfl_fd)
1267 == NULL)
1268 {
1269 /* Consumed on success, not on failure. */
1270 close (dwfl_fd);
1271 }
1272 else
1273 {
1274 dwfl_report_end (dwfl, NULL, NULL);
1275
1276 struct getdbg get = { .name = fname, .dbg = &dbg };
1277 dwfl_getmodules (dwfl, &getdbg_dwflmod, &get, 0);
1278 }
1279 }
1280 }
1281 }
1282 if (dbg != NULL)
1283 {
1284 (void) dwarf_getpubnames (dbg, get_global, NULL, 0);
1285
1286 get_local_names (dbg);
1287 }
1288 }
1289
1290 /* Get the data of the section. */
1291 Elf_Data *data = elf_getdata (scn, NULL);
1292 Elf_Data *xndxdata = elf_getdata (xndxscn, NULL);
1293 if (data == NULL || (xndxscn != NULL && xndxdata == NULL))
1294 INTERNAL_ERROR (fullname);
1295
1296 /* Allocate the memory.
1297
1298 XXX We can use a dirty trick here. Since GElf_Sym == Elf64_Sym we
1299 can use the data memory instead of copying again if what we read
1300 is a 64 bit file. */
1301 if (nentries > SIZE_MAX / sizeof (GElf_SymX))
1302 error (EXIT_FAILURE, 0,
1303 gettext ("%s: entries (%zd) in section %zd `%s' is too large"),
1304 fullname, nentries, elf_ndxscn (scn),
1305 elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
1306 GElf_SymX *sym_mem;
1307 if (nentries * sizeof (GElf_SymX) < MAX_STACK_ALLOC)
1308 sym_mem = (GElf_SymX *) alloca (nentries * sizeof (GElf_SymX));
1309 else
1310 sym_mem = (GElf_SymX *) xmalloc (nentries * sizeof (GElf_SymX));
1311
1312 /* Iterate over all symbols. */
1313#ifdef USE_DEMANGLE
1314 size_t demangle_buffer_len = 0;
1315 char *demangle_buffer = NULL;
1316#endif
1317 int longest_name = 4;
1318 int longest_where = 4;
1319 size_t nentries_used = 0;
1320 for (size_t cnt = 0; cnt < nentries; ++cnt)
1321 {
1322 GElf_Sym *sym = gelf_getsymshndx (data, xndxdata, cnt,
1323 &sym_mem[nentries_used].sym,
1324 &sym_mem[nentries_used].xndx);
1325 if (sym == NULL)
1326 INTERNAL_ERROR (fullname);
1327
1328 /* Filter out administrative symbols without a name and those
1329 deselected by the user with command line options. */
1330 if ((hide_undefined && sym->st_shndx == SHN_UNDEF)
1331 || (hide_defined && sym->st_shndx != SHN_UNDEF)
1332 || (hide_local && GELF_ST_BIND (sym->st_info) == STB_LOCAL))
1333 continue;
1334
1335 sym_mem[nentries_used].where = "";
1336 if (format == format_sysv)
1337 {
1338 const char *symstr = elf_strptr (ebl->elf, shdr->sh_link,
1339 sym->st_name);
1340 if (symstr == NULL)
1341 continue;
1342
1343#ifdef USE_DEMANGLE
1344 /* Demangle if necessary. Require GNU v3 ABI by the "_Z" prefix. */
1345 if (demangle && symstr[0] == '_' && symstr[1] == 'Z')
1346 {
1347 int status = -1;
1348 char *dmsymstr = __cxa_demangle (symstr, demangle_buffer,
1349 &demangle_buffer_len, &status);
1350
1351 if (status == 0)
1352 symstr = dmsymstr;
1353 }
1354#endif
1355
1356 longest_name = MAX ((size_t) longest_name, strlen (symstr));
1357
1358 if (sym->st_shndx != SHN_UNDEF
1359 && GELF_ST_BIND (sym->st_info) != STB_LOCAL
1360 && global_root != NULL)
1361 {
1362 Dwarf_Global fake = { .name = symstr };
1363 Dwarf_Global **found = tfind (&fake, &global_root,
1364 global_compare);
1365 if (found != NULL)
1366 {
1367 Dwarf_Die die_mem;
1368 Dwarf_Die *die = dwarf_offdie (dbg, (*found)->die_offset,
1369 &die_mem);
1370
1371 Dwarf_Die cudie_mem;
1372 Dwarf_Die *cudie = NULL;
1373
1374 Dwarf_Addr lowpc;
1375 Dwarf_Addr highpc;
1376 if (die != NULL
1377 && dwarf_lowpc (die, &lowpc) == 0
1378 && lowpc <= sym->st_value
1379 && dwarf_highpc (die, &highpc) == 0
1380 && highpc > sym->st_value)
1381 cudie = dwarf_offdie (dbg, (*found)->cu_offset,
1382 &cudie_mem);
1383 if (cudie != NULL)
1384 {
1385 Dwarf_Line *line = dwarf_getsrc_die (cudie,
1386 sym->st_value);
1387 if (line != NULL)
1388 {
1389 /* We found the line. */
1390 int lineno;
1391 (void) dwarf_lineno (line, &lineno);
1392 const char *file = dwarf_linesrc (line, NULL, NULL);
1393 file = (file != NULL) ? basename (file) : "???";
1394 int n;
1395 n = obstack_printf (&whereob, "%s:%d%c", file,
1396 lineno, '\0');
1397 sym_mem[nentries_used].where
1398 = obstack_finish (&whereob);
1399
1400 /* The return value of obstack_print included the
1401 NUL byte, so subtract one. */
1402 if (--n > (int) longest_where)
1403 longest_where = (size_t) n;
1404 }
1405 }
1406 }
1407 }
1408
1409 /* Try to find the symbol among the local symbols. */
1410 if (sym_mem[nentries_used].where[0] == '\0')
1411 {
1412 struct local_name fake =
1413 {
1414 .name = symstr,
1415 .lowpc = sym->st_value,
1416 .highpc = sym->st_value,
1417 };
1418 struct local_name **found = tfind (&fake, &local_root,
1419 local_compare);
1420 if (found != NULL)
1421 {
1422 /* We found the line. */
1423 int n = obstack_printf (&whereob, "%s:%" PRIu64 "%c",
1424 basename ((*found)->file),
1425 (*found)->lineno,
1426 '\0');
1427 sym_mem[nentries_used].where = obstack_finish (&whereob);
1428
1429 /* The return value of obstack_print included the
1430 NUL byte, so subtract one. */
1431 if (--n > (int) longest_where)
1432 longest_where = (size_t) n;
1433 }
1434 }
1435 }
1436
1437 /* We use this entry. */
1438 ++nentries_used;
1439 }
1440#ifdef USE_DEMANGLE
1441 free (demangle_buffer);
1442#endif
1443 /* Now we know the exact number. */
1444 nentries = nentries_used;
1445
1446 /* Sort the entries according to the users wishes. */
1447 if (sort == sort_name)
1448 {
1449 sort_by_name_strtab = elf_getdata (elf_getscn (ebl->elf, shdr->sh_link),
1450 NULL);
1451 qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_name);
1452 }
1453 else if (sort == sort_numeric)
1454 qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_address);
1455
1456 /* Finally print according to the users selection. */
1457 switch (format)
1458 {
1459 case format_sysv:
1460 show_symbols_sysv (ebl, shdr->sh_link, fullname, sym_mem, nentries,
1461 longest_name, longest_where);
1462 break;
1463
1464 case format_bsd:
1465 show_symbols_bsd (ebl->elf, ehdr, shdr->sh_link, prefix, fname, fullname,
1466 sym_mem, nentries);
1467 break;
1468
1469 case format_posix:
1470 default:
1471 assert (format == format_posix);
1472 show_symbols_posix (ebl->elf, ehdr, shdr->sh_link, prefix, fullname,
1473 sym_mem, nentries);
1474 break;
1475 }
1476
1477 /* Free all memory. */
1478 if (nentries * sizeof (sym_mem[0]) >= MAX_STACK_ALLOC)
1479 free (sym_mem);
1480
1481 obstack_free (&whereob, NULL);
1482
1483 if (dbg != NULL)
1484 {
1485 tdestroy (global_root, free);
1486 global_root = NULL;
1487
1488 tdestroy (local_root, free);
1489 local_root = NULL;
1490
1491 if (dwfl == NULL)
1492 (void) dwarf_end (dbg);
1493 }
1494 if (dwfl != NULL)
1495 dwfl_end (dwfl);
1496}
1497
1498
1499static int
1500handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
1501 const char *suffix)
1502{
1503 size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
1504 size_t suffix_len = suffix == NULL ? 0 : strlen (suffix);
1505 size_t fname_len = strlen (fname) + 1;
1506 char fullname[prefix_len + 1 + fname_len + suffix_len];
1507 char *cp = fullname;
1508 Elf_Scn *scn = NULL;
1509 int any = 0;
1510 int result = 0;
1511 GElf_Ehdr ehdr_mem;
1512 GElf_Ehdr *ehdr;
1513 Ebl *ebl;
1514
1515 /* Get the backend for this object file type. */
1516 ebl = ebl_openbackend (elf);
1517
1518 /* We need the ELF header in a few places. */
1519 ehdr = gelf_getehdr (elf, &ehdr_mem);
1520 if (ehdr == NULL)
1521 INTERNAL_ERROR (fullname);
1522
1523 /* If we are asked to print the dynamic symbol table and this is
1524 executable or dynamic executable, fail. */
1525 if (symsec_type == SHT_DYNSYM
1526 && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
1527 {
1528 /* XXX Add machine specific object file types. */
1529 error (0, 0, gettext ("%s%s%s%s: Invalid operation"),
1530 prefix ?: "", prefix ? "(" : "", fname, prefix ? ")" : "");
1531 result = 1;
1532 goto out;
1533 }
1534
1535 /* Create the full name of the file. */
1536 if (prefix != NULL)
1537 cp = mempcpy (cp, prefix, prefix_len);
1538 cp = mempcpy (cp, fname, fname_len);
1539 if (suffix != NULL)
1540 memcpy (cp - 1, suffix, suffix_len + 1);
1541
1542 /* Find the symbol table.
1543
1544 XXX Can there be more than one? Do we print all? Currently we do. */
1545 while ((scn = elf_nextscn (elf, scn)) != NULL)
1546 {
1547 GElf_Shdr shdr_mem;
1548 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1549
1550 if (shdr == NULL)
1551 INTERNAL_ERROR (fullname);
1552
1553 if (shdr->sh_type == symsec_type)
1554 {
1555 Elf_Scn *xndxscn = NULL;
1556
1557 /* We have a symbol table. First make sure we remember this. */
1558 any = 1;
1559
1560 /* Look for an extended section index table for this section. */
1561 if (symsec_type == SHT_SYMTAB)
1562 {
1563 size_t scnndx = elf_ndxscn (scn);
1564
1565 while ((xndxscn = elf_nextscn (elf, xndxscn)) != NULL)
1566 {
1567 GElf_Shdr xndxshdr_mem;
1568 GElf_Shdr *xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem);
1569
1570 if (xndxshdr == NULL)
1571 INTERNAL_ERROR (fullname);
1572
1573 if (xndxshdr->sh_type == SHT_SYMTAB_SHNDX
1574 && xndxshdr->sh_link == scnndx)
1575 break;
1576 }
1577 }
1578
1579 show_symbols (fd, ebl, ehdr, scn, xndxscn, shdr, prefix, fname,
1580 fullname);
1581 }
1582 }
1583
1584 if (! any)
1585 {
1586 error (0, 0, gettext ("%s%s%s: no symbols"),
1587 prefix ?: "", prefix ? ":" : "", fname);
1588 result = 1;
1589 }
1590
1591 out:
1592 /* Close the ELF backend library descriptor. */
1593 ebl_closebackend (ebl);
1594
1595 return result;
1596}
1597
1598
1599#include "debugpred.h"