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