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