summaryrefslogtreecommitdiffstats
path: root/src/readelf.c
diff options
context:
space:
mode:
authorBen Cheng <bccheng@google.com>2012-03-07 23:04:02 -0800
committerBen Cheng <bccheng@google.com>2012-03-08 17:00:54 -0800
commitcc6695e2684ce93cdf8bd2da63d55d2cf49ff076 (patch)
tree58f9941f89a1bde4e068610a507f86c6cb02eadf /src/readelf.c
parent669e96ff41a1b72aa034a26563d90b4768d51482 (diff)
downloadandroid_external_elfutils-cc6695e2684ce93cdf8bd2da63d55d2cf49ff076.tar.gz
android_external_elfutils-cc6695e2684ce93cdf8bd2da63d55d2cf49ff076.tar.bz2
android_external_elfutils-cc6695e2684ce93cdf8bd2da63d55d2cf49ff076.zip
Upgrade elfutils from version 0.97 to 0.138
This upgrade is in preparation for adding perf to the Android tree, where perf needs newer version of elfutils. This particular snapshot also cleans up the current makefile where only the host version of libelf.a (needed by elftree). Additional build targets for libebl.a, libebl_arm.a, and libebl_sh.a are eliminated since they are not used in the tree at all. Changes that build other target modules and associated modifications to work with bionic will be added later. Change-Id: Ifa808ba5ad2881ccb2c0cf44d134931faad801e1
Diffstat (limited to 'src/readelf.c')
-rw-r--r--src/readelf.c3836
1 files changed, 2870 insertions, 966 deletions
diff --git a/src/readelf.c b/src/readelf.c
index 6129e29d..2797a849 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -1,16 +1,28 @@
/* Print information from ELF file in human-readable form.
- Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
+ Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 1999.
- This program is Open Source software; you can redistribute it and/or
- modify it under the terms of the Open Software License version 1.0 as
- published by the Open Source Initiative.
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
- You should have received a copy of the Open Software License along
- with this program; if not, you may obtain a copy of the Open Software
- License version 1.0 from http://www.opensource.org/licenses/osl.php or
- by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
- 3001 King Ranch Road, Ukiah, CA 95482. */
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
@@ -18,6 +30,7 @@
#include <argp.h>
#include <assert.h>
+#include <ctype.h>
#include <dwarf.h>
#include <errno.h>
#include <error.h>
@@ -26,9 +39,10 @@
#include <inttypes.h>
#include <langinfo.h>
#include <libdw.h>
-#include <libebl.h>
+#include <libdwfl.h>
#include <libintl.h>
#include <locale.h>
+#include <stdarg.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
@@ -37,7 +51,11 @@
#include <sys/param.h>
#include <system.h>
+#include "../libelf/libelfP.h"
+#include "../libelf/common.h"
+#include "../libebl/libeblP.h"
#include "../libdw/libdwP.h"
+#include "../libdwfl/libdwflP.h"
#include "../libdw/memory-access.h"
@@ -45,30 +63,43 @@
static void print_version (FILE *stream, struct argp_state *state);
void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
+/* Bug report address. */
+const char *argp_program_bug_address = PACKAGE_BUGREPORT;
+
/* Definitions of arguments for argp functions. */
static const struct argp_option options[] =
{
- { NULL, 0, NULL, 0, N_("Output selection:") },
- { "all", 'a', NULL, 0, N_("Equivalent to: -h -l") },
- { "dynamic", 'd', NULL, 0, N_("Display the dynamic segment") },
- { "file-header", 'h', NULL, 0, N_("Display the ELF file header") },
+ { NULL, 0, NULL, 0, N_("Output selection:"), 0 },
+ { "all", 'a', NULL, 0, N_("Equivalent to: -h -l"), 0 },
+ { "dynamic", 'd', NULL, 0, N_("Display the dynamic segment"), 0 },
+ { "file-header", 'h', NULL, 0, N_("Display the ELF file header"), 0 },
{ "histogram", 'I', NULL, 0,
- N_("Display histogram of bucket list lengths") },
- { "program-headers", 'l', NULL, 0, N_("Display the program headers") },
- { "relocs", 'r', NULL, 0, N_("Display relocations") },
- { "section-headers", 'S', NULL, 0, N_("Display the sections' header") },
- { "symbols", 's', NULL, 0, N_("Display the symbol table") },
- { "version-info", 'V', NULL, 0, N_("Display versioning information") },
+ N_("Display histogram of bucket list lengths"), 0 },
+ { "program-headers", 'l', NULL, 0, N_("Display the program headers"), 0 },
+ { "segments", 'l', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 },
+ { "relocs", 'r', NULL, 0, N_("Display relocations"), 0 },
+ { "section-headers", 'S', NULL, 0, N_("Display the sections' header"), 0 },
+ { "sections", 'S', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 },
+ { "symbols", 's', NULL, 0, N_("Display the symbol table"), 0 },
+ { "version-info", 'V', NULL, 0, N_("Display versioning information"), 0 },
{ "debug-dump", 'w', "SECTION", OPTION_ARG_OPTIONAL,
N_("Display DWARF section content. SECTION can be one of abbrev, "
- "aranges, frame, info, loc, line, pubnames, str, or macinfo.") },
- { "notes", 'n', NULL, 0, N_("Display the core notes") },
+ "aranges, frame, info, loc, line, ranges, pubnames, str, or macinfo."),
+ 0 },
+ { "notes", 'n', NULL, 0, N_("Display the core notes"), 0 },
{ "arch-specific", 'A', NULL, 0,
- N_("Display architecture specific information (if any)") },
-
- { NULL, 0, NULL, 0, N_("Output control:") },
-
- { NULL, 0, NULL, 0, NULL }
+ N_("Display architecture specific information (if any)"), 0 },
+ { "hex-dump", 'x', "SECTION", 0,
+ N_("Dump the uninterpreted contents of SECTION, by number or name"), 0 },
+ { "strings", 'p', "SECTION", OPTION_ARG_OPTIONAL,
+ N_("Print string contents of sections"), 0 },
+ { "string-dump", 'p', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 },
+ { "archive-index", 'c', NULL, 0,
+ N_("Display the symbol index of an archive"), 0 },
+
+ { NULL, 0, NULL, 0, N_("Output control:"), 0 },
+
+ { NULL, 0, NULL, 0, NULL, 0 }
};
/* Short description of program. */
@@ -81,21 +112,15 @@ static const char args_doc[] = N_("FILE...");
/* Prototype for option handler. */
static error_t parse_opt (int key, char *arg, struct argp_state *state);
-/* Function to print some extra text in the help message. */
-static char *more_help (int key, const char *text, void *input);
-
/* Data structure to communicate with argp functions. */
static struct argp argp =
{
- options, parse_opt, args_doc, doc, NULL, more_help
+ options, parse_opt, args_doc, doc, NULL, NULL, NULL
};
/* Flags set by the option controlling the output. */
-/* True if any of the control options is set. */
-static bool any_control_option;
-
/* True if dynamic segment should be printed. */
static bool print_dynamic_table;
@@ -129,6 +154,15 @@ static bool print_arch;
/* True if note section content should be printed. */
static bool print_notes;
+/* True if SHF_STRINGS section content should be printed. */
+static bool print_string_sections;
+
+/* True if archive index should be printed. */
+static bool print_archive_index;
+
+/* True if any of the control options except print_archive_index is set. */
+static bool any_control_option;
+
/* Select printing of debugging sections. */
static enum section_e
{
@@ -141,102 +175,89 @@ static enum section_e
section_pubnames = 64,/* .debug_pubnames */
section_str = 128, /* .debug_str */
section_macinfo = 256,/* .debug_macinfo */
+ section_ranges = 512, /* .debug_ranges */
section_all = (section_abbrev | section_aranges | section_frame
| section_info | section_line | section_loc
- | section_pubnames | section_str | section_macinfo)
+ | section_pubnames | section_str | section_macinfo
+ | section_ranges)
} print_debug_sections;
+/* Select hex dumping of sections. */
+static struct section_argument *dump_data_sections;
+static struct section_argument **dump_data_sections_tail = &dump_data_sections;
+
+/* Select string dumping of sections. */
+static struct section_argument *string_sections;
+static struct section_argument **string_sections_tail = &string_sections;
+
+struct section_argument
+{
+ struct section_argument *next;
+ const char *arg;
+};
+
/* Number of sections in the file. */
static size_t shnum;
/* Declarations of local functions. */
-static void process_file (int fd, Elf *elf, const char *prefix,
- const char *fname, bool only_one);
-static void process_elf_file (Elf *elf, const char *prefix, const char *fname,
- bool only_one);
+static void process_file (int fd, const char *fname, bool only_one);
+static void process_elf_file (Dwfl_Module *dwflmod, int fd);
static void print_ehdr (Ebl *ebl, GElf_Ehdr *ehdr);
static void print_shdr (Ebl *ebl, GElf_Ehdr *ehdr);
static void print_phdr (Ebl *ebl, GElf_Ehdr *ehdr);
-static void print_scngrp (Ebl *ebl, GElf_Ehdr *ehdr);
+static void print_scngrp (Ebl *ebl);
static void print_dynamic (Ebl *ebl, GElf_Ehdr *ehdr);
-static void print_relocs (Ebl *ebl, GElf_Ehdr *ehdr);
-static void handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
- GElf_Shdr *shdr);
-static void handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
- GElf_Shdr *shdr);
-static void print_symtab (Ebl *ebl, GElf_Ehdr *ehdr, int type);
-static void handle_symtab (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
- GElf_Shdr *shdr);
-static void print_verinfo (Ebl *ebl, GElf_Ehdr *ehdr);
-static void handle_verneed (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
- GElf_Shdr *shdr);
-static void handle_verdef (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
- GElf_Shdr *shdr);
-static void handle_versym (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
+static void print_relocs (Ebl *ebl);
+static void handle_relocs_rel (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
+static void handle_relocs_rela (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
+static void print_symtab (Ebl *ebl, int type);
+static void handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
+static void print_verinfo (Ebl *ebl);
+static void handle_verneed (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
+static void handle_verdef (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
+static void handle_versym (Ebl *ebl, Elf_Scn *scn,
GElf_Shdr *shdr);
-static void print_debug (Ebl *ebl, GElf_Ehdr *ehdr);
-static void handle_hash (Ebl *ebl, GElf_Ehdr *ehdr);
+static void print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr);
+static void handle_hash (Ebl *ebl);
static void handle_notes (Ebl *ebl, GElf_Ehdr *ehdr);
-static void print_liblist (Ebl *ebl, GElf_Ehdr *ehdr);
+static void print_liblist (Ebl *ebl);
+static void print_attributes (Ebl *ebl, const GElf_Ehdr *ehdr);
+static void dump_data (Ebl *ebl);
+static void dump_strings (Ebl *ebl);
+static void print_strings (Ebl *ebl);
+static void dump_archive_index (Elf *, const char *);
int
main (int argc, char *argv[])
{
- int remaining;
- bool only_one;
-
/* Set locale. */
setlocale (LC_ALL, "");
/* Initialize the message catalog. */
- textdomain (PACKAGE);
+ textdomain (PACKAGE_TARNAME);
/* Parse and process arguments. */
+ int remaining;
argp_parse (&argp, argc, argv, 0, &remaining, NULL);
- /* If no control option or no ELF file is given punt. */
- if ((any_control_option == 0 && print_debug_sections == 0)
- || remaining >= argc)
- {
- argp_help (&argp, stdout, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR,
- program_invocation_short_name);
- exit (1);
- }
-
/* Before we start tell the ELF library which version we are using. */
elf_version (EV_CURRENT);
/* Now process all the files given at the command line. */
- only_one = remaining + 1 == argc;
+ bool only_one = remaining + 1 == argc;
do
{
- int fd;
- Elf *elf;
-
/* Open the file. */
- fd = open (argv[remaining], O_RDONLY);
+ int fd = open (argv[remaining], O_RDONLY);
if (fd == -1)
{
error (0, errno, gettext ("cannot open input file"));
continue;
}
- /* Create an `Elf' descriptor. */
- elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
- if (elf == NULL)
- error (0, 0, gettext ("cannot generate Elf descriptor: %s\n"),
- elf_errmsg (-1));
- else
- {
- process_file (fd, elf, NULL, argv[remaining], only_one);
-
- /* Now we can close the descriptor. */
- if (elf_end (elf) != 0)
- error (0, 0, gettext ("error while closing Elf descriptor: %s"),
- elf_errmsg (-1));
- }
+ process_file (fd, argv[remaining], only_one);
close (fd);
}
@@ -248,7 +269,8 @@ main (int argc, char *argv[])
/* Handle program arguments. */
static error_t
-parse_opt (int key, char *arg, struct argp_state *state)
+parse_opt (int key, char *arg,
+ struct argp_state *state __attribute__ ((unused)))
{
switch (key)
{
@@ -310,6 +332,9 @@ parse_opt (int key, char *arg, struct argp_state *state)
print_version_info = true;
any_control_option = true;
break;
+ case 'c':
+ print_archive_index = true;
+ break;
case 'w':
if (arg == NULL)
print_debug_sections = section_all;
@@ -317,6 +342,8 @@ parse_opt (int key, char *arg, struct argp_state *state)
print_debug_sections |= section_abbrev;
else if (strcmp (arg, "aranges") == 0)
print_debug_sections |= section_aranges;
+ else if (strcmp (arg, "ranges") == 0)
+ print_debug_sections |= section_ranges;
else if (strcmp (arg, "frame") == 0)
print_debug_sections |= section_frame;
else if (strcmp (arg, "info") == 0)
@@ -339,6 +366,40 @@ parse_opt (int key, char *arg, struct argp_state *state)
program_invocation_short_name);
exit (1);
}
+ any_control_option = true;
+ break;
+ case 'p':
+ any_control_option = true;
+ if (arg == NULL)
+ {
+ print_string_sections = true;
+ break;
+ }
+ /* Fall through. */
+ case 'x':
+ {
+ struct section_argument *a = xmalloc (sizeof *a);
+ a->arg = arg;
+ a->next = NULL;
+ struct section_argument ***tailp
+ = key == 'x' ? &dump_data_sections_tail : &string_sections_tail;
+ **tailp = a;
+ *tailp = &a->next;
+ }
+ any_control_option = true;
+ break;
+ case ARGP_KEY_NO_ARGS:
+ fputs (gettext ("Missing file name.\n"), stderr);
+ goto do_argp_help;
+ case ARGP_KEY_FINI:
+ if (! any_control_option && ! print_archive_index)
+ {
+ fputs (gettext ("No operation specified.\n"), stderr);
+ do_argp_help:
+ argp_help (&argp, stderr, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR,
+ program_invocation_short_name);
+ exit (1);
+ }
break;
default:
return ARGP_ERR_UNKNOWN;
@@ -347,177 +408,265 @@ parse_opt (int key, char *arg, struct argp_state *state)
}
-static char *
-more_help (int key, const char *text, void *input)
-{
- char *buf;
-
- switch (key)
- {
- case ARGP_KEY_HELP_EXTRA:
- /* We print some extra information. */
- if (asprintf (&buf, gettext ("Please report bugs to %s.\n"),
- PACKAGE_BUGREPORT) < 0)
- buf = NULL;
- return buf;
-
- default:
- break;
- }
- return (char *) text;
-}
-
-
/* Print the version information. */
static void
-print_version (FILE *stream, struct argp_state *state)
+print_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
{
- fprintf (stream, "readelf (%s) %s\n", PACKAGE_NAME, VERSION);
+ fprintf (stream, "readelf (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
fprintf (stream, gettext ("\
Copyright (C) %s Red Hat, Inc.\n\
This is free software; see the source for copying conditions. There is NO\n\
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
-"), "2004");
+"), "2008");
fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
}
-/* Process one file. */
+/* Check if the file is an archive, and if so dump its index. */
static void
-process_file (int fd, Elf *elf, const char *prefix, const char *fname,
- bool only_one)
+check_archive_index (int fd, const char *fname, bool only_one)
+{
+ /* Create an `Elf' descriptor. */
+ Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
+ if (elf == NULL)
+ error (0, 0, gettext ("cannot generate Elf descriptor: %s"),
+ elf_errmsg (-1));
+ else
+ {
+ if (elf_kind (elf) == ELF_K_AR)
+ {
+ if (!only_one)
+ printf ("\n%s:\n\n", fname);
+ dump_archive_index (elf, fname);
+ }
+ else
+ error (0, 0,
+ gettext ("'%s' is not an archive, cannot print archive index"),
+ fname);
+
+ /* Now we can close the descriptor. */
+ if (elf_end (elf) != 0)
+ error (0, 0, gettext ("error while closing Elf descriptor: %s"),
+ elf_errmsg (-1));
+ }
+}
+
+/* Trivial callback used for checking if we opened an archive. */
+static int
+count_dwflmod (Dwfl_Module *dwflmod __attribute__ ((unused)),
+ void **userdata __attribute__ ((unused)),
+ const char *name __attribute__ ((unused)),
+ Dwarf_Addr base __attribute__ ((unused)),
+ void *arg)
+{
+ if (*(bool *) arg)
+ return DWARF_CB_ABORT;
+ *(bool *) arg = true;
+ return DWARF_CB_OK;
+}
+
+struct process_dwflmod_args
{
- /* We can handle two types of files: ELF files and archives. */
- Elf_Kind kind = elf_kind (elf);
- struct stat64 st;
+ int fd;
+ bool only_one;
+};
- switch (kind)
+static int
+process_dwflmod (Dwfl_Module *dwflmod,
+ void **userdata __attribute__ ((unused)),
+ const char *name __attribute__ ((unused)),
+ Dwarf_Addr base __attribute__ ((unused)),
+ void *arg)
+{
+ const struct process_dwflmod_args *a = arg;
+
+ /* Print the file name. */
+ if (!a->only_one)
{
- case ELF_K_ELF:
- /* Yes! It's an ELF file. */
- process_elf_file (elf, prefix, fname, only_one);
- break;
+ const char *fname;
+ dwfl_module_info (dwflmod, NULL, NULL, NULL, NULL, NULL, &fname, NULL);
- case ELF_K_AR:
- {
- Elf *subelf;
- Elf_Cmd cmd = ELF_C_READ_MMAP;
- size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
- size_t fname_len = strlen (fname) + 1;
- char new_prefix[prefix_len + 1 + fname_len];
- char *cp = new_prefix;
-
- /* Create the full name of the file. */
- if (prefix != NULL)
- {
- cp = mempcpy (cp, prefix, prefix_len);
- *cp++ = ':';
- }
- memcpy (cp, fname, fname_len);
+ printf ("\n%s:\n\n", fname);
+ }
- /* It's an archive. We process each file in it. */
- while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
- {
- kind = elf_kind (subelf);
+ process_elf_file (dwflmod, a->fd);
- /* Call this function recursively. */
- if (kind == ELF_K_ELF || kind == ELF_K_AR)
- {
- Elf_Arhdr *arhdr = elf_getarhdr (subelf);
- assert (arhdr != NULL);
+ return DWARF_CB_OK;
+}
- process_file (fd, subelf, new_prefix, arhdr->ar_name, false);
- }
+/* Stub libdwfl callback, only the ELF handle already open is ever used. */
+static int
+find_no_debuginfo (Dwfl_Module *mod __attribute__ ((unused)),
+ void **userdata __attribute__ ((unused)),
+ const char *modname __attribute__ ((unused)),
+ Dwarf_Addr base __attribute__ ((unused)),
+ const char *file_name __attribute__ ((unused)),
+ const char *debuglink_file __attribute__ ((unused)),
+ GElf_Word debuglink_crc __attribute__ ((unused)),
+ char **debuginfo_file_name __attribute__ ((unused)))
+{
+ return -1;
+}
- /* Get next archive element. */
- cmd = elf_next (subelf);
- if (elf_end (subelf) != 0)
- error (0, 0,
- gettext (" error while freeing sub-ELF descriptor: %s\n"),
- elf_errmsg (-1));
- }
- }
- break;
+/* Process one input file. */
+static void
+process_file (int fd, const char *fname, bool only_one)
+{
+ if (print_archive_index)
+ check_archive_index (fd, fname, only_one);
- default:
+ if (!any_control_option)
+ return;
+
+ /* Duplicate an fd for dwfl_report_offline to swallow. */
+ int dwfl_fd = dup (fd);
+ if (unlikely (dwfl_fd < 0))
+ error (EXIT_FAILURE, errno, "dup");
+
+ /* Use libdwfl in a trivial way to open the libdw handle for us.
+ This takes care of applying relocations to DWARF data in ET_REL files. */
+ static const Dwfl_Callbacks callbacks =
+ {
+ .section_address = dwfl_offline_section_address,
+ .find_debuginfo = find_no_debuginfo
+ };
+ Dwfl *dwfl = dwfl_begin (&callbacks);
+ if (likely (dwfl != NULL))
+ /* Let 0 be the logical address of the file (or first in archive). */
+ dwfl->offline_next_address = 0;
+ if (dwfl_report_offline (dwfl, fname, fname, dwfl_fd) == NULL)
+ {
+ struct stat64 st;
if (fstat64 (fd, &st) != 0)
error (0, errno, gettext ("cannot stat input file"));
- else if (st.st_size == 0)
+ else if (unlikely (st.st_size == 0))
error (0, 0, gettext ("input file is empty"));
else
- /* We cannot do anything. */
- error (0, 0, gettext ("\
-Not an ELF file - it has the wrong magic bytes at the start"));
- break;
+ error (0, 0, gettext ("failed reading '%s': %s"),
+ fname, dwfl_errmsg (-1));
}
+ else
+ {
+ dwfl_report_end (dwfl, NULL, NULL);
+
+ if (only_one)
+ {
+ /* Clear ONLY_ONE if we have multiple modules, from an archive. */
+ bool seen = false;
+ only_one = dwfl_getmodules (dwfl, &count_dwflmod, &seen, 0) == 0;
+ }
+
+ /* Process the one or more modules gleaned from this file. */
+ struct process_dwflmod_args a = { .fd = fd, .only_one = only_one };
+ dwfl_getmodules (dwfl, &process_dwflmod, &a, 0);
+ }
+ dwfl_end (dwfl);
}
-/* Process one file. */
+/* Process one ELF file. */
static void
-process_elf_file (Elf *elf, const char *prefix, const char *fname,
- bool only_one)
+process_elf_file (Dwfl_Module *dwflmod, int fd)
{
+ GElf_Addr dwflbias;
+ Elf *elf = dwfl_module_getelf (dwflmod, &dwflbias);
+
GElf_Ehdr ehdr_mem;
GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
- Ebl *ebl;
-
- /* Print the file name. */
- if (!only_one)
- {
- if (prefix != NULL)
- printf ("\n%s(%s):\n\n", prefix, fname);
- else
- printf ("\n%s:\n\n", fname);
- }
if (ehdr == NULL)
{
+ elf_error:
error (0, 0, gettext ("cannot read ELF header: %s"), elf_errmsg (-1));
return;
}
- ebl = ebl_openbackend (elf);
- if (ebl == NULL)
+ Ebl *ebl = ebl_openbackend (elf);
+ if (unlikely (ebl == NULL))
{
+ ebl_error:
error (0, errno, gettext ("cannot create EBL handle"));
return;
}
/* Determine the number of sections. */
- if (elf_getshnum (ebl->elf, &shnum) < 0)
+ if (unlikely (elf_getshnum (ebl->elf, &shnum) < 0))
error (EXIT_FAILURE, 0,
gettext ("cannot determine number of sections: %s"),
elf_errmsg (-1));
+ /* For an ET_REL file, libdwfl has adjusted the in-core shdrs
+ and may have applied relocation to some sections.
+ So we need to get a fresh Elf handle on the file to display those. */
+ bool print_unrelocated = (print_section_header
+ || print_relocations
+ || dump_data_sections != NULL
+ || print_notes);
+
+ Elf *pure_elf = NULL;
+ Ebl *pure_ebl = ebl;
+ if (ehdr->e_type == ET_REL && print_unrelocated)
+ {
+ /* Read the file afresh. */
+ off64_t aroff = elf_getaroff (elf);
+ pure_elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
+ if (aroff > 0)
+ {
+ /* Archive member. */
+ (void) elf_rand (pure_elf, aroff);
+ Elf *armem = elf_begin (-1, ELF_C_READ_MMAP, pure_elf);
+ elf_end (pure_elf);
+ pure_elf = armem;
+ }
+ if (pure_elf == NULL)
+ goto elf_error;
+ pure_ebl = ebl_openbackend (pure_elf);
+ if (pure_ebl == NULL)
+ goto ebl_error;
+ }
+
if (print_file_header)
print_ehdr (ebl, ehdr);
if (print_section_header)
- print_shdr (ebl, ehdr);
+ print_shdr (pure_ebl, ehdr);
if (print_program_header)
print_phdr (ebl, ehdr);
if (print_section_groups)
- print_scngrp (ebl, ehdr);
+ print_scngrp (ebl);
if (print_dynamic_table)
print_dynamic (ebl, ehdr);
if (print_relocations)
- print_relocs (ebl, ehdr);
+ print_relocs (pure_ebl);
if (print_histogram)
- handle_hash (ebl, ehdr);
+ handle_hash (ebl);
if (print_symbol_table)
- print_symtab (ebl, ehdr, SHT_DYNSYM);
+ print_symtab (ebl, SHT_DYNSYM);
if (print_version_info)
- print_verinfo (ebl, ehdr);
+ print_verinfo (ebl);
if (print_symbol_table)
- print_symtab (ebl, ehdr, SHT_SYMTAB);
+ print_symtab (ebl, SHT_SYMTAB);
+ if (print_arch)
+ print_liblist (ebl);
if (print_arch)
- print_liblist (ebl, ehdr);
+ print_attributes (ebl, ehdr);
+ if (dump_data_sections != NULL)
+ dump_data (pure_ebl);
+ if (string_sections != NULL)
+ dump_strings (ebl);
if (print_debug_sections != 0)
- print_debug (ebl, ehdr);
+ print_debug (dwflmod, ebl, ehdr);
if (print_notes)
- handle_notes (ebl, ehdr);
+ handle_notes (pure_ebl, ehdr);
+ if (print_string_sections)
+ print_strings (ebl);
ebl_closebackend (ebl);
+
+ if (pure_ebl != ebl)
+ {
+ ebl_closebackend (pure_ebl);
+ elf_end (pure_elf);
+ }
}
@@ -525,9 +674,9 @@ process_elf_file (Elf *elf, const char *prefix, const char *fname,
static void
print_file_type (unsigned short int e_type)
{
- if (e_type <= ET_CORE)
+ if (likely (e_type <= ET_CORE))
{
- static const char *knowntypes[] =
+ static const char *const knowntypes[] =
{
N_("NONE (None)"),
N_("REL (Relocatable file)"),
@@ -550,11 +699,8 @@ print_file_type (unsigned short int e_type)
static void
print_ehdr (Ebl *ebl, GElf_Ehdr *ehdr)
{
- char buf[512];
- size_t cnt;
-
fputs_unlocked (gettext ("ELF Header:\n Magic: "), stdout);
- for (cnt = 0; cnt < EI_NIDENT; ++cnt)
+ for (size_t cnt = 0; cnt < EI_NIDENT; ++cnt)
printf (" %02hhx", ehdr->e_ident[cnt]);
printf (gettext ("\n Class: %s\n"),
@@ -568,11 +714,12 @@ print_ehdr (Ebl *ebl, GElf_Ehdr *ehdr)
: ehdr->e_ident[EI_DATA] == ELFDATA2MSB
? "2's complement, big endian" : "\?\?\?");
- printf (gettext (" Version: %hhd %s\n"),
+ printf (gettext (" Ident Version: %hhd %s\n"),
ehdr->e_ident[EI_VERSION],
ehdr->e_ident[EI_VERSION] == EV_CURRENT ? gettext ("(current)")
: "(\?\?\?)");
+ char buf[512];
printf (gettext (" OS/ABI: %s\n"),
ebl_osabi_name (ebl, ehdr->e_ident[EI_OSABI], buf, sizeof (buf)));
@@ -617,9 +764,7 @@ print_ehdr (Ebl *ebl, GElf_Ehdr *ehdr)
if (ehdr->e_shnum == 0)
{
GElf_Shdr shdr_mem;
- GElf_Shdr *shdr;
-
- shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
+ GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
if (shdr != NULL)
printf (gettext (" (%" PRIu32 " in [0].sh_size)"),
(uint32_t) shdr->sh_size);
@@ -628,12 +773,10 @@ print_ehdr (Ebl *ebl, GElf_Ehdr *ehdr)
}
fputc_unlocked ('\n', stdout);
- if (ehdr->e_shstrndx == SHN_XINDEX)
+ if (unlikely (ehdr->e_shstrndx == SHN_XINDEX))
{
GElf_Shdr shdr_mem;
- GElf_Shdr *shdr;
-
- shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
+ GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
if (shdr != NULL)
/* We managed to get the zeroth section. */
snprintf (buf, sizeof (buf), gettext (" (%" PRIu32 " in [0].sh_link)"),
@@ -686,7 +829,7 @@ There are %d section headers, starting at offset %#" PRIx64 ":\n\
ehdr->e_shnum, ehdr->e_shoff);
/* Get the section header string table index. */
- if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+ if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
error (EXIT_FAILURE, 0,
gettext ("cannot get section header string table index"));
@@ -699,24 +842,21 @@ There are %d section headers, starting at offset %#" PRIx64 ":\n\
for (cnt = 0; cnt < shnum; ++cnt)
{
- char buf[128];
- char flagbuf[20];
- char *cp;
Elf_Scn *scn = elf_getscn (ebl->elf, cnt);
- GElf_Shdr shdr_mem;
- GElf_Shdr *shdr;
- if (scn == NULL)
+ if (unlikely (scn == NULL))
error (EXIT_FAILURE, 0, gettext ("cannot get section: %s"),
elf_errmsg (-1));
/* Get the section header. */
- shdr = gelf_getshdr (scn, &shdr_mem);
- if (shdr == NULL)
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ if (unlikely (shdr == NULL))
error (EXIT_FAILURE, 0, gettext ("cannot get section header: %s"),
elf_errmsg (-1));
- cp = flagbuf;
+ char flagbuf[20];
+ char *cp = flagbuf;
if (shdr->sh_flags & SHF_WRITE)
*cp++ = 'W';
if (shdr->sh_flags & SHF_ALLOC)
@@ -743,6 +883,7 @@ There are %d section headers, starting at offset %#" PRIx64 ":\n\
*cp++ = 'E';
*cp = '\0';
+ char buf[128];
printf ("[%2zu] %-20s %-12s %0*" PRIx64 " %0*" PRIx64 " %0*" PRIx64
" %2" PRId64 " %-5s %2" PRId32 " %3" PRId32
" %2" PRId64 "\n",
@@ -765,9 +906,6 @@ There are %d section headers, starting at offset %#" PRIx64 ":\n\
static void
print_phdr (Ebl *ebl, GElf_Ehdr *ehdr)
{
- size_t cnt;
- size_t shstrndx;
-
if (ehdr->e_phnum == 0)
/* No program header, this is OK in relocatable objects. */
return;
@@ -784,14 +922,14 @@ print_phdr (Ebl *ebl, GElf_Ehdr *ehdr)
bool has_relro = false;
GElf_Addr relro_from = 0;
GElf_Addr relro_to = 0;
- for (cnt = 0; cnt < ehdr->e_phnum; ++cnt)
+ for (size_t cnt = 0; cnt < ehdr->e_phnum; ++cnt)
{
char buf[128];
GElf_Phdr mem;
GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &mem);
/* If for some reason the header cannot be returned show this. */
- if (phdr == NULL)
+ if (unlikely (phdr == NULL))
{
puts (" ???");
continue;
@@ -829,42 +967,40 @@ print_phdr (Ebl *ebl, GElf_Ehdr *ehdr)
}
/* Get the section header string table index. */
- if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+ size_t shstrndx;
+ if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
error (EXIT_FAILURE, 0,
gettext ("cannot get section header string table index"));
puts (gettext ("\n Section to Segment mapping:\n Segment Sections..."));
- for (cnt = 0; cnt < ehdr->e_phnum; ++cnt)
+ for (size_t cnt = 0; cnt < ehdr->e_phnum; ++cnt)
{
- GElf_Phdr phdr_mem;
- GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &phdr_mem);
- size_t inner;
-
/* Print the segment number. */
printf (" %2.2zu ", cnt);
+ GElf_Phdr phdr_mem;
+ GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &phdr_mem);
/* This must not happen. */
- if (phdr == NULL)
+ if (unlikely (phdr == NULL))
error (EXIT_FAILURE, 0, gettext ("cannot get program header: %s"),
elf_errmsg (-1));
/* Iterate over the sections. */
bool in_relro = false;
- for (inner = 1; inner < shnum; ++inner)
+ bool in_ro = false;
+ for (size_t inner = 1; inner < shnum; ++inner)
{
Elf_Scn *scn = elf_getscn (ebl->elf, inner);
- GElf_Shdr shdr_mem;
- GElf_Shdr *shdr;
-
- /* It should not happen. */
- if (scn == NULL)
+ /* This should not happen. */
+ if (unlikely (scn == NULL))
error (EXIT_FAILURE, 0, gettext ("cannot get section: %s"),
elf_errmsg (-1));
/* Get the section header. */
- shdr = gelf_getshdr (scn, &shdr_mem);
- if (shdr == NULL)
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ if (unlikely (shdr == NULL))
error (EXIT_FAILURE, 0,
gettext ("cannot get section header: %s"),
elf_errmsg (-1));
@@ -895,6 +1031,45 @@ print_phdr (Ebl *ebl, GElf_Ehdr *ehdr)
else if (has_relro && in_relro
&& shdr->sh_addr + shdr->sh_size > relro_to)
fputs_unlocked ("] <RELRO:", stdout);
+ else if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_W) == 0)
+ {
+ if (!in_ro)
+ {
+ fputs_unlocked (" [RO:", stdout);
+ in_ro = true;
+ }
+ }
+ else
+ {
+ /* Determine the segment this section is part of. */
+ size_t cnt2;
+ GElf_Phdr *phdr2 = NULL;
+ for (cnt2 = 0; cnt2 < ehdr->e_phnum; ++cnt2)
+ {
+ GElf_Phdr phdr2_mem;
+ phdr2 = gelf_getphdr (ebl->elf, cnt2, &phdr2_mem);
+
+ if (phdr2 != NULL && phdr2->p_type == PT_LOAD
+ && shdr->sh_addr >= phdr2->p_vaddr
+ && (shdr->sh_addr + shdr->sh_size
+ <= phdr2->p_vaddr + phdr2->p_memsz))
+ break;
+ }
+
+ if (cnt2 < ehdr->e_phnum)
+ {
+ if ((phdr2->p_flags & PF_W) == 0 && !in_ro)
+ {
+ fputs_unlocked (" [RO:", stdout);
+ in_ro = true;
+ }
+ else if ((phdr2->p_flags & PF_W) != 0 && in_ro)
+ {
+ fputs_unlocked ("]", stdout);
+ in_ro = false;
+ }
+ }
+ }
printf (" %s",
elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
@@ -908,7 +1083,7 @@ print_phdr (Ebl *ebl, GElf_Ehdr *ehdr)
}
}
}
- if (in_relro)
+ if (in_relro || in_ro)
fputs_unlocked ("]", stdout);
/* Finish the line. */
@@ -918,36 +1093,29 @@ print_phdr (Ebl *ebl, GElf_Ehdr *ehdr)
static void
-handle_scngrp (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
+handle_scngrp (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
{
- Elf_Data *data;
- Elf32_Word *grpref;
- Elf_Scn *symscn;
- GElf_Shdr symshdr_mem;
- GElf_Shdr *symshdr;
- Elf_Data *symdata;
- GElf_Sym sym_mem;
- size_t cnt;
- size_t shstrndx;
-
/* Get the data of the section. */
- data = elf_getdata (scn, NULL);
+ Elf_Data *data = elf_getdata (scn, NULL);
- symscn = elf_getscn (ebl->elf, shdr->sh_link);
- symshdr = gelf_getshdr (symscn, &symshdr_mem);
- symdata = elf_getdata (symscn, NULL);
+ Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
+ GElf_Shdr symshdr_mem;
+ GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
+ Elf_Data *symdata = elf_getdata (symscn, NULL);
if (data == NULL || data->d_size < sizeof (Elf32_Word) || symshdr == NULL
|| symdata == NULL)
return;
/* Get the section header string table index. */
- if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+ size_t shstrndx;
+ if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
error (EXIT_FAILURE, 0,
gettext ("cannot get section header string table index"));
- grpref = (Elf32_Word *) data->d_buf;
+ Elf32_Word *grpref = (Elf32_Word *) data->d_buf;
+ GElf_Sym sym_mem;
printf ((grpref[0] & GRP_COMDAT)
? ngettext ("\
\nCOMDAT section group [%2zu] '%s' with signature '%s' contains %zu entry:\n",
@@ -965,27 +1133,24 @@ handle_scngrp (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
?: gettext ("<INVALID SYMBOL>"),
data->d_size / sizeof (Elf32_Word) - 1);
- for (cnt = 1; cnt < data->d_size / sizeof (Elf32_Word); ++cnt)
+ for (size_t cnt = 1; cnt < data->d_size / sizeof (Elf32_Word); ++cnt)
{
GElf_Shdr grpshdr_mem;
- GElf_Shdr *grpshdr;
-
- grpshdr = gelf_getshdr (elf_getscn (ebl->elf, grpref[cnt]),
- &grpshdr_mem);
-
- if (grpshdr == NULL)
- printf (gettext (" [%2u] <INVALID SECTION>\n"), grpref[cnt]);
- else
- printf (" [%2u] %s\n",
- grpref[cnt],
- elf_strptr (ebl->elf, shstrndx, grpshdr->sh_name)
- ?: gettext ("<INVALID SECTION>"));
+ GElf_Shdr *grpshdr = gelf_getshdr (elf_getscn (ebl->elf, grpref[cnt]),
+ &grpshdr_mem);
+
+ const char *str;
+ printf (" [%2u] %s\n",
+ grpref[cnt],
+ grpshdr != NULL
+ && (str = elf_strptr (ebl->elf, shstrndx, grpshdr->sh_name))
+ ? str : gettext ("<INVALID SECTION>"));
}
}
static void
-print_scngrp (Ebl *ebl, GElf_Ehdr *ehdr)
+print_scngrp (Ebl *ebl)
{
/* Find all relocation sections and handle them. */
Elf_Scn *scn = NULL;
@@ -997,7 +1162,7 @@ print_scngrp (Ebl *ebl, GElf_Ehdr *ehdr)
GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
if (shdr != NULL && shdr->sh_type == SHT_GROUP)
- handle_scngrp (ebl, ehdr, scn, shdr);
+ handle_scngrp (ebl, scn, shdr);
}
}
@@ -1112,7 +1277,7 @@ print_dt_posflag_1 (int class, GElf_Xword d_val)
static void
-handle_dynamic (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
+handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
{
int class = gelf_getclass (ebl->elf);
GElf_Shdr glink;
@@ -1126,7 +1291,7 @@ handle_dynamic (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
return;
/* Get the section header string table index. */
- if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+ if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
error (EXIT_FAILURE, 0,
gettext ("cannot get section header string table index"));
@@ -1146,14 +1311,12 @@ handle_dynamic (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
for (cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt)
{
- char buf[64];
GElf_Dyn dynmem;
- GElf_Dyn *dyn;
-
- dyn = gelf_getdyn (data, cnt, &dynmem);
+ GElf_Dyn *dyn = gelf_getdyn (data, cnt, &dynmem);
if (dyn == NULL)
break;
+ char buf[64];
printf (" %-17s ",
ebl_dynamic_tag_name (ebl, dyn->d_tag, buf, sizeof (buf)));
@@ -1164,7 +1327,7 @@ handle_dynamic (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
case DT_BIND_NOW:
case DT_TEXTREL:
/* No further output. */
- fputc ('\n', stdout);
+ fputc_unlocked ('\n', stdout);
break;
case DT_NEEDED:
@@ -1246,18 +1409,18 @@ handle_dynamic (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
static void
print_dynamic (Ebl *ebl, GElf_Ehdr *ehdr)
{
- /* Find all relocation sections and handle them. */
- Elf_Scn *scn = NULL;
-
- while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
+ for (int i = 0; i < ehdr->e_phnum; ++i)
{
- /* Handle the section if it is a symbol table. */
- GElf_Shdr shdr_mem;
- GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ GElf_Phdr phdr_mem;
+ GElf_Phdr *phdr = gelf_getphdr (ebl->elf, i, &phdr_mem);
- if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC)
+ if (phdr != NULL && phdr->p_type == PT_DYNAMIC)
{
- handle_dynamic (ebl, ehdr, scn, shdr);
+ Elf_Scn *scn = gelf_offscn (ebl->elf, phdr->p_offset);
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC)
+ handle_dynamic (ebl, scn, shdr);
break;
}
}
@@ -1266,7 +1429,7 @@ print_dynamic (Ebl *ebl, GElf_Ehdr *ehdr)
/* Print relocations. */
static void
-print_relocs (Ebl *ebl, GElf_Ehdr *ehdr)
+print_relocs (Ebl *ebl)
{
/* Find all relocation sections and handle them. */
Elf_Scn *scn = NULL;
@@ -1277,12 +1440,12 @@ print_relocs (Ebl *ebl, GElf_Ehdr *ehdr)
GElf_Shdr shdr_mem;
GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
- if (shdr != NULL)
+ if (likely (shdr != NULL))
{
if (shdr->sh_type == SHT_REL)
- handle_relocs_rel (ebl, ehdr, scn, shdr);
+ handle_relocs_rel (ebl, scn, shdr);
else if (shdr->sh_type == SHT_RELA)
- handle_relocs_rela (ebl, ehdr, scn, shdr);
+ handle_relocs_rela (ebl, scn, shdr);
}
}
}
@@ -1290,37 +1453,28 @@ print_relocs (Ebl *ebl, GElf_Ehdr *ehdr)
/* Handle a relocation section. */
static void
-handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
+handle_relocs_rel (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
{
int class = gelf_getclass (ebl->elf);
int nentries = shdr->sh_size / shdr->sh_entsize;
- int cnt;
- Elf_Data *data;
- Elf_Scn *symscn;
- GElf_Shdr symshdr_mem;
- GElf_Shdr *symshdr;
- Elf_Data *symdata;
- GElf_Shdr destshdr_mem;
- GElf_Shdr *destshdr;
- Elf_Scn *xndxscn;
- Elf_Data *xndxdata = NULL;
- size_t shstrndx;
/* Get the data of the section. */
- data = elf_getdata (scn, NULL);
+ Elf_Data *data = elf_getdata (scn, NULL);
if (data == NULL)
return;
/* Get the symbol table information. */
- symscn = elf_getscn (ebl->elf, shdr->sh_link);
- symshdr = gelf_getshdr (symscn, &symshdr_mem);
- symdata = elf_getdata (symscn, NULL);
+ Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
+ GElf_Shdr symshdr_mem;
+ GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
+ Elf_Data *symdata = elf_getdata (symscn, NULL);
/* Get the section header of the section the relocations are for. */
- destshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info),
- &destshdr_mem);
+ GElf_Shdr destshdr_mem;
+ GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info),
+ &destshdr_mem);
- if (symshdr == NULL || symdata == NULL || destshdr == NULL)
+ if (unlikely (symshdr == NULL || symdata == NULL || destshdr == NULL))
{
printf (gettext ("\nInvalid symbol table at offset %#0" PRIx64 "\n"),
shdr->sh_offset);
@@ -1328,24 +1482,14 @@ handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
}
/* Search for the optional extended section index table. */
- xndxscn = NULL;
- while ((xndxscn = elf_nextscn (ebl->elf, xndxscn)) != NULL)
- {
- GElf_Shdr xndxshdr_mem;
- GElf_Shdr *xndxshdr;
-
- xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem);
- if (xndxshdr != NULL && xndxshdr->sh_type == SHT_SYMTAB_SHNDX
- && xndxshdr->sh_link == elf_ndxscn (symscn))
- {
- /* Found it. */
- xndxdata = elf_getdata (xndxscn, NULL);
- break;
- }
- }
+ Elf_Data *xndxdata = NULL;
+ int xndxscnidx = elf_scnshndx (scn);
+ if (unlikely (xndxscnidx > 0))
+ xndxdata = elf_getdata (elf_getscn (ebl->elf, xndxscnidx), NULL);
/* Get the section header string table index. */
- if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+ size_t shstrndx;
+ if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
error (EXIT_FAILURE, 0,
gettext ("cannot get section header string table index"));
@@ -1381,22 +1525,19 @@ handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
Offset Type Value Name\n"),
stdout);
- for (cnt = 0; cnt < nentries; ++cnt)
+ for (int cnt = 0; cnt < nentries; ++cnt)
{
GElf_Rel relmem;
- GElf_Rel *rel;
-
- rel = gelf_getrel (data, cnt, &relmem);
- if (rel != NULL)
+ GElf_Rel *rel = gelf_getrel (data, cnt, &relmem);
+ if (likely (rel != NULL))
{
char buf[128];
GElf_Sym symmem;
- GElf_Sym *sym;
Elf32_Word xndx;
-
- sym = gelf_getsymshndx (symdata, xndxdata, GELF_R_SYM (rel->r_info),
- &symmem, &xndx);
- if (sym == NULL)
+ GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata,
+ GELF_R_SYM (rel->r_info),
+ &symmem, &xndx);
+ if (unlikely (sym == NULL))
printf (" %#0*" PRIx64 " %-20s <%s %ld>\n",
class == ELFCLASS32 ? 10 : 18, rel->r_offset,
ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
@@ -1410,7 +1551,8 @@ handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
printf (" %#0*" PRIx64 " %-20s %#0*" PRIx64 " %s\n",
class == ELFCLASS32 ? 10 : 18, rel->r_offset,
- ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+ likely (ebl_reloc_type_check (ebl,
+ GELF_R_TYPE (rel->r_info)))
/* Avoid the leading R_ which isn't carrying any
information. */
? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
@@ -1425,7 +1567,7 @@ handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
? xndx : sym->st_shndx),
&destshdr_mem);
- if (shdr == NULL)
+ if (unlikely (destshdr == NULL))
printf (" %#0*" PRIx64 " %-20s <%s %ld>\n",
class == ELFCLASS32 ? 10 : 18, rel->r_offset,
ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
@@ -1456,7 +1598,7 @@ handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
/* Handle a relocation section. */
static void
-handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
+handle_relocs_rela (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
{
int class = gelf_getclass (ebl->elf);
int nentries = shdr->sh_size / shdr->sh_entsize;
@@ -1477,7 +1619,7 @@ handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info),
&destshdr_mem);
- if (symshdr == NULL || symdata == NULL || destshdr == NULL)
+ if (unlikely (symshdr == NULL || symdata == NULL || destshdr == NULL))
{
printf (gettext ("\nInvalid symbol table at offset %#0" PRIx64 "\n"),
shdr->sh_offset);
@@ -1486,25 +1628,13 @@ handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
/* Search for the optional extended section index table. */
Elf_Data *xndxdata = NULL;
- Elf_Scn *xndxscn = NULL;
- while ((xndxscn = elf_nextscn (ebl->elf, xndxscn)) != NULL)
- {
- GElf_Shdr xndxshdr_mem;
- GElf_Shdr *xndxshdr;
-
- xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem);
- if (xndxshdr != NULL && xndxshdr->sh_type == SHT_SYMTAB_SHNDX
- && xndxshdr->sh_link == elf_ndxscn (symscn))
- {
- /* Found it. */
- xndxdata = elf_getdata (xndxscn, NULL);
- break;
- }
- }
+ int xndxscnidx = elf_scnshndx (scn);
+ if (unlikely (xndxscnidx > 0))
+ xndxdata = elf_getdata (elf_getscn (ebl->elf, xndxscnidx), NULL);
/* Get the section header string table index. */
size_t shstrndx;
- if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+ if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
error (EXIT_FAILURE, 0,
gettext ("cannot get section header string table index"));
@@ -1530,17 +1660,16 @@ handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
{
GElf_Rela relmem;
GElf_Rela *rel = gelf_getrela (data, cnt, &relmem);
- if (rel != NULL)
+ if (likely (rel != NULL))
{
char buf[64];
GElf_Sym symmem;
- GElf_Sym *sym;
Elf32_Word xndx;
+ GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata,
+ GELF_R_SYM (rel->r_info),
+ &symmem, &xndx);
- sym = gelf_getsymshndx (symdata, xndxdata, GELF_R_SYM (rel->r_info),
- &symmem, &xndx);
-
- if (sym == NULL)
+ if (unlikely (sym == NULL))
printf (" %#0*" PRIx64 " %-15s <%s %ld>\n",
class == ELFCLASS32 ? 10 : 18, rel->r_offset,
ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
@@ -1553,9 +1682,10 @@ handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
(long int) GELF_R_SYM (rel->r_info));
else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
printf ("\
- %#0*" PRIx64 " %-15s %#0*" PRIx64 " +%5" PRId64 " %s\n",
+ %#0*" PRIx64 " %-15s %#0*" PRIx64 " %+6" PRId64 " %s\n",
class == ELFCLASS32 ? 10 : 18, rel->r_offset,
- ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+ likely (ebl_reloc_type_check (ebl,
+ GELF_R_TYPE (rel->r_info)))
/* Avoid the leading R_ which isn't carrying any
information. */
? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
@@ -1571,7 +1701,7 @@ handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
? xndx : sym->st_shndx),
&destshdr_mem);
- if (shdr == NULL)
+ if (unlikely (shdr == NULL))
printf (" %#0*" PRIx64 " %-15s <%s %ld>\n",
class == ELFCLASS32 ? 10 : 18, rel->r_offset,
ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
@@ -1585,7 +1715,7 @@ handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
? xndx : sym->st_shndx));
else
printf ("\
- %#0*" PRIx64 " %-15s %#0*" PRIx64 " +%5" PRId64 " %s\n",
+ %#0*" PRIx64 " %-15s %#0*" PRIx64 " %+6" PRId64 " %s\n",
class == ELFCLASS32 ? 10 : 18, rel->r_offset,
ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
/* Avoid the leading R_ which isn't carrying any
@@ -1604,7 +1734,7 @@ handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
/* Print the program header. */
static void
-print_symtab (Ebl *ebl, GElf_Ehdr *ehdr, int type)
+print_symtab (Ebl *ebl, int type)
{
/* Find the symbol table(s). For this we have to search through the
section table. */
@@ -1617,41 +1747,35 @@ print_symtab (Ebl *ebl, GElf_Ehdr *ehdr, int type)
GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
if (shdr != NULL && shdr->sh_type == (GElf_Word) type)
- handle_symtab (ebl, ehdr, scn, shdr);
+ handle_symtab (ebl, scn, shdr);
}
}
static void
-handle_symtab (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
+handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
{
Elf_Data *versym_data = NULL;
Elf_Data *verneed_data = NULL;
Elf_Data *verdef_data = NULL;
Elf_Data *xndx_data = NULL;
- Elf_Scn *runscn;
- Elf_Data *data;
int class = gelf_getclass (ebl->elf);
- unsigned int nsyms;
- unsigned int cnt;
Elf32_Word verneed_stridx = 0;
Elf32_Word verdef_stridx = 0;
- GElf_Shdr glink;
- size_t shstrndx;
/* Get the data of the section. */
- data = elf_getdata (scn, NULL);
+ Elf_Data *data = elf_getdata (scn, NULL);
if (data == NULL)
return;
/* Find out whether we have other sections we might need. */
- runscn = NULL;
+ Elf_Scn *runscn = NULL;
while ((runscn = elf_nextscn (ebl->elf, runscn)) != NULL)
{
GElf_Shdr runshdr_mem;
GElf_Shdr *runshdr = gelf_getshdr (runscn, &runshdr_mem);
- if (runshdr != NULL)
+ if (likely (runshdr != NULL))
{
if (runshdr->sh_type == SHT_GNU_versym
&& runshdr->sh_link == elf_ndxscn (scn))
@@ -1677,19 +1801,22 @@ handle_symtab (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
}
/* Get the section header string table index. */
- if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+ size_t shstrndx;
+ if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
error (EXIT_FAILURE, 0,
gettext ("cannot get section header string table index"));
/* Now we can compute the number of entries in the section. */
- nsyms = data->d_size / (class == ELFCLASS32
- ? sizeof (Elf32_Sym) : sizeof (Elf64_Sym));
+ unsigned int nsyms = data->d_size / (class == ELFCLASS32
+ ? sizeof (Elf32_Sym)
+ : sizeof (Elf64_Sym));
printf (ngettext ("\nSymbol table [%2u] '%s' contains %u entry:\n",
"\nSymbol table [%2u] '%s' contains %u entries:\n",
nsyms),
(unsigned int) elf_ndxscn (scn),
elf_strptr (ebl->elf, shstrndx, shdr->sh_name), nsyms);
+ GElf_Shdr glink;
printf (ngettext (" %lu local symbol String table: [%2u] '%s'\n",
" %lu local symbols String table: [%2u] '%s'\n",
shdr->sh_info),
@@ -1706,7 +1833,7 @@ handle_symtab (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
Num: Value Size Type Bind Vis Ndx Name\n"),
stdout);
- for (cnt = 0; cnt < nsyms; ++cnt)
+ for (unsigned int cnt = 0; cnt < nsyms; ++cnt)
{
char typebuf[64];
char bindbuf[64];
@@ -1715,11 +1842,11 @@ handle_symtab (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
GElf_Sym sym_mem;
GElf_Sym *sym = gelf_getsymshndx (data, xndx_data, cnt, &sym_mem, &xndx);
- if (sym == NULL)
+ if (unlikely (sym == NULL))
continue;
/* Determine the real section index. */
- if (sym->st_shndx != SHN_XINDEX)
+ if (likely (sym->st_shndx != SHN_XINDEX))
xndx = sym->st_shndx;
printf (gettext ("\
@@ -1741,9 +1868,7 @@ handle_symtab (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
{
/* Get the version information. */
GElf_Versym versym_mem;
- GElf_Versym *versym;
-
- versym = gelf_getversym (versym_data, cnt, &versym_mem);
+ GElf_Versym *versym = gelf_getversym (versym_data, cnt, &versym_mem);
if (versym != NULL && ((*versym & 0x8000) != 0 || *versym > 1))
{
@@ -1763,13 +1888,13 @@ handle_symtab (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
if (is_nobits || ! check_def)
{
/* We must test both. */
- GElf_Verneed verneed_mem;
- GElf_Verneed *verneed;
GElf_Vernaux vernaux_mem;
GElf_Vernaux *vernaux = NULL;
size_t vn_offset = 0;
- verneed = gelf_getverneed (verneed_data, 0, &verneed_mem);
+ GElf_Verneed verneed_mem;
+ GElf_Verneed *verneed = gelf_getverneed (verneed_data, 0,
+ &verneed_mem);
while (verneed != NULL)
{
size_t vna_offset = vn_offset;
@@ -1811,7 +1936,7 @@ handle_symtab (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
(unsigned int) vernaux->vna_other);
check_def = 0;
}
- else if (! is_nobits)
+ else if (unlikely (! is_nobits))
error (0, 0, gettext ("bad dynamic symbol"));
else
check_def = 1;
@@ -1820,11 +1945,11 @@ handle_symtab (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
if (check_def && *versym != 0x8001)
{
/* We must test both. */
- GElf_Verdef verdef_mem;
- GElf_Verdef *verdef;
size_t vd_offset = 0;
- verdef = gelf_getverdef (verdef_data, 0, &verdef_mem);
+ GElf_Verdef verdef_mem;
+ GElf_Verdef *verdef = gelf_getverdef (verdef_data, 0,
+ &verdef_mem);
while (verdef != NULL)
{
if (verdef->vd_ndx == (*versym & 0x7fff))
@@ -1841,11 +1966,10 @@ handle_symtab (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
if (verdef != NULL)
{
GElf_Verdaux verdaux_mem;
- GElf_Verdaux *verdaux;
-
- verdaux = gelf_getverdaux (verdef_data,
- vd_offset + verdef->vd_aux,
- &verdaux_mem);
+ GElf_Verdaux *verdaux
+ = gelf_getverdaux (verdef_data,
+ vd_offset + verdef->vd_aux,
+ &verdaux_mem);
if (verdaux != NULL)
printf ((*versym & 0x8000) ? "@%s" : "@@%s",
@@ -1856,14 +1980,14 @@ handle_symtab (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
}
}
- putchar ('\n');
+ putchar_unlocked ('\n');
}
}
/* Print version information. */
static void
-print_verinfo (Ebl *ebl, GElf_Ehdr *ehdr)
+print_verinfo (Ebl *ebl)
{
/* Find the version information sections. For this we have to
search through the section table. */
@@ -1875,14 +1999,14 @@ print_verinfo (Ebl *ebl, GElf_Ehdr *ehdr)
GElf_Shdr shdr_mem;
GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
- if (shdr != NULL)
+ if (likely (shdr != NULL))
{
if (shdr->sh_type == SHT_GNU_verneed)
- handle_verneed (ebl, ehdr, scn, shdr);
+ handle_verneed (ebl, scn, shdr);
else if (shdr->sh_type == SHT_GNU_verdef)
- handle_verdef (ebl, ehdr, scn, shdr);
+ handle_verdef (ebl, scn, shdr);
else if (shdr->sh_type == SHT_GNU_versym)
- handle_versym (ebl, ehdr, scn, shdr);
+ handle_versym (ebl, scn, shdr);
}
}
}
@@ -1910,7 +2034,7 @@ get_ver_flags (unsigned int flags)
endp = stpcpy (endp, "WEAK ");
}
- if (flags & ~(VER_FLG_BASE | VER_FLG_WEAK))
+ if (unlikely (flags & ~(VER_FLG_BASE | VER_FLG_WEAK)))
{
strncpy (endp, gettext ("| <unknown>"), buf + sizeof (buf) - endp);
buf[sizeof (buf) - 1] = '\0';
@@ -1921,25 +2045,22 @@ get_ver_flags (unsigned int flags)
static void
-handle_verneed (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
+handle_verneed (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
{
- Elf_Data *data;
int class = gelf_getclass (ebl->elf);
- GElf_Shdr glink;
- int cnt;
- unsigned int offset;
- size_t shstrndx;
/* Get the data of the section. */
- data = elf_getdata (scn, NULL);
+ Elf_Data *data = elf_getdata (scn, NULL);
if (data == NULL)
return;
/* Get the section header string table index. */
- if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+ size_t shstrndx;
+ if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
error (EXIT_FAILURE, 0,
gettext ("cannot get section header string table index"));
+ GElf_Shdr glink;
printf (ngettext ("\
\nVersion needs section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
"\
@@ -1954,17 +2075,13 @@ handle_verneed (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
&glink)->sh_name));
- offset = 0;
- for (cnt = shdr->sh_info; --cnt >= 0; )
+ unsigned int offset = 0;
+ for (int cnt = shdr->sh_info; --cnt >= 0; )
{
- GElf_Verneed needmem;
- GElf_Verneed *need;
- unsigned int auxoffset;
- int cnt2;
-
/* Get the data at the next offset. */
- need = gelf_getverneed (data, offset, &needmem);
- if (need == NULL)
+ GElf_Verneed needmem;
+ GElf_Verneed *need = gelf_getverneed (data, offset, &needmem);
+ if (unlikely (need == NULL))
break;
printf (gettext (" %#06x: Version: %hu File: %s Cnt: %hu\n"),
@@ -1972,14 +2089,12 @@ handle_verneed (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
elf_strptr (ebl->elf, shdr->sh_link, need->vn_file),
(unsigned short int) need->vn_cnt);
- auxoffset = offset + need->vn_aux;
- for (cnt2 = need->vn_cnt; --cnt2 >= 0; )
+ unsigned int auxoffset = offset + need->vn_aux;
+ for (int cnt2 = need->vn_cnt; --cnt2 >= 0; )
{
GElf_Vernaux auxmem;
- GElf_Vernaux *aux;
-
- aux = gelf_getvernaux (data, auxoffset, &auxmem);
- if (aux == NULL)
+ GElf_Vernaux *aux = gelf_getvernaux (data, auxoffset, &auxmem);
+ if (unlikely (aux == NULL))
break;
printf (gettext (" %#06x: Name: %s Flags: %s Version: %hu\n"),
@@ -1998,25 +2113,21 @@ handle_verneed (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
static void
-handle_verdef (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
+handle_verdef (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
{
- Elf_Data *data;
- int class = gelf_getclass (ebl->elf);
- GElf_Shdr glink;
- int cnt;
- unsigned int offset;
- size_t shstrndx;
-
/* Get the data of the section. */
- data = elf_getdata (scn, NULL);
+ Elf_Data *data = elf_getdata (scn, NULL);
if (data == NULL)
return;
/* Get the section header string table index. */
- if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+ size_t shstrndx;
+ if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
error (EXIT_FAILURE, 0,
gettext ("cannot get section header string table index"));
+ int class = gelf_getclass (ebl->elf);
+ GElf_Shdr glink;
printf (ngettext ("\
\nVersion definition section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
"\
@@ -2032,24 +2143,19 @@ handle_verdef (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
&glink)->sh_name));
- offset = 0;
- for (cnt = shdr->sh_info; --cnt >= 0; )
+ unsigned int offset = 0;
+ for (int cnt = shdr->sh_info; --cnt >= 0; )
{
- GElf_Verdef defmem;
- GElf_Verdef *def;
- GElf_Verdaux auxmem;
- GElf_Verdaux *aux;
- unsigned int auxoffset;
- int cnt2;
-
/* Get the data at the next offset. */
- def = gelf_getverdef (data, offset, &defmem);
- if (def == NULL)
+ GElf_Verdef defmem;
+ GElf_Verdef *def = gelf_getverdef (data, offset, &defmem);
+ if (unlikely (def == NULL))
break;
- auxoffset = offset + def->vd_aux;
- aux = gelf_getverdaux (data, auxoffset, &auxmem);
- if (aux == NULL)
+ unsigned int auxoffset = offset + def->vd_aux;
+ GElf_Verdaux auxmem;
+ GElf_Verdaux *aux = gelf_getverdaux (data, auxoffset, &auxmem);
+ if (unlikely (aux == NULL))
break;
printf (gettext ("\
@@ -2061,10 +2167,10 @@ handle_verdef (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
elf_strptr (ebl->elf, shdr->sh_link, aux->vda_name));
auxoffset += aux->vda_next;
- for (cnt2 = 1; cnt2 < def->vd_cnt; ++cnt2)
+ for (int cnt2 = 1; cnt2 < def->vd_cnt; ++cnt2)
{
aux = gelf_getverdaux (data, auxoffset, &auxmem);
- if (aux == NULL)
+ if (unlikely (aux == NULL))
break;
printf (gettext (" %#06x: Parent %d: %s\n"),
@@ -2081,42 +2187,35 @@ handle_verdef (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
static void
-handle_versym (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
+handle_versym (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
{
- Elf_Data *data;
int class = gelf_getclass (ebl->elf);
- Elf_Scn *verscn;
- GElf_Shdr glink;
- Elf_Scn *defscn;
- Elf_Scn *needscn;
const char **vername;
const char **filename;
- size_t nvername;
- unsigned int cnt;
- size_t shstrndx;
/* Get the data of the section. */
- data = elf_getdata (scn, NULL);
+ Elf_Data *data = elf_getdata (scn, NULL);
if (data == NULL)
return;
/* Get the section header string table index. */
- if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+ size_t shstrndx;
+ if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
error (EXIT_FAILURE, 0,
gettext ("cannot get section header string table index"));
/* We have to find the version definition section and extract the
version names. */
- defscn = NULL;
- needscn = NULL;
+ Elf_Scn *defscn = NULL;
+ Elf_Scn *needscn = NULL;
- verscn = NULL;
+ Elf_Scn *verscn = NULL;
while ((verscn = elf_nextscn (ebl->elf, verscn)) != NULL)
{
GElf_Shdr vershdr_mem;
GElf_Shdr *vershdr = gelf_getshdr (verscn, &vershdr_mem);
- if (vershdr != NULL)
+ if (likely (vershdr != NULL))
{
if (vershdr->sh_type == SHT_GNU_verdef)
defscn = verscn;
@@ -2125,6 +2224,7 @@ handle_versym (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
}
}
+ size_t nvername;
if (defscn != NULL || needscn != NULL)
{
/* We have a version information (better should have). Now get
@@ -2140,21 +2240,21 @@ handle_versym (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
GElf_Shdr *defshdr;
defdata = elf_getdata (defscn, NULL);
- if (defdata == NULL)
+ if (unlikely (defdata == NULL))
return;
defshdr = gelf_getshdr (defscn, &defshdrmem);
- if (defshdr == NULL)
+ if (unlikely (defshdr == NULL))
return;
- for (cnt = 0; cnt < defshdr->sh_info; ++cnt)
+ for (unsigned int cnt = 0; cnt < defshdr->sh_info; ++cnt)
{
GElf_Verdef defmem;
GElf_Verdef *def;
/* Get the data at the next offset. */
def = gelf_getverdef (defdata, offset, &defmem);
- if (def == NULL)
+ if (unlikely (def == NULL))
break;
nvername = MAX (nvername, (size_t) (def->vd_ndx & 0x7fff));
@@ -2170,14 +2270,14 @@ handle_versym (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
GElf_Shdr *needshdr;
needdata = elf_getdata (needscn, NULL);
- if (needdata == NULL)
+ if (unlikely (needdata == NULL))
return;
needshdr = gelf_getshdr (needscn, &needshdrmem);
- if (needshdr == NULL)
+ if (unlikely (needshdr == NULL))
return;
- for (cnt = 0; cnt < needshdr->sh_info; ++cnt)
+ for (unsigned int cnt = 0; cnt < needshdr->sh_info; ++cnt)
{
GElf_Verneed needmem;
GElf_Verneed *need;
@@ -2186,7 +2286,7 @@ handle_versym (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
/* Get the data at the next offset. */
need = gelf_getverneed (needdata, offset, &needmem);
- if (need == NULL)
+ if (unlikely (need == NULL))
break;
/* Run through the auxiliary entries. */
@@ -2197,7 +2297,7 @@ handle_versym (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
GElf_Vernaux *aux;
aux = gelf_getvernaux (needdata, auxoffset, &auxmem);
- if (aux == NULL)
+ if (unlikely (aux == NULL))
break;
nvername = MAX (nvername,
@@ -2228,27 +2328,24 @@ handle_versym (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
GElf_Shdr *defshdr;
defdata = elf_getdata (defscn, NULL);
- if (defdata == NULL)
+ if (unlikely (defdata == NULL))
return;
defshdr = gelf_getshdr (defscn, &defshdrmem);
- if (defshdr == NULL)
+ if (unlikely (defshdr == NULL))
return;
- for (cnt = 0; cnt < defshdr->sh_info; ++cnt)
+ for (unsigned int cnt = 0; cnt < defshdr->sh_info; ++cnt)
{
- GElf_Verdef defmem;
- GElf_Verdef *def;
- GElf_Verdaux auxmem;
- GElf_Verdaux *aux;
/* Get the data at the next offset. */
- def = gelf_getverdef (defdata, offset, &defmem);
- if (def == NULL)
- break;
-
- aux = gelf_getverdaux (defdata, offset + def->vd_aux, &auxmem);
- if (aux == NULL)
+ GElf_Verdef defmem;
+ GElf_Verdef *def = gelf_getverdef (defdata, offset, &defmem);
+ GElf_Verdaux auxmem;
+ GElf_Verdaux *aux = gelf_getverdaux (defdata,
+ offset + def->vd_aux,
+ &auxmem);
+ if (unlikely (def == NULL || aux == NULL))
break;
vername[def->vd_ndx & 0x7fff]
@@ -2261,39 +2358,30 @@ handle_versym (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
if (needscn != NULL)
{
unsigned int offset = 0;
- Elf_Data *needdata;
- GElf_Shdr needshdrmem;
- GElf_Shdr *needshdr;
- needdata = elf_getdata (needscn, NULL);
- if (needdata == NULL)
- return;
-
- needshdr = gelf_getshdr (needscn, &needshdrmem);
- if (needshdr == NULL)
+ Elf_Data *needdata = elf_getdata (needscn, NULL);
+ GElf_Shdr needshdrmem;
+ GElf_Shdr *needshdr = gelf_getshdr (needscn, &needshdrmem);
+ if (unlikely (needdata == NULL || needshdr == NULL))
return;
- for (cnt = 0; cnt < needshdr->sh_info; ++cnt)
+ for (unsigned int cnt = 0; cnt < needshdr->sh_info; ++cnt)
{
- GElf_Verneed needmem;
- GElf_Verneed *need;
- unsigned int auxoffset;
- int cnt2;
-
/* Get the data at the next offset. */
- need = gelf_getverneed (needdata, offset, &needmem);
- if (need == NULL)
+ GElf_Verneed needmem;
+ GElf_Verneed *need = gelf_getverneed (needdata, offset,
+ &needmem);
+ if (unlikely (need == NULL))
break;
/* Run through the auxiliary entries. */
- auxoffset = offset + need->vn_aux;
- for (cnt2 = need->vn_cnt; --cnt2 >= 0; )
+ unsigned int auxoffset = offset + need->vn_aux;
+ for (int cnt2 = need->vn_cnt; --cnt2 >= 0; )
{
GElf_Vernaux auxmem;
- GElf_Vernaux *aux;
-
- aux = gelf_getvernaux (needdata, auxoffset, &auxmem);
- if (aux == NULL)
+ GElf_Vernaux *aux = gelf_getvernaux (needdata, auxoffset,
+ &auxmem);
+ if (unlikely (aux == NULL))
break;
vername[aux->vna_other & 0x7fff]
@@ -2316,6 +2404,7 @@ handle_versym (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
}
/* Print the header. */
+ GElf_Shdr glink;
printf (ngettext ("\
\nVersion symbols section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'",
"\
@@ -2332,21 +2421,19 @@ handle_versym (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
&glink)->sh_name));
/* Now we can finally look at the actual contents of this section. */
- for (cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt)
+ for (unsigned int cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt)
{
- GElf_Versym symmem;
- GElf_Versym *sym;
- ssize_t n;
-
if (cnt % 2 == 0)
printf ("\n %4d:", cnt);
- sym = gelf_getversym (data, cnt, &symmem);
+ GElf_Versym symmem;
+ GElf_Versym *sym = gelf_getversym (data, cnt, &symmem);
if (sym == NULL)
break;
switch (*sym)
{
+ ssize_t n;
case 0:
fputs_unlocked (gettext (" 0 *local* "),
stdout);
@@ -2369,138 +2456,276 @@ handle_versym (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
break;
}
}
- putchar ('\n');
+ putchar_unlocked ('\n');
}
static void
-handle_hash (Ebl *ebl, GElf_Ehdr *ehdr)
+print_hash_info (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx,
+ uint_fast32_t maxlength, Elf32_Word nbucket,
+ uint_fast32_t nsyms, uint32_t *lengths, const char *extrastr)
{
- /* Find the symbol table(s). For this we have to search through the
- section table. */
- Elf_Scn *scn = NULL;
- size_t shstrndx;
+ uint32_t *counts = (uint32_t *) xcalloc (maxlength + 1, sizeof (uint32_t));
- /* Get the section header string table index. */
- if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
- error (EXIT_FAILURE, 0,
- gettext ("cannot get section header string table index"));
+ for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt)
+ ++counts[lengths[cnt]];
- while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
+ GElf_Shdr glink;
+ printf (ngettext ("\
+\nHistogram for bucket list length in section [%2u] '%s' (total of %d bucket):\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
+ "\
+\nHistogram for bucket list length in section [%2u] '%s' (total of %d buckets):\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
+ nbucket),
+ (unsigned int) elf_ndxscn (scn),
+ elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
+ (int) nbucket,
+ gelf_getclass (ebl->elf) == ELFCLASS32 ? 10 : 18,
+ shdr->sh_addr,
+ shdr->sh_offset,
+ (unsigned int) shdr->sh_link,
+ elf_strptr (ebl->elf, shstrndx,
+ gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
+ &glink)->sh_name));
+
+ if (extrastr != NULL)
+ fputs (extrastr, stdout);
+
+ if (likely (nbucket > 0))
{
- /* Handle the section if it is a symbol table. */
- GElf_Shdr shdr_mem;
- GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ uint64_t success = 0;
+
+ fputs_unlocked (gettext ("\
+ Length Number % of total Coverage\n"), stdout);
+ printf (gettext (" 0 %6" PRIu32 " %5.1f%%\n"),
+ counts[0], (counts[0] * 100.0) / nbucket);
- if (shdr != NULL && shdr->sh_type == SHT_HASH)
+ uint64_t nzero_counts = 0;
+ for (Elf32_Word cnt = 1; cnt <= maxlength; ++cnt)
{
- Elf_Data *data = elf_getdata (scn, NULL);
- Elf32_Word nbucket;
- Elf32_Word nchain;
- Elf32_Word *bucket;
- Elf32_Word *chain;
- uint32_t *lengths;
- uint32_t *counts;
- Elf32_Word cnt;
- Elf32_Word maxlength = 0;
- Elf32_Word nsyms = 0;
- uint64_t nzero_counts = 0;
- GElf_Shdr glink;
+ nzero_counts += counts[cnt] * cnt;
+ printf (gettext ("\
+%7d %6" PRIu32 " %5.1f%% %5.1f%%\n"),
+ (int) cnt, counts[cnt], (counts[cnt] * 100.0) / nbucket,
+ (nzero_counts * 100.0) / nsyms);
+ }
- if (data == NULL)
- {
- error (0, 0, gettext ("cannot get data for section %d: %s"),
- (int) elf_ndxscn (scn), elf_errmsg (-1));
- continue;
- }
+ Elf32_Word acc = 0;
+ for (Elf32_Word cnt = 1; cnt <= maxlength; ++cnt)
+ {
+ acc += cnt;
+ success += counts[cnt] * acc;
+ }
+
+ printf (gettext ("\
+ Average number of tests: successful lookup: %f\n\
+ unsuccessful lookup: %f\n"),
+ (double) success / (double) nzero_counts,
+ (double) nzero_counts / (double) nbucket);
+ }
- nbucket = ((Elf32_Word *) data->d_buf)[0];
- nchain = ((Elf32_Word *) data->d_buf)[1];
- bucket = &((Elf32_Word *) data->d_buf)[2];
- chain = &((Elf32_Word *) data->d_buf)[2 + nbucket];
+ free (counts);
+}
- printf (ngettext ("\
-\nHistogram for bucket list length in section [%2u] '%s' (total of %d bucket):\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
- "\
-\nHistogram for bucket list length in section [%2u] '%s' (total of %d buckets):\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
- nbucket),
- (unsigned int) elf_ndxscn (scn),
- elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
- (int) nbucket,
- gelf_getclass (ebl->elf) == ELFCLASS32 ? 10 : 18,
- shdr->sh_addr,
- shdr->sh_offset,
- (unsigned int) shdr->sh_link,
- elf_strptr (ebl->elf, shstrndx,
- gelf_getshdr (elf_getscn (ebl->elf,
- shdr->sh_link),
- &glink)->sh_name));
- lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t));
+/* This function handles the traditional System V-style hash table format. */
+static void
+handle_sysv_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
+{
+ Elf_Data *data = elf_getdata (scn, NULL);
+ if (unlikely (data == NULL))
+ {
+ error (0, 0, gettext ("cannot get data for section %d: %s"),
+ (int) elf_ndxscn (scn), elf_errmsg (-1));
+ return;
+ }
- for (cnt = 0; cnt < nbucket; ++cnt)
- if (bucket[cnt] != 0)
- {
- Elf32_Word inner;
+ Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0];
+ Elf32_Word nchain = ((Elf32_Word *) data->d_buf)[1];
+ Elf32_Word *bucket = &((Elf32_Word *) data->d_buf)[2];
+ Elf32_Word *chain = &((Elf32_Word *) data->d_buf)[2 + nbucket];
- inner = bucket[cnt];
- while (inner > 0 && inner < nchain)
- {
- ++nsyms;
- if (maxlength < ++lengths[cnt])
- ++maxlength;
+ uint32_t *lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t));
- inner = chain[inner];
- }
- }
+ uint_fast32_t maxlength = 0;
+ uint_fast32_t nsyms = 0;
+ for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt)
+ {
+ Elf32_Word inner = bucket[cnt];
+ while (inner > 0 && inner < nchain)
+ {
+ ++nsyms;
+ if (maxlength < ++lengths[cnt])
+ ++maxlength;
- counts = (uint32_t *) xcalloc (maxlength + 1, sizeof (uint32_t));
+ inner = chain[inner];
+ }
+ }
- for (cnt = 0; cnt < nbucket; ++cnt)
- ++counts[lengths[cnt]];
+ print_hash_info (ebl, scn, shdr, shstrndx, maxlength, nbucket, nsyms,
+ lengths, NULL);
- if (nbucket > 0)
- {
- uint64_t success = 0;
- Elf32_Word acc;
+ free (lengths);
+}
- puts (gettext (" Length Number % of total Coverage"));
- printf (gettext (" 0 %6" PRIu32 " %5.1f%%\n"),
- counts[0], (counts[0] * 100.0) / nbucket);
- for (cnt = 1; cnt <= maxlength; ++cnt)
- {
- nzero_counts += counts[cnt] * cnt;
- printf (gettext ("\
-%7d %6" PRIu32 " %5.1f%% %5.1f%%\n"),
- (int) cnt,
- counts[cnt], (counts[cnt] * 100.0) / nbucket,
- (nzero_counts * 100.0) / nsyms);
- }
+/* This function handles the incorrect, System V-style hash table
+ format some 64-bit architectures use. */
+static void
+handle_sysv_hash64 (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
+{
+ Elf_Data *data = elf_getdata (scn, NULL);
+ if (unlikely (data == NULL))
+ {
+ error (0, 0, gettext ("cannot get data for section %d: %s"),
+ (int) elf_ndxscn (scn), elf_errmsg (-1));
+ return;
+ }
- acc = 0;
- for (cnt = 1; cnt <= maxlength; ++cnt)
- {
- acc += cnt;
- success += counts[cnt] * acc;
- }
+ Elf64_Xword nbucket = ((Elf64_Xword *) data->d_buf)[0];
+ Elf64_Xword nchain = ((Elf64_Xword *) data->d_buf)[1];
+ Elf64_Xword *bucket = &((Elf64_Xword *) data->d_buf)[2];
+ Elf64_Xword *chain = &((Elf64_Xword *) data->d_buf)[2 + nbucket];
- printf (gettext ("\
- Average number of tests: successful lookup: %f\n\
- unsuccessful lookup: %f\n"),
- (double) success / (double) nzero_counts,
- (double) nzero_counts / (double) nbucket);
- }
+ uint32_t *lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t));
- free (counts);
- free (lengths);
+ uint_fast32_t maxlength = 0;
+ uint_fast32_t nsyms = 0;
+ for (Elf64_Xword cnt = 0; cnt < nbucket; ++cnt)
+ {
+ Elf64_Xword inner = bucket[cnt];
+ while (inner > 0 && inner < nchain)
+ {
+ ++nsyms;
+ if (maxlength < ++lengths[cnt])
+ ++maxlength;
+
+ inner = chain[inner];
}
}
+
+ print_hash_info (ebl, scn, shdr, shstrndx, maxlength, nbucket, nsyms,
+ lengths, NULL);
+
+ free (lengths);
+}
+
+
+/* This function handles the GNU-style hash table format. */
+static void
+handle_gnu_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
+{
+ Elf_Data *data = elf_getdata (scn, NULL);
+ if (unlikely (data == NULL))
+ {
+ error (0, 0, gettext ("cannot get data for section %d: %s"),
+ (int) elf_ndxscn (scn), elf_errmsg (-1));
+ return;
+ }
+
+ Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0];
+ Elf32_Word symbias = ((Elf32_Word *) data->d_buf)[1];
+
+ /* Next comes the size of the bitmap. It's measured in words for
+ the architecture. It's 32 bits for 32 bit archs, and 64 bits for
+ 64 bit archs. */
+ Elf32_Word bitmask_words = ((Elf32_Word *) data->d_buf)[2];
+ if (gelf_getclass (ebl->elf) == ELFCLASS64)
+ bitmask_words *= 2;
+
+ Elf32_Word shift = ((Elf32_Word *) data->d_buf)[3];
+
+ uint32_t *lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t));
+
+ Elf32_Word *bitmask = &((Elf32_Word *) data->d_buf)[4];
+ Elf32_Word *bucket = &((Elf32_Word *) data->d_buf)[4 + bitmask_words];
+ Elf32_Word *chain = &((Elf32_Word *) data->d_buf)[4 + bitmask_words
+ + nbucket];
+
+ /* Compute distribution of chain lengths. */
+ uint_fast32_t maxlength = 0;
+ uint_fast32_t nsyms = 0;
+ for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt)
+ if (bucket[cnt] != 0)
+ {
+ Elf32_Word inner = bucket[cnt] - symbias;
+ do
+ {
+ ++nsyms;
+ if (maxlength < ++lengths[cnt])
+ ++maxlength;
+ }
+ while ((chain[inner++] & 1) == 0);
+ }
+
+ /* Count bits in bitmask. */
+ uint_fast32_t nbits = 0;
+ for (Elf32_Word cnt = 0; cnt < bitmask_words; ++cnt)
+ {
+ uint_fast32_t word = bitmask[cnt];
+
+ word = (word & 0x55555555) + ((word >> 1) & 0x55555555);
+ word = (word & 0x33333333) + ((word >> 2) & 0x33333333);
+ word = (word & 0x0f0f0f0f) + ((word >> 4) & 0x0f0f0f0f);
+ word = (word & 0x00ff00ff) + ((word >> 8) & 0x00ff00ff);
+ nbits += (word & 0x0000ffff) + ((word >> 16) & 0x0000ffff);
+ }
+
+ char *str;
+ if (unlikely (asprintf (&str, gettext ("\
+ Symbol Bias: %u\n\
+ Bitmask Size: %zu bytes %" PRIuFAST32 "%% bits set 2nd hash shift: %u\n"),
+ (unsigned int) symbias,
+ bitmask_words * sizeof (Elf32_Word),
+ ((nbits * 100 + 50)
+ / (uint_fast32_t) (bitmask_words
+ * sizeof (Elf32_Word) * 8)),
+ (unsigned int) shift) == -1))
+ error (EXIT_FAILURE, 0, gettext ("memory exhausted"));
+
+ print_hash_info (ebl, scn, shdr, shstrndx, maxlength, nbucket, nsyms,
+ lengths, str);
+
+ free (str);
+ free (lengths);
}
+/* Find the symbol table(s). For this we have to search through the
+ section table. */
static void
-print_liblist (Ebl *ebl, GElf_Ehdr *ehdr)
+handle_hash (Ebl *ebl)
+{
+ /* Get the section header string table index. */
+ size_t shstrndx;
+ if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
+ error (EXIT_FAILURE, 0,
+ gettext ("cannot get section header string table index"));
+
+ Elf_Scn *scn = NULL;
+ while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
+ {
+ /* Handle the section if it is a symbol table. */
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+
+ if (likely (shdr != NULL))
+ {
+ if (shdr->sh_type == SHT_HASH)
+ {
+ if (ebl_sysvhash_entrysize (ebl) == sizeof (Elf64_Xword))
+ handle_sysv_hash64 (ebl, scn, shdr, shstrndx);
+ else
+ handle_sysv_hash (ebl, scn, shdr, shstrndx);
+ }
+ else if (shdr->sh_type == SHT_GNU_HASH)
+ handle_gnu_hash (ebl, scn, shdr, shstrndx);
+ }
+ }
+}
+
+
+static void
+print_liblist (Ebl *ebl)
{
/* Find the library list sections. For this we have to search
through the section table. */
@@ -2508,7 +2733,7 @@ print_liblist (Ebl *ebl, GElf_Ehdr *ehdr)
/* Get the section header string table index. */
size_t shstrndx;
- if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+ if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
error (EXIT_FAILURE, 0,
gettext ("cannot get section header string table index"));
@@ -2541,12 +2766,12 @@ print_liblist (Ebl *ebl, GElf_Ehdr *ehdr)
{
GElf_Lib lib_mem;
GElf_Lib *lib = gelf_getlib (data, cnt, &lib_mem);
- if (lib == NULL)
+ if (unlikely (lib == NULL))
continue;
time_t t = (time_t) lib->l_time_stamp;
struct tm *tm = gmtime (&t);
- if (tm == NULL)
+ if (unlikely (tm == NULL))
continue;
printf (" [%2d] %-29s %04u-%02u-%02uT%02u:%02u:%02u %08x %-7u %u\n",
@@ -2561,11 +2786,244 @@ print_liblist (Ebl *ebl, GElf_Ehdr *ehdr)
}
}
+static void
+print_attributes (Ebl *ebl, const GElf_Ehdr *ehdr)
+{
+ /* Find the object attributes sections. For this we have to search
+ through the section table. */
+ Elf_Scn *scn = NULL;
+
+ /* Get the section header string table index. */
+ size_t shstrndx;
+ if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
+ error (EXIT_FAILURE, 0,
+ gettext ("cannot get section header string table index"));
+
+ while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
+ {
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+
+ if (shdr == NULL || shdr->sh_type != SHT_GNU_ATTRIBUTES)
+ continue;
+
+ printf (gettext ("\
+\nObject attributes section [%2zu] '%s' of %" PRIu64
+ " bytes at offset %#0" PRIx64 ":\n"),
+ elf_ndxscn (scn),
+ elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
+ shdr->sh_size, shdr->sh_offset);
+
+ Elf_Data *data = elf_rawdata (scn, NULL);
+ if (data == NULL)
+ return;
+
+ const unsigned char *p = data->d_buf;
+
+ if (unlikely (*p++ != 'A'))
+ return;
+
+ fputs_unlocked (gettext (" Owner Size\n"), stdout);
+
+ inline size_t left (void)
+ {
+ return (const unsigned char *) data->d_buf + data->d_size - p;
+ }
+
+ while (left () >= 4)
+ {
+ uint32_t len;
+ memcpy (&len, p, sizeof len);
+
+ if (MY_ELFDATA != ehdr->e_ident[EI_DATA])
+ CONVERT (len);
+
+ if (unlikely (len > left ()))
+ break;
+
+ const unsigned char *name = p + sizeof len;
+ p += len;
+
+ unsigned const char *q = memchr (name, '\0', len);
+ if (unlikely (q == NULL))
+ continue;
+ ++q;
+
+ printf (gettext (" %-13s %4" PRIu32 "\n"), name, len);
+
+ if (q - name == sizeof "gnu"
+ && !memcmp (name, "gnu", sizeof "gnu"))
+ while (q < p)
+ {
+ const unsigned char *const sub = q;
+
+ unsigned int subsection_tag;
+ get_uleb128 (subsection_tag, q);
+ if (unlikely (q >= p))
+ break;
+
+ uint32_t subsection_len;
+ if (unlikely (p - sub < (ptrdiff_t) sizeof subsection_len))
+ break;
+
+ memcpy (&subsection_len, q, sizeof subsection_len);
+
+ if (MY_ELFDATA != ehdr->e_ident[EI_DATA])
+ CONVERT (subsection_len);
+
+ if (unlikely (p - sub < (ptrdiff_t) subsection_len))
+ break;
+
+ const unsigned char *r = q + sizeof subsection_len;
+ q = sub + subsection_len;
+
+ switch (subsection_tag)
+ {
+ default:
+ printf (gettext (" %-4u %12" PRIu32 "\n"),
+ subsection_tag, subsection_len);
+ break;
+
+ case 1: /* Tag_File */
+ printf (gettext (" File: %11" PRIu32 "\n"),
+ subsection_len);
+
+ while (r < q)
+ {
+ unsigned int tag;
+ get_uleb128 (tag, r);
+ if (unlikely (r >= q))
+ break;
+
+ uint64_t value = 0;
+ const char *string = NULL;
+ if (tag == 32 || (tag & 1) == 0)
+ {
+ get_uleb128 (value, r);
+ if (r > q)
+ break;
+ }
+ if (tag == 32 || (tag & 1) != 0)
+ {
+ r = memchr (r, '\0', q - r);
+ if (r == NULL)
+ break;
+ ++r;
+ }
+
+ const char *tag_name = NULL;
+ const char *value_name = NULL;
+ ebl_check_object_attribute (ebl, (const char *) name,
+ tag, value,
+ &tag_name, &value_name);
+
+ if (tag_name != NULL)
+ {
+ if (tag == 32)
+ printf (gettext (" %s: %" PRId64 ", %s\n"),
+ tag_name, value, string);
+ else if (string == NULL && value_name == NULL)
+ printf (gettext (" %s: %" PRId64 "\n"),
+ tag_name, value);
+ else
+ printf (gettext (" %s: %s\n"),
+ tag_name, string ?: value_name);
+ }
+ else
+ {
+ assert (tag != 32);
+ if (string == NULL)
+ printf (gettext (" %u: %" PRId64 "\n"),
+ tag, value);
+ else
+ printf (gettext (" %u: %s\n"),
+ tag, string);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+static char *
+format_dwarf_addr (Dwfl_Module *dwflmod,
+ int address_size, Dwarf_Addr address)
+{
+ /* See if there is a name we can give for this address. */
+ GElf_Sym sym;
+ const char *name = dwfl_module_addrsym (dwflmod, address, &sym, NULL);
+ if (name != NULL)
+ sym.st_value = address - sym.st_value;
+
+ /* Relativize the address. */
+ int n = dwfl_module_relocations (dwflmod);
+ int i = n < 1 ? -1 : dwfl_module_relocate_address (dwflmod, &address);
+
+ /* In an ET_REL file there is a section name to refer to. */
+ const char *scn = (i < 0 ? NULL
+ : dwfl_module_relocation_info (dwflmod, i, NULL));
+
+ char *result;
+ if ((name != NULL
+ ? (sym.st_value != 0
+ ? (scn != NULL
+ ? (address_size == 0
+ ? asprintf (&result,
+ gettext ("%s+%#" PRIx64 " <%s+%#" PRIx64 ">"),
+ scn, address, name, sym.st_value)
+ : asprintf (&result,
+ gettext ("%s+%#0*" PRIx64 " <%s+%#" PRIx64 ">"),
+ scn, 2 + address_size * 2, address,
+ name, sym.st_value))
+ : (address_size == 0
+ ? asprintf (&result,
+ gettext ("%#" PRIx64 " <%s+%#" PRIx64 ">"),
+ address, name, sym.st_value)
+ : asprintf (&result,
+ gettext ("%#0*" PRIx64 " <%s+%#" PRIx64 ">"),
+ 2 + address_size * 2, address,
+ name, sym.st_value)))
+ : (scn != NULL
+ ? (address_size == 0
+ ? asprintf (&result,
+ gettext ("%s+%#" PRIx64 " <%s>"),
+ scn, address, name)
+ : asprintf (&result,
+ gettext ("%s+%#0*" PRIx64 " <%s>"),
+ scn, 2 + address_size * 2, address, name))
+ : (address_size == 0
+ ? asprintf (&result,
+ gettext ("%#" PRIx64 " <%s>"),
+ address, name)
+ : asprintf (&result,
+ gettext ("%#0*" PRIx64 " <%s>"),
+ 2 + address_size * 2, address, name))))
+ : (scn != NULL
+ ? (address_size == 0
+ ? asprintf (&result,
+ gettext ("%s+%#" PRIx64),
+ scn, address)
+ : asprintf (&result,
+ gettext ("%s+%#0*" PRIx64),
+ scn, 2 + address_size * 2, address))
+ : (address_size == 0
+ ? asprintf (&result,
+ "%#" PRIx64,
+ address)
+ : asprintf (&result,
+ "%#0*" PRIx64,
+ 2 + address_size * 2, address)))) < 0)
+ error (EXIT_FAILURE, 0, _("memory exhausted"));
+
+ return result;
+}
static const char *
dwarf_tag_string (unsigned int tag)
{
- static const char *known_tags[] =
+ static const char *const known_tags[] =
{
[DW_TAG_array_type] = "array_type",
[DW_TAG_class_type] = "class_type",
@@ -2607,23 +3065,34 @@ dwarf_tag_string (unsigned int tag)
[DW_TAG_namelist_item] = "namelist_item",
[DW_TAG_packed_type] = "packed_type",
[DW_TAG_subprogram] = "subprogram",
- [DW_TAG_template_type_param] = "template_type_param",
- [DW_TAG_template_value_param] = "template_value_param",
+ [DW_TAG_template_type_parameter] = "template_type_parameter",
+ [DW_TAG_template_value_parameter] = "template_value_parameter",
[DW_TAG_thrown_type] = "thrown_type",
[DW_TAG_try_block] = "try_block",
[DW_TAG_variant_part] = "variant_part",
[DW_TAG_variable] = "variable",
[DW_TAG_volatile_type] = "volatile_type",
+ [DW_TAG_dwarf_procedure] = "dwarf_procedure",
+ [DW_TAG_restrict_type] = "restrict_type",
+ [DW_TAG_interface_type] = "interface_type",
+ [DW_TAG_namespace] = "namespace",
+ [DW_TAG_imported_module] = "imported_module",
+ [DW_TAG_unspecified_type] = "unspecified_type",
+ [DW_TAG_partial_unit] = "partial_unit",
+ [DW_TAG_imported_unit] = "imported_unit",
+ [DW_TAG_mutable_type] = "mutable_type",
+ [DW_TAG_condition] = "condition",
+ [DW_TAG_shared_type] = "shared_type",
};
const unsigned int nknown_tags = (sizeof (known_tags)
/ sizeof (known_tags[0]));
static char buf[40];
const char *result = NULL;
- if (tag < nknown_tags)
+ if (likely (tag < nknown_tags))
result = known_tags[tag];
- if (result == NULL)
+ if (unlikely (result == NULL))
/* There are a few known extensions. */
switch (tag)
{
@@ -2659,7 +3128,7 @@ dwarf_tag_string (unsigned int tag)
static const char *
dwarf_attr_string (unsigned int attrnum)
{
- static const char *known_attrs[] =
+ static const char *const known_attrs[] =
{
[DW_AT_sibling] = "sibling",
[DW_AT_location] = "location",
@@ -2692,7 +3161,7 @@ dwarf_attr_string (unsigned int attrnum)
[DW_AT_prototyped] = "prototyped",
[DW_AT_return_addr] = "return_addr",
[DW_AT_start_scope] = "start_scope",
- [DW_AT_stride_size] = "stride_size",
+ [DW_AT_bit_stride] = "bit_stride",
[DW_AT_upper_bound] = "upper_bound",
[DW_AT_abstract_origin] = "abstract_origin",
[DW_AT_accessibility] = "accessibility",
@@ -2713,7 +3182,7 @@ dwarf_attr_string (unsigned int attrnum)
[DW_AT_friend] = "friend",
[DW_AT_identifier_case] = "identifier_case",
[DW_AT_macro_info] = "macro_info",
- [DW_AT_namelist_items] = "namelist_items",
+ [DW_AT_namelist_item] = "namelist_item",
[DW_AT_priority] = "priority",
[DW_AT_segment] = "segment",
[DW_AT_specification] = "specification",
@@ -2722,17 +3191,44 @@ dwarf_attr_string (unsigned int attrnum)
[DW_AT_use_location] = "use_location",
[DW_AT_variable_parameter] = "variable_parameter",
[DW_AT_virtuality] = "virtuality",
- [DW_AT_vtable_elem_location] = "vtable_elem_location"
+ [DW_AT_vtable_elem_location] = "vtable_elem_location",
+ [DW_AT_allocated] = "allocated",
+ [DW_AT_associated] = "associated",
+ [DW_AT_data_location] = "data_location",
+ [DW_AT_byte_stride] = "byte_stride",
+ [DW_AT_entry_pc] = "entry_pc",
+ [DW_AT_use_UTF8] = "use_UTF8",
+ [DW_AT_extension] = "extension",
+ [DW_AT_ranges] = "ranges",
+ [DW_AT_trampoline] = "trampoline",
+ [DW_AT_call_column] = "call_column",
+ [DW_AT_call_file] = "call_file",
+ [DW_AT_call_line] = "call_line",
+ [DW_AT_description] = "description",
+ [DW_AT_binary_scale] = "binary_scale",
+ [DW_AT_decimal_scale] = "decimal_scale",
+ [DW_AT_small] = "small",
+ [DW_AT_decimal_sign] = "decimal_sign",
+ [DW_AT_digit_count] = "digit_count",
+ [DW_AT_picture_string] = "picture_string",
+ [DW_AT_mutable] = "mutable",
+ [DW_AT_threads_scaled] = "threads_scaled",
+ [DW_AT_explicit] = "explicit",
+ [DW_AT_object_pointer] = "object_pointer",
+ [DW_AT_endianity] = "endianity",
+ [DW_AT_elemental] = "elemental",
+ [DW_AT_pure] = "pure",
+ [DW_AT_recursive] = "recursive",
};
const unsigned int nknown_attrs = (sizeof (known_attrs)
/ sizeof (known_attrs[0]));
static char buf[40];
const char *result = NULL;
- if (attrnum < nknown_attrs)
+ if (likely (attrnum < nknown_attrs))
result = known_attrs[attrnum];
- if (result == NULL)
+ if (unlikely (result == NULL))
/* There are a few known extensions. */
switch (attrnum)
{
@@ -2846,7 +3342,7 @@ dwarf_attr_string (unsigned int attrnum)
static const char *
dwarf_form_string (unsigned int form)
{
- static const char *known_forms[] =
+ static const char *const known_forms[] =
{
[DW_FORM_addr] = "addr",
[DW_FORM_block2] = "block2",
@@ -2875,10 +3371,10 @@ dwarf_form_string (unsigned int form)
static char buf[40];
const char *result = NULL;
- if (form < nknown_forms)
+ if (likely (form < nknown_forms))
result = known_forms[form];
- if (result == NULL)
+ if (unlikely (result == NULL))
snprintf (buf, sizeof buf, gettext ("unknown form %" PRIx64),
(uint64_t) form);
@@ -2889,12 +3385,12 @@ dwarf_form_string (unsigned int form)
static const char *
dwarf_lang_string (unsigned int lang)
{
- static const char *known[] =
+ static const char *const known[] =
{
[DW_LANG_C89] = "ISO C89",
[DW_LANG_C] = "C",
[DW_LANG_Ada83] = "Ada83",
- [DW_LANG_C_plus_plus ] = "C++",
+ [DW_LANG_C_plus_plus] = "C++",
[DW_LANG_Cobol74] = "Cobol74",
[DW_LANG_Cobol85] = "Cobol85",
[DW_LANG_Fortran77] = "Fortran77",
@@ -2905,10 +3401,14 @@ dwarf_lang_string (unsigned int lang)
[DW_LANG_C99] = "ISO C99",
[DW_LANG_Ada95] = "Ada95",
[DW_LANG_Fortran95] = "Fortran95",
- [DW_LANG_PL1] = "PL1"
+ [DW_LANG_PL1] = "PL1",
+ [DW_LANG_Objc] = "Objective C",
+ [DW_LANG_ObjC_plus_plus] = "Objective C++",
+ [DW_LANG_UPC] = "UPC",
+ [DW_LANG_D] = "D",
};
- if (lang < sizeof (known) / sizeof (known[0]))
+ if (likely (lang < sizeof (known) / sizeof (known[0])))
return known[lang];
else if (lang == DW_LANG_Mips_Assembler)
/* This language tag is used for assembler in general. */
@@ -2916,7 +3416,7 @@ dwarf_lang_string (unsigned int lang)
if (lang >= DW_LANG_lo_user && lang <= DW_LANG_hi_user)
{
- static char buf[100];
+ static char buf[30];
snprintf (buf, sizeof (buf), "lo_user+%u", lang - DW_LANG_lo_user);
return buf;
}
@@ -2925,11 +3425,191 @@ dwarf_lang_string (unsigned int lang)
}
+static const char *
+dwarf_inline_string (unsigned int code)
+{
+ static const char *const known[] =
+ {
+ [DW_INL_not_inlined] = "not_inlined",
+ [DW_INL_inlined] = "inlined",
+ [DW_INL_declared_not_inlined] = "declared_not_inlined",
+ [DW_INL_declared_inlined] = "declared_inlined"
+ };
+
+ if (likely (code < sizeof (known) / sizeof (known[0])))
+ return known[code];
+
+ return "???";
+}
+
+
+static const char *
+dwarf_encoding_string (unsigned int code)
+{
+ static const char *const known[] =
+ {
+ [DW_ATE_void] = "void",
+ [DW_ATE_address] = "address",
+ [DW_ATE_boolean] = "boolean",
+ [DW_ATE_complex_float] = "complex_float",
+ [DW_ATE_float] = "float",
+ [DW_ATE_signed] = "signed",
+ [DW_ATE_signed_char] = "signed_char",
+ [DW_ATE_unsigned] = "unsigned",
+ [DW_ATE_unsigned_char] = "unsigned_char",
+ [DW_ATE_imaginary_float] = "imaginary_float",
+ [DW_ATE_packed_decimal] = "packed_decimal",
+ [DW_ATE_numeric_string] = "numeric_string",
+ [DW_ATE_edited] = "edited",
+ [DW_ATE_signed_fixed] = "signed_fixed",
+ [DW_ATE_unsigned_fixed] = "unsigned_fixed",
+ [DW_ATE_decimal_float] = "decimal_float",
+ };
+
+ if (likely (code < sizeof (known) / sizeof (known[0])))
+ return known[code];
+
+ if (code >= DW_ATE_lo_user && code <= DW_ATE_hi_user)
+ {
+ static char buf[30];
+ snprintf (buf, sizeof (buf), "lo_user+%u", code - DW_ATE_lo_user);
+ return buf;
+ }
+
+ return "???";
+}
+
+
+static const char *
+dwarf_access_string (unsigned int code)
+{
+ static const char *const known[] =
+ {
+ [DW_ACCESS_public] = "public",
+ [DW_ACCESS_protected] = "protected",
+ [DW_ACCESS_private] = "private"
+ };
+
+ if (likely (code < sizeof (known) / sizeof (known[0])))
+ return known[code];
+
+ return "???";
+}
+
+
+static const char *
+dwarf_visibility_string (unsigned int code)
+{
+ static const char *const known[] =
+ {
+ [DW_VIS_local] = "local",
+ [DW_VIS_exported] = "exported",
+ [DW_VIS_qualified] = "qualified"
+ };
+
+ if (likely (code < sizeof (known) / sizeof (known[0])))
+ return known[code];
+
+ return "???";
+}
+
+
+static const char *
+dwarf_virtuality_string (unsigned int code)
+{
+ static const char *const known[] =
+ {
+ [DW_VIRTUALITY_none] = "none",
+ [DW_VIRTUALITY_virtual] = "virtual",
+ [DW_VIRTUALITY_pure_virtual] = "pure_virtual"
+ };
+
+ if (likely (code < sizeof (known) / sizeof (known[0])))
+ return known[code];
+
+ return "???";
+}
+
+
+static const char *
+dwarf_identifier_case_string (unsigned int code)
+{
+ static const char *const known[] =
+ {
+ [DW_ID_case_sensitive] = "sensitive",
+ [DW_ID_up_case] = "up_case",
+ [DW_ID_down_case] = "down_case",
+ [DW_ID_case_insensitive] = "insensitive"
+ };
+
+ if (likely (code < sizeof (known) / sizeof (known[0])))
+ return known[code];
+
+ return "???";
+}
+
+
+static const char *
+dwarf_calling_convention_string (unsigned int code)
+{
+ static const char *const known[] =
+ {
+ [DW_CC_normal] = "normal",
+ [DW_CC_program] = "program",
+ [DW_CC_nocall] = "nocall",
+ };
+
+ if (likely (code < sizeof (known) / sizeof (known[0])))
+ return known[code];
+
+ if (code >= DW_CC_lo_user && code <= DW_CC_hi_user)
+ {
+ static char buf[30];
+ snprintf (buf, sizeof (buf), "lo_user+%u", code - DW_CC_lo_user);
+ return buf;
+ }
+
+ return "???";
+}
+
+
+static const char *
+dwarf_ordering_string (unsigned int code)
+{
+ static const char *const known[] =
+ {
+ [DW_ORD_row_major] = "row_major",
+ [DW_ORD_col_major] = "col_major"
+ };
+
+ if (likely (code < sizeof (known) / sizeof (known[0])))
+ return known[code];
+
+ return "???";
+}
+
+
+static const char *
+dwarf_discr_list_string (unsigned int code)
+{
+ static const char *const known[] =
+ {
+ [DW_DSC_label] = "label",
+ [DW_DSC_range] = "range"
+ };
+
+ if (likely (code < sizeof (known) / sizeof (known[0])))
+ return known[code];
+
+ return "???";
+}
+
+
static void
-print_ops (Dwarf *dbg, int level, unsigned int addrsize, Dwarf_Word len,
- unsigned char *data)
+print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
+ unsigned int addrsize, Dwarf_Word len, const unsigned char *data)
{
- static const char *known[] =
+ static const char *const known[] =
{
[DW_OP_addr] = "addr",
[DW_OP_deref] = "deref",
@@ -3080,13 +3760,15 @@ print_ops (Dwarf *dbg, int level, unsigned int addrsize, Dwarf_Word len,
[DW_OP_call2] = "call2",
[DW_OP_call4] = "call4",
[DW_OP_call_ref] = "call_ref",
+ [DW_OP_form_tls_address] = "form_tls_address",
+ [DW_OP_call_frame_cfa] = "call_frame_cfa",
+ [DW_OP_bit_piece] = "bit_piece",
};
Dwarf_Word offset = 0;
while (len-- > 0)
{
- size_t op = *((unsigned char *) data);
- ++data;
+ uint_fast8_t op = *data++;
switch (op)
{
@@ -3104,18 +3786,27 @@ print_ops (Dwarf *dbg, int level, unsigned int addrsize, Dwarf_Word len,
data += addrsize;
len -= addrsize;
- printf (" %*s [%4" PRIuMAX "] %s %" PRIuMAX "\n",
- (int) (20 + level * 2), "", (uintmax_t) offset,
- known[op] ?: "???", (uintmax_t) addr);
+ if (op == DW_OP_addr)
+ {
+ char *a = format_dwarf_addr (dwflmod, 0, addr);
+ printf ("%*s[%4" PRIuMAX "] %s %s\n",
+ indent, "", (uintmax_t) offset,
+ known[op] ?: "???", a);
+ free (a);
+ }
+ else
+ printf ("%*s[%4" PRIuMAX "] %s %#" PRIxMAX "\n",
+ indent, "", (uintmax_t) offset,
+ known[op] ?: "???", (uintmax_t) addr);
offset += 1 + addrsize;
break;
- case DW_OP_deref_size: /* XXX Correct? */
- case DW_OP_xderef_size: /* XXX Correct? */
+ case DW_OP_deref_size:
+ case DW_OP_xderef_size:
case DW_OP_pick:
case DW_OP_const1u:
- printf (" %*s [%4" PRIuMAX "] %s %" PRIu8 "\n",
- (int) (20 + level * 2), "", (uintmax_t) offset,
+ printf ("%*s[%4" PRIuMAX "] %s %" PRIu8 "\n",
+ indent, "", (uintmax_t) offset,
known[op] ?: "???", *((uint8_t *) data));
++data;
--len;
@@ -3123,8 +3814,8 @@ print_ops (Dwarf *dbg, int level, unsigned int addrsize, Dwarf_Word len,
break;
case DW_OP_const2u:
- printf (" %*s [%4" PRIuMAX "] %s %" PRIu16 "\n",
- (int) (20 + level * 2), "", (uintmax_t) offset,
+ printf ("%*s[%4" PRIuMAX "] %s %" PRIu16 "\n",
+ indent, "", (uintmax_t) offset,
known[op] ?: "???", read_2ubyte_unaligned (dbg, data));
len -= 2;
data += 2;
@@ -3132,8 +3823,8 @@ print_ops (Dwarf *dbg, int level, unsigned int addrsize, Dwarf_Word len,
break;
case DW_OP_const4u:
- printf (" %*s [%4" PRIuMAX "] %s %" PRIu32 "\n",
- (int) (20 + level * 2), "", (uintmax_t) offset,
+ printf ("%*s[%4" PRIuMAX "] %s %" PRIu32 "\n",
+ indent, "", (uintmax_t) offset,
known[op] ?: "???", read_4ubyte_unaligned (dbg, data));
len -= 4;
data += 4;
@@ -3141,8 +3832,8 @@ print_ops (Dwarf *dbg, int level, unsigned int addrsize, Dwarf_Word len,
break;
case DW_OP_const8u:
- printf (" %*s [%4" PRIuMAX "] %s %" PRIu64 "\n",
- (int) (20 + level * 2), "", (uintmax_t) offset,
+ printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 "\n",
+ indent, "", (uintmax_t) offset,
known[op] ?: "???", read_8ubyte_unaligned (dbg, data));
len -= 8;
data += 8;
@@ -3150,8 +3841,8 @@ print_ops (Dwarf *dbg, int level, unsigned int addrsize, Dwarf_Word len,
break;
case DW_OP_const1s:
- printf (" %*s [%4" PRIuMAX "] %s %" PRId8 "\n",
- (int) (20 + level * 2), "", (uintmax_t) offset,
+ printf ("%*s[%4" PRIuMAX "] %s %" PRId8 "\n",
+ indent, "", (uintmax_t) offset,
known[op] ?: "???", *((int8_t *) data));
++data;
--len;
@@ -3159,8 +3850,8 @@ print_ops (Dwarf *dbg, int level, unsigned int addrsize, Dwarf_Word len,
break;
case DW_OP_const2s:
- printf (" %*s [%4" PRIuMAX "] %s %" PRId16 "\n",
- (int) (20 + level * 2), "", (uintmax_t) offset,
+ printf ("%*s[%4" PRIuMAX "] %s %" PRId16 "\n",
+ indent, "", (uintmax_t) offset,
known[op] ?: "???", read_2sbyte_unaligned (dbg, data));
len -= 2;
data += 2;
@@ -3168,8 +3859,8 @@ print_ops (Dwarf *dbg, int level, unsigned int addrsize, Dwarf_Word len,
break;
case DW_OP_const4s:
- printf (" %*s [%4" PRIuMAX "] %s %" PRId32 "\n",
- (int) (20 + level * 2), "", (uintmax_t) offset,
+ printf ("%*s[%4" PRIuMAX "] %s %" PRId32 "\n",
+ indent, "", (uintmax_t) offset,
known[op] ?: "???", read_4sbyte_unaligned (dbg, data));
len -= 4;
data += 4;
@@ -3177,36 +3868,48 @@ print_ops (Dwarf *dbg, int level, unsigned int addrsize, Dwarf_Word len,
break;
case DW_OP_const8s:
- printf (" %*s [%4" PRIuMAX "] %s %" PRId64 "\n",
- (int) (20 + level * 2), "", (uintmax_t) offset,
+ printf ("%*s[%4" PRIuMAX "] %s %" PRId64 "\n",
+ indent, "", (uintmax_t) offset,
known[op] ?: "???", read_8sbyte_unaligned (dbg, data));
len -= 8;
data += 8;
offset += 9;
break;
- case DW_OP_piece: /* XXX Correct? */
+ case DW_OP_piece:
case DW_OP_regx:
case DW_OP_plus_uconst:
case DW_OP_constu:;
- unsigned char *start = data;
+ const unsigned char *start = data;
unsigned int uleb;
get_uleb128 (uleb, data);
- printf (" %*s [%4" PRIuMAX "] %s %u\n",
- (int) (20 + level * 2), "", (uintmax_t) offset,
+ printf ("%*s[%4" PRIuMAX "] %s %u\n",
+ indent, "", (uintmax_t) offset,
known[op] ?: "???", uleb);
len -= data - start;
offset += 1 + (data - start);
break;
+ case DW_OP_bit_piece:
+ start = data;
+ unsigned int uleb2;
+ get_uleb128 (uleb, data);
+ get_uleb128 (uleb2, data);
+ printf ("%*s[%4" PRIuMAX "] %s %u, %u\n",
+ indent, "", (uintmax_t) offset,
+ known[op] ?: "???", uleb, uleb2);
+ len -= data - start;
+ offset += 1 + (data - start);
+ break;
+
case DW_OP_fbreg:
case DW_OP_breg0 ... DW_OP_breg31:
case DW_OP_consts:
start = data;
unsigned int sleb;
get_sleb128 (sleb, data);
- printf (" %*s [%4" PRIuMAX "] %s %d\n",
- (int) (20 + level * 2), "", (uintmax_t) offset,
+ printf ("%*s[%4" PRIuMAX "] %s %d\n",
+ indent, "", (uintmax_t) offset,
known[op] ?: "???", sleb);
len -= data - start;
offset += 1 + (data - start);
@@ -3216,8 +3919,8 @@ print_ops (Dwarf *dbg, int level, unsigned int addrsize, Dwarf_Word len,
start = data;
get_uleb128 (uleb, data);
get_sleb128 (sleb, data);
- printf (" %*s [%4" PRIuMAX "] %s %u %d\n",
- (int) (20 + level * 2), "", (uintmax_t) offset,
+ printf ("%*s[%4" PRIuMAX "] %s %u %d\n",
+ indent, "", (uintmax_t) offset,
known[op] ?: "???", uleb, sleb);
len -= data - start;
offset += 1 + (data - start);
@@ -3227,8 +3930,8 @@ print_ops (Dwarf *dbg, int level, unsigned int addrsize, Dwarf_Word len,
case DW_OP_call4:
case DW_OP_skip:
case DW_OP_bra:
- printf (" %*s [%4" PRIuMAX "] %s %" PRIuMAX "\n",
- (int) (20 + level * 2), "", (uintmax_t) offset,
+ printf ("%*s[%4" PRIuMAX "] %s %" PRIuMAX "\n",
+ indent, "", (uintmax_t) offset,
known[op] ?: "???",
(uintmax_t) (offset + read_2sbyte_unaligned (dbg, data)));
len -= 2;
@@ -3238,18 +3941,26 @@ print_ops (Dwarf *dbg, int level, unsigned int addrsize, Dwarf_Word len,
default:
/* No Operand. */
- printf (" %*s [%4" PRIuMAX "] %s\n",
- (int) (20 + level * 2), "", (uintmax_t) offset,
- known[op] ?: "???");
+ if (op < sizeof known / sizeof known[0] && known[op] != NULL)
+ printf ("%*s[%4" PRIuMAX "] %s\n",
+ indent, "", (uintmax_t) offset, known[op]);
+ else
+ printf ("%*s[%4" PRIuMAX "] %#x\n",
+ indent, "", (uintmax_t) offset, op);
++offset;
break;
}
+
+ indent = indentrest;
}
}
static void
-print_debug_abbrev_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
+print_debug_abbrev_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
+ Ebl *ebl __attribute__ ((unused)),
+ GElf_Ehdr *ehdr __attribute__ ((unused)),
+ Elf_Scn *scn __attribute__ ((unused)),
GElf_Shdr *shdr, Dwarf *dbg)
{
printf (gettext ("\nDWARF section '%s' at offset %#" PRIx64 ":\n"
@@ -3257,47 +3968,59 @@ print_debug_abbrev_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
".debug_abbrev", (uint64_t) shdr->sh_offset);
Dwarf_Off offset = 0;
- while (1)
+ while (offset < shdr->sh_size)
{
- size_t length;
- Dwarf_Abbrev abbrev;
+ printf (gettext ("\nAbbreviation section at offset %" PRIu64 ":\n"),
+ offset);
- if (dwarf_offabbrev (dbg, offset, &length, &abbrev) != 0)
+ while (1)
{
- printf (gettext (" *** error while reading abbreviation: %s\n"),
- dwarf_errmsg (-1));
- break;
- }
+ size_t length;
+ Dwarf_Abbrev abbrev;
- if (length == 1)
- /* This is the NUL byte at the end of the section. */
- break;
+ int res = dwarf_offabbrev (dbg, offset, &length, &abbrev);
+ if (res != 0)
+ {
+ if (unlikely (res < 0))
+ {
+ printf (gettext ("\
+ *** error while reading abbreviation: %s\n"),
+ dwarf_errmsg (-1));
+ return;
+ }
- /* We know these calls can never fail. */
- unsigned int code = dwarf_getabbrevcode (&abbrev);
- unsigned int tag = dwarf_getabbrevtag (&abbrev);
- int has_children = dwarf_abbrevhaschildren (&abbrev);
+ /* This is the NUL byte at the end of the section. */
+ ++offset;
+ break;
+ }
- printf (gettext (" [%5u] offset: %" PRId64
- ", children: %s, tag: %s\n"),
- code, (int64_t) offset,
- has_children ? gettext ("yes") : gettext ("no"),
- dwarf_tag_string (tag));
+ /* We know these calls can never fail. */
+ unsigned int code = dwarf_getabbrevcode (&abbrev);
+ unsigned int tag = dwarf_getabbrevtag (&abbrev);
+ int has_children = dwarf_abbrevhaschildren (&abbrev);
+
+ printf (gettext (" [%5u] offset: %" PRId64
+ ", children: %s, tag: %s\n"),
+ code, (int64_t) offset,
+ has_children ? gettext ("yes") : gettext ("no"),
+ dwarf_tag_string (tag));
+
+ size_t cnt = 0;
+ unsigned int name;
+ unsigned int form;
+ Dwarf_Off enoffset;
+ while (dwarf_getabbrevattr (&abbrev, cnt,
+ &name, &form, &enoffset) == 0)
+ {
+ printf (" attr: %s, form: %s, offset: %#" PRIx64 "\n",
+ dwarf_attr_string (name), dwarf_form_string (form),
+ (uint64_t) enoffset);
- size_t cnt = 0;
- unsigned int name;
- unsigned int form;
- Dwarf_Off enoffset;
- while (dwarf_getabbrevattr (&abbrev, cnt, &name, &form, &enoffset) == 0)
- {
- printf (" attr: %s, form: %s, offset: %#" PRIx64 "\n",
- dwarf_attr_string (name), dwarf_form_string (form),
- (uint64_t) enoffset);
+ ++cnt;
+ }
- ++cnt;
+ offset += length;
}
-
- offset += length;
}
}
@@ -3306,12 +4029,15 @@ print_debug_abbrev_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
not have to know a bit about the structure of the section, libdwarf
takes care of it. */
static void
-print_debug_aranges_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
+print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
+ Ebl *ebl __attribute__ ((unused)),
+ GElf_Ehdr *ehdr __attribute__ ((unused)),
+ Elf_Scn *scn __attribute__ ((unused)),
GElf_Shdr *shdr, Dwarf *dbg)
{
Dwarf_Aranges *aranges;
size_t cnt;
- if (dwarf_getaranges (dbg, &aranges, &cnt) != 0)
+ if (unlikely (dwarf_getaranges (dbg, &aranges, &cnt) != 0))
{
error (0, 0, gettext ("cannot get .debug_aranges content: %s"),
dwarf_errmsg (-1));
@@ -3337,7 +4063,7 @@ print_debug_aranges_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
for (size_t n = 0; n < cnt; ++n)
{
Dwarf_Arange *runp = dwarf_onearange (aranges, n);
- if (runp == NULL)
+ if (unlikely (runp == NULL))
{
printf ("cannot get arange %zu: %s\n", n, dwarf_errmsg (-1));
return;
@@ -3347,7 +4073,7 @@ print_debug_aranges_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
Dwarf_Word length;
Dwarf_Off offset;
- if (dwarf_getarangeinfo (runp, &start, &length, &offset) != 0)
+ if (unlikely (dwarf_getarangeinfo (runp, &start, &length, &offset) != 0))
printf (gettext (" [%*zu] ???\n"), digits, n);
else
printf (gettext (" [%*zu] start: %0#*" PRIx64
@@ -3358,16 +4084,95 @@ print_debug_aranges_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
}
}
+/* Print content of DWARF .debug_ranges section. */
+static void
+print_debug_ranges_section (Dwfl_Module *dwflmod,
+ Ebl *ebl __attribute__ ((unused)),
+ GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr,
+ Dwarf *dbg)
+{
+ Elf_Data *data = elf_rawdata (scn, NULL);
+
+ if (unlikely (data == NULL))
+ {
+ error (0, 0, gettext ("cannot get .debug_ranges content: %s"),
+ elf_errmsg (-1));
+ return;
+ }
+
+ printf (gettext ("\
+\nDWARF section '%s' at offset %#" PRIx64 ":\n"),
+ ".debug_ranges", (uint64_t) shdr->sh_offset);
+
+ size_t address_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
+
+ bool first = true;
+ unsigned char *readp = data->d_buf;
+ while (readp < (unsigned char *) data->d_buf + data->d_size)
+ {
+ ptrdiff_t offset = readp - (unsigned char *) data->d_buf;
+
+ if (unlikely (data->d_size - offset < address_size * 2))
+ {
+ printf (gettext (" [%6tx] <INVALID DATA>\n"), offset);
+ break;
+ }
+
+ Dwarf_Addr begin;
+ Dwarf_Addr end;
+ if (address_size == 8)
+ {
+ begin = read_8ubyte_unaligned_inc (dbg, readp);
+ end = read_8ubyte_unaligned_inc (dbg, readp);
+ }
+ else
+ {
+ begin = read_4ubyte_unaligned_inc (dbg, readp);
+ end = read_4ubyte_unaligned_inc (dbg, readp);
+ if (begin == (Dwarf_Addr) (uint32_t) -1)
+ begin = (Dwarf_Addr) -1l;
+ }
+
+ if (begin == (Dwarf_Addr) -1l) /* Base address entry. */
+ {
+ char *b = format_dwarf_addr (dwflmod, address_size, end);
+ printf (gettext (" [%6tx] base address %s\n"), offset, b);
+ free (b);
+ }
+ else if (begin == 0 && end == 0) /* End of list entry. */
+ first = true;
+ else
+ {
+ char *b = format_dwarf_addr (dwflmod, address_size, begin);
+ char *e = format_dwarf_addr (dwflmod, address_size, end);
+ /* We have an address range entry. */
+ if (first) /* First address range entry in a list. */
+ printf (gettext (" [%6tx] %s..%s\n"), offset, b, e);
+ else
+ printf (gettext (" %s..%s\n"), b, e);
+ free (b);
+ free (e);
+
+ first = false;
+ }
+ }
+}
+
static void
-print_debug_frame_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
- GElf_Shdr *shdr, Dwarf *dbg)
+print_debug_frame_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
+ Ebl *ebl __attribute__ ((unused)),
+ GElf_Ehdr *ehdr __attribute__ ((unused)),
+ Elf_Scn *scn __attribute__ ((unused)),
+ GElf_Shdr *shdr __attribute__ ((unused)),
+ Dwarf *dbg __attribute__ ((unused)))
{
}
struct attrcb_args
{
+ Dwfl_Module *dwflmod;
Dwarf *dbg;
int level;
unsigned int addrsize;
@@ -3399,18 +4204,21 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
switch (form)
{
- case DW_FORM_addr:;
- Dwarf_Addr addr;
- if (unlikely (dwarf_formaddr (attrp, &addr) != 0))
- {
- attrval_out:
- error (0, 0, gettext ("cannot get attribute value: %s"),
- dwarf_errmsg (-1));
- return DWARF_CB_ABORT;
- }
- printf (" %*s%-20s %#0*" PRIxMAX "\n",
- (int) (level * 2), "", dwarf_attr_string (attr),
- (int) (cbargs->addrsize * 2), (uintmax_t) addr);
+ case DW_FORM_addr:
+ {
+ Dwarf_Addr addr;
+ if (unlikely (dwarf_formaddr (attrp, &addr) != 0))
+ {
+ attrval_out:
+ error (0, 0, gettext ("cannot get attribute value: %s"),
+ dwarf_errmsg (-1));
+ return DWARF_CB_ABORT;
+ }
+ char *a = format_dwarf_addr (cbargs->dwflmod, cbargs->addrsize, addr);
+ printf (" %*s%-20s %s\n",
+ (int) (level * 2), "", dwarf_attr_string (attr), a);
+ free (a);
+ }
break;
case DW_FORM_indirect:
@@ -3429,13 +4237,13 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
case DW_FORM_ref4:
case DW_FORM_ref2:
case DW_FORM_ref1:;
- Dwarf_Off ref;
- if (unlikely (dwarf_formref (attrp, &ref) != 0))
+ Dwarf_Die ref;
+ if (unlikely (dwarf_formref_die (attrp, &ref) == NULL))
goto attrval_out;
printf (" %*s%-20s [%6" PRIxMAX "]\n",
(int) (level * 2), "", dwarf_attr_string (attr),
- (uintmax_t) (ref + cbargs->cu_offset));
+ (uintmax_t) dwarf_dieoffset (&ref));
break;
case DW_FORM_udata:
@@ -3448,17 +4256,72 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
if (unlikely (dwarf_formudata (attrp, &num) != 0))
goto attrval_out;
- if (attr == DW_AT_language)
+ const char *valuestr = NULL;
+ switch (attr)
{
- printf (" %*s%-20s %s (%d)\n",
+ case DW_AT_location:
+ case DW_AT_data_location:
+ case DW_AT_data_member_location:
+ case DW_AT_vtable_elem_location:
+ case DW_AT_string_length:
+ case DW_AT_use_location:
+ case DW_AT_frame_base:
+ case DW_AT_return_addr:
+ case DW_AT_static_link:
+ printf (" %*s%-20s location list [%6" PRIxMAX "]\n",
(int) (level * 2), "", dwarf_attr_string (attr),
- dwarf_lang_string (num), (int) num);
+ (uintmax_t) num);
+ return DWARF_CB_OK;
+
+ case DW_AT_ranges:
+ printf (" %*s%-20s range list [%6" PRIxMAX "]\n",
+ (int) (level * 2), "", dwarf_attr_string (attr),
+ (uintmax_t) num);
+ return DWARF_CB_OK;
+
+ case DW_AT_language:
+ valuestr = dwarf_lang_string (num);
+ break;
+ case DW_AT_encoding:
+ valuestr = dwarf_encoding_string (num);
+ break;
+ case DW_AT_accessibility:
+ valuestr = dwarf_access_string (num);
+ break;
+ case DW_AT_visibility:
+ valuestr = dwarf_visibility_string (num);
+ break;
+ case DW_AT_virtuality:
+ valuestr = dwarf_virtuality_string (num);
+ break;
+ case DW_AT_identifier_case:
+ valuestr = dwarf_identifier_case_string (num);
+ break;
+ case DW_AT_calling_convention:
+ valuestr = dwarf_calling_convention_string (num);
+ break;
+ case DW_AT_inline:
+ valuestr = dwarf_inline_string (num);
+ break;
+ case DW_AT_ordering:
+ valuestr = dwarf_ordering_string (num);
+ break;
+ case DW_AT_discr_list:
+ valuestr = dwarf_discr_list_string (num);
+ break;
+ default:
+ /* Nothing. */
break;
}
- printf (" %*s%-20s %" PRIuMAX "\n",
- (int) (level * 2), "", dwarf_attr_string (attr),
- (uintmax_t) num);
+ if (valuestr == NULL)
+ printf (" %*s%-20s %" PRIuMAX "\n",
+ (int) (level * 2), "", dwarf_attr_string (attr),
+ (uintmax_t) num);
+ else
+ printf (" %*s%-20s %s (%" PRIuMAX ")\n",
+ (int) (level * 2), "", dwarf_attr_string (attr),
+ valuestr, (uintmax_t) num);
break;
case DW_FORM_flag:;
@@ -3483,9 +4346,32 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
(int) (level * 2), "", dwarf_attr_string (attr),
(uintmax_t) block.length);
- if (attr == DW_AT_data_member_location)
- print_ops (cbargs->dbg, level, cbargs->addrsize, block.length,
- block.data);
+ switch (attr)
+ {
+ case DW_AT_location:
+ case DW_AT_data_location:
+ case DW_AT_data_member_location:
+ case DW_AT_vtable_elem_location:
+ case DW_AT_string_length:
+ case DW_AT_use_location:
+ case DW_AT_frame_base:
+ case DW_AT_return_addr:
+ case DW_AT_static_link:
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_bit_size:
+ case DW_AT_bit_offset:
+ case DW_AT_bit_stride:
+ case DW_AT_byte_size:
+ case DW_AT_byte_stride:
+ case DW_AT_count:
+ case DW_AT_lower_bound:
+ case DW_AT_upper_bound:
+ print_ops (cbargs->dwflmod, cbargs->dbg,
+ 12 + level * 2, 12 + level * 2,
+ cbargs->addrsize, block.length, block.data);
+ break;
+ }
break;
default:
@@ -3500,7 +4386,10 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
static void
-print_debug_info_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
+print_debug_info_section (Dwfl_Module *dwflmod,
+ Ebl *ebl __attribute__ ((unused)),
+ GElf_Ehdr *ehdr __attribute__ ((unused)),
+ Elf_Scn *scn __attribute__ ((unused)),
GElf_Shdr *shdr, Dwarf *dbg)
{
printf (gettext ("\
@@ -3511,7 +4400,7 @@ print_debug_info_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
if (shdr->sh_size == 0)
return;
- size_t maxdies = 20;
+ int maxdies = 20;
Dwarf_Die *dies = (Dwarf_Die *) xmalloc (maxdies * sizeof (Dwarf_Die));
Dwarf_Off offset = 0;
@@ -3535,6 +4424,7 @@ print_debug_info_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
struct attrcb_args args;
+ args.dwflmod = dwflmod;
args.dbg = dbg;
args.addrsize = addrsize;
args.cu_offset = offset;
@@ -3554,7 +4444,7 @@ print_debug_info_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
do
{
offset = dwarf_dieoffset (&dies[level]);
- if (offset == -1l)
+ if (unlikely (offset == ~0ul))
{
error (0, 0, gettext ("cannot get DIE offset: %s"),
dwarf_errmsg (-1));
@@ -3562,7 +4452,7 @@ print_debug_info_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
}
int tag = dwarf_tag (&dies[level]);
- if (tag == DW_TAG_invalid)
+ if (unlikely (tag == DW_TAG_invalid))
{
error (0, 0, gettext ("cannot get tag of DIE at offset %" PRIu64
" in section '%s': %s"),
@@ -3570,93 +4460,9 @@ print_debug_info_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
goto do_return;
}
- static const char *const lowtags[] =
- {
- [DW_TAG_array_type] = "array_type",
- [DW_TAG_class_type] = "class_type",
- [DW_TAG_entry_point] = "entry_point",
- [DW_TAG_enumeration_type] = "enumeration_type",
- [DW_TAG_formal_parameter] = "formal_parameter",
- [DW_TAG_imported_declaration] = "imported_declaration",
- [DW_TAG_label] = "label",
- [DW_TAG_lexical_block] = "lexical_block",
- [DW_TAG_member] = "member",
- [DW_TAG_pointer_type] = "pointer_type",
- [DW_TAG_reference_type] = "reference_type",
- [DW_TAG_compile_unit] = "compile_unit",
- [DW_TAG_string_type] = "string_type",
- [DW_TAG_structure_type] = "structure_type",
- [DW_TAG_subroutine_type] = "subroutine_type",
- [DW_TAG_typedef] = "typedef",
- [DW_TAG_union_type] = "union_type",
- [DW_TAG_unspecified_parameters] = "unspecified_parameters",
- [DW_TAG_variant] = "variant",
- [DW_TAG_common_block] = "common_block",
- [DW_TAG_common_inclusion] = "common_inclusion",
- [DW_TAG_inheritance] = "inheritance",
- [DW_TAG_inlined_subroutine] = "inlined_subroutine",
- [DW_TAG_module] = "module",
- [DW_TAG_ptr_to_member_type] = "ptr_to_member_type",
- [DW_TAG_set_type] = "set_type",
- [DW_TAG_subrange_type] = "subrange_type",
- [DW_TAG_with_stmt] = "with_stmt",
- [DW_TAG_access_declaration] = "access_declaration",
- [DW_TAG_base_type] = "base_type",
- [DW_TAG_catch_block] = "catch_block",
- [DW_TAG_const_type] = "const_type",
- [DW_TAG_constant] = "constant",
- [DW_TAG_enumerator] = "enumerator",
- [DW_TAG_file_type] = "file_type",
- [DW_TAG_friend] = "friend",
- [DW_TAG_namelist] = "namelist",
- [DW_TAG_namelist_item] = "namelist_item",
- [DW_TAG_packed_type] = "packed_type",
- [DW_TAG_subprogram] = "subprogram",
- [DW_TAG_template_type_param] = "template_type_param",
- [DW_TAG_template_value_param] = "template_value_param",
- [DW_TAG_thrown_type] = "thrown_type",
- [DW_TAG_try_block] = "try_block",
- [DW_TAG_variant_part] = "variant_part",
- [DW_TAG_variable] = "variable",
- [DW_TAG_volatile_type] = "volatile_type"
- };
-
- const char *tagstr;
- switch (tag)
- {
- case DW_TAG_lo_user:
- tagstr = "lo_user";
- break;
-
- case DW_TAG_MIPS_loop:
- tagstr = "MIPS_loop";
- break;
-
- case DW_TAG_format_label:
- tagstr = "format_label";
- break;
-
- case DW_TAG_function_template:
- tagstr = "function_template";
- break;
-
- case DW_TAG_class_template:
- tagstr = "class_template";
- break;
- case DW_TAG_hi_user:
- tagstr = "hi_user";
- break;
-
- default:
- if (tag < sizeof (lowtags) / sizeof (lowtags[0]))
- tagstr = lowtags[tag];
- else
- tagstr = "???";
- break;
- }
-
printf (" [%6" PRIx64 "] %*s%s\n",
- (uint64_t) offset, (int) (level * 2), "", tagstr);
+ (uint64_t) offset, (int) (level * 2), "",
+ dwarf_tag_string (tag));
/* Print the attribute values. */
args.level = level;
@@ -3675,7 +4481,7 @@ print_debug_info_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
if (level-- == 0)
break;
- if (res == -1)
+ if (unlikely (res == -1))
{
error (0, 0, gettext ("cannot get next DIE: %s\n"),
dwarf_errmsg (-1));
@@ -3703,8 +4509,9 @@ print_debug_info_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
static void
-print_debug_line_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
- GElf_Shdr *shdr, Dwarf *dbg)
+print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
+ GElf_Ehdr *ehdr __attribute__ ((unused)),
+ Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
{
printf (gettext ("\
\nDWARF section '%s' at offset %#" PRIx64 ":\n"),
@@ -3716,7 +4523,7 @@ print_debug_line_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
/* There is no functionality in libdw to read the information in the
way it is represented here. Hardcode the decoder. */
Elf_Data *data = elf_getdata (scn, NULL);
- if (data == NULL || data->d_buf == NULL)
+ if (unlikely (data == NULL || data->d_buf == NULL))
{
error (0, 0, gettext ("cannot get line data section data: %s"),
elf_errmsg (-1));
@@ -3731,6 +4538,8 @@ print_debug_line_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
{
size_t start_offset = linep - (const unsigned char *) data->d_buf;
+ printf (gettext ("\nTable at offset %Zu:\n"), start_offset);
+
Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep);
unsigned int length = 4;
if (unlikely (unit_length == 0xffffffff))
@@ -3797,7 +4606,15 @@ print_debug_line_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
line_range, opcode_base);
if (unlikely (linep + opcode_base - 1 >= lineendp))
- goto invalid_data;
+ {
+ invalid_unit:
+ error (0, 0,
+ gettext ("invalid data at offset %tu in section [%zu] '%s'"),
+ linep - (const unsigned char *) data->d_buf,
+ elf_ndxscn (scn), ".debug_line");
+ linep = lineendp;
+ continue;
+ }
int opcode_base_l10 = 1;
unsigned int tmp = opcode_base;
while (tmp > 10)
@@ -3813,14 +4630,14 @@ print_debug_line_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
opcode_base_l10, cnt, linep[cnt - 1]);
linep += opcode_base - 1;
if (unlikely (linep >= lineendp))
- goto invalid_data;
+ goto invalid_unit;
puts (gettext ("\nDirectory table:"));
while (*linep != 0)
{
unsigned char *endp = memchr (linep, '\0', lineendp - linep);
- if (endp == NULL)
- goto invalid_data;
+ if (unlikely (endp == NULL))
+ goto invalid_unit;
printf (" %s\n", (char *) linep);
@@ -3830,7 +4647,7 @@ print_debug_line_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
++linep;
if (unlikely (linep >= lineendp))
- goto invalid_data;
+ goto invalid_unit;
puts (gettext ("\nFile name table:\n"
" Entry Dir Time Size Name"));
for (unsigned int cnt = 1; *linep != 0; ++cnt)
@@ -3838,8 +4655,8 @@ print_debug_line_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
/* First comes the file name. */
char *fname = (char *) linep;
unsigned char *endp = memchr (fname, '\0', lineendp - linep);
- if (endp == NULL)
- goto invalid_data;
+ if (unlikely (endp == NULL))
+ goto invalid_unit;
linep = endp + 1;
/* Then the index. */
@@ -3920,22 +4737,23 @@ print_debug_line_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
line += line_increment;
address += address_increment;
+ char *a = format_dwarf_addr (dwflmod, 0, address);
printf (gettext ("\
- special opcode %u: address+%u = %#" PRIx64 ", line%+d = %zu\n"),
- opcode, address_increment, (uint64_t) address,
- line_increment, line);
+ special opcode %u: address+%u = %s, line%+d = %zu\n"),
+ opcode, address_increment, a, line_increment, line);
+ free (a);
}
else if (opcode == 0)
{
/* This an extended opcode. */
if (unlikely (linep + 2 > lineendp))
- goto invalid_data;
+ goto invalid_unit;
/* The length. */
unsigned int len = *linep++;
if (unlikely (linep + len > lineendp))
- goto invalid_data;
+ goto invalid_unit;
/* The sub-opcode. */
opcode = *linep++;
@@ -3958,8 +4776,11 @@ print_debug_line_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
address = read_4ubyte_unaligned_inc (dbg, linep);
else
address = read_8ubyte_unaligned_inc (dbg, linep);
- printf (gettext ("set address to %#" PRIx64 "\n"),
- (uint64_t) address);
+ {
+ char *a = format_dwarf_addr (dwflmod, 0, address);
+ printf (gettext ("set address to %s\n"), a);
+ free (a);
+ }
break;
case DW_LNE_define_file:
@@ -3967,8 +4788,8 @@ print_debug_line_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
char *fname = (char *) linep;
unsigned char *endp = memchr (linep, '\0',
lineendp - linep);
- if (endp == NULL)
- goto invalid_data;
+ if (unlikely (endp == NULL))
+ goto invalid_unit;
linep = endp + 1;
unsigned int diridx;
@@ -3992,7 +4813,7 @@ define new file: dir=%u, mtime=%" PRIu64 ", length=%" PRIu64 ", name=%s\n"),
break;
}
}
- else if (opcode <= DW_LNS_set_epilog_begin)
+ else if (opcode <= DW_LNS_set_epilogue_begin)
{
/* This is a known standard opcode. */
switch (opcode)
@@ -4007,9 +4828,12 @@ define new file: dir=%u, mtime=%" PRIu64 ", length=%" PRIu64 ", name=%s\n"),
address. */
get_uleb128 (u128, linep);
address += minimum_instr_len * u128;
- printf (gettext ("\
- advance address by %u to %#" PRIx64 "\n"),
- u128, (uint64_t) address);
+ {
+ char *a = format_dwarf_addr (dwflmod, 0, address);
+ printf (gettext ("advance address by %u to %s\n"),
+ u128, a);
+ free (a);
+ }
break;
case DW_LNS_advance_line:
@@ -4032,7 +4856,7 @@ define new file: dir=%u, mtime=%" PRIu64 ", length=%" PRIu64 ", name=%s\n"),
case DW_LNS_set_column:
/* Takes one uleb128 parameter which is stored in column. */
if (unlikely (standard_opcode_lengths[opcode] != 1))
- goto invalid_data;
+ goto invalid_unit;
get_uleb128 (u128, linep);
printf (gettext (" set column to %" PRIu64 "\n"),
@@ -4056,22 +4880,29 @@ define new file: dir=%u, mtime=%" PRIu64 ", length=%" PRIu64 ", name=%s\n"),
u128 = (minimum_instr_len
* ((255 - opcode_base) / line_range));
address += u128;
- printf (gettext ("\
- advance address by constant %u to %#" PRIx64 "\n"),
- u128, (uint64_t) address);
+ {
+ char *a = format_dwarf_addr (dwflmod, 0, address);
+ printf (gettext ("advance address by constant %u to %s\n"),
+ u128, a);
+ free (a);
+ }
break;
case DW_LNS_fixed_advance_pc:
/* Takes one 16 bit parameter which is added to the
address. */
if (unlikely (standard_opcode_lengths[opcode] != 1))
- goto invalid_data;
+ goto invalid_unit;
u128 = read_2ubyte_unaligned_inc (dbg, linep);
address += u128;
- printf (gettext ("\
- advance address by fixed value %u to %#" PRIx64 "\n"),
- u128, (uint64_t) address);
+ {
+ char *a = format_dwarf_addr (dwflmod, 0, address);
+ printf (gettext ("\
+advance address by fixed value %u to %s\n"),
+ u128, a);
+ free (a);
+ }
break;
case DW_LNS_set_prologue_end:
@@ -4079,7 +4910,7 @@ define new file: dir=%u, mtime=%" PRIu64 ", length=%" PRIu64 ", name=%s\n"),
puts (gettext (" set prologue end flag"));
break;
- case DW_LNS_set_epilog_begin:
+ case DW_LNS_set_epilogue_begin:
/* Takes no argument. */
puts (gettext (" set epilogue begin flag"));
break;
@@ -4114,16 +4945,87 @@ define new file: dir=%u, mtime=%" PRIu64 ", length=%" PRIu64 ", name=%s\n"),
static void
-print_debug_loc_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
- GElf_Shdr *shdr, Dwarf *dbg)
+print_debug_loc_section (Dwfl_Module *dwflmod,
+ Ebl *ebl __attribute__ ((unused)),
+ GElf_Ehdr *ehdr __attribute__ ((unused)),
+ Elf_Scn *scn __attribute__ ((unused)),
+ GElf_Shdr *shdr,
+ Dwarf *dbg __attribute__ ((unused)))
{
+ Elf_Data *data = elf_rawdata (scn, NULL);
+
+ if (unlikely (data == NULL))
+ {
+ error (0, 0, gettext ("cannot get .debug_loc content: %s"),
+ elf_errmsg (-1));
+ return;
+ }
+
printf (gettext ("\
\nDWARF section '%s' at offset %#" PRIx64 ":\n"),
".debug_loc", (uint64_t) shdr->sh_offset);
- // XXX add something
-}
+ size_t address_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
+
+ bool first = true;
+ unsigned char *readp = data->d_buf;
+ while (readp < (unsigned char *) data->d_buf + data->d_size)
+ {
+ ptrdiff_t offset = readp - (unsigned char *) data->d_buf;
+ if (unlikely (data->d_size - offset < address_size * 2))
+ {
+ printf (gettext (" [%6tx] <INVALID DATA>\n"), offset);
+ break;
+ }
+
+ Dwarf_Addr begin;
+ Dwarf_Addr end;
+ if (address_size == 8)
+ {
+ begin = read_8ubyte_unaligned_inc (dbg, readp);
+ end = read_8ubyte_unaligned_inc (dbg, readp);
+ }
+ else
+ {
+ begin = read_4ubyte_unaligned_inc (dbg, readp);
+ end = read_4ubyte_unaligned_inc (dbg, readp);
+ if (begin == (Dwarf_Addr) (uint32_t) -1)
+ begin = (Dwarf_Addr) -1l;
+ }
+
+ if (begin == (Dwarf_Addr) -1l) /* Base address entry. */
+ {
+ char *b = format_dwarf_addr (dwflmod, address_size, end);
+ printf (gettext (" [%6tx] base address %s\n"), offset, b);
+ free (b);
+ }
+ else if (begin == 0 && end == 0) /* End of list entry. */
+ first = true;
+ else
+ {
+ /* We have a location expression entry. */
+ uint_fast16_t len = read_2ubyte_unaligned_inc (dbg, readp);
+
+ char *b = format_dwarf_addr (dwflmod, address_size, begin);
+ char *e = format_dwarf_addr (dwflmod, address_size, end);
+
+ if (first) /* First entry in a list. */
+ printf (gettext (" [%6tx] %s..%s"), offset, b, e);
+ else
+ printf (gettext (" %s..%s"), b, e);
+
+ free (b);
+ free (e);
+
+ print_ops (dwflmod, dbg, 1, 18 + (address_size * 4),
+ address_size, len, readp);
+
+ first = false;
+ readp += len;
+ }
+ }
+}
struct mac_culist
{
@@ -4149,8 +5051,10 @@ mac_compare (const void *p1, const void *p2)
static void
-print_debug_macinfo_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
- GElf_Shdr *shdr, Dwarf *dbg)
+print_debug_macinfo_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
+ Ebl *ebl __attribute__ ((unused)),
+ GElf_Ehdr *ehdr __attribute__ ((unused)),
+ Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
{
printf (gettext ("\
\nDWARF section '%s' at offset %#" PRIx64 ":\n"),
@@ -4160,7 +5064,7 @@ print_debug_macinfo_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
/* There is no function in libdw to iterate over the raw content of
the section but it is easy enough to do. */
Elf_Data *data = elf_getdata (scn, NULL);
- if (data == NULL || data->d_buf == NULL)
+ if (unlikely (data == NULL || data->d_buf == NULL))
{
error (0, 0, gettext ("cannot get macro information section data: %s"),
elf_errmsg (-1));
@@ -4239,7 +5143,7 @@ print_debug_macinfo_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
get_uleb128 (u128, readp);
endp = memchr (readp, '\0', readendp - readp);
- if (endp == NULL)
+ if (unlikely (endp == NULL))
{
printf (gettext ("\
%*s*** non-terminated string at end of section"),
@@ -4265,7 +5169,7 @@ print_debug_macinfo_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
get_uleb128 (u128_2, readp);
/* Find the CU DIE for this file. */
- ptrdiff_t macoff = readp - (const unsigned char *) data->d_buf;
+ size_t macoff = readp - (const unsigned char *) data->d_buf;
const char *fname = "???";
if (macoff >= cus[0].offset)
{
@@ -4294,7 +5198,7 @@ print_debug_macinfo_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
default:
// XXX gcc seems to generate files with a trailing zero.
- if (opcode != 0 || readp != readendp)
+ if (unlikely (opcode != 0 || readp != readendp))
printf ("%*s*** invalid opcode %u\n", level, "", opcode);
break;
}
@@ -4304,7 +5208,8 @@ print_debug_macinfo_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
/* Callback for printing global names. */
static int
-print_pubnames (Dwarf *dbg, Dwarf_Global *global, void *arg)
+print_pubnames (Dwarf *dbg __attribute__ ((unused)), Dwarf_Global *global,
+ void *arg)
{
int *np = (int *) arg;
@@ -4318,7 +5223,10 @@ print_pubnames (Dwarf *dbg, Dwarf_Global *global, void *arg)
/* Print the known exported symbols in the DWARF section '.debug_pubnames'. */
static void
-print_debug_pubnames_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
+print_debug_pubnames_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
+ Ebl *ebl __attribute__ ((unused)),
+ GElf_Ehdr *ehdr __attribute__ ((unused)),
+ Elf_Scn *scn __attribute__ ((unused)),
GElf_Shdr *shdr, Dwarf *dbg)
{
printf (gettext ("\nDWARF section '%s' at offset %#" PRIx64 ":\n"),
@@ -4330,7 +5238,10 @@ print_debug_pubnames_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
/* Print the content of the DWARF string section '.debug_str'. */
static void
-print_debug_str_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
+print_debug_str_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
+ Ebl *ebl __attribute__ ((unused)),
+ GElf_Ehdr *ehdr __attribute__ ((unused)),
+ Elf_Scn *scn __attribute__ ((unused)),
GElf_Shdr *shdr, Dwarf *dbg)
{
/* Compute floor(log16(shdr->sh_size)). */
@@ -4354,7 +5265,7 @@ print_debug_str_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
{
size_t len;
const char *str = dwarf_getstring (dbg, offset, &len);
- if (str == NULL)
+ if (unlikely (str == NULL))
{
printf (gettext (" *** error while reading strings: %s\n"),
dwarf_errmsg (-1));
@@ -4367,44 +5278,40 @@ print_debug_str_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
}
}
-
static void
-print_debug (Ebl *ebl, GElf_Ehdr *ehdr)
+print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr)
{
- /* Find the version information sections. For this we have to
- search through the section table. */
- Dwarf *dbg;
- Elf_Scn *scn;
- size_t shstrndx;
-
/* Before we start the real work get a debug context descriptor. */
- dbg = dwarf_begin_elf (ebl->elf, DWARF_C_READ, NULL);
+ Dwarf_Addr dwbias;
+ Dwarf *dbg = dwfl_module_getdwarf (dwflmod, &dwbias);
if (dbg == NULL)
{
error (0, 0, gettext ("cannot get debug context descriptor: %s"),
- dwarf_errmsg (-1));
+ dwfl_errmsg (-1));
return;
}
/* Get the section header string table index. */
- if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+ size_t shstrndx;
+ if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
error (EXIT_FAILURE, 0,
gettext ("cannot get section header string table index"));
- scn = NULL;
+ /* Look through all the sections for the debugging sections to print. */
+ Elf_Scn *scn = NULL;
while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
{
- /* Handle the section if it is part of the versioning handling. */
GElf_Shdr shdr_mem;
GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
- if (shdr != NULL || shdr->sh_type != SHT_PROGBITS)
+ if (shdr != NULL && shdr->sh_type == SHT_PROGBITS)
{
static const struct
{
const char *name;
enum section_e bitmask;
- void (*fp) (Ebl *, GElf_Ehdr *, Elf_Scn *, GElf_Shdr *, Dwarf *);
+ void (*fp) (Dwfl_Module *, Ebl *,
+ GElf_Ehdr *, Elf_Scn *, GElf_Shdr *, Dwarf *);
} debug_sections[] =
{
#define NEW_SECTION(name) \
@@ -4418,6 +5325,7 @@ print_debug (Ebl *ebl, GElf_Ehdr *ehdr)
NEW_SECTION (pubnames),
NEW_SECTION (str),
NEW_SECTION (macinfo),
+ NEW_SECTION (ranges),
{ ".eh_frame", section_frame, print_debug_frame_section }
};
const int ndebug_sections = (sizeof (debug_sections)
@@ -4430,26 +5338,851 @@ print_debug (Ebl *ebl, GElf_Ehdr *ehdr)
if (strcmp (name, debug_sections[n].name) == 0)
{
if (print_debug_sections & debug_sections[n].bitmask)
- debug_sections[n].fp (ebl, ehdr, scn, shdr, dbg);
+ debug_sections[n].fp (dwflmod, ebl, ehdr, scn, shdr, dbg);
break;
}
}
}
+}
+
+
+#define ITEM_INDENT 4
+#define ITEM_WRAP_COLUMN 150
+#define REGISTER_WRAP_COLUMN 75
+
+/* Print "NAME: FORMAT", wrapping when FORMAT_MAX chars of FORMAT would
+ make the line exceed ITEM_WRAP_COLUMN. Unpadded numbers look better
+ for the core items. But we do not want the line breaks to depend on
+ the particular values. */
+static unsigned int
+__attribute__ ((format (printf, 7, 8)))
+print_core_item (unsigned int colno, char sep, unsigned int wrap,
+ size_t name_width, const char *name,
+ size_t format_max, const char *format, ...)
+{
+ size_t len = strlen (name);
+ if (name_width < len)
+ name_width = len;
+
+ size_t n = name_width + sizeof ": " - 1 + format_max;
+
+ if (colno == 0)
+ {
+ printf ("%*s", ITEM_INDENT, "");
+ colno = ITEM_INDENT + n;
+ }
+ else if (colno + 2 + n < wrap)
+ {
+ printf ("%c ", sep);
+ colno += 2 + n;
+ }
+ else
+ {
+ printf ("\n%*s", ITEM_INDENT, "");
+ colno = ITEM_INDENT + n;
+ }
+
+ printf ("%s: %*s", name, (int) (name_width - len), "");
+
+ va_list ap;
+ va_start (ap, format);
+ vprintf (format, ap);
+ va_end (ap);
+
+ return colno;
+}
+
+static const void *
+convert (Elf *core, Elf_Type type, uint_fast16_t count,
+ void *value, const void *data, size_t size)
+{
+ Elf_Data valuedata =
+ {
+ .d_type = type,
+ .d_buf = value,
+ .d_size = size ?: gelf_fsize (core, type, count, EV_CURRENT),
+ .d_version = EV_CURRENT,
+ };
+ Elf_Data indata =
+ {
+ .d_type = type,
+ .d_buf = (void *) data,
+ .d_size = valuedata.d_size,
+ .d_version = EV_CURRENT,
+ };
+
+ Elf_Data *d = (gelf_getclass (core) == ELFCLASS32
+ ? elf32_xlatetom : elf64_xlatetom)
+ (&valuedata, &indata, elf_getident (core, NULL)[EI_DATA]);
+ if (d == NULL)
+ error (EXIT_FAILURE, 0,
+ gettext ("cannot convert core note data: %s"), elf_errmsg (-1));
+
+ return data + indata.d_size;
+}
+
+typedef uint8_t GElf_Byte;
+
+static unsigned int
+handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
+ unsigned int colno, size_t *repeated_size)
+{
+ uint_fast16_t count = item->count ?: 1;
+
+#define TYPES \
+ DO_TYPE (BYTE, Byte, "0x%.2" PRIx8, "%" PRId8, 4); \
+ DO_TYPE (HALF, Half, "0x%.4" PRIx16, "%" PRId16, 6); \
+ DO_TYPE (WORD, Word, "0x%.8" PRIx32, "%" PRId32, 11); \
+ DO_TYPE (SWORD, Sword, "%" PRId32, "%" PRId32, 11); \
+ DO_TYPE (XWORD, Xword, "0x%.16" PRIx64, "%" PRId64, 20); \
+ DO_TYPE (SXWORD, Sxword, "%" PRId64, "%" PRId64, 20)
+
+#define DO_TYPE(NAME, Name, hex, dec, max) GElf_##Name Name[count]
+ union { TYPES; } value;
+#undef DO_TYPE
+
+ void *data = &value;
+ size_t size = gelf_fsize (core, item->type, count, EV_CURRENT);
+ size_t convsize = size;
+ if (repeated_size != NULL)
+ {
+ if (*repeated_size > size && (item->format == 'b' || item->format == 'B'))
+ {
+ data = alloca (*repeated_size);
+ count *= *repeated_size / size;
+ convsize = count * size;
+ *repeated_size -= convsize;
+ }
+ else
+ *repeated_size -= size;
+ }
+
+ desc = convert (core, item->type, count, data, desc + item->offset, convsize);
+
+ Elf_Type type = item->type;
+ if (type == ELF_T_ADDR)
+ type = gelf_getclass (core) == ELFCLASS32 ? ELF_T_WORD : ELF_T_XWORD;
+
+ switch (item->format)
+ {
+ case 'd':
+ assert (count == 1);
+ switch (type)
+ {
+#define DO_TYPE(NAME, Name, hex, dec, max) \
+ case ELF_T_##NAME: \
+ colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, \
+ 0, item->name, max, dec, value.Name[0]); \
+ break
+ TYPES;
+#undef DO_TYPE
+ default:
+ abort ();
+ }
+ break;
+
+ case 'x':
+ assert (count == 1);
+ switch (type)
+ {
+#define DO_TYPE(NAME, Name, hex, dec, max) \
+ case ELF_T_##NAME: \
+ colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, \
+ 0, item->name, max, hex, value.Name[0]); \
+ break
+ TYPES;
+#undef DO_TYPE
+ default:
+ abort ();
+ }
+ break;
+
+ case 'b':
+ case 'B':
+ assert (size % sizeof (unsigned int) == 0);
+ unsigned int nbits = count * size * 8;
+ unsigned int pop = 0;
+ for (const unsigned int *i = data; (void *) i < data + count * size; ++i)
+ pop += __builtin_popcount (*i);
+ bool negate = pop > nbits / 2;
+ const unsigned int bias = item->format == 'b';
+
+ {
+ char printed[(negate ? nbits - pop : pop) * 16];
+ char *p = printed;
+ *p = '\0';
+
+ if (BYTE_ORDER != LITTLE_ENDIAN && size > sizeof (unsigned int))
+ {
+ assert (size == sizeof (unsigned int) * 2);
+ for (unsigned int *i = data;
+ (void *) i < data + count * size; i += 2)
+ {
+ unsigned int w = i[1];
+ i[1] = i[0];
+ i[0] = w;
+ }
+ }
+
+ unsigned int lastbit = 0;
+ for (const unsigned int *i = data;
+ (void *) i < data + count * size; ++i)
+ {
+ unsigned int bit = ((void *) i - data) * 8;
+ unsigned int w = negate ? ~*i : *i;
+ while (w != 0)
+ {
+ int n = ffs (w);
+ w >>= n;
+ bit += n;
+
+ if (lastbit + 1 != bit)
+ p += sprintf (p, "-%u,%u", lastbit - bias, bit - bias);
+ else if (lastbit == 0)
+ p += sprintf (p, "%u", bit - bias);
+
+ lastbit = bit;
+ }
+ }
+ if (lastbit > 0 && lastbit + 1 != nbits)
+ p += sprintf (p, "-%u", nbits - bias);
+
+ colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, 0, item->name,
+ 4 + nbits * 4,
+ negate ? "~<%s>" : "<%s>", printed);
+ }
+ break;
+
+ case 'T':
+ case (char) ('T'|0x80):
+ assert (count == 2);
+ Dwarf_Word sec;
+ Dwarf_Word usec;
+ size_t maxfmt = 7;
+ switch (type)
+ {
+#define DO_TYPE(NAME, Name, hex, dec, max) \
+ case ELF_T_##NAME: \
+ sec = value.Name[0]; \
+ usec = value.Name[1]; \
+ maxfmt += max; \
+ break
+ TYPES;
+#undef DO_TYPE
+ default:
+ abort ();
+ }
+ if (unlikely (item->format == (char) ('T'|0x80)))
+ {
+ /* This is a hack for an ill-considered 64-bit ABI where
+ tv_usec is actually a 32-bit field with 32 bits of padding
+ rounding out struct timeval. We've already converted it as
+ a 64-bit field. For little-endian, this just means the
+ high half is the padding; it's presumably zero, but should
+ be ignored anyway. For big-endian, it means the 32-bit
+ field went into the high half of USEC. */
+ GElf_Ehdr ehdr_mem;
+ GElf_Ehdr *ehdr = gelf_getehdr (core, &ehdr_mem);
+ if (likely (ehdr->e_ident[EI_DATA] == ELFDATA2MSB))
+ usec >>= 32;
+ else
+ usec &= UINT32_MAX;
+ }
+ colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, 0, item->name,
+ maxfmt, "%" PRIu64 ".%.6" PRIu64, sec, usec);
+ break;
+
+ case 'c':
+ assert (count == 1);
+ colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, 0, item->name,
+ 1, "%c", value.Byte[0]);
+ break;
+
+ case 's':
+ colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, 0, item->name,
+ count, "%.*s", (int) count, value.Byte);
+ break;
+
+ default:
+ error (0, 0, "XXX not handling format '%c' for %s",
+ item->format, item->name);
+ break;
+ }
+
+#undef TYPES
+
+ return colno;
+}
+
+
+/* Sort items by group, and by layout offset within each group. */
+static int
+compare_core_items (const void *a, const void *b)
+{
+ const Ebl_Core_Item *const *p1 = a;
+ const Ebl_Core_Item *const *p2 = b;
+ const Ebl_Core_Item *item1 = *p1;
+ const Ebl_Core_Item *item2 = *p2;
+
+ return ((item1->group == item2->group ? 0
+ : strcmp (item1->group, item2->group))
+ ?: (int) item1->offset - (int) item2->offset);
+}
+
+/* Sort item groups by layout offset of the first item in the group. */
+static int
+compare_core_item_groups (const void *a, const void *b)
+{
+ const Ebl_Core_Item *const *const *p1 = a;
+ const Ebl_Core_Item *const *const *p2 = b;
+ const Ebl_Core_Item *const *group1 = *p1;
+ const Ebl_Core_Item *const *group2 = *p2;
+ const Ebl_Core_Item *item1 = *group1;
+ const Ebl_Core_Item *item2 = *group2;
+
+ return (int) item1->offset - (int) item2->offset;
+}
+
+static unsigned int
+handle_core_items (Elf *core, const void *desc, size_t descsz,
+ const Ebl_Core_Item *items, size_t nitems)
+{
+ if (nitems == 0)
+ return 0;
+
+ /* Sort to collect the groups together. */
+ const Ebl_Core_Item *sorted_items[nitems];
+ for (size_t i = 0; i < nitems; ++i)
+ sorted_items[i] = &items[i];
+ qsort (sorted_items, nitems, sizeof sorted_items[0], &compare_core_items);
+
+ /* Collect the unique groups and sort them. */
+ const Ebl_Core_Item **groups[nitems];
+ groups[0] = &sorted_items[0];
+ size_t ngroups = 1;
+ for (size_t i = 1; i < nitems; ++i)
+ if (sorted_items[i]->group != sorted_items[i - 1]->group
+ && strcmp (sorted_items[i]->group, sorted_items[i - 1]->group))
+ groups[ngroups++] = &sorted_items[i];
+ qsort (groups, ngroups, sizeof groups[0], &compare_core_item_groups);
+
+ /* Write out all the groups. */
+ unsigned int colno = 0;
+
+ const void *last = desc;
+ if (nitems == 1)
+ {
+ size_t size = descsz;
+ colno = handle_core_item (core, sorted_items[0], desc, colno, &size);
+ if (size == 0)
+ return colno;
+ desc += descsz - size;
+ descsz = size;
+ }
+
+ do
+ {
+ for (size_t i = 0; i < ngroups; ++i)
+ {
+ for (const Ebl_Core_Item **item = groups[i];
+ (item < &sorted_items[nitems]
+ && ((*item)->group == groups[i][0]->group
+ || !strcmp ((*item)->group, groups[i][0]->group)));
+ ++item)
+ colno = handle_core_item (core, *item, desc, colno, NULL);
+
+ /* Force a line break at the end of the group. */
+ colno = ITEM_WRAP_COLUMN;
+ }
+
+ if (descsz == 0)
+ break;
+
+ /* This set of items consumed a certain amount of the note's data.
+ If there is more data there, we have another unit of the same size.
+ Loop to print that out too. */
+ const Ebl_Core_Item *item = &items[nitems - 1];
+ size_t eltsz = item->offset + gelf_fsize (core, item->type,
+ item->count ?: 1, EV_CURRENT);
+
+ int reps = -1;
+ do
+ {
+ ++reps;
+ desc += eltsz;
+ descsz -= eltsz;
+ }
+ while (descsz >= eltsz && !memcmp (desc, last, eltsz));
+
+ if (reps == 1)
+ {
+ /* For just one repeat, print it unabridged twice. */
+ desc -= eltsz;
+ descsz += eltsz;
+ }
+ else if (reps > 1)
+ printf (gettext ("\n%*s... <repeats %u more times> ..."),
+ ITEM_INDENT, "", reps);
+
+ last = desc;
+ }
+ while (descsz > 0);
+
+ return colno;
+}
+
+static unsigned int
+handle_bit_registers (const Ebl_Register_Location *regloc, const void *desc,
+ unsigned int colno)
+{
+ desc += regloc->offset;
+
+ abort (); /* XXX */
+ return colno;
+}
+
+
+static unsigned int
+handle_core_register (Ebl *ebl, Elf *core, int maxregname,
+ const Ebl_Register_Location *regloc, const void *desc,
+ unsigned int colno)
+{
+ if (regloc->bits % 8 != 0)
+ return handle_bit_registers (regloc, desc, colno);
+
+ desc += regloc->offset;
+
+ for (int reg = regloc->regno; reg < regloc->regno + regloc->count; ++reg)
+ {
+ const char *pfx;
+ const char *set;
+ char name[16];
+ int bits;
+ int type;
+ ssize_t n = ebl_register_info (ebl, reg, name, sizeof name,
+ &pfx, &set, &bits, &type);
+ if (n <= 0)
+ error (EXIT_FAILURE, 0,
+ gettext ("unable to handle register number %d"),
+ regloc->regno);
+
+#define TYPES \
+ BITS (8, BYTE, "%4" PRId8, "0x%.2" PRIx8, 4); \
+ BITS (16, HALF, "%6" PRId16, "0x%.4" PRIx16, 6); \
+ BITS (32, WORD, "%11" PRId32, " 0x%.8" PRIx32, 11); \
+ BITS (64, XWORD, "%20" PRId64, " 0x%.16" PRIx64, 20)
+
+#define BITS(bits, xtype, sfmt, ufmt, max) \
+ uint##bits##_t b##bits; int##bits##_t b##bits##s
+ union { TYPES; uint64_t b128[2]; } value;
+#undef BITS
+
+ switch (type)
+ {
+ case DW_ATE_unsigned:
+ case DW_ATE_signed:
+ case DW_ATE_address:
+ switch (bits)
+ {
+#define BITS(bits, xtype, sfmt, ufmt, max) \
+ case bits: \
+ desc = convert (core, ELF_T_##xtype, 1, &value, desc, 0); \
+ if (type == DW_ATE_signed) \
+ colno = print_core_item (colno, ' ', REGISTER_WRAP_COLUMN, \
+ maxregname, name, \
+ max, sfmt, value.b##bits##s); \
+ else \
+ colno = print_core_item (colno, ' ', REGISTER_WRAP_COLUMN, \
+ maxregname, name, \
+ max, ufmt, value.b##bits); \
+ break
+
+ TYPES;
+
+ case 128:
+ assert (type == DW_ATE_unsigned);
+ desc = convert (core, ELF_T_XWORD, 2, &value, desc, 0);
+ int be = elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB;
+ colno = print_core_item (colno, ' ', REGISTER_WRAP_COLUMN,
+ maxregname, name,
+ 34, "0x%.16" PRIx64 "%.16" PRIx64,
+ value.b128[!be], value.b128[be]);
+ break;
+
+ default:
+ abort ();
+#undef BITS
+ }
+ break;
+
+ default:
+ /* Print each byte in hex, the whole thing in native byte order. */
+ assert (bits % 8 == 0);
+ const uint8_t *bytes = desc;
+ desc += bits / 8;
+ char hex[bits / 4 + 1];
+ hex[bits / 4] = '\0';
+ int incr = 1;
+ if (elf_getident (core, NULL)[EI_DATA] == ELFDATA2LSB)
+ {
+ bytes += bits / 8 - 1;
+ incr = -1;
+ }
+ size_t idx = 0;
+ for (char *h = hex; bits > 0; bits -= 8, idx += incr)
+ {
+ *h++ = "0123456789abcdef"[bytes[idx] >> 4];
+ *h++ = "0123456789abcdef"[bytes[idx] & 0xf];
+ }
+ colno = print_core_item (colno, ' ', REGISTER_WRAP_COLUMN,
+ maxregname, name,
+ 2 + sizeof hex - 1, "0x%s", hex);
+ break;
+ }
+ desc += regloc->pad;
+
+#undef TYPES
+ }
+
+ return colno;
+}
+
+
+struct register_info
+{
+ const Ebl_Register_Location *regloc;
+ const char *set;
+ char name[16];
+ Dwarf_Half regno;
+ uint8_t bits;
+ uint8_t type;
+};
+
+static int
+register_bitpos (const struct register_info *r)
+{
+ return (r->regloc->offset * 8
+ + ((r->regno - r->regloc->regno)
+ * (r->regloc->bits + r->regloc->pad * 8)));
+}
+
+static int
+compare_sets_by_info (const struct register_info *r1,
+ const struct register_info *r2)
+{
+ return ((int) r2->bits - (int) r1->bits
+ ?: register_bitpos (r1) - register_bitpos (r2));
+}
+
+/* Sort registers by set, and by size and layout offset within each set. */
+static int
+compare_registers (const void *a, const void *b)
+{
+ const struct register_info *r1 = a;
+ const struct register_info *r2 = b;
+
+ /* Unused elements sort last. */
+ if (r1->regloc == NULL)
+ return r2->regloc == NULL ? 0 : 1;
+ if (r2->regloc == NULL)
+ return -1;
+
+ return ((r1->set == r2->set ? 0 : strcmp (r1->set, r2->set))
+ ?: compare_sets_by_info (r1, r2));
+}
+
+/* Sort register sets by layout offset of the first register in the set. */
+static int
+compare_register_sets (const void *a, const void *b)
+{
+ const struct register_info *const *p1 = a;
+ const struct register_info *const *p2 = b;
+ return compare_sets_by_info (*p1, *p2);
+}
+
+static unsigned int
+handle_core_registers (Ebl *ebl, Elf *core, const void *desc,
+ const Ebl_Register_Location *reglocs, size_t nregloc)
+{
+ if (nregloc == 0)
+ return 0;
+
+ ssize_t maxnreg = ebl_register_info (ebl, 0, NULL, 0, NULL, NULL, NULL, NULL);
+ if (maxnreg <= 0)
+ error (EXIT_FAILURE, 0,
+ gettext ("cannot register info: %s"), elf_errmsg (-1));
+
+ struct register_info regs[maxnreg];
+ memset (regs, 0, sizeof regs);
+
+ /* Sort to collect the sets together. */
+ int maxreg = 0;
+ for (size_t i = 0; i < nregloc; ++i)
+ for (int reg = reglocs[i].regno;
+ reg < reglocs[i].regno + reglocs[i].count;
+ ++reg)
+ {
+ assert (reg < maxnreg);
+ if (reg > maxreg)
+ maxreg = reg;
+ struct register_info *info = &regs[reg];
+
+ const char *pfx;
+ int bits;
+ int type;
+ ssize_t n = ebl_register_info (ebl, reg, info->name, sizeof info->name,
+ &pfx, &info->set, &bits, &type);
+ if (n <= 0)
+ error (EXIT_FAILURE, 0,
+ gettext ("cannot register info: %s"), elf_errmsg (-1));
+
+ info->regloc = &reglocs[i];
+ info->regno = reg;
+ info->bits = bits;
+ info->type = type;
+ }
+ qsort (regs, maxreg + 1, sizeof regs[0], &compare_registers);
+
+ /* Collect the unique sets and sort them. */
+ inline bool same_set (const struct register_info *a,
+ const struct register_info *b)
+ {
+ return (a < &regs[maxnreg] && a->regloc != NULL
+ && b < &regs[maxnreg] && b->regloc != NULL
+ && a->bits == b->bits
+ && (a->set == b->set || !strcmp (a->set, b->set)));
+ }
+ struct register_info *sets[maxreg + 1];
+ sets[0] = &regs[0];
+ size_t nsets = 1;
+ for (int i = 1; i <= maxreg; ++i)
+ if (regs[i].regloc != NULL && !same_set (&regs[i], &regs[i - 1]))
+ sets[nsets++] = &regs[i];
+ qsort (sets, nsets, sizeof sets[0], &compare_register_sets);
+
+ /* Write out all the sets. */
+ unsigned int colno = 0;
+ for (size_t i = 0; i < nsets; ++i)
+ {
+ /* Find the longest name of a register in this set. */
+ size_t maxname = 0;
+ const struct register_info *end;
+ for (end = sets[i]; same_set (sets[i], end); ++end)
+ {
+ size_t len = strlen (end->name);
+ if (len > maxname)
+ maxname = len;
+ }
+
+ for (const struct register_info *reg = sets[i];
+ reg < end;
+ reg += reg->regloc->count ?: 1)
+ colno = handle_core_register (ebl, core, maxname,
+ reg->regloc, desc, colno);
+
+ /* Force a line break at the end of the group. */
+ colno = REGISTER_WRAP_COLUMN;
+ }
- /* We are done with the DWARF handling. */
- dwarf_end (dbg);
+ return colno;
}
+static void
+handle_auxv_note (Ebl *ebl, Elf *core, GElf_Word descsz, GElf_Off desc_pos)
+{
+ Elf_Data *data = elf_getdata_rawchunk (core, desc_pos, descsz, ELF_T_AUXV);
+ if (data == NULL)
+ elf_error:
+ error (EXIT_FAILURE, 0,
+ gettext ("cannot convert core note data: %s"), elf_errmsg (-1));
+
+ const size_t nauxv = descsz / gelf_fsize (core, ELF_T_AUXV, 1, EV_CURRENT);
+ for (size_t i = 0; i < nauxv; ++i)
+ {
+ GElf_auxv_t av_mem;
+ GElf_auxv_t *av = gelf_getauxv (data, i, &av_mem);
+ if (av == NULL)
+ goto elf_error;
+
+ const char *name;
+ const char *fmt;
+ if (ebl_auxv_info (ebl, av->a_type, &name, &fmt) == 0)
+ {
+ /* Unknown type. */
+ if (av->a_un.a_val == 0)
+ printf (" %" PRIu64 "\n", av->a_type);
+ else
+ printf (" %" PRIu64 ": %#" PRIx64 "\n",
+ av->a_type, av->a_un.a_val);
+ }
+ else
+ switch (fmt[0])
+ {
+ case '\0': /* Normally zero. */
+ if (av->a_un.a_val == 0)
+ {
+ printf (" %s\n", name);
+ break;
+ }
+ /* Fall through */
+ case 'x': /* hex */
+ case 'p': /* address */
+ case 's': /* address of string */
+ printf (" %s: %#" PRIx64 "\n", name, av->a_un.a_val);
+ break;
+ case 'u':
+ printf (" %s: %" PRIu64 "\n", name, av->a_un.a_val);
+ break;
+ case 'd':
+ printf (" %s: %" PRId64 "\n", name, av->a_un.a_val);
+ break;
+
+ case 'b':
+ printf (" %s: %#" PRIx64 " ", name, av->a_un.a_val);
+ GElf_Xword bit = 1;
+ const char *pfx = "<";
+ for (const char *p = fmt + 1; *p != 0; p = strchr (p, '\0') + 1)
+ {
+ if (av->a_un.a_val & bit)
+ {
+ printf ("%s%s", pfx, p);
+ pfx = " ";
+ }
+ bit <<= 1;
+ }
+ printf (">\n");
+ break;
+
+ default:
+ abort ();
+ }
+ }
+}
+
+static void
+handle_core_note (Ebl *ebl, const GElf_Nhdr *nhdr, const void *desc)
+{
+ GElf_Word regs_offset;
+ size_t nregloc;
+ const Ebl_Register_Location *reglocs;
+ size_t nitems;
+ const Ebl_Core_Item *items;
+
+ if (! ebl_core_note (ebl, nhdr->n_type, nhdr->n_descsz,
+ &regs_offset, &nregloc, &reglocs, &nitems, &items))
+ return;
+
+ /* Pass 0 for DESCSZ when there are registers in the note,
+ so that the ITEMS array does not describe the whole thing.
+ For non-register notes, the actual descsz might be a multiple
+ of the unit size, not just exactly the unit size. */
+ unsigned int colno = handle_core_items (ebl->elf, desc,
+ nregloc == 0 ? nhdr->n_descsz : 0,
+ items, nitems);
+ if (colno != 0)
+ putchar_unlocked ('\n');
+
+ colno = handle_core_registers (ebl, ebl->elf, desc + regs_offset,
+ reglocs, nregloc);
+ if (colno != 0)
+ putchar_unlocked ('\n');
+}
+
+static void
+handle_notes_data (Ebl *ebl, const GElf_Ehdr *ehdr,
+ GElf_Off start, Elf_Data *data)
+{
+ fputs_unlocked (gettext (" Owner Data size Type\n"), stdout);
+
+ if (data == NULL)
+ goto bad_note;
+
+ size_t offset = 0;
+ GElf_Nhdr nhdr;
+ size_t name_offset;
+ size_t desc_offset;
+ while (offset < data->d_size
+ && (offset = gelf_getnote (data, offset,
+ &nhdr, &name_offset, &desc_offset)) > 0)
+ {
+ const char *name = data->d_buf + name_offset;
+ const char *desc = data->d_buf + desc_offset;
+
+ char buf[100];
+ char buf2[100];
+ printf (gettext (" %-13.*s %9" PRId32 " %s\n"),
+ (int) nhdr.n_namesz, name, nhdr.n_descsz,
+ ehdr->e_type == ET_CORE
+ ? ebl_core_note_type_name (ebl, nhdr.n_type,
+ buf, sizeof (buf))
+ : ebl_object_note_type_name (ebl, nhdr.n_type,
+ buf2, sizeof (buf2)));
+
+ /* Filter out invalid entries. */
+ if (memchr (name, '\0', nhdr.n_namesz) != NULL
+ /* XXX For now help broken Linux kernels. */
+ || 1)
+ {
+ if (ehdr->e_type == ET_CORE)
+ {
+ if (nhdr.n_type == NT_AUXV)
+ handle_auxv_note (ebl, ebl->elf, nhdr.n_descsz,
+ start + desc_offset);
+ else
+ handle_core_note (ebl, &nhdr, desc);
+ }
+ else
+ ebl_object_note (ebl, name, nhdr.n_type, nhdr.n_descsz, desc);
+ }
+ }
+
+ if (offset == data->d_size)
+ return;
+
+ bad_note:
+ error (EXIT_FAILURE, 0,
+ gettext ("cannot get content of note section: %s"),
+ elf_errmsg (-1));
+}
static void
handle_notes (Ebl *ebl, GElf_Ehdr *ehdr)
{
- int class = gelf_getclass (ebl->elf);
- size_t cnt;
+ /* If we have section headers, just look for SHT_NOTE sections.
+ In a debuginfo file, the program headers are not reliable. */
+ if (shnum != 0)
+ {
+ /* Get the section header string table index. */
+ size_t shstrndx;
+ if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+ error (EXIT_FAILURE, 0,
+ gettext ("cannot get section header string table index"));
+
+ Elf_Scn *scn = NULL;
+ while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
+ {
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+
+ if (shdr == NULL || shdr->sh_type != SHT_NOTE)
+ /* Not what we are looking for. */
+ continue;
+
+ printf (gettext ("\
+\nNote section [%2zu] '%s' of %" PRIu64 " bytes at offset %#0" PRIx64 ":\n"),
+ elf_ndxscn (scn),
+ elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
+ shdr->sh_size, shdr->sh_offset);
+
+ handle_notes_data (ebl, ehdr, shdr->sh_offset,
+ elf_getdata (scn, NULL));
+ }
+ return;
+ }
/* We have to look through the program header to find the note
sections. There can be more than one. */
- for (cnt = 0; cnt < ehdr->e_phnum; ++cnt)
+ for (size_t cnt = 0; cnt < ehdr->e_phnum; ++cnt)
{
GElf_Phdr mem;
GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &mem);
@@ -4459,83 +6192,254 @@ handle_notes (Ebl *ebl, GElf_Ehdr *ehdr)
continue;
printf (gettext ("\
-\nNote segment of %" PRId64 " bytes at offset %#0" PRIx64 ":\n"),
+\nNote segment of %" PRIu64 " bytes at offset %#0" PRIx64 ":\n"),
phdr->p_filesz, phdr->p_offset);
- char *notemem = gelf_rawchunk (ebl->elf, phdr->p_offset, phdr->p_filesz);
- if (notemem == NULL)
- error (EXIT_FAILURE, 0,
- gettext ("cannot get content of note section: %s"),
- elf_errmsg (-1));
+ handle_notes_data (ebl, ehdr, phdr->p_offset,
+ elf_getdata_rawchunk (ebl->elf,
+ phdr->p_offset, phdr->p_filesz,
+ ELF_T_NHDR));
+ }
+}
- fputs_unlocked (gettext (" Owner Data size Type\n"), stdout);
+static void
+hex_dump (const uint8_t *data, size_t len)
+{
+ size_t pos = 0;
+ while (pos < len)
+ {
+ printf (" 0x%08Zx ", pos);
- /* Handle the note section content. It consists of one or more
- entries each of which consists of five parts:
+ const size_t chunk = MIN (len - pos, 16);
- - a 32-bit name length
- - a 32-bit descriptor length
- - a 32-bit type field
- - the NUL-terminated name, length as specified in the first field
- - the descriptor, length as specified in the second field
+ for (size_t i = 0; i < chunk; ++i)
+ if (i % 4 == 3)
+ printf ("%02x ", data[pos + i]);
+ else
+ printf ("%02x", data[pos + i]);
- The variable sized fields are padded to 32- or 64-bits
- depending on whether the file is a 32- or 64-bit ELF file.
- */
- size_t align = class == ELFCLASS32 ? 4 : 8;
-#define ALIGNED_LEN(len) (((len) + align - 1) & ~(align - 1))
+ if (chunk < 16)
+ printf ("%*s", (int) ((16 - chunk) * 2 + (16 - chunk + 3) / 4), "");
- size_t idx = 0;
- while (idx < phdr->p_filesz)
+ for (size_t i = 0; i < chunk; ++i)
{
- /* XXX Handle 64-bit note section entries correctly. */
- struct
- {
- uint32_t namesz;
- uint32_t descsz;
- uint32_t type;
- char name[0];
- } *noteentry = (__typeof (noteentry)) (notemem + idx);
-
- if (idx + 12 > phdr->p_filesz
- || (idx + 12 + ALIGNED_LEN (noteentry->namesz)
- + ALIGNED_LEN (noteentry->descsz) > phdr->p_filesz))
- /* This entry isn't completely contained in the note
- section. Ignore it. */
- break;
+ unsigned char b = data[pos + i];
+ printf ("%c", isprint (b) ? b : '.');
+ }
+
+ putchar ('\n');
+ pos += chunk;
+ }
+}
+
+static void
+dump_data_section (Elf_Scn *scn, const GElf_Shdr *shdr, const char *name)
+{
+ if (shdr->sh_size == 0 || shdr->sh_type == SHT_NOBITS)
+ printf (gettext ("\nSection [%Zu] '%s' has no data to dump.\n"),
+ elf_ndxscn (scn), name);
+ else
+ {
+ Elf_Data *data = elf_rawdata (scn, NULL);
+ if (data == NULL)
+ error (0, 0, gettext ("cannot get data for section [%Zu] '%s': %s"),
+ elf_ndxscn (scn), name, elf_errmsg (-1));
+ else
+ {
+ printf (gettext ("\nHex dump of section [%Zu] '%s', %" PRIu64
+ " bytes at offset %#0" PRIx64 ":\n"),
+ elf_ndxscn (scn), name,
+ shdr->sh_size, shdr->sh_offset);
+ hex_dump (data->d_buf, data->d_size);
+ }
+ }
+}
- char buf[100];
- char buf2[100];
- printf (gettext (" %-13.*s %9" PRId32 " %s\n"),
- (int) noteentry->namesz, noteentry->name,
- noteentry->descsz,
- ehdr->e_type == ET_CORE
- ? ebl_core_note_type_name (ebl, noteentry->type,
- buf, sizeof (buf))
- : ebl_object_note_type_name (ebl, noteentry->type,
- buf2, sizeof (buf2)));
-
- /* Filter out invalid entries. */
- if (memchr (noteentry->name, '\0', noteentry->namesz) != NULL
- /* XXX For now help broken Linux kernels. */
- || 1)
+static void
+print_string_section (Elf_Scn *scn, const GElf_Shdr *shdr, const char *name)
+{
+ if (shdr->sh_size == 0)
+ printf (gettext ("\nSection [%Zu] '%s' is empty.\n"),
+ elf_ndxscn (scn), name);
+
+ Elf_Data *data = elf_rawdata (scn, NULL);
+ if (data == NULL)
+ error (0, 0, gettext ("cannot get data for section [%Zu] '%s': %s"),
+ elf_ndxscn (scn), name, elf_errmsg (-1));
+ else
+ {
+ printf (gettext ("\nString section [%Zu] '%s' contains %" PRIu64
+ " bytes at offset %#0" PRIx64 ":\n"),
+ elf_ndxscn (scn), name,
+ shdr->sh_size, shdr->sh_offset);
+
+ const char *start = data->d_buf;
+ const char *const limit = start + data->d_size;
+ do
+ {
+ const char *end = memchr (start, '\0', limit - start);
+ const size_t pos = start - (const char *) data->d_buf;
+ if (unlikely (end == NULL))
{
- if (ehdr->e_type == ET_CORE)
- ebl_core_note (ebl, noteentry->name, noteentry->type,
- noteentry->descsz,
- &noteentry->name[ALIGNED_LEN (noteentry->namesz)]);
- else
- ebl_object_note (ebl, noteentry->name, noteentry->type,
- noteentry->descsz,
- &noteentry->name[ALIGNED_LEN (noteentry->namesz)]);
+ printf (" [%6Zx]- %.*s\n",
+ pos, (int) (limit - start), start);
+ break;
}
+ printf (" [%6Zx] %s\n", pos, start);
+ start = end + 1;
+ } while (start < limit);
+ }
+}
- /* Move to the next entry. */
- idx += (12 + ALIGNED_LEN (noteentry->namesz)
- + ALIGNED_LEN (noteentry->descsz));
+static void
+for_each_section_argument (Elf *elf, const struct section_argument *list,
+ void (*dump) (Elf_Scn *scn, const GElf_Shdr *shdr,
+ const char *name))
+{
+ /* Get the section header string table index. */
+ size_t shstrndx;
+ if (elf_getshstrndx (elf, &shstrndx) < 0)
+ error (EXIT_FAILURE, 0,
+ gettext ("cannot get section header string table index"));
+
+ for (const struct section_argument *a = list; a != NULL; a = a->next)
+ {
+ Elf_Scn *scn;
+ GElf_Shdr shdr_mem;
+ const char *name = NULL;
+
+ char *endp = NULL;
+ unsigned long int shndx = strtoul (a->arg, &endp, 0);
+ if (endp != a->arg && *endp == '\0')
+ {
+ scn = elf_getscn (elf, shndx);
+ if (scn == NULL)
+ {
+ error (0, 0, gettext ("\nsection [%lu] does not exist"), shndx);
+ continue;
+ }
+
+ if (gelf_getshdr (scn, &shdr_mem) == NULL)
+ error (EXIT_FAILURE, 0, gettext ("cannot get section header: %s"),
+ elf_errmsg (-1));
+ name = elf_strptr (elf, shstrndx, shdr_mem.sh_name);
+ }
+ else
+ {
+ /* Need to look up the section by name. */
+ scn = NULL;
+ while ((scn = elf_nextscn (elf, scn)) != NULL)
+ {
+ if (gelf_getshdr (scn, &shdr_mem) == NULL)
+ continue;
+ name = elf_strptr (elf, shstrndx, shdr_mem.sh_name);
+ if (name == NULL)
+ continue;
+ if (!strcmp (name, a->arg))
+ break;
+ }
+
+ if (unlikely (scn == NULL))
+ {
+ error (0, 0, gettext ("\nsection '%s' does not exist"), a->arg);
+ continue;
+ }
+ }
+
+ (*dump) (scn, &shdr_mem, name);
+ }
+}
+
+static void
+dump_data (Ebl *ebl)
+{
+ for_each_section_argument (ebl->elf, dump_data_sections, &dump_data_section);
+}
+
+static void
+dump_strings (Ebl *ebl)
+{
+ for_each_section_argument (ebl->elf, string_sections, &print_string_section);
+}
+
+static void
+print_strings (Ebl *ebl)
+{
+ /* Get the section header string table index. */
+ size_t shstrndx;
+ if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
+ error (EXIT_FAILURE, 0,
+ gettext ("cannot get section header string table index"));
+
+ Elf_Scn *scn;
+ GElf_Shdr shdr_mem;
+ const char *name;
+ scn = NULL;
+ while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
+ {
+ if (gelf_getshdr (scn, &shdr_mem) == NULL)
+ continue;
+
+ if (shdr_mem.sh_type != SHT_PROGBITS
+ || !(shdr_mem.sh_flags & SHF_STRINGS))
+ continue;
+
+ name = elf_strptr (ebl->elf, shstrndx, shdr_mem.sh_name);
+ if (name == NULL)
+ continue;
+
+ print_string_section (scn, &shdr_mem, name);
+ }
+}
+
+static void
+dump_archive_index (Elf *elf, const char *fname)
+{
+ size_t narsym;
+ const Elf_Arsym *arsym = elf_getarsym (elf, &narsym);
+ if (arsym == NULL)
+ {
+ int result = elf_errno ();
+ if (unlikely (result != ELF_E_NO_INDEX))
+ error (EXIT_FAILURE, 0,
+ gettext ("cannot get symbol index of archive '%s': %s"),
+ fname, elf_errmsg (result));
+ else
+ printf (gettext ("\nArchive '%s' has no symbol index\n"), fname);
+ return;
+ }
+
+ printf (gettext ("\nIndex of archive '%s' has %Zu entries:\n"),
+ fname, narsym);
+
+ size_t as_off = 0;
+ for (const Elf_Arsym *s = arsym; s < &arsym[narsym - 1]; ++s)
+ {
+ if (s->as_off != as_off)
+ {
+ as_off = s->as_off;
+
+ Elf *subelf;
+ if (unlikely (elf_rand (elf, as_off) == 0)
+ || unlikely ((subelf = elf_begin (-1, ELF_C_READ_MMAP, elf))
+ == NULL))
+#if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 7)
+ while (1)
+#endif
+ error (EXIT_FAILURE, 0,
+ gettext ("cannot extract member at offset %Zu in '%s': %s"),
+ as_off, fname, elf_errmsg (-1));
+
+ const Elf_Arhdr *h = elf_getarhdr (subelf);
+
+ printf (gettext ("Archive member '%s' contains:\n"), h->ar_name);
+
+ elf_end (subelf);
}
- gelf_freechunk (ebl->elf, notemem);
+ printf ("\t%s\n", s->as_name);
}
}
+
+#include "debugpred.h"