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