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