Blame src/nm.c

Packit Service 97d2fb
/* Print symbol information from ELF file in human-readable form.
Packit Service 97d2fb
   Copyright (C) 2000-2008, 2009, 2011, 2012, 2014, 2015, 2020 Red Hat, Inc.
Packit Service 97d2fb
   This file is part of elfutils.
Packit Service 97d2fb
   Written by Ulrich Drepper <drepper@redhat.com>, 2000.
Packit Service 97d2fb
Packit Service 97d2fb
   This file is free software; you can redistribute it and/or modify
Packit Service 97d2fb
   it under the terms of the GNU General Public License as published by
Packit Service 97d2fb
   the Free Software Foundation; either version 3 of the License, or
Packit Service 97d2fb
   (at your option) any later version.
Packit Service 97d2fb
Packit Service 97d2fb
   elfutils is distributed in the hope that it will be useful, but
Packit Service 97d2fb
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 97d2fb
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 97d2fb
   GNU General Public License for more details.
Packit Service 97d2fb
Packit Service 97d2fb
   You should have received a copy of the GNU General Public License
Packit Service 97d2fb
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef HAVE_CONFIG_H
Packit Service 97d2fb
# include <config.h>
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
#include <ar.h>
Packit Service 97d2fb
#include <argp.h>
Packit Service 97d2fb
#include <assert.h>
Packit Service 97d2fb
#include <ctype.h>
Packit Service 97d2fb
#include <dwarf.h>
Packit Service 97d2fb
#include <errno.h>
Packit Service 97d2fb
#include <fcntl.h>
Packit Service 97d2fb
#include <gelf.h>
Packit Service 97d2fb
#include <inttypes.h>
Packit Service 97d2fb
#include <libdw.h>
Packit Service 97d2fb
#include <libintl.h>
Packit Service 97d2fb
#include <locale.h>
Packit Service 97d2fb
#include <obstack.h>
Packit Service 97d2fb
#include <search.h>
Packit Service 97d2fb
#include <stdbool.h>
Packit Service 97d2fb
#include <stdio.h>
Packit Service 97d2fb
#include <stdio_ext.h>
Packit Service 97d2fb
#include <stdlib.h>
Packit Service 97d2fb
#include <string.h>
Packit Service 97d2fb
#include <unistd.h>
Packit Service 97d2fb
Packit Service 97d2fb
#include <libeu.h>
Packit Service 97d2fb
#include <system.h>
Packit Service 97d2fb
#include <color.h>
Packit Service 97d2fb
#include <printversion.h>
Packit Service 97d2fb
#include "../libebl/libeblP.h"
Packit Service 97d2fb
#include "../libdwfl/libdwflP.h"
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Name and version of program.  */
Packit Service 97d2fb
ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
Packit Service 97d2fb
Packit Service 97d2fb
/* Bug report address.  */
Packit Service 97d2fb
ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Values for the parameters which have no short form.  */
Packit Service 97d2fb
#define OPT_DEFINED		0x100
Packit Service 97d2fb
#define OPT_MARK_SPECIAL	0x101
Packit Service 97d2fb
Packit Service 97d2fb
/* Definitions of arguments for argp functions.  */
Packit Service 97d2fb
static const struct argp_option options[] =
Packit Service 97d2fb
{
Packit Service 97d2fb
  { NULL, 0, NULL, 0, N_("Output selection:"), 0 },
Packit Service 97d2fb
  { "debug-syms", 'a', NULL, 0, N_("Display debugger-only symbols"), 0 },
Packit Service 97d2fb
  { "defined-only", OPT_DEFINED, NULL, 0, N_("Display only defined symbols"),
Packit Service 97d2fb
    0 },
Packit Service 97d2fb
  { "dynamic", 'D', NULL, 0,
Packit Service 97d2fb
    N_("Display dynamic symbols instead of normal symbols"), 0 },
Packit Service 97d2fb
  { "extern-only", 'g', NULL, 0, N_("Display only external symbols"), 0 },
Packit Service 97d2fb
  { "undefined-only", 'u', NULL, 0, N_("Display only undefined symbols"), 0 },
Packit Service 97d2fb
  { "print-armap", 's', NULL, 0,
Packit Service 97d2fb
    N_("Include index for symbols from archive members"), 0 },
Packit Service 97d2fb
Packit Service 97d2fb
  { NULL, 0, NULL, 0, N_("Output format:"), 0 },
Packit Service 97d2fb
  { "print-file-name", 'A', NULL, 0,
Packit Service 97d2fb
    N_("Print name of the input file before every symbol"), 0 },
Packit Service 97d2fb
  { NULL, 'o', NULL, OPTION_HIDDEN, "Same as -A", 0 },
Packit Service 97d2fb
  { "format", 'f', "FORMAT", 0,
Packit Service 97d2fb
    N_("Use the output format FORMAT.  FORMAT can be `bsd', `sysv' or `posix'.  The default is `sysv'"),
Packit Service 97d2fb
    0 },
Packit Service 97d2fb
  { NULL, 'B', NULL, 0, N_("Same as --format=bsd"), 0 },
Packit Service 97d2fb
  { "portability", 'P', NULL, 0, N_("Same as --format=posix"), 0 },
Packit Service 97d2fb
  { "radix", 't', "RADIX", 0, N_("Use RADIX for printing symbol values"), 0 },
Packit Service 97d2fb
  { "mark-special", OPT_MARK_SPECIAL, NULL, 0, N_("Mark special symbols"), 0 },
Packit Service 97d2fb
  { "mark-weak", OPT_MARK_SPECIAL, NULL, OPTION_HIDDEN, "", 0 },
Packit Service 97d2fb
  { "print-size", 'S', NULL, 0, N_("Print size of defined symbols"), 0 },
Packit Service 97d2fb
Packit Service 97d2fb
  { NULL, 0, NULL, 0, N_("Output options:"), 0 },
Packit Service 97d2fb
  { "numeric-sort", 'n', NULL, 0, N_("Sort symbols numerically by address"),
Packit Service 97d2fb
    0 },
Packit Service 97d2fb
  { "no-sort", 'p', NULL, 0, N_("Do not sort the symbols"), 0 },
Packit Service 97d2fb
  { "reverse-sort", 'r', NULL, 0, N_("Reverse the sense of the sort"), 0 },
Packit Service 97d2fb
#ifdef USE_DEMANGLE
Packit Service 97d2fb
  { "demangle", 'C', NULL, 0,
Packit Service 97d2fb
    N_("Decode low-level symbol names into source code names"), 0 },
Packit Service 97d2fb
#endif
Packit Service 97d2fb
  { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 },
Packit Service 97d2fb
  { NULL, 0, NULL, 0, NULL, 0 }
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
/* Short description of program.  */
Packit Service 97d2fb
static const char doc[] = N_("List symbols from FILEs (a.out by default).");
Packit Service 97d2fb
Packit Service 97d2fb
/* Strings for arguments in help texts.  */
Packit Service 97d2fb
static const char args_doc[] = N_("[FILE...]");
Packit Service 97d2fb
Packit Service 97d2fb
/* Prototype for option handler.  */
Packit Service 97d2fb
static error_t parse_opt (int key, char *arg, struct argp_state *state);
Packit Service 97d2fb
Packit Service 97d2fb
/* Parser children.  */
Packit Service 97d2fb
static struct argp_child argp_children[] =
Packit Service 97d2fb
  {
Packit Service 97d2fb
    { &color_argp, 0, N_("Output formatting"), 2 },
Packit Service 97d2fb
    { NULL, 0, NULL, 0}
Packit Service 97d2fb
  };
Packit Service 97d2fb
Packit Service 97d2fb
/* Data structure to communicate with argp functions.  */
Packit Service 97d2fb
static struct argp argp =
Packit Service 97d2fb
{
Packit Service 97d2fb
  options, parse_opt, args_doc, doc, argp_children, NULL, NULL
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Print symbols in file named FNAME.  */
Packit Service 97d2fb
static int process_file (const char *fname, bool more_than_one);
Packit Service 97d2fb
Packit Service 97d2fb
/* Handle content of archive.  */
Packit Service 97d2fb
static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
Packit Service 97d2fb
		      const char *suffix);
Packit Service 97d2fb
Packit Service 97d2fb
/* Handle ELF file.  */
Packit Service 97d2fb
static int handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
Packit Service 97d2fb
		       const char *suffix);
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
#define INTERNAL_ERROR(fname) \
Packit Service 97d2fb
  error (EXIT_FAILURE, 0, gettext ("%s: INTERNAL ERROR %d (%s): %s"),      \
Packit Service 97d2fb
	 fname, __LINE__, PACKAGE_VERSION, elf_errmsg (-1))
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Internal representation of symbols.  */
Packit Service 97d2fb
typedef struct GElf_SymX
Packit Service 97d2fb
{
Packit Service 97d2fb
  GElf_Sym sym;
Packit Service 97d2fb
  Elf32_Word xndx;
Packit Service 97d2fb
  char *where;
Packit Service 97d2fb
} GElf_SymX;
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* User-selectable options.  */
Packit Service 97d2fb
Packit Service 97d2fb
/* The selected output format.  */
Packit Service 97d2fb
static enum
Packit Service 97d2fb
{
Packit Service 97d2fb
  format_sysv = 0,
Packit Service 97d2fb
  format_bsd,
Packit Service 97d2fb
  format_posix
Packit Service 97d2fb
} format;
Packit Service 97d2fb
Packit Service 97d2fb
/* Print defined, undefined, or both?  */
Packit Service 97d2fb
static bool hide_undefined;
Packit Service 97d2fb
static bool hide_defined;
Packit Service 97d2fb
Packit Service 97d2fb
/* Print local symbols also?  */
Packit Service 97d2fb
static bool hide_local;
Packit Service 97d2fb
Packit Service 97d2fb
/* Nonzero if full filename should precede every symbol.  */
Packit Service 97d2fb
static bool print_file_name;
Packit Service 97d2fb
Packit Service 97d2fb
/* If true print size of defined symbols in BSD format.  */
Packit Service 97d2fb
static bool print_size;
Packit Service 97d2fb
Packit Service 97d2fb
/* If true print archive index.  */
Packit Service 97d2fb
static bool print_armap;
Packit Service 97d2fb
Packit Service 97d2fb
/* If true reverse sorting.  */
Packit Service 97d2fb
static bool reverse_sort;
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef USE_DEMANGLE
Packit Service 97d2fb
/* If true demangle symbols.  */
Packit Service 97d2fb
static bool demangle;
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
/* Type of the section we are printing.  */
Packit Service 97d2fb
static GElf_Word symsec_type = SHT_SYMTAB;
Packit Service 97d2fb
Packit Service 97d2fb
/* Sorting selection.  */
Packit Service 97d2fb
static enum
Packit Service 97d2fb
{
Packit Service 97d2fb
  sort_name = 0,
Packit Service 97d2fb
  sort_numeric,
Packit Service 97d2fb
  sort_nosort
Packit Service 97d2fb
} sort;
Packit Service 97d2fb
Packit Service 97d2fb
/* Radix for printed numbers.  */
Packit Service 97d2fb
static enum
Packit Service 97d2fb
{
Packit Service 97d2fb
  radix_hex = 0,
Packit Service 97d2fb
  radix_decimal,
Packit Service 97d2fb
  radix_octal
Packit Service 97d2fb
} radix;
Packit Service 97d2fb
Packit Service 97d2fb
/* If nonzero mark special symbols:
Packit Service 97d2fb
   - weak symbols are distinguished from global symbols by adding
Packit Service 97d2fb
     a `*' after the identifying letter for the symbol class and type.
Packit Service 97d2fb
   - TLS symbols are distinguished from normal symbols by adding
Packit Service 97d2fb
     a '@' after the identifying letter for the symbol class and type.  */
Packit Service 97d2fb
static bool mark_special;
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
main (int argc, char *argv[])
Packit Service 97d2fb
{
Packit Service 97d2fb
  int remaining;
Packit Service 97d2fb
  int result = 0;
Packit Service 97d2fb
Packit Service 97d2fb
  /* We use no threads here which can interfere with handling a stream.  */
Packit Service 97d2fb
  (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);
Packit Service 97d2fb
  (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
Packit Service 97d2fb
  (void) __fsetlocking (stderr, FSETLOCKING_BYCALLER);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Set locale.  */
Packit Service 97d2fb
  (void) setlocale (LC_ALL, "");
Packit Service 97d2fb
Packit Service 97d2fb
  /* Make sure the message catalog can be found.  */
Packit Service 97d2fb
  (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Initialize the message catalog.  */
Packit Service 97d2fb
  (void) textdomain (PACKAGE_TARNAME);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Parse and process arguments.  */
Packit Service 97d2fb
  (void) argp_parse (&argp, argc, argv, 0, &remaining, NULL);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Tell the library which version we are expecting.  */
Packit Service 97d2fb
  (void) elf_version (EV_CURRENT);
Packit Service 97d2fb
Packit Service 97d2fb
  if (remaining == argc)
Packit Service 97d2fb
    /* The user didn't specify a name so we use a.out.  */
Packit Service 97d2fb
    result = process_file ("a.out", false);
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Process all the remaining files.  */
Packit Service 97d2fb
      const bool more_than_one = remaining + 1 < argc;
Packit Service 97d2fb
Packit Service 97d2fb
      do
Packit Service 97d2fb
	result |= process_file (argv[remaining], more_than_one);
Packit Service 97d2fb
      while (++remaining < argc);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Handle program arguments.  */
Packit Service 97d2fb
static error_t
Packit Service 97d2fb
parse_opt (int key, char *arg,
Packit Service 97d2fb
	   struct argp_state *state __attribute__ ((unused)))
Packit Service 97d2fb
{
Packit Service 97d2fb
  switch (key)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case 'a':
Packit Service 97d2fb
      /* XXX */
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef USE_DEMANGLE
Packit Service 97d2fb
    case 'C':
Packit Service 97d2fb
      demangle = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
    case 'f':
Packit Service 97d2fb
      if (strcmp (arg, "bsd") == 0)
Packit Service 97d2fb
	format = format_bsd;
Packit Service 97d2fb
      else if (strcmp (arg, "posix") == 0)
Packit Service 97d2fb
	format = format_posix;
Packit Service 97d2fb
      else
Packit Service 97d2fb
	/* Be bug compatible.  The BFD implementation also defaulted to
Packit Service 97d2fb
	   using the SysV format if nothing else matches.  */
Packit Service 97d2fb
	format = format_sysv;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'g':
Packit Service 97d2fb
      hide_local = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'n':
Packit Service 97d2fb
      sort = sort_numeric;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'p':
Packit Service 97d2fb
      sort = sort_nosort;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 't':
Packit Service 97d2fb
      if (strcmp (arg, "10") == 0 || strcmp (arg, "d") == 0)
Packit Service 97d2fb
	radix = radix_decimal;
Packit Service 97d2fb
      else if (strcmp (arg, "8") == 0 || strcmp (arg, "o") == 0)
Packit Service 97d2fb
	radix = radix_octal;
Packit Service 97d2fb
      else
Packit Service 97d2fb
	radix = radix_hex;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'u':
Packit Service 97d2fb
      hide_undefined = false;
Packit Service 97d2fb
      hide_defined = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'A':
Packit Service 97d2fb
    case 'o':
Packit Service 97d2fb
      print_file_name = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'B':
Packit Service 97d2fb
      format = format_bsd;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'D':
Packit Service 97d2fb
      symsec_type = SHT_DYNSYM;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'P':
Packit Service 97d2fb
      format = format_posix;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case OPT_DEFINED:
Packit Service 97d2fb
      hide_undefined = true;
Packit Service 97d2fb
      hide_defined = false;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case OPT_MARK_SPECIAL:
Packit Service 97d2fb
      mark_special = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'S':
Packit Service 97d2fb
      print_size = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 's':
Packit Service 97d2fb
      print_armap = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'r':
Packit Service 97d2fb
      reverse_sort = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      return ARGP_ERR_UNKNOWN;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Open the file and determine the type.  */
Packit Service 97d2fb
static int
Packit Service 97d2fb
process_file (const char *fname, bool more_than_one)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* Open the file.  */
Packit Service 97d2fb
  int fd = open (fname, O_RDONLY);
Packit Service 97d2fb
  if (fd == -1)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      error (0, errno, gettext ("cannot open '%s'"), fname);
Packit Service 97d2fb
      return 1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Now get the ELF descriptor.  */
Packit Service 97d2fb
  Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
Packit Service 97d2fb
  if (elf != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (elf_kind (elf) == ELF_K_ELF)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  int result = handle_elf (fd, elf, more_than_one ? "" : NULL,
Packit Service 97d2fb
				   fname, NULL);
Packit Service 97d2fb
Packit Service 97d2fb
	  if (elf_end (elf) != 0)
Packit Service 97d2fb
	    INTERNAL_ERROR (fname);
Packit Service 97d2fb
Packit Service 97d2fb
	  if (close (fd) != 0)
Packit Service 97d2fb
	    error (EXIT_FAILURE, errno, gettext ("while closing '%s'"), fname);
Packit Service 97d2fb
Packit Service 97d2fb
	  return result;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else if (elf_kind (elf) == ELF_K_AR)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  int result = handle_ar (fd, elf, NULL, fname, NULL);
Packit Service 97d2fb
Packit Service 97d2fb
	  if (elf_end (elf) != 0)
Packit Service 97d2fb
	    INTERNAL_ERROR (fname);
Packit Service 97d2fb
Packit Service 97d2fb
	  if (close (fd) != 0)
Packit Service 97d2fb
	    error (EXIT_FAILURE, errno, gettext ("while closing '%s'"), fname);
Packit Service 97d2fb
Packit Service 97d2fb
	  return result;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* We cannot handle this type.  Close the descriptor anyway.  */
Packit Service 97d2fb
      if (elf_end (elf) != 0)
Packit Service 97d2fb
	INTERNAL_ERROR (fname);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  error (0, 0, gettext ("%s: File format not recognized"), fname);
Packit Service 97d2fb
Packit Service 97d2fb
  return 1;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
Packit Service 97d2fb
	   const char *suffix)
Packit Service 97d2fb
{
Packit Service 97d2fb
  size_t fname_len = strlen (fname) + 1;
Packit Service 97d2fb
  size_t prefix_len = prefix != NULL ? strlen (prefix) : 0;
Packit Service 97d2fb
  char new_prefix[prefix_len + fname_len + 2];
Packit Service 97d2fb
  size_t suffix_len = suffix != NULL ? strlen (suffix) : 0;
Packit Service 97d2fb
  char new_suffix[suffix_len + 2];
Packit Service 97d2fb
  Elf *subelf;
Packit Service 97d2fb
  Elf_Cmd cmd = ELF_C_READ_MMAP;
Packit Service 97d2fb
  int result = 0;
Packit Service 97d2fb
Packit Service 97d2fb
  char *cp = new_prefix;
Packit Service 97d2fb
  if (prefix != NULL)
Packit Service 97d2fb
    cp = stpcpy (cp, prefix);
Packit Service 97d2fb
  cp = stpcpy (cp, fname);
Packit Service 97d2fb
  stpcpy (cp, "[");
Packit Service 97d2fb
Packit Service 97d2fb
  cp = new_suffix;
Packit Service 97d2fb
  if (suffix != NULL)
Packit Service 97d2fb
    cp = stpcpy (cp, suffix);
Packit Service 97d2fb
  stpcpy (cp, "]");
Packit Service 97d2fb
Packit Service 97d2fb
  /* First print the archive index if this is wanted.  */
Packit Service 97d2fb
  if (print_armap)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Elf_Arsym *arsym = elf_getarsym (elf, NULL);
Packit Service 97d2fb
Packit Service 97d2fb
      if (arsym != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  Elf_Arhdr *arhdr = NULL;
Packit Service 97d2fb
	  size_t arhdr_off = 0;	/* Note: 0 is no valid offset.  */
Packit Service 97d2fb
Packit Service 97d2fb
	  fputs_unlocked (gettext("\nArchive index:\n"), stdout);
Packit Service 97d2fb
Packit Service 97d2fb
	  while (arsym->as_off != 0)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      if (arhdr_off != arsym->as_off
Packit Service 97d2fb
		  && (elf_rand (elf, arsym->as_off) != arsym->as_off
Packit Service 97d2fb
		      || (subelf = elf_begin (fd, cmd, elf)) == NULL
Packit Service 97d2fb
		      || (arhdr = elf_getarhdr (subelf)) == NULL))
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  error (0, 0, gettext ("invalid offset %zu for symbol %s"),
Packit Service 97d2fb
			 arsym->as_off, arsym->as_name);
Packit Service 97d2fb
		  break;
Packit Service 97d2fb
		}
Packit Service 97d2fb
Packit Service 97d2fb
	      printf (gettext ("%s in %s\n"), arsym->as_name, arhdr->ar_name);
Packit Service 97d2fb
Packit Service 97d2fb
	      ++arsym;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  if (elf_rand (elf, SARMAG) != SARMAG)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      error (0, 0,
Packit Service 97d2fb
		     gettext ("cannot reset archive offset to beginning"));
Packit Service 97d2fb
	      return 1;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Process all the files contained in the archive.  */
Packit Service 97d2fb
  while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* The the header for this element.  */
Packit Service 97d2fb
      Elf_Arhdr *arhdr = elf_getarhdr (subelf);
Packit Service 97d2fb
Packit Service 97d2fb
      /* Skip over the index entries.  */
Packit Service 97d2fb
      if (strcmp (arhdr->ar_name, "/") != 0
Packit Service 97d2fb
	  && strcmp (arhdr->ar_name, "//") != 0
Packit Service 97d2fb
	  && strcmp (arhdr->ar_name, "/SYM64/") != 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (elf_kind (subelf) == ELF_K_ELF)
Packit Service 97d2fb
	    result |= handle_elf (fd, subelf, new_prefix, arhdr->ar_name,
Packit Service 97d2fb
				  new_suffix);
Packit Service 97d2fb
	  else if (elf_kind (subelf) == ELF_K_AR)
Packit Service 97d2fb
	    result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name,
Packit Service 97d2fb
				 new_suffix);
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      error (0, 0, gettext ("%s%s%s: file format not recognized"),
Packit Service 97d2fb
		     new_prefix, arhdr->ar_name, new_suffix);
Packit Service 97d2fb
	      result = 1;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Get next archive element.  */
Packit Service 97d2fb
      cmd = elf_next (subelf);
Packit Service 97d2fb
      if (elf_end (subelf) != 0)
Packit Service 97d2fb
	INTERNAL_ERROR (fname);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Mapping of radix and binary class to length.  */
Packit Service 97d2fb
static const int length_map[2][3] =
Packit Service 97d2fb
{
Packit Service 97d2fb
  [ELFCLASS32 - 1] =
Packit Service 97d2fb
  {
Packit Service 97d2fb
    [radix_hex] = 8,
Packit Service 97d2fb
    [radix_decimal] = 10,
Packit Service 97d2fb
    [radix_octal] = 11
Packit Service 97d2fb
  },
Packit Service 97d2fb
  [ELFCLASS64 - 1] =
Packit Service 97d2fb
  {
Packit Service 97d2fb
    [radix_hex] = 16,
Packit Service 97d2fb
    [radix_decimal] = 20,
Packit Service 97d2fb
    [radix_octal] = 22
Packit Service 97d2fb
  }
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
global_compare (const void *p1, const void *p2)
Packit Service 97d2fb
{
Packit Service 97d2fb
  const Dwarf_Global *g1 = (const Dwarf_Global *) p1;
Packit Service 97d2fb
  const Dwarf_Global *g2 = (const Dwarf_Global *) p2;
Packit Service 97d2fb
Packit Service 97d2fb
  return strcmp (g1->name, g2->name);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static void *global_root;
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
get_global (Dwarf *dbg __attribute__ ((unused)), Dwarf_Global *global,
Packit Service 97d2fb
	    void *arg __attribute__ ((unused)))
Packit Service 97d2fb
{
Packit Service 97d2fb
  tsearch (memcpy (xmalloc (sizeof (Dwarf_Global)), global,
Packit Service 97d2fb
		   sizeof (Dwarf_Global)),
Packit Service 97d2fb
	   &global_root, global_compare);
Packit Service 97d2fb
Packit Service 97d2fb
  return DWARF_CB_OK;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
struct local_name
Packit Service 97d2fb
{
Packit Service 97d2fb
  const char *name;
Packit Service 97d2fb
  const char *file;
Packit Service 97d2fb
  Dwarf_Word lineno;
Packit Service 97d2fb
  Dwarf_Addr lowpc;
Packit Service 97d2fb
  Dwarf_Addr highpc;
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
local_compare (const void *p1, const void *p2)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct local_name *g1 = (struct local_name *) p1;
Packit Service 97d2fb
  struct local_name *g2 = (struct local_name *) p2;
Packit Service 97d2fb
  int result;
Packit Service 97d2fb
Packit Service 97d2fb
  result = strcmp (g1->name, g2->name);
Packit Service 97d2fb
  if (result == 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (g1->lowpc <= g2->lowpc && g1->highpc >= g2->highpc)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* g2 is contained in g1.  Update the data.  */
Packit Service 97d2fb
	  g2->lowpc = g1->lowpc;
Packit Service 97d2fb
	  g2->highpc = g1->highpc;
Packit Service 97d2fb
	  result = 0;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else if (g2->lowpc <= g1->lowpc && g2->highpc >= g1->highpc)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* g1 is contained in g2.  Update the data.  */
Packit Service 97d2fb
	  g1->lowpc = g2->lowpc;
Packit Service 97d2fb
	  g1->highpc = g2->highpc;
Packit Service 97d2fb
	  result = 0;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	result = g1->lowpc < g2->lowpc ? -1 : 1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
get_var_range (Dwarf_Die *die, Dwarf_Word *lowpc, Dwarf_Word *highpc)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwarf_Attribute locattr_mem;
Packit Service 97d2fb
  Dwarf_Attribute *locattr = dwarf_attr (die, DW_AT_location, &locattr_mem);
Packit Service 97d2fb
  if  (locattr == NULL)
Packit Service 97d2fb
    return 1;
Packit Service 97d2fb
Packit Service 97d2fb
  Dwarf_Op *loc;
Packit Service 97d2fb
  size_t nloc;
Packit Service 97d2fb
  if (dwarf_getlocation (locattr, &loc, &nloc) != 0)
Packit Service 97d2fb
    return 1;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Interpret the location expressions.  */
Packit Service 97d2fb
  // XXX For now just the simple one:
Packit Service 97d2fb
  if (nloc == 1 && loc[0].atom == DW_OP_addr)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      *lowpc = *highpc = loc[0].number;
Packit Service 97d2fb
      return 0;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return 1;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static void *local_root;
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
get_local_names (Dwarf *dbg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwarf_Off offset = 0;
Packit Service 97d2fb
  Dwarf_Off old_offset;
Packit Service 97d2fb
  size_t hsize;
Packit Service 97d2fb
Packit Service 97d2fb
  while (dwarf_nextcu (dbg, old_offset = offset, &offset, &hsize, NULL, NULL,
Packit Service 97d2fb
		       NULL) == 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Dwarf_Die cudie_mem;
Packit Service 97d2fb
      Dwarf_Die *cudie = dwarf_offdie (dbg, old_offset + hsize, &cudie_mem);
Packit Service 97d2fb
Packit Service 97d2fb
      /* If we cannot get the CU DIE there is no need to go on with
Packit Service 97d2fb
	 this CU.  */
Packit Service 97d2fb
      if (cudie == NULL)
Packit Service 97d2fb
	continue;
Packit Service 97d2fb
      /* This better be a CU DIE.  */
Packit Service 97d2fb
      if (dwarf_tag (cudie) != DW_TAG_compile_unit)
Packit Service 97d2fb
	continue;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Get the line information.  */
Packit Service 97d2fb
      Dwarf_Files *files;
Packit Service 97d2fb
      size_t nfiles;
Packit Service 97d2fb
      if (dwarf_getsrcfiles (cudie, &files, &nfiles) != 0)
Packit Service 97d2fb
	continue;
Packit Service 97d2fb
Packit Service 97d2fb
      Dwarf_Die die_mem;
Packit Service 97d2fb
      Dwarf_Die *die = &die_mem;
Packit Service 97d2fb
      if (dwarf_child (cudie, die) == 0)
Packit Service 97d2fb
	/* Iterate over all immediate children of the CU DIE.  */
Packit Service 97d2fb
	do
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    int tag = dwarf_tag (die);
Packit Service 97d2fb
	    if (tag != DW_TAG_subprogram && tag != DW_TAG_variable)
Packit Service 97d2fb
	      continue;
Packit Service 97d2fb
Packit Service 97d2fb
	    /* We are interested in five attributes: name, decl_file,
Packit Service 97d2fb
	       decl_line, low_pc, and high_pc.  */
Packit Service 97d2fb
	    Dwarf_Attribute attr_mem;
Packit Service 97d2fb
	    Dwarf_Attribute *attr = dwarf_attr (die, DW_AT_name, &attr_mem);
Packit Service 97d2fb
	    const char *name = dwarf_formstring (attr);
Packit Service 97d2fb
	    if (name == NULL)
Packit Service 97d2fb
	      continue;
Packit Service 97d2fb
Packit Service 97d2fb
	    Dwarf_Word fileidx;
Packit Service 97d2fb
	    attr = dwarf_attr (die, DW_AT_decl_file, &attr_mem);
Packit Service 97d2fb
	    if (dwarf_formudata (attr, &fileidx) != 0 || fileidx >= nfiles)
Packit Service 97d2fb
	      continue;
Packit Service 97d2fb
Packit Service 97d2fb
	    Dwarf_Word lineno;
Packit Service 97d2fb
	    attr = dwarf_attr (die, DW_AT_decl_line, &attr_mem);
Packit Service 97d2fb
	    if (dwarf_formudata (attr, &lineno) != 0 || lineno == 0)
Packit Service 97d2fb
	      continue;
Packit Service 97d2fb
Packit Service 97d2fb
	    Dwarf_Addr lowpc;
Packit Service 97d2fb
	    Dwarf_Addr highpc;
Packit Service 97d2fb
	    if (tag == DW_TAG_subprogram)
Packit Service 97d2fb
	      {
Packit Service 97d2fb
		if (dwarf_lowpc (die, &lowpc) != 0
Packit Service 97d2fb
		    || dwarf_highpc (die, &highpc) != 0)
Packit Service 97d2fb
		  continue;
Packit Service 97d2fb
	      }
Packit Service 97d2fb
	    else
Packit Service 97d2fb
	      {
Packit Service 97d2fb
		if (get_var_range (die, &lowpc, &highpc) != 0)
Packit Service 97d2fb
		  continue;
Packit Service 97d2fb
	      }
Packit Service 97d2fb
Packit Service 97d2fb
	    /* We have all the information.  Create a record.  */
Packit Service 97d2fb
	    struct local_name *newp
Packit Service 97d2fb
	      = (struct local_name *) xmalloc (sizeof (*newp));
Packit Service 97d2fb
	    newp->name = name;
Packit Service 97d2fb
	    newp->file = dwarf_filesrc (files, fileidx, NULL, NULL);
Packit Service 97d2fb
	    newp->lineno = lineno;
Packit Service 97d2fb
	    newp->lowpc = lowpc;
Packit Service 97d2fb
	    newp->highpc = highpc;
Packit Service 97d2fb
Packit Service 97d2fb
	   /* Check whether a similar local_name is already in the
Packit Service 97d2fb
	      cache.  That should not happen.  But if it does, we
Packit Service 97d2fb
	      don't want to leak memory.  */
Packit Service 97d2fb
	    struct local_name **tres = tsearch (newp, &local_root,
Packit Service 97d2fb
						local_compare);
Packit Service 97d2fb
	    if (tres == NULL)
Packit Service 97d2fb
              error (EXIT_FAILURE, errno,
Packit Service 97d2fb
                     gettext ("cannot create search tree"));
Packit Service 97d2fb
	    else if (*tres != newp)
Packit Service 97d2fb
	      free (newp);
Packit Service 97d2fb
	  }
Packit Service 97d2fb
	while (dwarf_siblingof (die, die) == 0);
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Do elf_strptr, but return a backup string and never NULL.  */
Packit Service 97d2fb
static const char *
Packit Service 97d2fb
sym_name (Elf *elf, GElf_Word strndx, GElf_Word st_name, char buf[], size_t n)
Packit Service 97d2fb
{
Packit Service 97d2fb
  const char *symstr = elf_strptr (elf, strndx, st_name);
Packit Service 97d2fb
  if (symstr == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      snprintf (buf, n, "[invalid st_name %#" PRIx32 "]", st_name);
Packit Service 97d2fb
      symstr = buf;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  return symstr;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Show symbols in SysV format.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
show_symbols_sysv (Ebl *ebl, GElf_Word strndx, const char *fullname,
Packit Service 97d2fb
		   GElf_SymX *syms, size_t nsyms, int longest_name,
Packit Service 97d2fb
		   int longest_where)
Packit Service 97d2fb
{
Packit Service 97d2fb
  size_t shnum;
Packit Service 97d2fb
  if (elf_getshdrnum (ebl->elf, &shnum) < 0)
Packit Service 97d2fb
    INTERNAL_ERROR (fullname);
Packit Service 97d2fb
Packit Service 97d2fb
  bool scnnames_malloced = shnum * sizeof (const char *) > 128 * 1024;
Packit Service 97d2fb
  const char **scnnames;
Packit Service 97d2fb
  if (scnnames_malloced)
Packit Service 97d2fb
    scnnames = (const char **) xmalloc (sizeof (const char *) * shnum);
Packit Service 97d2fb
  else
Packit Service 97d2fb
    scnnames = (const char **) alloca (sizeof (const char *) * shnum);
Packit Service 97d2fb
  /* Get the section header string table index.  */
Packit Service 97d2fb
  size_t shstrndx;
Packit Service 97d2fb
  if (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0)
Packit Service 97d2fb
    error (EXIT_FAILURE, 0,
Packit Service 97d2fb
	   gettext ("cannot get section header string table index"));
Packit Service 97d2fb
Packit Service 97d2fb
  /* Cache the section names.  */
Packit Service 97d2fb
  Elf_Scn *scn = NULL;
Packit Service 97d2fb
  size_t cnt = 1;
Packit Service 97d2fb
  while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Shdr shdr_mem;
Packit Service 97d2fb
      GElf_Shdr *shdr;
Packit Service 97d2fb
Packit Service 97d2fb
      assert (elf_ndxscn (scn) == cnt);
Packit Service 97d2fb
      cnt++;
Packit Service 97d2fb
Packit Service 97d2fb
      char *name = NULL;
Packit Service 97d2fb
      shdr = gelf_getshdr (scn, &shdr_mem);
Packit Service 97d2fb
      if (shdr != NULL)
Packit Service 97d2fb
	name = elf_strptr (ebl->elf, shstrndx, shdr->sh_name);
Packit Service 97d2fb
      if (unlikely (name == NULL))
Packit Service 97d2fb
	name = "[invalid section name]";
Packit Service 97d2fb
      scnnames[elf_ndxscn (scn)] = name;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  int digits = length_map[gelf_getclass (ebl->elf) - 1][radix];
Packit Service 97d2fb
Packit Service 97d2fb
  /* We always print this prolog.  */
Packit Service 97d2fb
  printf (gettext ("\n\nSymbols from %s:\n\n"), fullname);
Packit Service 97d2fb
Packit Service 97d2fb
  /* The header line.  */
Packit Service 97d2fb
  printf (gettext ("%*s%-*s %-*s Class  Type     %-*s %*s Section\n\n"),
Packit Service 97d2fb
	  print_file_name ? (int) strlen (fullname) + 1: 0, "",
Packit Service 97d2fb
	  longest_name, sgettext ("sysv|Name"),
Packit Service 97d2fb
	  /* TRANS: the "sysv|" parts makes the string unique.  */
Packit Service 97d2fb
	  digits, sgettext ("sysv|Value"),
Packit Service 97d2fb
	  /* TRANS: the "sysv|" parts makes the string unique.  */
Packit Service 97d2fb
	  digits, sgettext ("sysv|Size"),
Packit Service 97d2fb
	  /* TRANS: the "sysv|" parts makes the string unique.  */
Packit Service 97d2fb
	  longest_where, sgettext ("sysv|Line"));
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef USE_DEMANGLE
Packit Service 97d2fb
  size_t demangle_buffer_len = 0;
Packit Service 97d2fb
  char *demangle_buffer = NULL;
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
  /* Iterate over all symbols.  */
Packit Service 97d2fb
  for (cnt = 0; cnt < nsyms; ++cnt)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* In this format SECTION entries are not printed.  */
Packit Service 97d2fb
      if (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_SECTION)
Packit Service 97d2fb
	continue;
Packit Service 97d2fb
Packit Service 97d2fb
      char symstrbuf[50];
Packit Service 97d2fb
      const char *symstr = sym_name (ebl->elf, strndx, syms[cnt].sym.st_name,
Packit Service 97d2fb
				     symstrbuf, sizeof symstrbuf);
Packit Service 97d2fb
Packit Service 97d2fb
      /* Printing entries with a zero-length name makes the output
Packit Service 97d2fb
	 not very well parseable.  Since these entries don't carry
Packit Service 97d2fb
	 much information we leave them out.  */
Packit Service 97d2fb
      if (symstr[0] == '\0')
Packit Service 97d2fb
	continue;
Packit Service 97d2fb
Packit Service 97d2fb
      /* We do not print the entries for files.  */
Packit Service 97d2fb
      if (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_FILE)
Packit Service 97d2fb
	continue;
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef USE_DEMANGLE
Packit Service 97d2fb
      /* Demangle if necessary.  Require GNU v3 ABI by the "_Z" prefix.  */
Packit Service 97d2fb
      if (demangle && symstr[0] == '_' && symstr[1] == 'Z')
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  int status = -1;
Packit Service 97d2fb
	  char *dmsymstr = __cxa_demangle (symstr, demangle_buffer,
Packit Service 97d2fb
					   &demangle_buffer_len, &status);
Packit Service 97d2fb
Packit Service 97d2fb
	  if (status == 0)
Packit Service 97d2fb
	    symstr = dmsymstr;
Packit Service 97d2fb
	}
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
      char symbindbuf[50];
Packit Service 97d2fb
      char symtypebuf[50];
Packit Service 97d2fb
      char secnamebuf[1024];
Packit Service 97d2fb
      char addressbuf[(64 + 2) / 3 + 1];
Packit Service 97d2fb
      char sizebuf[(64 + 2) / 3 + 1];
Packit Service 97d2fb
Packit Service 97d2fb
      /* If we have to precede the line with the file name.  */
Packit Service 97d2fb
      if (print_file_name)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  fputs_unlocked (fullname, stdout);
Packit Service 97d2fb
	  putchar_unlocked (':');
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Covert the address.  */
Packit Service 97d2fb
      if (syms[cnt].sym.st_shndx == SHN_UNDEF)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  sprintf (addressbuf, "%*c", digits, ' ');
Packit Service 97d2fb
	  sprintf (sizebuf, "%*c", digits, ' ');
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  snprintf (addressbuf, sizeof (addressbuf),
Packit Service 97d2fb
		    (radix == radix_hex ? "%0*" PRIx64
Packit Service 97d2fb
		     : (radix == radix_decimal ? "%0*" PRId64
Packit Service 97d2fb
			: "%0*" PRIo64)),
Packit Service 97d2fb
		    digits, syms[cnt].sym.st_value);
Packit Service 97d2fb
	  snprintf (sizebuf, sizeof (sizebuf),
Packit Service 97d2fb
		    (radix == radix_hex ? "%0*" PRIx64
Packit Service 97d2fb
		     : (radix == radix_decimal ? "%0*" PRId64
Packit Service 97d2fb
			: "%0*" PRIo64)),
Packit Service 97d2fb
		    digits, syms[cnt].sym.st_size);
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Print the actual string.  */
Packit Service 97d2fb
      const char *bind;
Packit Service 97d2fb
      bind = ebl_symbol_binding_name (ebl,
Packit Service 97d2fb
				      GELF_ST_BIND (syms[cnt].sym.st_info),
Packit Service 97d2fb
				      symbindbuf, sizeof (symbindbuf));
Packit Service 97d2fb
      if (bind != NULL && strncmp (bind, "GNU_", strlen ("GNU_")) == 0)
Packit Service 97d2fb
	bind += strlen ("GNU_");
Packit Service 97d2fb
      printf ("%-*s|%s|%-6s|%-8s|%s|%*s|%s\n",
Packit Service 97d2fb
	      longest_name, symstr, addressbuf, bind,
Packit Service 97d2fb
	      ebl_symbol_type_name (ebl, GELF_ST_TYPE (syms[cnt].sym.st_info),
Packit Service 97d2fb
				    symtypebuf, sizeof (symtypebuf)),
Packit Service 97d2fb
	      sizebuf, longest_where, syms[cnt].where,
Packit Service 97d2fb
	      ebl_section_name (ebl, syms[cnt].sym.st_shndx, syms[cnt].xndx,
Packit Service 97d2fb
				secnamebuf, sizeof (secnamebuf), scnnames,
Packit Service 97d2fb
				shnum));
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef USE_DEMANGLE
Packit Service 97d2fb
  free (demangle_buffer);
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
  if (scnnames_malloced)
Packit Service 97d2fb
    free (scnnames);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static char
Packit Service 97d2fb
class_type_char (Elf *elf, const GElf_Ehdr *ehdr, GElf_Sym *sym)
Packit Service 97d2fb
{
Packit Service 97d2fb
  int local_p = GELF_ST_BIND (sym->st_info) == STB_LOCAL;
Packit Service 97d2fb
Packit Service 97d2fb
  /* XXX Add support for architecture specific types and classes.  */
Packit Service 97d2fb
  if (sym->st_shndx == SHN_ABS)
Packit Service 97d2fb
    return local_p ? 'a' : 'A';
Packit Service 97d2fb
Packit Service 97d2fb
  if (sym->st_shndx == SHN_UNDEF)
Packit Service 97d2fb
    /* Undefined symbols must be global.  */
Packit Service 97d2fb
    return 'U';
Packit Service 97d2fb
Packit Service 97d2fb
  char result = "NDTSFBD         "[GELF_ST_TYPE (sym->st_info)];
Packit Service 97d2fb
Packit Service 97d2fb
  if (result == 'D')
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Special handling: unique data symbols.  */
Packit Service 97d2fb
      if (ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX
Packit Service 97d2fb
	  && GELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE)
Packit Service 97d2fb
	result = 'u';
Packit Service 97d2fb
      else if (GELF_ST_BIND (sym->st_info) == STB_WEAK)
Packit Service 97d2fb
	result = 'V';
Packit Service 97d2fb
      else if (sym->st_shndx == SHN_COMMON)
Packit Service 97d2fb
	result = 'C';
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  GElf_Shdr shdr_mem;
Packit Service 97d2fb
	  GElf_Shdr *shdr = gelf_getshdr (elf_getscn (elf, sym->st_shndx),
Packit Service 97d2fb
					  &shdr_mem);
Packit Service 97d2fb
	  if (shdr != NULL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      if ((shdr->sh_flags & SHF_WRITE) == 0)
Packit Service 97d2fb
		result = 'R';
Packit Service 97d2fb
	      else if (shdr->sh_type == SHT_NOBITS)
Packit Service 97d2fb
		result = 'B';
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else if (result == 'T')
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (GELF_ST_BIND (sym->st_info) == STB_WEAK)
Packit Service 97d2fb
	result = 'W';
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return local_p ? tolower (result) : result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
show_symbols_bsd (Elf *elf, const GElf_Ehdr *ehdr, GElf_Word strndx,
Packit Service 97d2fb
		  const char *prefix, const char *fname, const char *fullname,
Packit Service 97d2fb
		  GElf_SymX *syms, size_t nsyms)
Packit Service 97d2fb
{
Packit Service 97d2fb
  int digits = length_map[gelf_getclass (elf) - 1][radix];
Packit Service 97d2fb
Packit Service 97d2fb
  if (prefix != NULL && ! print_file_name)
Packit Service 97d2fb
    printf ("\n%s:\n", fname);
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef USE_DEMANGLE
Packit Service 97d2fb
  size_t demangle_buffer_len = 0;
Packit Service 97d2fb
  char *demangle_buffer = NULL;
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
  /* Iterate over all symbols.  */
Packit Service 97d2fb
  for (size_t cnt = 0; cnt < nsyms; ++cnt)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      char symstrbuf[50];
Packit Service 97d2fb
      const char *symstr = sym_name (elf, strndx, syms[cnt].sym.st_name,
Packit Service 97d2fb
				     symstrbuf, sizeof symstrbuf);
Packit Service 97d2fb
Packit Service 97d2fb
      /* Printing entries with a zero-length name makes the output
Packit Service 97d2fb
	 not very well parseable.  Since these entries don't carry
Packit Service 97d2fb
	 much information we leave them out.  */
Packit Service 97d2fb
      if (symstr[0] == '\0')
Packit Service 97d2fb
	continue;
Packit Service 97d2fb
Packit Service 97d2fb
      /* We do not print the entries for files.  */
Packit Service 97d2fb
      if (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_FILE)
Packit Service 97d2fb
	continue;
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef USE_DEMANGLE
Packit Service 97d2fb
      /* Demangle if necessary.  Require GNU v3 ABI by the "_Z" prefix.  */
Packit Service 97d2fb
      if (demangle && symstr[0] == '_' && symstr[1] == 'Z')
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  int status = -1;
Packit Service 97d2fb
	  char *dmsymstr = __cxa_demangle (symstr, demangle_buffer,
Packit Service 97d2fb
					   &demangle_buffer_len, &status);
Packit Service 97d2fb
Packit Service 97d2fb
	  if (status == 0)
Packit Service 97d2fb
	    symstr = dmsymstr;
Packit Service 97d2fb
	}
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
      /* If we have to precede the line with the file name.  */
Packit Service 97d2fb
      if (print_file_name)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  fputs_unlocked (fullname, stdout);
Packit Service 97d2fb
	  putchar_unlocked (':');
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      bool is_tls = GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_TLS;
Packit Service 97d2fb
      bool is_weak = GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK;
Packit Service 97d2fb
      const char *marker = (mark_special
Packit Service 97d2fb
			    ? (is_tls ? "@" : (is_weak ? "*" : " ")) : "");
Packit Service 97d2fb
Packit Service 97d2fb
      if (syms[cnt].sym.st_shndx == SHN_UNDEF)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  const char *color = "";
Packit Service 97d2fb
	  if (color_mode)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      if (is_tls)
Packit Service 97d2fb
		color = color_undef_tls;
Packit Service 97d2fb
	      else if (is_weak)
Packit Service 97d2fb
		color = color_undef_weak;
Packit Service 97d2fb
	      else
Packit Service 97d2fb
		color = color_undef;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  printf ("%*s %sU%s %s", digits, "", color, marker, symstr);
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  const char *color = "";
Packit Service 97d2fb
	  if (color_mode)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      if (is_tls)
Packit Service 97d2fb
		color = color_tls;
Packit Service 97d2fb
	      else if (is_weak)
Packit Service 97d2fb
		color = color_weak;
Packit Service 97d2fb
	      else
Packit Service 97d2fb
		color = color_symbol;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  if (print_size && syms[cnt].sym.st_size != 0)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
#define HEXFMT "%6$s%2$0*1$" PRIx64 "%8$s %10$0*9$" PRIx64 " %7$s%3$c%4$s %5$s"
Packit Service 97d2fb
#define DECFMT "%6$s%2$*1$" PRId64 "%8$s %10$*9$" PRId64 " %7$s%3$c%4$s %5$s"
Packit Service 97d2fb
#define OCTFMT "%6$s%2$0*1$" PRIo64 "%8$s %10$0*9$" PRIo64 " %7$s%3$c%4$s %5$s"
Packit Service 97d2fb
	      printf ((radix == radix_hex ? HEXFMT
Packit Service 97d2fb
		       : (radix == radix_decimal ? DECFMT : OCTFMT)),
Packit Service 97d2fb
		      digits, syms[cnt].sym.st_value,
Packit Service 97d2fb
		      class_type_char (elf, ehdr, &syms[cnt].sym), marker,
Packit Service 97d2fb
		      symstr,
Packit Service 97d2fb
		      color_mode ? color_address : "",
Packit Service 97d2fb
		      color,
Packit Service 97d2fb
		      color_mode ? color_off : "",
Packit Service 97d2fb
		      digits, (uint64_t) syms[cnt].sym.st_size);
Packit Service 97d2fb
#undef HEXFMT
Packit Service 97d2fb
#undef DECFMT
Packit Service 97d2fb
#undef OCTFMT
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    {
Packit Service 97d2fb
#define HEXFMT "%6$s%2$0*1$" PRIx64 "%8$s %7$s%3$c%4$s %5$s"
Packit Service 97d2fb
#define DECFMT "%6$s%2$*1$" PRId64 "%8$s %7$s%3$c%4$s %5$s"
Packit Service 97d2fb
#define OCTFMT "%6$s%2$0*1$" PRIo64 "%8$s %7$s%3$c%4$s %5$s"
Packit Service 97d2fb
	      printf ((radix == radix_hex ? HEXFMT
Packit Service 97d2fb
		       : (radix == radix_decimal ? DECFMT : OCTFMT)),
Packit Service 97d2fb
		      digits, syms[cnt].sym.st_value,
Packit Service 97d2fb
		      class_type_char (elf, ehdr, &syms[cnt].sym), marker,
Packit Service 97d2fb
		      symstr,
Packit Service 97d2fb
		      color_mode ? color_address : "",
Packit Service 97d2fb
		      color,
Packit Service 97d2fb
		      color_mode ? color_off : "");
Packit Service 97d2fb
#undef HEXFMT
Packit Service 97d2fb
#undef DECFMT
Packit Service 97d2fb
#undef OCTFMT
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      if (color_mode)
Packit Service 97d2fb
	fputs_unlocked (color_off, stdout);
Packit Service 97d2fb
      putchar_unlocked ('\n');
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef USE_DEMANGLE
Packit Service 97d2fb
  free (demangle_buffer);
Packit Service 97d2fb
#endif
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
show_symbols_posix (Elf *elf, const GElf_Ehdr *ehdr, GElf_Word strndx,
Packit Service 97d2fb
		    const char *prefix, const char *fullname, GElf_SymX *syms,
Packit Service 97d2fb
		    size_t nsyms)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (prefix != NULL && ! print_file_name)
Packit Service 97d2fb
    printf ("%s:\n", fullname);
Packit Service 97d2fb
Packit Service 97d2fb
  int digits = length_map[gelf_getclass (elf) - 1][radix];
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef USE_DEMANGLE
Packit Service 97d2fb
  size_t demangle_buffer_len = 0;
Packit Service 97d2fb
  char *demangle_buffer = NULL;
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
  /* Iterate over all symbols.  */
Packit Service 97d2fb
  for (size_t cnt = 0; cnt < nsyms; ++cnt)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      char symstrbuf[50];
Packit Service 97d2fb
      const char *symstr = sym_name (elf, strndx, syms[cnt].sym.st_name,
Packit Service 97d2fb
				     symstrbuf, sizeof symstrbuf);
Packit Service 97d2fb
Packit Service 97d2fb
      /* Printing entries with a zero-length name makes the output
Packit Service 97d2fb
	 not very well parseable.  Since these entries don't carry
Packit Service 97d2fb
	 much information we leave them out.  */
Packit Service 97d2fb
      if (symstr[0] == '\0')
Packit Service 97d2fb
	continue;
Packit Service 97d2fb
Packit Service 97d2fb
      /* We do not print the entries for files.  */
Packit Service 97d2fb
      if (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_FILE)
Packit Service 97d2fb
	continue;
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef USE_DEMANGLE
Packit Service 97d2fb
      /* Demangle if necessary.  Require GNU v3 ABI by the "_Z" prefix.  */
Packit Service 97d2fb
      if (demangle && symstr[0] == '_' && symstr[1] == 'Z')
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  int status = -1;
Packit Service 97d2fb
	  char *dmsymstr = __cxa_demangle (symstr, demangle_buffer,
Packit Service 97d2fb
					   &demangle_buffer_len, &status);
Packit Service 97d2fb
Packit Service 97d2fb
	  if (status == 0)
Packit Service 97d2fb
	    symstr = dmsymstr;
Packit Service 97d2fb
	}
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
      /* If we have to precede the line with the file name.  */
Packit Service 97d2fb
      if (print_file_name)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  fputs_unlocked (fullname, stdout);
Packit Service 97d2fb
	  putchar_unlocked (':');
Packit Service 97d2fb
	  putchar_unlocked (' ');
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      printf ("%s %c%s", symstr,
Packit Service 97d2fb
	      class_type_char (elf, ehdr, &syms[cnt].sym),
Packit Service 97d2fb
	      mark_special
Packit Service 97d2fb
	      ? (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_TLS
Packit Service 97d2fb
		 ? "@"
Packit Service 97d2fb
		 : (GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK
Packit Service 97d2fb
		    ? "*" : " "))
Packit Service 97d2fb
	      : "");
Packit Service 97d2fb
      if (syms[cnt].sym.st_shndx != SHN_UNDEF)
Packit Service 97d2fb
	printf ((radix == radix_hex
Packit Service 97d2fb
		 ? " %0*" PRIx64 " %0*" PRIx64
Packit Service 97d2fb
		 : (radix == radix_decimal
Packit Service 97d2fb
		    ? " %*" PRId64 " %*" PRId64
Packit Service 97d2fb
		    : " %0*" PRIo64 " %0*" PRIo64)),
Packit Service 97d2fb
		digits, syms[cnt].sym.st_value,
Packit Service 97d2fb
		digits, syms[cnt].sym.st_size);
Packit Service 97d2fb
      putchar ('\n');
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef USE_DEMANGLE
Packit Service 97d2fb
  free (demangle_buffer);
Packit Service 97d2fb
#endif
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Maximum size of memory we allocate on the stack.  */
Packit Service 97d2fb
#define MAX_STACK_ALLOC	65536
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
sort_by_address (const void *p1, const void *p2)
Packit Service 97d2fb
{
Packit Service 97d2fb
  GElf_SymX *s1 = (GElf_SymX *) p1;
Packit Service 97d2fb
  GElf_SymX *s2 = (GElf_SymX *) p2;
Packit Service 97d2fb
Packit Service 97d2fb
  int result = (s1->sym.st_value < s2->sym.st_value
Packit Service 97d2fb
		? -1 : (s1->sym.st_value == s2->sym.st_value ? 0 : 1));
Packit Service 97d2fb
Packit Service 97d2fb
  return reverse_sort ? -result : result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static Elf *sort_by_name_elf;
Packit Service 97d2fb
static size_t sort_by_name_ndx;
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
sort_by_name (const void *p1, const void *p2)
Packit Service 97d2fb
{
Packit Service 97d2fb
  GElf_SymX *s1 = (GElf_SymX *) p1;
Packit Service 97d2fb
  GElf_SymX *s2 = (GElf_SymX *) p2;
Packit Service 97d2fb
Packit Service 97d2fb
  const char *n1 = elf_strptr (sort_by_name_elf, sort_by_name_ndx,
Packit Service 97d2fb
			       s1->sym.st_name) ?: "";
Packit Service 97d2fb
  const char *n2 = elf_strptr (sort_by_name_elf, sort_by_name_ndx,
Packit Service 97d2fb
			       s2->sym.st_name) ?: "";
Packit Service 97d2fb
Packit Service 97d2fb
  int result = strcmp (n1, n2);
Packit Service 97d2fb
Packit Service 97d2fb
  return reverse_sort ? -result : result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Stub libdwfl callback, only the ELF handle already open is ever
Packit Service 97d2fb
   used.  Only used for finding the alternate debug file if the Dwarf
Packit Service 97d2fb
   comes from the main file.  We are not interested in separate
Packit Service 97d2fb
   debuginfo.  */
Packit Service 97d2fb
static int
Packit Service 97d2fb
find_no_debuginfo (Dwfl_Module *mod,
Packit Service 97d2fb
		   void **userdata,
Packit Service 97d2fb
		   const char *modname,
Packit Service 97d2fb
		   Dwarf_Addr base,
Packit Service 97d2fb
		   const char *file_name,
Packit Service 97d2fb
		   const char *debuglink_file,
Packit Service 97d2fb
		   GElf_Word debuglink_crc,
Packit Service 97d2fb
		   char **debuginfo_file_name)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwarf_Addr dwbias;
Packit Service 97d2fb
  dwfl_module_info (mod, NULL, NULL, NULL, &dwbias, NULL, NULL, NULL);
Packit Service 97d2fb
Packit Service 97d2fb
  /* We are only interested if the Dwarf has been setup on the main
Packit Service 97d2fb
     elf file but is only missing the alternate debug link.  If dwbias
Packit Service 97d2fb
     hasn't even been setup, this is searching for separate debuginfo
Packit Service 97d2fb
     for the main elf.  We don't care in that case.  */
Packit Service 97d2fb
  if (dwbias == (Dwarf_Addr) -1)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  return dwfl_standard_find_debuginfo (mod, userdata, modname, base,
Packit Service 97d2fb
				       file_name, debuglink_file,
Packit Service 97d2fb
				       debuglink_crc, debuginfo_file_name);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Get the Dwarf for the module/file we want.  */
Packit Service 97d2fb
struct getdbg
Packit Service 97d2fb
{
Packit Service 97d2fb
  const char *name;
Packit Service 97d2fb
  Dwarf **dbg;
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
getdbg_dwflmod (Dwfl_Module *dwflmod,
Packit Service 97d2fb
		void **userdata __attribute__ ((unused)),
Packit Service 97d2fb
		const char *name,
Packit Service 97d2fb
		Dwarf_Addr base __attribute__ ((unused)),
Packit Service 97d2fb
		void *arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct getdbg *get = (struct getdbg *) arg;
Packit Service 97d2fb
  if (get != NULL && get->name != NULL && strcmp (get->name, name) == 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Dwarf_Addr bias;
Packit Service 97d2fb
      *get->dbg = dwfl_module_getdwarf (dwflmod, &bias);
Packit Service 97d2fb
      return DWARF_CB_ABORT;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return DWARF_CB_OK;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
show_symbols (int fd, Ebl *ebl, GElf_Ehdr *ehdr,
Packit Service 97d2fb
	      Elf_Scn *scn, Elf_Scn *xndxscn,
Packit Service 97d2fb
	      GElf_Shdr *shdr, const char *prefix, const char *fname,
Packit Service 97d2fb
	      const char *fullname)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* Get the section header string table index.  */
Packit Service 97d2fb
  size_t shstrndx;
Packit Service 97d2fb
  if (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0)
Packit Service 97d2fb
    error (EXIT_FAILURE, 0,
Packit Service 97d2fb
	   gettext ("cannot get section header string table index"));
Packit Service 97d2fb
Packit Service 97d2fb
  /* The section is that large.  */
Packit Service 97d2fb
  size_t size = shdr->sh_size;
Packit Service 97d2fb
  /* One entry is this large.  */
Packit Service 97d2fb
  size_t entsize = shdr->sh_entsize;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Consistency checks.  */
Packit Service 97d2fb
  if (entsize == 0
Packit Service 97d2fb
      || entsize != gelf_fsize (ebl->elf, ELF_T_SYM, 1, EV_CURRENT))
Packit Service 97d2fb
    error (0, 0,
Packit Service 97d2fb
	   gettext ("%s: entry size in section %zd `%s' is not what we expect"),
Packit Service 97d2fb
	   fullname, elf_ndxscn (scn),
Packit Service 97d2fb
	   elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
Packit Service 97d2fb
  else if (size % entsize != 0)
Packit Service 97d2fb
    error (0, 0,
Packit Service 97d2fb
	   gettext ("%s: size of section %zd `%s' is not multiple of entry size"),
Packit Service 97d2fb
	   fullname, elf_ndxscn (scn),
Packit Service 97d2fb
	   elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
Packit Service 97d2fb
Packit Service 97d2fb
  /* Compute number of entries.  Handle buggy entsize values.  */
Packit Service 97d2fb
  size_t nentries = size / (entsize ?: 1);
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
#define obstack_chunk_alloc xmalloc
Packit Service 97d2fb
#define obstack_chunk_free free
Packit Service 97d2fb
  struct obstack whereob;
Packit Service 97d2fb
  obstack_init (&whereob);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Get a DWARF debugging descriptor.  It's no problem if this isn't
Packit Service 97d2fb
     possible.  We just won't print any line number information.  */
Packit Service 97d2fb
  Dwarf *dbg = NULL;
Packit Service 97d2fb
  Dwfl *dwfl = NULL;
Packit Service 97d2fb
  if (format == format_sysv)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (ehdr->e_type != ET_REL)
Packit Service 97d2fb
	dbg = dwarf_begin_elf (ebl->elf, DWARF_C_READ, NULL);
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Abuse libdwfl to do the relocations for us.  This is just
Packit Service 97d2fb
	     for the ET_REL file containing Dwarf, so no need for
Packit Service 97d2fb
	     fancy lookups.  */
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Duplicate an fd for dwfl_report_offline to swallow.  */
Packit Service 97d2fb
	  int dwfl_fd = dup (fd);
Packit Service 97d2fb
	  if (likely (dwfl_fd >= 0))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      static const Dwfl_Callbacks callbacks =
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  .section_address = dwfl_offline_section_address,
Packit Service 97d2fb
		  .find_debuginfo = find_no_debuginfo
Packit Service 97d2fb
		};
Packit Service 97d2fb
	      dwfl = dwfl_begin (&callbacks);
Packit Service 97d2fb
	      if (likely (dwfl != NULL))
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  /* Let 0 be the logical address of the file (or
Packit Service 97d2fb
		     first in archive).  */
Packit Service 97d2fb
		  dwfl->offline_next_address = 0;
Packit Service 97d2fb
		  if (dwfl_report_offline (dwfl, fname, fname, dwfl_fd)
Packit Service 97d2fb
		      == NULL)
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      /* Consumed on success, not on failure.  */
Packit Service 97d2fb
		      close (dwfl_fd);
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		  else
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      dwfl_report_end (dwfl, NULL, NULL);
Packit Service 97d2fb
Packit Service 97d2fb
		      struct getdbg get = { .name = fname, .dbg = &dbg };
Packit Service 97d2fb
		      dwfl_getmodules (dwfl, &getdbg_dwflmod, &get, 0);
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		}
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
      if (dbg != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  (void) dwarf_getpubnames (dbg, get_global, NULL, 0);
Packit Service 97d2fb
Packit Service 97d2fb
	  get_local_names (dbg);
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Get the data of the section.  */
Packit Service 97d2fb
  Elf_Data *data = elf_getdata (scn, NULL);
Packit Service 97d2fb
  Elf_Data *xndxdata = elf_getdata (xndxscn, NULL);
Packit Service 97d2fb
  if (data == NULL || (xndxscn != NULL && xndxdata == NULL))
Packit Service 97d2fb
    INTERNAL_ERROR (fullname);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Allocate the memory.
Packit Service 97d2fb
Packit Service 97d2fb
     XXX We can use a dirty trick here.  Since GElf_Sym == Elf64_Sym we
Packit Service 97d2fb
     can use the data memory instead of copying again if what we read
Packit Service 97d2fb
     is a 64 bit file.  */
Packit Service 97d2fb
  if (nentries > SIZE_MAX / sizeof (GElf_SymX))
Packit Service 97d2fb
    error (EXIT_FAILURE, 0,
Packit Service 97d2fb
          gettext ("%s: entries (%zd) in section %zd `%s' is too large"),
Packit Service 97d2fb
          fullname, nentries, elf_ndxscn (scn),
Packit Service 97d2fb
          elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
Packit Service 97d2fb
  GElf_SymX *sym_mem;
Packit Service 97d2fb
  if (nentries * sizeof (GElf_SymX) < MAX_STACK_ALLOC)
Packit Service 97d2fb
    sym_mem = (GElf_SymX *) alloca (nentries * sizeof (GElf_SymX));
Packit Service 97d2fb
  else
Packit Service 97d2fb
    sym_mem = (GElf_SymX *) xmalloc (nentries * sizeof (GElf_SymX));
Packit Service 97d2fb
Packit Service 97d2fb
  /* Iterate over all symbols.  */
Packit Service 97d2fb
#ifdef USE_DEMANGLE
Packit Service 97d2fb
  size_t demangle_buffer_len = 0;
Packit Service 97d2fb
  char *demangle_buffer = NULL;
Packit Service 97d2fb
#endif
Packit Service 97d2fb
  int longest_name = 4;
Packit Service 97d2fb
  int longest_where = 4;
Packit Service 97d2fb
  size_t nentries_used = 0;
Packit Service 97d2fb
  for (size_t cnt = 0; cnt < nentries; ++cnt)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Sym *sym = gelf_getsymshndx (data, xndxdata, cnt,
Packit Service 97d2fb
					&sym_mem[nentries_used].sym,
Packit Service 97d2fb
					&sym_mem[nentries_used].xndx);
Packit Service 97d2fb
      if (sym == NULL)
Packit Service 97d2fb
	INTERNAL_ERROR (fullname);
Packit Service 97d2fb
Packit Service 97d2fb
      /* Filter out administrative symbols without a name and those
Packit Service 97d2fb
	 deselected by the user with command line options.  */
Packit Service 97d2fb
      if ((hide_undefined && sym->st_shndx == SHN_UNDEF)
Packit Service 97d2fb
	  || (hide_defined && sym->st_shndx != SHN_UNDEF)
Packit Service 97d2fb
	  || (hide_local && GELF_ST_BIND (sym->st_info) == STB_LOCAL))
Packit Service 97d2fb
	continue;
Packit Service 97d2fb
Packit Service 97d2fb
      sym_mem[nentries_used].where = "";
Packit Service 97d2fb
      if (format == format_sysv)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  const char *symstr = elf_strptr (ebl->elf, shdr->sh_link,
Packit Service 97d2fb
					   sym->st_name);
Packit Service 97d2fb
	  if (symstr == NULL)
Packit Service 97d2fb
	    continue;
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef USE_DEMANGLE
Packit Service 97d2fb
	  /* Demangle if necessary.  Require GNU v3 ABI by the "_Z" prefix.  */
Packit Service 97d2fb
	  if (demangle && symstr[0] == '_' && symstr[1] == 'Z')
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      int status = -1;
Packit Service 97d2fb
	      char *dmsymstr = __cxa_demangle (symstr, demangle_buffer,
Packit Service 97d2fb
					       &demangle_buffer_len, &status);
Packit Service 97d2fb
Packit Service 97d2fb
	      if (status == 0)
Packit Service 97d2fb
		symstr = dmsymstr;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
	  longest_name = MAX ((size_t) longest_name, strlen (symstr));
Packit Service 97d2fb
Packit Service 97d2fb
	  if (sym->st_shndx != SHN_UNDEF
Packit Service 97d2fb
	      && GELF_ST_BIND (sym->st_info) != STB_LOCAL
Packit Service 97d2fb
	      && global_root != NULL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      Dwarf_Global fake = { .name = symstr };
Packit Service 97d2fb
	      Dwarf_Global **found = tfind (&fake, &global_root,
Packit Service 97d2fb
					    global_compare);
Packit Service 97d2fb
	      if (found != NULL)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  Dwarf_Die die_mem;
Packit Service 97d2fb
		  Dwarf_Die *die = dwarf_offdie (dbg, (*found)->die_offset,
Packit Service 97d2fb
						 &die_mem);
Packit Service 97d2fb
Packit Service 97d2fb
		  Dwarf_Die cudie_mem;
Packit Service 97d2fb
		  Dwarf_Die *cudie = NULL;
Packit Service 97d2fb
Packit Service 97d2fb
		  Dwarf_Addr lowpc;
Packit Service 97d2fb
		  Dwarf_Addr highpc;
Packit Service 97d2fb
		  if (die != NULL
Packit Service 97d2fb
		      && dwarf_lowpc (die, &lowpc) == 0
Packit Service 97d2fb
		      && lowpc <= sym->st_value
Packit Service 97d2fb
		      && dwarf_highpc (die, &highpc) == 0
Packit Service 97d2fb
		      && highpc > sym->st_value)
Packit Service 97d2fb
		    cudie = dwarf_offdie (dbg, (*found)->cu_offset,
Packit Service 97d2fb
					  &cudie_mem);
Packit Service 97d2fb
		  if (cudie != NULL)
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      Dwarf_Line *line = dwarf_getsrc_die (cudie,
Packit Service 97d2fb
							   sym->st_value);
Packit Service 97d2fb
		      if (line != NULL)
Packit Service 97d2fb
			{
Packit Service 97d2fb
			  /* We found the line.  */
Packit Service 97d2fb
			  int lineno;
Packit Service 97d2fb
			  (void) dwarf_lineno (line, &lineno);
Packit Service 97d2fb
			  const char *file = dwarf_linesrc (line, NULL, NULL);
Packit Service 97d2fb
			  file = (file != NULL) ? basename (file) : "???";
Packit Service 97d2fb
			  int n;
Packit Service 97d2fb
			  n = obstack_printf (&whereob, "%s:%d%c", file,
Packit Service 97d2fb
					      lineno, '\0');
Packit Service 97d2fb
			  sym_mem[nentries_used].where
Packit Service 97d2fb
			    = obstack_finish (&whereob);
Packit Service 97d2fb
Packit Service 97d2fb
			  /* The return value of obstack_print included the
Packit Service 97d2fb
			     NUL byte, so subtract one.  */
Packit Service 97d2fb
			  if (--n > (int) longest_where)
Packit Service 97d2fb
			    longest_where = (size_t) n;
Packit Service 97d2fb
			}
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		}
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Try to find the symbol among the local symbols.  */
Packit Service 97d2fb
	  if (sym_mem[nentries_used].where[0] == '\0')
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      struct local_name fake =
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  .name = symstr,
Packit Service 97d2fb
		  .lowpc = sym->st_value,
Packit Service 97d2fb
		  .highpc = sym->st_value,
Packit Service 97d2fb
		};
Packit Service 97d2fb
	      struct local_name **found = tfind (&fake, &local_root,
Packit Service 97d2fb
						 local_compare);
Packit Service 97d2fb
	      if (found != NULL)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  /* We found the line.  */
Packit Service 97d2fb
		  int n = obstack_printf (&whereob, "%s:%" PRIu64 "%c",
Packit Service 97d2fb
					  basename ((*found)->file),
Packit Service 97d2fb
					  (*found)->lineno,
Packit Service 97d2fb
					  '\0');
Packit Service 97d2fb
		  sym_mem[nentries_used].where = obstack_finish (&whereob);
Packit Service 97d2fb
Packit Service 97d2fb
		  /* The return value of obstack_print included the
Packit Service 97d2fb
		     NUL byte, so subtract one.  */
Packit Service 97d2fb
		  if (--n > (int) longest_where)
Packit Service 97d2fb
		    longest_where = (size_t) n;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* We use this entry.  */
Packit Service 97d2fb
      ++nentries_used;
Packit Service 97d2fb
    }
Packit Service 97d2fb
#ifdef USE_DEMANGLE
Packit Service 97d2fb
  free (demangle_buffer);
Packit Service 97d2fb
#endif
Packit Service 97d2fb
  /* Now we know the exact number.  */
Packit Service 97d2fb
  size_t nentries_orig = nentries;
Packit Service 97d2fb
  nentries = nentries_used;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Sort the entries according to the users wishes.  */
Packit Service 97d2fb
  if (sort == sort_name)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      sort_by_name_elf = ebl->elf;
Packit Service 97d2fb
      sort_by_name_ndx = shdr->sh_link;
Packit Service 97d2fb
      qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_name);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else if (sort == sort_numeric)
Packit Service 97d2fb
    qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_address);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Finally print according to the users selection.  */
Packit Service 97d2fb
  switch (format)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case format_sysv:
Packit Service 97d2fb
      show_symbols_sysv (ebl, shdr->sh_link, fullname, sym_mem, nentries,
Packit Service 97d2fb
			 longest_name, longest_where);
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case format_bsd:
Packit Service 97d2fb
      show_symbols_bsd (ebl->elf, ehdr, shdr->sh_link, prefix, fname, fullname,
Packit Service 97d2fb
			sym_mem, nentries);
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case format_posix:
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      assert (format == format_posix);
Packit Service 97d2fb
      show_symbols_posix (ebl->elf, ehdr, shdr->sh_link, prefix, fullname,
Packit Service 97d2fb
			  sym_mem, nentries);
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Free all memory.  */
Packit Service 97d2fb
  if (nentries_orig * sizeof (sym_mem[0]) >= MAX_STACK_ALLOC)
Packit Service 97d2fb
    free (sym_mem);
Packit Service 97d2fb
Packit Service 97d2fb
  obstack_free (&whereob, NULL);
Packit Service 97d2fb
Packit Service 97d2fb
  if (dbg != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      tdestroy (global_root, free);
Packit Service 97d2fb
      global_root = NULL;
Packit Service 97d2fb
Packit Service 97d2fb
      tdestroy (local_root, free);
Packit Service 97d2fb
      local_root = NULL;
Packit Service 97d2fb
Packit Service 97d2fb
      if (dwfl == NULL)
Packit Service 97d2fb
	(void) dwarf_end (dbg);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  if (dwfl != NULL)
Packit Service 97d2fb
    dwfl_end (dwfl);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
Packit Service 97d2fb
	    const char *suffix)
Packit Service 97d2fb
{
Packit Service 97d2fb
  size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
Packit Service 97d2fb
  size_t suffix_len = suffix == NULL ? 0 : strlen (suffix);
Packit Service 97d2fb
  size_t fname_len = strlen (fname) + 1;
Packit Service 97d2fb
  char fullname[prefix_len + 1 + fname_len + suffix_len];
Packit Service 97d2fb
  char *cp = fullname;
Packit Service 97d2fb
  Elf_Scn *scn = NULL;
Packit Service 97d2fb
  int any = 0;
Packit Service 97d2fb
  int result = 0;
Packit Service 97d2fb
  GElf_Ehdr ehdr_mem;
Packit Service 97d2fb
  GElf_Ehdr *ehdr;
Packit Service 97d2fb
  Ebl *ebl;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Create the full name of the file.  */
Packit Service 97d2fb
  if (prefix != NULL)
Packit Service 97d2fb
    cp = mempcpy (cp, prefix, prefix_len);
Packit Service 97d2fb
  cp = mempcpy (cp, fname, fname_len);
Packit Service 97d2fb
  if (suffix != NULL)
Packit Service 97d2fb
    memcpy (cp - 1, suffix, suffix_len + 1);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Get the backend for this object file type.  */
Packit Service 97d2fb
  ebl = ebl_openbackend (elf);
Packit Service 97d2fb
  if (ebl == NULL)
Packit Service 97d2fb
    INTERNAL_ERROR (fullname);
Packit Service 97d2fb
Packit Service 97d2fb
  /* We need the ELF header in a few places.  */
Packit Service 97d2fb
  ehdr = gelf_getehdr (elf, &ehdr_mem);
Packit Service 97d2fb
  if (ehdr == NULL)
Packit Service 97d2fb
    INTERNAL_ERROR (fullname);
Packit Service 97d2fb
Packit Service 97d2fb
  /* If we are asked to print the dynamic symbol table and this is
Packit Service 97d2fb
     executable or dynamic executable, fail.  */
Packit Service 97d2fb
  if (symsec_type == SHT_DYNSYM
Packit Service 97d2fb
      && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* XXX Add machine specific object file types.  */
Packit Service 97d2fb
      error (0, 0, gettext ("%s%s%s%s: Invalid operation"),
Packit Service 97d2fb
	     prefix ?: "", prefix ? "(" : "", fname, prefix ? ")" : "");
Packit Service 97d2fb
      result = 1;
Packit Service 97d2fb
      goto out;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Find the symbol table.
Packit Service 97d2fb
Packit Service 97d2fb
     XXX Can there be more than one?  Do we print all?  Currently we do.  */
Packit Service 97d2fb
  while ((scn = elf_nextscn (elf, scn)) != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Shdr shdr_mem;
Packit Service 97d2fb
      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
Packit Service 97d2fb
Packit Service 97d2fb
      if (shdr == NULL)
Packit Service 97d2fb
	INTERNAL_ERROR (fullname);
Packit Service 97d2fb
Packit Service 97d2fb
      if (shdr->sh_type == symsec_type)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  Elf_Scn *xndxscn = NULL;
Packit Service 97d2fb
Packit Service 97d2fb
	  /* We have a symbol table.  First make sure we remember this.  */
Packit Service 97d2fb
	  any = 1;
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Look for an extended section index table for this section.  */
Packit Service 97d2fb
	  if (symsec_type == SHT_SYMTAB)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      size_t scnndx = elf_ndxscn (scn);
Packit Service 97d2fb
Packit Service 97d2fb
	      while ((xndxscn = elf_nextscn (elf, xndxscn)) != NULL)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  GElf_Shdr xndxshdr_mem;
Packit Service 97d2fb
		  GElf_Shdr *xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem);
Packit Service 97d2fb
Packit Service 97d2fb
		  if (xndxshdr == NULL)
Packit Service 97d2fb
		    INTERNAL_ERROR (fullname);
Packit Service 97d2fb
Packit Service 97d2fb
		  if (xndxshdr->sh_type == SHT_SYMTAB_SHNDX
Packit Service 97d2fb
		      && xndxshdr->sh_link == scnndx)
Packit Service 97d2fb
		    break;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  show_symbols (fd, ebl, ehdr, scn, xndxscn, shdr, prefix, fname,
Packit Service 97d2fb
			fullname);
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (! any)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      error (0, 0, gettext ("%s%s%s: no symbols"),
Packit Service 97d2fb
	     prefix ?: "", prefix ? ":" : "", fname);
Packit Service 97d2fb
      result = 1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
 out:
Packit Service 97d2fb
  /* Close the ELF backend library descriptor.  */
Packit Service 97d2fb
  ebl_closebackend (ebl);
Packit Service 97d2fb
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
#include "debugpred.h"