• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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