diff options
Diffstat (limited to 'src/readelf.c')
-rw-r--r-- | src/readelf.c | 4541 |
1 files changed, 0 insertions, 4541 deletions
diff --git a/src/readelf.c b/src/readelf.c deleted file mode 100644 index 6129e29d..00000000 --- a/src/readelf.c +++ /dev/null @@ -1,4541 +0,0 @@ -/* Print information from ELF file in human-readable form. - Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. - 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. - - 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. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <argp.h> -#include <assert.h> -#include <dwarf.h> -#include <errno.h> -#include <error.h> -#include <fcntl.h> -#include <gelf.h> -#include <inttypes.h> -#include <langinfo.h> -#include <libdw.h> -#include <libebl.h> -#include <libintl.h> -#include <locale.h> -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> -#include <sys/param.h> - -#include <system.h> -#include "../libdw/libdwP.h" -#include "../libdw/memory-access.h" - - -/* Name and version of program. */ -static void print_version (FILE *stream, struct argp_state *state); -void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; - -/* 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") }, - { "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") }, - { "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") }, - { "arch-specific", 'A', NULL, 0, - N_("Display architecture specific information (if any)") }, - - { NULL, 0, NULL, 0, N_("Output control:") }, - - { NULL, 0, NULL, 0, NULL } -}; - -/* Short description of program. */ -static const char doc[] = N_("\ -Print information from ELF file in human-readable form."); - -/* Strings for arguments in help texts. */ -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 -}; - - -/* 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; - -/* True if the file header should be printed. */ -static bool print_file_header; - -/* True if the program headers should be printed. */ -static bool print_program_header; - -/* True if relocations should be printed. */ -static bool print_relocations; - -/* True if the section headers should be printed. */ -static bool print_section_header; - -/* True if the symbol table should be printed. */ -static bool print_symbol_table; - -/* True if the version information should be printed. */ -static bool print_version_info; - -/* True if section groups should be printed. */ -static bool print_section_groups; - -/* True if bucket list length histogram should be printed. */ -static bool print_histogram; - -/* True if the architecture specific data should be printed. */ -static bool print_arch; - -/* True if note section content should be printed. */ -static bool print_notes; - -/* Select printing of debugging sections. */ -static enum section_e -{ - section_abbrev = 1, /* .debug_abbrev */ - section_aranges = 2, /* .debug_aranges */ - section_frame = 4, /* .debug_frame or .eh_frame */ - section_info = 8, /* .debug_info */ - section_line = 16, /* .debug_line */ - section_loc = 32, /* .debug_loc */ - section_pubnames = 64,/* .debug_pubnames */ - section_str = 128, /* .debug_str */ - section_macinfo = 256,/* .debug_macinfo */ - section_all = (section_abbrev | section_aranges | section_frame - | section_info | section_line | section_loc - | section_pubnames | section_str | section_macinfo) -} print_debug_sections; - -/* 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 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_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, - GElf_Shdr *shdr); -static void print_debug (Ebl *ebl, GElf_Ehdr *ehdr); -static void handle_hash (Ebl *ebl, GElf_Ehdr *ehdr); -static void handle_notes (Ebl *ebl, GElf_Ehdr *ehdr); -static void print_liblist (Ebl *ebl, GElf_Ehdr *ehdr); - - -int -main (int argc, char *argv[]) -{ - int remaining; - bool only_one; - - /* Set locale. */ - setlocale (LC_ALL, ""); - - /* Initialize the message catalog. */ - textdomain (PACKAGE); - - /* Parse and process arguments. */ - 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; - do - { - int fd; - Elf *elf; - - /* Open the file. */ - 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)); - } - - close (fd); - } - while (++remaining < argc); - - return error_message_count != 0; -} - - -/* Handle program arguments. */ -static error_t -parse_opt (int key, char *arg, struct argp_state *state) -{ - switch (key) - { - case 'a': - print_file_header = true; - print_program_header = true; - print_relocations = true; - print_section_header = true; - print_symbol_table = true; - print_version_info = true; - print_dynamic_table = true; - print_section_groups = true; - print_histogram = true; - print_arch = true; - print_notes = true; - any_control_option = true; - break; - case 'A': - print_arch = true; - any_control_option = true; - break; - case 'd': - print_dynamic_table = true; - any_control_option = true; - break; - case 'g': - print_section_groups = true; - any_control_option = true; - break; - case 'h': - print_file_header = true; - any_control_option = true; - break; - case 'I': - print_histogram = true; - any_control_option = true; - break; - case 'l': - print_program_header = true; - any_control_option = true; - break; - case 'n': - print_notes = true; - any_control_option = true; - break; - case 'r': - print_relocations = true; - any_control_option = true; - break; - case 'S': - print_section_header = true; - any_control_option = true; - break; - case 's': - print_symbol_table = true; - any_control_option = true; - break; - case 'V': - print_version_info = true; - any_control_option = true; - break; - case 'w': - if (arg == NULL) - print_debug_sections = section_all; - else if (strcmp (arg, "abbrev") == 0) - print_debug_sections |= section_abbrev; - else if (strcmp (arg, "aranges") == 0) - print_debug_sections |= section_aranges; - else if (strcmp (arg, "frame") == 0) - print_debug_sections |= section_frame; - else if (strcmp (arg, "info") == 0) - print_debug_sections |= section_info; - else if (strcmp (arg, "loc") == 0) - print_debug_sections |= section_loc; - else if (strcmp (arg, "line") == 0) - print_debug_sections |= section_line; - else if (strcmp (arg, "pubnames") == 0) - print_debug_sections |= section_pubnames; - else if (strcmp (arg, "str") == 0) - print_debug_sections |= section_str; - else if (strcmp (arg, "macinfo") == 0) - print_debug_sections |= section_macinfo; - else - { - fprintf (stderr, gettext ("Unknown DWARF debug section `%s'.\n"), - arg); - argp_help (&argp, stderr, ARGP_HELP_SEE, - program_invocation_short_name); - exit (1); - } - break; - default: - return ARGP_ERR_UNKNOWN; - } - return 0; -} - - -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) -{ - fprintf (stream, "readelf (%s) %s\n", PACKAGE_NAME, 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"); - fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); -} - - -/* Process one file. */ -static void -process_file (int fd, Elf *elf, const char *prefix, const char *fname, - bool only_one) -{ - /* We can handle two types of files: ELF files and archives. */ - Elf_Kind kind = elf_kind (elf); - struct stat64 st; - - switch (kind) - { - case ELF_K_ELF: - /* Yes! It's an ELF file. */ - process_elf_file (elf, prefix, fname, only_one); - break; - - 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); - - /* It's an archive. We process each file in it. */ - while ((subelf = elf_begin (fd, cmd, elf)) != NULL) - { - kind = elf_kind (subelf); - - /* Call this function recursively. */ - if (kind == ELF_K_ELF || kind == ELF_K_AR) - { - Elf_Arhdr *arhdr = elf_getarhdr (subelf); - assert (arhdr != NULL); - - process_file (fd, subelf, new_prefix, arhdr->ar_name, false); - } - - /* 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; - - default: - if (fstat64 (fd, &st) != 0) - error (0, errno, gettext ("cannot stat input file")); - else if (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; - } -} - - -/* Process one file. */ -static void -process_elf_file (Elf *elf, const char *prefix, const char *fname, - bool only_one) -{ - 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) - { - error (0, 0, gettext ("cannot read ELF header: %s"), elf_errmsg (-1)); - return; - } - - ebl = ebl_openbackend (elf); - if (ebl == NULL) - { - error (0, errno, gettext ("cannot create EBL handle")); - return; - } - - /* Determine the number of sections. */ - if (elf_getshnum (ebl->elf, &shnum) < 0) - error (EXIT_FAILURE, 0, - gettext ("cannot determine number of sections: %s"), - elf_errmsg (-1)); - - if (print_file_header) - print_ehdr (ebl, ehdr); - if (print_section_header) - print_shdr (ebl, ehdr); - if (print_program_header) - print_phdr (ebl, ehdr); - if (print_section_groups) - print_scngrp (ebl, ehdr); - if (print_dynamic_table) - print_dynamic (ebl, ehdr); - if (print_relocations) - print_relocs (ebl, ehdr); - if (print_histogram) - handle_hash (ebl, ehdr); - if (print_symbol_table) - print_symtab (ebl, ehdr, SHT_DYNSYM); - if (print_version_info) - print_verinfo (ebl, ehdr); - if (print_symbol_table) - print_symtab (ebl, ehdr, SHT_SYMTAB); - if (print_arch) - print_liblist (ebl, ehdr); - if (print_debug_sections != 0) - print_debug (ebl, ehdr); - if (print_notes) - handle_notes (ebl, ehdr); - - ebl_closebackend (ebl); -} - - -/* Print file type. */ -static void -print_file_type (unsigned short int e_type) -{ - if (e_type <= ET_CORE) - { - static const char *knowntypes[] = - { - N_("NONE (None)"), - N_("REL (Relocatable file)"), - N_("EXEC (Executable file)"), - N_("DYN (Shared object file)"), - N_("CORE (Core file)") - }; - puts (gettext (knowntypes[e_type])); - } - else if (e_type >= ET_LOOS && e_type <= ET_HIOS) - printf (gettext ("OS Specific: (%x)\n"), e_type); - else if (e_type >= ET_LOPROC /* && e_type <= ET_HIPROC always true */) - printf (gettext ("Processor Specific: (%x)\n"), e_type); - else - puts ("???"); -} - - -/* Print ELF header. */ -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) - printf (" %02hhx", ehdr->e_ident[cnt]); - - printf (gettext ("\n Class: %s\n"), - ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? "ELF32" - : ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? "ELF64" - : "\?\?\?"); - - printf (gettext (" Data: %s\n"), - ehdr->e_ident[EI_DATA] == ELFDATA2LSB - ? "2's complement, little endian" - : ehdr->e_ident[EI_DATA] == ELFDATA2MSB - ? "2's complement, big endian" : "\?\?\?"); - - printf (gettext (" Version: %hhd %s\n"), - ehdr->e_ident[EI_VERSION], - ehdr->e_ident[EI_VERSION] == EV_CURRENT ? gettext ("(current)") - : "(\?\?\?)"); - - printf (gettext (" OS/ABI: %s\n"), - ebl_osabi_name (ebl, ehdr->e_ident[EI_OSABI], buf, sizeof (buf))); - - printf (gettext (" ABI Version: %hhd\n"), - ehdr->e_ident[EI_ABIVERSION]); - - fputs_unlocked (gettext (" Type: "), stdout); - print_file_type (ehdr->e_type); - - printf (gettext (" Machine: %s\n"), ebl->name); - - printf (gettext (" Version: %d %s\n"), - ehdr->e_version, - ehdr->e_version == EV_CURRENT ? gettext ("(current)") : "(\?\?\?)"); - - printf (gettext (" Entry point address: %#" PRIx64 "\n"), - ehdr->e_entry); - - printf (gettext (" Start of program headers: %" PRId64 " %s\n"), - ehdr->e_phoff, gettext ("(bytes into file)")); - - printf (gettext (" Start of section headers: %" PRId64 " %s\n"), - ehdr->e_shoff, gettext ("(bytes into file)")); - - printf (gettext (" Flags: %s\n"), - ebl_machine_flag_name (ebl, ehdr->e_flags, buf, sizeof (buf))); - - printf (gettext (" Size of this header: %" PRId16 " %s\n"), - ehdr->e_ehsize, gettext ("(bytes)")); - - printf (gettext (" Size of program header entries: %" PRId16 " %s\n"), - ehdr->e_phentsize, gettext ("(bytes)")); - - printf (gettext (" Number of program headers entries: %" PRId16 "\n"), - ehdr->e_phnum); - - printf (gettext (" Size of section header entries: %" PRId16 " %s\n"), - ehdr->e_shentsize, gettext ("(bytes)")); - - printf (gettext (" Number of section headers entries: %" PRId16), - ehdr->e_shnum); - if (ehdr->e_shnum == 0) - { - GElf_Shdr shdr_mem; - GElf_Shdr *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); - else - fputs_unlocked (gettext (" ([0] not available)"), stdout); - } - fputc_unlocked ('\n', stdout); - - if (ehdr->e_shstrndx == SHN_XINDEX) - { - GElf_Shdr shdr_mem; - GElf_Shdr *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)"), - (uint32_t) shdr->sh_link); - else - { - strncpy (buf, gettext (" ([0] not available)"), sizeof (buf)); - buf[sizeof (buf) - 1] = '\0'; - } - - printf (gettext (" Section header string table index: XINDEX%s\n\n"), - buf); - } - else - printf (gettext (" Section header string table index: %" PRId16 "\n\n"), - ehdr->e_shstrndx); -} - - -static const char * -get_visibility_type (int value) -{ - switch (value) - { - case STV_DEFAULT: - return "DEFAULT"; - case STV_INTERNAL: - return "INTERNAL"; - case STV_HIDDEN: - return "HIDDEN"; - case STV_PROTECTED: - return "PROTECTED"; - default: - return "???"; - } -} - - -/* Print the section headers. */ -static void -print_shdr (Ebl *ebl, GElf_Ehdr *ehdr) -{ - size_t cnt; - size_t shstrndx; - - if (! print_file_header) - printf (gettext ("\ -There are %d section headers, starting at offset %#" PRIx64 ":\n\ -\n"), - ehdr->e_shnum, ehdr->e_shoff); - - /* 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")); - - puts (gettext ("Section Headers:")); - - if (ehdr->e_ident[EI_CLASS] == ELFCLASS32) - puts (gettext ("[Nr] Name Type Addr Off Size ES Flags Lk Inf Al")); - else - puts (gettext ("[Nr] Name Type Addr Off Size ES Flags Lk Inf Al")); - - 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) - 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) - error (EXIT_FAILURE, 0, gettext ("cannot get section header: %s"), - elf_errmsg (-1)); - - cp = flagbuf; - if (shdr->sh_flags & SHF_WRITE) - *cp++ = 'W'; - if (shdr->sh_flags & SHF_ALLOC) - *cp++ = 'A'; - if (shdr->sh_flags & SHF_EXECINSTR) - *cp++ = 'X'; - if (shdr->sh_flags & SHF_MERGE) - *cp++ = 'M'; - if (shdr->sh_flags & SHF_STRINGS) - *cp++ = 'S'; - if (shdr->sh_flags & SHF_INFO_LINK) - *cp++ = 'I'; - if (shdr->sh_flags & SHF_LINK_ORDER) - *cp++ = 'L'; - if (shdr->sh_flags & SHF_OS_NONCONFORMING) - *cp++ = 'N'; - if (shdr->sh_flags & SHF_GROUP) - *cp++ = 'G'; - if (shdr->sh_flags & SHF_TLS) - *cp++ = 'T'; - if (shdr->sh_flags & SHF_ORDERED) - *cp++ = 'O'; - if (shdr->sh_flags & SHF_EXCLUDE) - *cp++ = 'E'; - *cp = '\0'; - - printf ("[%2zu] %-20s %-12s %0*" PRIx64 " %0*" PRIx64 " %0*" PRIx64 - " %2" PRId64 " %-5s %2" PRId32 " %3" PRId32 - " %2" PRId64 "\n", - cnt, - elf_strptr (ebl->elf, shstrndx, shdr->sh_name) - ?: "<corrupt>", - ebl_section_type_name (ebl, shdr->sh_type, buf, sizeof (buf)), - ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16, shdr->sh_addr, - ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 6 : 8, shdr->sh_offset, - ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 6 : 8, shdr->sh_size, - shdr->sh_entsize, flagbuf, shdr->sh_link, shdr->sh_info, - shdr->sh_addralign); - } - - fputc_unlocked ('\n', stdout); -} - - -/* Print the program header. */ -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; - - puts (gettext ("Program Headers:")); - if (ehdr->e_ident[EI_CLASS] == ELFCLASS32) - puts (gettext ("\ - Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align")); - else - puts (gettext ("\ - Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align")); - - /* Process all program headers. */ - bool has_relro = false; - GElf_Addr relro_from = 0; - GElf_Addr relro_to = 0; - for (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) - { - puts (" ???"); - continue; - } - - printf (" %-14s 0x%06" PRIx64 " 0x%0*" PRIx64 " 0x%0*" PRIx64 - " 0x%06" PRIx64 " 0x%06" PRIx64 " %c%c%c 0x%" PRIx64 "\n", - ebl_segment_type_name (ebl, phdr->p_type, buf, sizeof (buf)), - phdr->p_offset, - ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16, phdr->p_vaddr, - ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16, phdr->p_paddr, - phdr->p_filesz, - phdr->p_memsz, - phdr->p_flags & PF_R ? 'R' : ' ', - phdr->p_flags & PF_W ? 'W' : ' ', - phdr->p_flags & PF_X ? 'E' : ' ', - phdr->p_align); - - if (phdr->p_type == PT_INTERP) - { - /* We can show the user the name of the interpreter. */ - size_t maxsize; - char *filedata = elf_rawfile (ebl->elf, &maxsize); - - if (filedata != NULL && phdr->p_offset < maxsize) - printf (gettext ("\t[Requesting program interpreter: %s]\n"), - filedata + phdr->p_offset); - } - else if (phdr->p_type == PT_GNU_RELRO) - { - has_relro = true; - relro_from = phdr->p_vaddr; - relro_to = relro_from + phdr->p_memsz; - } - } - - /* 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")); - - puts (gettext ("\n Section to Segment mapping:\n Segment Sections...")); - - for (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); - - /* This must not happen. */ - if (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) - { - Elf_Scn *scn = elf_getscn (ebl->elf, inner); - GElf_Shdr shdr_mem; - GElf_Shdr *shdr; - - /* It should not happen. */ - if (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) - error (EXIT_FAILURE, 0, - gettext ("cannot get section header: %s"), - elf_errmsg (-1)); - - if (shdr->sh_size > 0 - /* Compare allocated sections by VMA, unallocated - sections by file offset. */ - && (shdr->sh_flags & SHF_ALLOC - ? (shdr->sh_addr >= phdr->p_vaddr - && (shdr->sh_addr + shdr->sh_size - <= phdr->p_vaddr + phdr->p_memsz)) - : (shdr->sh_offset >= phdr->p_offset - && (shdr->sh_offset + shdr->sh_size - <= phdr->p_offset + phdr->p_filesz)))) - { - if (has_relro && !in_relro - && shdr->sh_addr >= relro_from - && shdr->sh_addr + shdr->sh_size <= relro_to) - { - fputs_unlocked (" [RELRO:", stdout); - in_relro = true; - } - else if (has_relro && in_relro && shdr->sh_addr >= relro_to) - { - fputs_unlocked ("]", stdout); - in_relro = false; - } - else if (has_relro && in_relro - && shdr->sh_addr + shdr->sh_size > relro_to) - fputs_unlocked ("] <RELRO:", stdout); - - printf (" %s", - elf_strptr (ebl->elf, shstrndx, shdr->sh_name)); - - /* Signal that this sectin is only partially covered. */ - if (has_relro && in_relro - && shdr->sh_addr + shdr->sh_size > relro_to) - { - fputs_unlocked (">", stdout); - in_relro = false; - } - } - } - if (in_relro) - fputs_unlocked ("]", stdout); - - /* Finish the line. */ - fputc_unlocked ('\n', stdout); - } -} - - -static void -handle_scngrp (Ebl *ebl, GElf_Ehdr *ehdr, 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); - - symscn = elf_getscn (ebl->elf, shdr->sh_link); - symshdr = gelf_getshdr (symscn, &symshdr_mem); - 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) - error (EXIT_FAILURE, 0, - gettext ("cannot get section header string table index")); - - grpref = (Elf32_Word *) data->d_buf; - - printf ((grpref[0] & GRP_COMDAT) - ? ngettext ("\ -\nCOMDAT section group [%2zu] '%s' with signature '%s' contains %zu entry:\n", - "\ -\nCOMDAT section group [%2zu] '%s' with signature '%s' contains %zu entries:\n", - data->d_size / sizeof (Elf32_Word) - 1) - : ngettext ("\ -\nSection group [%2zu] '%s' with signature '%s' contains %zu entry:\n", "\ -\nSection group [%2zu] '%s' with signature '%s' contains %zu entries:\n", - data->d_size / sizeof (Elf32_Word) - 1), - elf_ndxscn (scn), - elf_strptr (ebl->elf, shstrndx, shdr->sh_name), - elf_strptr (ebl->elf, symshdr->sh_link, - gelf_getsym (symdata, shdr->sh_info, &sym_mem)->st_name) - ?: gettext ("<INVALID SYMBOL>"), - data->d_size / sizeof (Elf32_Word) - 1); - - for (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>")); - } -} - - -static void -print_scngrp (Ebl *ebl, GElf_Ehdr *ehdr) -{ - /* Find all relocation sections and handle them. */ - 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 (shdr != NULL && shdr->sh_type == SHT_GROUP) - handle_scngrp (ebl, ehdr, scn, shdr); - } -} - - -static const struct flags -{ - int mask; - const char *str; -} dt_flags[] = - { - { DF_ORIGIN, "ORIGIN" }, - { DF_SYMBOLIC, "SYMBOLIC" }, - { DF_TEXTREL, "TEXTREL" }, - { DF_BIND_NOW, "BIND_NOW" }, - { DF_STATIC_TLS, "STATIC_TLS" } - }; -static const int ndt_flags = sizeof (dt_flags) / sizeof (dt_flags[0]); - -static const struct flags dt_flags_1[] = - { - { DF_1_NOW, "NOW" }, - { DF_1_GLOBAL, "GLOBAL" }, - { DF_1_GROUP, "GROUP" }, - { DF_1_NODELETE, "NODELETE" }, - { DF_1_LOADFLTR, "LOADFLTR" }, - { DF_1_INITFIRST, "INITFIRST" }, - { DF_1_NOOPEN, "NOOPEN" }, - { DF_1_ORIGIN, "ORIGIN" }, - { DF_1_DIRECT, "DIRECT" }, - { DF_1_TRANS, "TRANS" }, - { DF_1_INTERPOSE, "INTERPOSE" }, - { DF_1_NODEFLIB, "NODEFLIB" }, - { DF_1_NODUMP, "NODUMP" }, - { DF_1_CONFALT, "CONFALT" }, - { DF_1_ENDFILTEE, "ENDFILTEE" }, - { DF_1_DISPRELDNE, "DISPRELDNE" }, - { DF_1_DISPRELPND, "DISPRELPND" }, - }; -static const int ndt_flags_1 = sizeof (dt_flags_1) / sizeof (dt_flags_1[0]); - -static const struct flags dt_feature_1[] = - { - { DTF_1_PARINIT, "PARINIT" }, - { DTF_1_CONFEXP, "CONFEXP" } - }; -static const int ndt_feature_1 = (sizeof (dt_feature_1) - / sizeof (dt_feature_1[0])); - -static const struct flags dt_posflag_1[] = - { - { DF_P1_LAZYLOAD, "LAZYLOAD" }, - { DF_P1_GROUPPERM, "GROUPPERM" } - }; -static const int ndt_posflag_1 = (sizeof (dt_posflag_1) - / sizeof (dt_posflag_1[0])); - - -static void -print_flags (int class, GElf_Xword d_val, const struct flags *flags, - int nflags) -{ - bool first = true; - int cnt; - - for (cnt = 0; cnt < nflags; ++cnt) - if (d_val & flags[cnt].mask) - { - if (!first) - putchar_unlocked (' '); - fputs_unlocked (flags[cnt].str, stdout); - d_val &= ~flags[cnt].mask; - first = false; - } - - if (d_val != 0) - { - if (!first) - putchar_unlocked (' '); - printf ("%#0*" PRIx64, class == ELFCLASS32 ? 10 : 18, d_val); - } - - putchar_unlocked ('\n'); -} - - -static void -print_dt_flags (int class, GElf_Xword d_val) -{ - print_flags (class, d_val, dt_flags, ndt_flags); -} - - -static void -print_dt_flags_1 (int class, GElf_Xword d_val) -{ - print_flags (class, d_val, dt_flags_1, ndt_flags_1); -} - - -static void -print_dt_feature_1 (int class, GElf_Xword d_val) -{ - print_flags (class, d_val, dt_feature_1, ndt_feature_1); -} - - -static void -print_dt_posflag_1 (int class, GElf_Xword d_val) -{ - print_flags (class, d_val, dt_posflag_1, ndt_posflag_1); -} - - -static void -handle_dynamic (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) -{ - int class = gelf_getclass (ebl->elf); - GElf_Shdr glink; - Elf_Data *data; - size_t cnt; - size_t shstrndx; - - /* Get the data of the section. */ - data = elf_getdata (scn, NULL); - if (data == NULL) - return; - - /* 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")); - - printf (ngettext ("\ -\nDynamic segment contains %lu entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", - "\ -\nDynamic segment contains %lu entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", - shdr->sh_size / shdr->sh_entsize), - (unsigned long int) (shdr->sh_size / shdr->sh_entsize), - class == ELFCLASS32 ? 10 : 18, shdr->sh_addr, - shdr->sh_offset, - (int) shdr->sh_link, - elf_strptr (ebl->elf, shstrndx, - gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), - &glink)->sh_name)); - fputs_unlocked (gettext (" Type Value\n"), stdout); - - 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); - if (dyn == NULL) - break; - - printf (" %-17s ", - ebl_dynamic_tag_name (ebl, dyn->d_tag, buf, sizeof (buf))); - - switch (dyn->d_tag) - { - case DT_NULL: - case DT_DEBUG: - case DT_BIND_NOW: - case DT_TEXTREL: - /* No further output. */ - fputc ('\n', stdout); - break; - - case DT_NEEDED: - printf (gettext ("Shared library: [%s]\n"), - elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val)); - break; - - case DT_SONAME: - printf (gettext ("Library soname: [%s]\n"), - elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val)); - break; - - case DT_RPATH: - printf (gettext ("Library rpath: [%s]\n"), - elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val)); - break; - - case DT_RUNPATH: - printf (gettext ("Library runpath: [%s]\n"), - elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val)); - break; - - case DT_PLTRELSZ: - case DT_RELASZ: - case DT_STRSZ: - case DT_RELSZ: - case DT_RELAENT: - case DT_SYMENT: - case DT_RELENT: - case DT_PLTPADSZ: - case DT_MOVEENT: - case DT_MOVESZ: - case DT_INIT_ARRAYSZ: - case DT_FINI_ARRAYSZ: - case DT_SYMINSZ: - case DT_SYMINENT: - case DT_GNU_CONFLICTSZ: - case DT_GNU_LIBLISTSZ: - printf (gettext ("%" PRId64 " (bytes)\n"), dyn->d_un.d_val); - break; - - case DT_VERDEFNUM: - case DT_VERNEEDNUM: - case DT_RELACOUNT: - case DT_RELCOUNT: - printf ("%" PRId64 "\n", dyn->d_un.d_val); - break; - - case DT_PLTREL: - puts (ebl_dynamic_tag_name (ebl, dyn->d_un.d_val, NULL, 0)); - break; - - case DT_FLAGS: - print_dt_flags (class, dyn->d_un.d_val); - break; - - case DT_FLAGS_1: - print_dt_flags_1 (class, dyn->d_un.d_val); - break; - - case DT_FEATURE_1: - print_dt_feature_1 (class, dyn->d_un.d_val); - break; - - case DT_POSFLAG_1: - print_dt_posflag_1 (class, dyn->d_un.d_val); - break; - - default: - printf ("%#0*" PRIx64 "\n", - class == ELFCLASS32 ? 10 : 18, dyn->d_un.d_val); - break; - } - } -} - - -/* Print the dynamic segment. */ -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) - { - /* Handle the section if it is a symbol table. */ - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - - if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC) - { - handle_dynamic (ebl, ehdr, scn, shdr); - break; - } - } -} - - -/* Print relocations. */ -static void -print_relocs (Ebl *ebl, GElf_Ehdr *ehdr) -{ - /* Find all relocation sections and handle them. */ - 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 (shdr != NULL) - { - if (shdr->sh_type == SHT_REL) - handle_relocs_rel (ebl, ehdr, scn, shdr); - else if (shdr->sh_type == SHT_RELA) - handle_relocs_rela (ebl, ehdr, scn, shdr); - } - } -} - - -/* Handle a relocation section. */ -static void -handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, 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); - 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); - - /* Get the section header of the section the relocations are for. */ - destshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info), - &destshdr_mem); - - if (symshdr == NULL || symdata == NULL || destshdr == NULL) - { - printf (gettext ("\nInvalid symbol table at offset %#0" PRIx64 "\n"), - shdr->sh_offset); - return; - } - - /* 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; - } - } - - /* 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")); - - if (shdr->sh_info != 0) - printf (ngettext ("\ -\nRelocation section [%2u] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n", - "\ -\nRelocation section [%2u] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n", - nentries), - (unsigned int) elf_ndxscn (scn), - elf_strptr (ebl->elf, shstrndx, shdr->sh_name), - (unsigned int) shdr->sh_info, - elf_strptr (ebl->elf, shstrndx, destshdr->sh_name), - shdr->sh_offset, - nentries); - else - /* The .rel.dyn section does not refer to a specific section but - instead of section index zero. Do not try to print a section - name. */ - printf (ngettext ("\ -\nRelocation section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n", - "\ -\nRelocation section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n", - nentries), - (unsigned int) elf_ndxscn (scn), - elf_strptr (ebl->elf, shstrndx, shdr->sh_name), - shdr->sh_offset, - nentries); - fputs_unlocked (class == ELFCLASS32 - ? gettext ("\ - Offset Type Value Name\n") - : gettext ("\ - Offset Type Value Name\n"), - stdout); - - for (cnt = 0; cnt < nentries; ++cnt) - { - GElf_Rel relmem; - GElf_Rel *rel; - - rel = gelf_getrel (data, cnt, &relmem); - if (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) - 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)) - /* Avoid the leading R_ which isn't carrying any - information. */ - ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), - buf, sizeof (buf)) + 2 - : gettext ("<INVALID RELOC>"), - gettext ("INVALID SYMBOL"), - (long int) GELF_R_SYM (rel->r_info)); - 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)) - /* Avoid the leading R_ which isn't carrying any - information. */ - ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), - buf, sizeof (buf)) + 2 - : gettext ("<INVALID RELOC>"), - class == ELFCLASS32 ? 10 : 18, sym->st_value, - elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name)); - else - { - destshdr = gelf_getshdr (elf_getscn (ebl->elf, - sym->st_shndx == SHN_XINDEX - ? xndx : sym->st_shndx), - &destshdr_mem); - - if (shdr == 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)) - /* Avoid the leading R_ which isn't carrying any - information. */ - ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), - buf, sizeof (buf)) + 2 - : gettext ("<INVALID RELOC>"), - gettext ("INVALID SECTION"), - (long int) (sym->st_shndx == SHN_XINDEX - ? xndx : sym->st_shndx)); - else - 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)) - /* Avoid the leading R_ which isn't carrying any - information. */ - ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), - buf, sizeof (buf)) + 2 - : gettext ("<INVALID RELOC>"), - class == ELFCLASS32 ? 10 : 18, sym->st_value, - elf_strptr (ebl->elf, shstrndx, destshdr->sh_name)); - } - } - } -} - - -/* Handle a relocation section. */ -static void -handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) -{ - int class = gelf_getclass (ebl->elf); - int nentries = shdr->sh_size / shdr->sh_entsize; - - /* Get the data of the section. */ - Elf_Data *data = elf_getdata (scn, NULL); - if (data == NULL) - return; - - /* Get the symbol table information. */ - 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. */ - 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) - { - printf (gettext ("\nInvalid symbol table at offset %#0" PRIx64 "\n"), - shdr->sh_offset); - return; - } - - /* 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; - } - } - - /* 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")); - - printf (ngettext ("\ -\nRelocation section [%2zu] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n", - "\ -\nRelocation section [%2zu] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n", - nentries), - elf_ndxscn (scn), - elf_strptr (ebl->elf, shstrndx, shdr->sh_name), - (unsigned int) shdr->sh_info, - elf_strptr (ebl->elf, shstrndx, destshdr->sh_name), - shdr->sh_offset, - nentries); - fputs_unlocked (class == ELFCLASS32 - ? gettext ("\ - Offset Type Value Addend Name\n") - : gettext ("\ - Offset Type Value Addend Name\n"), - stdout); - - for (int cnt = 0; cnt < nentries; ++cnt) - { - GElf_Rela relmem; - GElf_Rela *rel = gelf_getrela (data, cnt, &relmem); - if (rel != NULL) - { - char buf[64]; - 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) - 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)) - /* Avoid the leading R_ which isn't carrying any - information. */ - ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), - buf, sizeof (buf)) + 2 - : gettext ("<INVALID RELOC>"), - gettext ("INVALID SYMBOL"), - (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", - 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 - information. */ - ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), - buf, sizeof (buf)) + 2 - : gettext ("<INVALID RELOC>"), - class == ELFCLASS32 ? 10 : 18, sym->st_value, - rel->r_addend, - elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name)); - else - { - destshdr = gelf_getshdr (elf_getscn (ebl->elf, - sym->st_shndx == SHN_XINDEX - ? xndx : sym->st_shndx), - &destshdr_mem); - - if (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)) - /* Avoid the leading R_ which isn't carrying any - information. */ - ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), - buf, sizeof (buf)) + 2 - : gettext ("<INVALID RELOC>"), - gettext ("INVALID SECTION"), - (long int) (sym->st_shndx == SHN_XINDEX - ? xndx : sym->st_shndx)); - else - printf ("\ - %#0*" PRIx64 " %-15s %#0*" PRIx64 " +%5" 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 - information. */ - ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), - buf, sizeof (buf)) + 2 - : gettext ("<INVALID RELOC>"), - class == ELFCLASS32 ? 10 : 18, sym->st_value, - rel->r_addend, - elf_strptr (ebl->elf, shstrndx, destshdr->sh_name)); - } - } - } -} - - -/* Print the program header. */ -static void -print_symtab (Ebl *ebl, GElf_Ehdr *ehdr, int type) -{ - /* Find the symbol table(s). For this we have to search through the - section table. */ - 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 (shdr != NULL && shdr->sh_type == (GElf_Word) type) - handle_symtab (ebl, ehdr, scn, shdr); - } -} - - -static void -handle_symtab (Ebl *ebl, GElf_Ehdr *ehdr, 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); - if (data == NULL) - return; - - /* Find out whether we have other sections we might need. */ - 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 (runshdr->sh_type == SHT_GNU_versym - && runshdr->sh_link == elf_ndxscn (scn)) - /* Bingo, found the version information. Now get the data. */ - versym_data = elf_getdata (runscn, NULL); - else if (runshdr->sh_type == SHT_GNU_verneed) - { - /* This is the information about the needed versions. */ - verneed_data = elf_getdata (runscn, NULL); - verneed_stridx = runshdr->sh_link; - } - else if (runshdr->sh_type == SHT_GNU_verdef) - { - /* This is the information about the defined versions. */ - verdef_data = elf_getdata (runscn, NULL); - verdef_stridx = runshdr->sh_link; - } - else if (runshdr->sh_type == SHT_SYMTAB_SHNDX - && runshdr->sh_link == elf_ndxscn (scn)) - /* Extended section index. */ - xndx_data = elf_getdata (runscn, NULL); - } - } - - /* 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")); - - /* Now we can compute the number of entries in the section. */ - 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); - printf (ngettext (" %lu local symbol String table: [%2u] '%s'\n", - " %lu local symbols String table: [%2u] '%s'\n", - shdr->sh_info), - (unsigned long int) shdr->sh_info, - (unsigned int) shdr->sh_link, - elf_strptr (ebl->elf, shstrndx, - gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), - &glink)->sh_name)); - - fputs_unlocked (class == ELFCLASS32 - ? gettext ("\ - Num: Value Size Type Bind Vis Ndx Name\n") - : gettext ("\ - Num: Value Size Type Bind Vis Ndx Name\n"), - stdout); - - for (cnt = 0; cnt < nsyms; ++cnt) - { - char typebuf[64]; - char bindbuf[64]; - char scnbuf[64]; - Elf32_Word xndx; - GElf_Sym sym_mem; - GElf_Sym *sym = gelf_getsymshndx (data, xndx_data, cnt, &sym_mem, &xndx); - - if (sym == NULL) - continue; - - /* Determine the real section index. */ - if (sym->st_shndx != SHN_XINDEX) - xndx = sym->st_shndx; - - printf (gettext ("\ -%5u: %0*" PRIx64 " %6" PRId64 " %-7s %-6s %-9s %6s %s"), - cnt, - class == ELFCLASS32 ? 8 : 16, - sym->st_value, - sym->st_size, - ebl_symbol_type_name (ebl, GELF_ST_TYPE (sym->st_info), - typebuf, sizeof (typebuf)), - ebl_symbol_binding_name (ebl, GELF_ST_BIND (sym->st_info), - bindbuf, sizeof (bindbuf)), - get_visibility_type (GELF_ST_VISIBILITY (sym->st_other)), - ebl_section_name (ebl, sym->st_shndx, xndx, scnbuf, - sizeof (scnbuf), NULL, shnum), - elf_strptr (ebl->elf, shdr->sh_link, sym->st_name)); - - if (versym_data != NULL) - { - /* Get the version information. */ - GElf_Versym versym_mem; - GElf_Versym *versym; - - versym = gelf_getversym (versym_data, cnt, &versym_mem); - - if (versym != NULL && ((*versym & 0x8000) != 0 || *versym > 1)) - { - bool is_nobits = false; - bool check_def = xndx != SHN_UNDEF; - - if (xndx < SHN_LORESERVE || sym->st_shndx == SHN_XINDEX) - { - GElf_Shdr symshdr_mem; - GElf_Shdr *symshdr = - gelf_getshdr (elf_getscn (ebl->elf, xndx), &symshdr_mem); - - is_nobits = (symshdr != NULL - && symshdr->sh_type == SHT_NOBITS); - } - - 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); - while (verneed != NULL) - { - size_t vna_offset = vn_offset; - - vernaux = gelf_getvernaux (verneed_data, - vna_offset += verneed->vn_aux, - &vernaux_mem); - while (vernaux != NULL - && vernaux->vna_other != *versym - && vernaux->vna_next != 0) - { - /* Update the offset. */ - vna_offset += vernaux->vna_next; - - vernaux = (vernaux->vna_next == 0 - ? NULL - : gelf_getvernaux (verneed_data, - vna_offset, - &vernaux_mem)); - } - - /* Check whether we found the version. */ - if (vernaux != NULL && vernaux->vna_other == *versym) - /* Found it. */ - break; - - vn_offset += verneed->vn_next; - verneed = (verneed->vn_next == 0 - ? NULL - : gelf_getverneed (verneed_data, vn_offset, - &verneed_mem)); - } - - if (vernaux != NULL && vernaux->vna_other == *versym) - { - printf ("@%s (%u)", - elf_strptr (ebl->elf, verneed_stridx, - vernaux->vna_name), - (unsigned int) vernaux->vna_other); - check_def = 0; - } - else if (! is_nobits) - error (0, 0, gettext ("bad dynamic symbol")); - else - check_def = 1; - } - - 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); - while (verdef != NULL) - { - if (verdef->vd_ndx == (*versym & 0x7fff)) - /* Found the definition. */ - break; - - vd_offset += verdef->vd_next; - verdef = (verdef->vd_next == 0 - ? NULL - : gelf_getverdef (verdef_data, vd_offset, - &verdef_mem)); - } - - if (verdef != NULL) - { - GElf_Verdaux verdaux_mem; - GElf_Verdaux *verdaux; - - verdaux = gelf_getverdaux (verdef_data, - vd_offset + verdef->vd_aux, - &verdaux_mem); - - if (verdaux != NULL) - printf ((*versym & 0x8000) ? "@%s" : "@@%s", - elf_strptr (ebl->elf, verdef_stridx, - verdaux->vda_name)); - } - } - } - } - - putchar ('\n'); - } -} - - -/* Print version information. */ -static void -print_verinfo (Ebl *ebl, GElf_Ehdr *ehdr) -{ - /* Find the version information sections. For this we have to - search through the section table. */ - 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) - { - if (shdr->sh_type == SHT_GNU_verneed) - handle_verneed (ebl, ehdr, scn, shdr); - else if (shdr->sh_type == SHT_GNU_verdef) - handle_verdef (ebl, ehdr, scn, shdr); - else if (shdr->sh_type == SHT_GNU_versym) - handle_versym (ebl, ehdr, scn, shdr); - } - } -} - - -static const char * -get_ver_flags (unsigned int flags) -{ - static char buf[32]; - char *endp; - - if (flags == 0) - return gettext ("none"); - - if (flags & VER_FLG_BASE) - endp = stpcpy (buf, "BASE "); - else - endp = buf; - - if (flags & VER_FLG_WEAK) - { - if (endp != buf) - endp = stpcpy (endp, "| "); - - endp = stpcpy (endp, "WEAK "); - } - - if (flags & ~(VER_FLG_BASE | VER_FLG_WEAK)) - { - strncpy (endp, gettext ("| <unknown>"), buf + sizeof (buf) - endp); - buf[sizeof (buf) - 1] = '\0'; - } - - return buf; -} - - -static void -handle_verneed (Ebl *ebl, GElf_Ehdr *ehdr, 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); - if (data == NULL) - return; - - /* 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")); - - printf (ngettext ("\ -\nVersion needs section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", - "\ -\nVersion needs section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", - shdr->sh_info), - (unsigned int) elf_ndxscn (scn), - elf_strptr (ebl->elf, shstrndx, shdr->sh_name), shdr->sh_info, - class == 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)); - - offset = 0; - for (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) - break; - - printf (gettext (" %#06x: Version: %hu File: %s Cnt: %hu\n"), - offset, (unsigned short int) need->vn_version, - 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; ) - { - GElf_Vernaux auxmem; - GElf_Vernaux *aux; - - aux = gelf_getvernaux (data, auxoffset, &auxmem); - if (aux == NULL) - break; - - printf (gettext (" %#06x: Name: %s Flags: %s Version: %hu\n"), - auxoffset, - elf_strptr (ebl->elf, shdr->sh_link, aux->vna_name), - get_ver_flags (aux->vna_flags), - (unsigned short int) aux->vna_other); - - auxoffset += aux->vna_next; - } - - /* Find the next offset. */ - offset += need->vn_next; - } -} - - -static void -handle_verdef (Ebl *ebl, GElf_Ehdr *ehdr, 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); - if (data == NULL) - return; - - /* 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")); - - printf (ngettext ("\ -\nVersion definition section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", - "\ -\nVersion definition section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", - shdr->sh_info), - (unsigned int) elf_ndxscn (scn), - elf_strptr (ebl->elf, shstrndx, shdr->sh_name), - shdr->sh_info, - class == 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)); - - offset = 0; - for (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) - break; - - auxoffset = offset + def->vd_aux; - aux = gelf_getverdaux (data, auxoffset, &auxmem); - if (aux == NULL) - break; - - printf (gettext ("\ - %#06x: Version: %hd Flags: %s Index: %hd Cnt: %hd Name: %s\n"), - offset, def->vd_version, - get_ver_flags (def->vd_flags), - def->vd_ndx, - def->vd_cnt, - elf_strptr (ebl->elf, shdr->sh_link, aux->vda_name)); - - auxoffset += aux->vda_next; - for (cnt2 = 1; cnt2 < def->vd_cnt; ++cnt2) - { - aux = gelf_getverdaux (data, auxoffset, &auxmem); - if (aux == NULL) - break; - - printf (gettext (" %#06x: Parent %d: %s\n"), - auxoffset, cnt2, - elf_strptr (ebl->elf, shdr->sh_link, aux->vda_name)); - - auxoffset += aux->vda_next; - } - - /* Find the next offset. */ - offset += def->vd_next; - } -} - - -static void -handle_versym (Ebl *ebl, GElf_Ehdr *ehdr, 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); - if (data == NULL) - return; - - /* 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")); - - /* We have to find the version definition section and extract the - version names. */ - defscn = NULL; - needscn = NULL; - - 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 (vershdr->sh_type == SHT_GNU_verdef) - defscn = verscn; - else if (vershdr->sh_type == SHT_GNU_verneed) - needscn = verscn; - } - } - - if (defscn != NULL || needscn != NULL) - { - /* We have a version information (better should have). Now get - the version names. First find the maximum version number. */ - nvername = 0; - if (defscn != NULL) - { - /* Run through the version definitions and find the highest - index. */ - unsigned int offset = 0; - Elf_Data *defdata; - GElf_Shdr defshdrmem; - GElf_Shdr *defshdr; - - defdata = elf_getdata (defscn, NULL); - if (defdata == NULL) - return; - - defshdr = gelf_getshdr (defscn, &defshdrmem); - if (defshdr == NULL) - return; - - for (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) - break; - - nvername = MAX (nvername, (size_t) (def->vd_ndx & 0x7fff)); - - offset += def->vd_next; - } - } - 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) - return; - - for (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) - break; - - /* Run through the auxiliary entries. */ - auxoffset = offset + need->vn_aux; - for (cnt2 = need->vn_cnt; --cnt2 >= 0; ) - { - GElf_Vernaux auxmem; - GElf_Vernaux *aux; - - aux = gelf_getvernaux (needdata, auxoffset, &auxmem); - if (aux == NULL) - break; - - nvername = MAX (nvername, - (size_t) (aux->vna_other & 0x7fff)); - - auxoffset += aux->vna_next; - } - - offset += need->vn_next; - } - } - - /* This is the number of versions we know about. */ - ++nvername; - - /* Allocate the array. */ - vername = (const char **) alloca (nvername * sizeof (const char *)); - filename = (const char **) alloca (nvername * sizeof (const char *)); - - /* Run through the data structures again and collect the strings. */ - if (defscn != NULL) - { - /* Run through the version definitions and find the highest - index. */ - unsigned int offset = 0; - Elf_Data *defdata; - GElf_Shdr defshdrmem; - GElf_Shdr *defshdr; - - defdata = elf_getdata (defscn, NULL); - if (defdata == NULL) - return; - - defshdr = gelf_getshdr (defscn, &defshdrmem); - if (defshdr == NULL) - return; - - for (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) - break; - - vername[def->vd_ndx & 0x7fff] - = elf_strptr (ebl->elf, defshdr->sh_link, aux->vda_name); - filename[def->vd_ndx & 0x7fff] = NULL; - - offset += def->vd_next; - } - } - 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) - return; - - for (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) - break; - - /* Run through the auxiliary entries. */ - auxoffset = offset + need->vn_aux; - for (cnt2 = need->vn_cnt; --cnt2 >= 0; ) - { - GElf_Vernaux auxmem; - GElf_Vernaux *aux; - - aux = gelf_getvernaux (needdata, auxoffset, &auxmem); - if (aux == NULL) - break; - - vername[aux->vna_other & 0x7fff] - = elf_strptr (ebl->elf, needshdr->sh_link, aux->vna_name); - filename[aux->vna_other & 0x7fff] - = elf_strptr (ebl->elf, needshdr->sh_link, need->vn_file); - - auxoffset += aux->vna_next; - } - - offset += need->vn_next; - } - } - } - else - { - vername = NULL; - nvername = 1; - filename = NULL; - } - - /* Print the header. */ - printf (ngettext ("\ -\nVersion symbols section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'", - "\ -\nVersion symbols section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'", - shdr->sh_size / shdr->sh_entsize), - (unsigned int) elf_ndxscn (scn), - elf_strptr (ebl->elf, shstrndx, shdr->sh_name), - (int) (shdr->sh_size / shdr->sh_entsize), - class == 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)); - - /* Now we can finally look at the actual contents of this section. */ - for (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); - if (sym == NULL) - break; - - switch (*sym) - { - case 0: - fputs_unlocked (gettext (" 0 *local* "), - stdout); - break; - - case 1: - fputs_unlocked (gettext (" 1 *global* "), - stdout); - break; - - default: - n = printf ("%4d%c%s", - *sym & 0x7fff, *sym & 0x8000 ? 'h' : ' ', - (unsigned int) (*sym & 0x7fff) < nvername - ? vername[*sym & 0x7fff] : "???"); - if ((unsigned int) (*sym & 0x7fff) < nvername - && filename[*sym & 0x7fff] != NULL) - n += printf ("(%s)", filename[*sym & 0x7fff]); - printf ("%*s", MAX (0, 33 - (int) n), " "); - break; - } - } - putchar ('\n'); -} - - -static void -handle_hash (Ebl *ebl, GElf_Ehdr *ehdr) -{ - /* Find the symbol table(s). For this we have to search through the - section table. */ - Elf_Scn *scn = NULL; - size_t shstrndx; - - /* 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")); - - 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 (shdr != NULL && shdr->sh_type == SHT_HASH) - { - 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; - - if (data == NULL) - { - error (0, 0, gettext ("cannot get data for section %d: %s"), - (int) elf_ndxscn (scn), elf_errmsg (-1)); - continue; - } - - 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]; - - 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)); - - for (cnt = 0; cnt < nbucket; ++cnt) - if (bucket[cnt] != 0) - { - Elf32_Word inner; - - inner = bucket[cnt]; - while (inner > 0 && inner < nchain) - { - ++nsyms; - if (maxlength < ++lengths[cnt]) - ++maxlength; - - inner = chain[inner]; - } - } - - counts = (uint32_t *) xcalloc (maxlength + 1, sizeof (uint32_t)); - - for (cnt = 0; cnt < nbucket; ++cnt) - ++counts[lengths[cnt]]; - - if (nbucket > 0) - { - uint64_t success = 0; - Elf32_Word acc; - - 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); - } - - acc = 0; - for (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); - } - - free (counts); - free (lengths); - } - } -} - - -static void -print_liblist (Ebl *ebl, GElf_Ehdr *ehdr) -{ - /* Find the library list 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 (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_LIBLIST) - { - int nentries = shdr->sh_size / shdr->sh_entsize; - printf (ngettext ("\ -\nLibrary list section [%2zu] '%s' at offset %#0" PRIx64 " contains %d entry:\n", - "\ -\nLibrary list section [%2zu] '%s' at offset %#0" PRIx64 " contains %d entries:\n", - nentries), - elf_ndxscn (scn), - elf_strptr (ebl->elf, shstrndx, shdr->sh_name), - shdr->sh_offset, - nentries); - - Elf_Data *data = elf_getdata (scn, NULL); - if (data == NULL) - return; - - puts (gettext ("\ - Library Time Stamp Checksum Version Flags")); - - for (int cnt = 0; cnt < nentries; ++cnt) - { - GElf_Lib lib_mem; - GElf_Lib *lib = gelf_getlib (data, cnt, &lib_mem); - if (lib == NULL) - continue; - - time_t t = (time_t) lib->l_time_stamp; - struct tm *tm = gmtime (&t); - if (tm == NULL) - continue; - - printf (" [%2d] %-29s %04u-%02u-%02uT%02u:%02u:%02u %08x %-7u %u\n", - cnt, elf_strptr (ebl->elf, shdr->sh_link, lib->l_name), - tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec, - (unsigned int) lib->l_checksum, - (unsigned int) lib->l_version, - (unsigned int) lib->l_flags); - } - } - } -} - - -static const char * -dwarf_tag_string (unsigned int tag) -{ - static const char *known_tags[] = - { - [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 unsigned int nknown_tags = (sizeof (known_tags) - / sizeof (known_tags[0])); - static char buf[40]; - const char *result = NULL; - - if (tag < nknown_tags) - result = known_tags[tag]; - - if (result == NULL) - /* There are a few known extensions. */ - switch (tag) - { - case DW_TAG_MIPS_loop: - result = "MIPS_loop"; - break; - - case DW_TAG_format_label: - result = "format_label"; - break; - - case DW_TAG_function_template: - result = "function_template"; - break; - - case DW_TAG_class_template: - result = "class_template"; - break; - - default: - if (tag < DW_TAG_lo_user) - snprintf (buf, sizeof buf, gettext ("unknown tag %hx"), tag); - else - snprintf (buf, sizeof buf, gettext ("unknown user tag %hx"), tag); - result = buf; - break; - } - - return result; -} - - -static const char * -dwarf_attr_string (unsigned int attrnum) -{ - static const char *known_attrs[] = - { - [DW_AT_sibling] = "sibling", - [DW_AT_location] = "location", - [DW_AT_name] = "name", - [DW_AT_ordering] = "ordering", - [DW_AT_subscr_data] = "subscr_data", - [DW_AT_byte_size] = "byte_size", - [DW_AT_bit_offset] = "bit_offset", - [DW_AT_bit_size] = "bit_size", - [DW_AT_element_list] = "element_list", - [DW_AT_stmt_list] = "stmt_list", - [DW_AT_low_pc] = "low_pc", - [DW_AT_high_pc] = "high_pc", - [DW_AT_language] = "language", - [DW_AT_member] = "member", - [DW_AT_discr] = "discr", - [DW_AT_discr_value] = "discr_value", - [DW_AT_visibility] = "visibility", - [DW_AT_import] = "import", - [DW_AT_string_length] = "string_length", - [DW_AT_common_reference] = "common_reference", - [DW_AT_comp_dir] = "comp_dir", - [DW_AT_const_value] = "const_value", - [DW_AT_containing_type] = "containing_type", - [DW_AT_default_value] = "default_value", - [DW_AT_inline] = "inline", - [DW_AT_is_optional] = "is_optional", - [DW_AT_lower_bound] = "lower_bound", - [DW_AT_producer] = "producer", - [DW_AT_prototyped] = "prototyped", - [DW_AT_return_addr] = "return_addr", - [DW_AT_start_scope] = "start_scope", - [DW_AT_stride_size] = "stride_size", - [DW_AT_upper_bound] = "upper_bound", - [DW_AT_abstract_origin] = "abstract_origin", - [DW_AT_accessibility] = "accessibility", - [DW_AT_address_class] = "address_class", - [DW_AT_artificial] = "artificial", - [DW_AT_base_types] = "base_types", - [DW_AT_calling_convention] = "calling_convention", - [DW_AT_count] = "count", - [DW_AT_data_member_location] = "data_member_location", - [DW_AT_decl_column] = "decl_column", - [DW_AT_decl_file] = "decl_file", - [DW_AT_decl_line] = "decl_line", - [DW_AT_declaration] = "declaration", - [DW_AT_discr_list] = "discr_list", - [DW_AT_encoding] = "encoding", - [DW_AT_external] = "external", - [DW_AT_frame_base] = "frame_base", - [DW_AT_friend] = "friend", - [DW_AT_identifier_case] = "identifier_case", - [DW_AT_macro_info] = "macro_info", - [DW_AT_namelist_items] = "namelist_items", - [DW_AT_priority] = "priority", - [DW_AT_segment] = "segment", - [DW_AT_specification] = "specification", - [DW_AT_static_link] = "static_link", - [DW_AT_type] = "type", - [DW_AT_use_location] = "use_location", - [DW_AT_variable_parameter] = "variable_parameter", - [DW_AT_virtuality] = "virtuality", - [DW_AT_vtable_elem_location] = "vtable_elem_location" - }; - const unsigned int nknown_attrs = (sizeof (known_attrs) - / sizeof (known_attrs[0])); - static char buf[40]; - const char *result = NULL; - - if (attrnum < nknown_attrs) - result = known_attrs[attrnum]; - - if (result == NULL) - /* There are a few known extensions. */ - switch (attrnum) - { - case DW_AT_MIPS_fde: - result = "MIPS_fde"; - break; - - case DW_AT_MIPS_loop_begin: - result = "MIPS_loop_begin"; - break; - - case DW_AT_MIPS_tail_loop_begin: - result = "MIPS_tail_loop_begin"; - break; - - case DW_AT_MIPS_epilog_begin: - result = "MIPS_epilog_begin"; - break; - - case DW_AT_MIPS_loop_unroll_factor: - result = "MIPS_loop_unroll_factor"; - break; - - case DW_AT_MIPS_software_pipeline_depth: - result = "MIPS_software_pipeline_depth"; - break; - - case DW_AT_MIPS_linkage_name: - result = "MIPS_linkage_name"; - break; - - case DW_AT_MIPS_stride: - result = "MIPS_stride"; - break; - - case DW_AT_MIPS_abstract_name: - result = "MIPS_abstract_name"; - break; - - case DW_AT_MIPS_clone_origin: - result = "MIPS_clone_origin"; - break; - - case DW_AT_MIPS_has_inlines: - result = "MIPS_has_inlines"; - break; - - case DW_AT_MIPS_stride_byte: - result = "MIPS_stride_byte"; - break; - - case DW_AT_MIPS_stride_elem: - result = "MIPS_stride_elem"; - break; - - case DW_AT_MIPS_ptr_dopetype: - result = "MIPS_ptr_dopetype"; - break; - - case DW_AT_MIPS_allocatable_dopetype: - result = "MIPS_allocatable_dopetype"; - break; - - case DW_AT_MIPS_assumed_shape_dopetype: - result = "MIPS_assumed_shape_dopetype"; - break; - - case DW_AT_MIPS_assumed_size: - result = "MIPS_assumed_size"; - break; - - case DW_AT_sf_names: - result = "sf_names"; - break; - - case DW_AT_src_info: - result = "src_info"; - break; - - case DW_AT_mac_info: - result = "mac_info"; - break; - - case DW_AT_src_coords: - result = "src_coords"; - break; - - case DW_AT_body_begin: - result = "body_begin"; - break; - - case DW_AT_body_end: - result = "body_end"; - break; - - default: - if (attrnum < DW_AT_lo_user) - snprintf (buf, sizeof buf, gettext ("unknown attribute %hx"), - attrnum); - else - snprintf (buf, sizeof buf, gettext ("unknown user attribute %hx"), - attrnum); - result = buf; - break; - } - - return result; -} - - -static const char * -dwarf_form_string (unsigned int form) -{ - static const char *known_forms[] = - { - [DW_FORM_addr] = "addr", - [DW_FORM_block2] = "block2", - [DW_FORM_block4] = "block4", - [DW_FORM_data2] = "data2", - [DW_FORM_data4] = "data4", - [DW_FORM_data8] = "data8", - [DW_FORM_string] = "string", - [DW_FORM_block] = "block", - [DW_FORM_block1] = "block1", - [DW_FORM_data1] = "data1", - [DW_FORM_flag] = "flag", - [DW_FORM_sdata] = "sdata", - [DW_FORM_strp] = "strp", - [DW_FORM_udata] = "udata", - [DW_FORM_ref_addr] = "ref_addr", - [DW_FORM_ref1] = "ref1", - [DW_FORM_ref2] = "ref2", - [DW_FORM_ref4] = "ref4", - [DW_FORM_ref8] = "ref8", - [DW_FORM_ref_udata] = "ref_udata", - [DW_FORM_indirect] = "indirect" - }; - const unsigned int nknown_forms = (sizeof (known_forms) - / sizeof (known_forms[0])); - static char buf[40]; - const char *result = NULL; - - if (form < nknown_forms) - result = known_forms[form]; - - if (result == NULL) - snprintf (buf, sizeof buf, gettext ("unknown form %" PRIx64), - (uint64_t) form); - - return result; -} - - -static const char * -dwarf_lang_string (unsigned int lang) -{ - static const char *known[] = - { - [DW_LANG_C89] = "ISO C89", - [DW_LANG_C] = "C", - [DW_LANG_Ada83] = "Ada83", - [DW_LANG_C_plus_plus ] = "C++", - [DW_LANG_Cobol74] = "Cobol74", - [DW_LANG_Cobol85] = "Cobol85", - [DW_LANG_Fortran77] = "Fortran77", - [DW_LANG_Fortran90] = "Fortran90", - [DW_LANG_Pascal83] = "Pascal83", - [DW_LANG_Modula2] = "Modula2", - [DW_LANG_Java] = "Java", - [DW_LANG_C99] = "ISO C99", - [DW_LANG_Ada95] = "Ada95", - [DW_LANG_Fortran95] = "Fortran95", - [DW_LANG_PL1] = "PL1" - }; - - if (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. */ - return "Assembler"; - - if (lang >= DW_LANG_lo_user && lang <= DW_LANG_hi_user) - { - static char buf[100]; - snprintf (buf, sizeof (buf), "lo_user+%u", lang - DW_LANG_lo_user); - return buf; - } - - return "???"; -} - - -static void -print_ops (Dwarf *dbg, int level, unsigned int addrsize, Dwarf_Word len, - unsigned char *data) -{ - static const char *known[] = - { - [DW_OP_addr] = "addr", - [DW_OP_deref] = "deref", - [DW_OP_const1u] = "const1u", - [DW_OP_const1s] = "const1s", - [DW_OP_const2u] = "const2u", - [DW_OP_const2s] = "const2s", - [DW_OP_const4u] = "const4u", - [DW_OP_const4s] = "const4s", - [DW_OP_const8u] = "const8u", - [DW_OP_const8s] = "const8s", - [DW_OP_constu] = "constu", - [DW_OP_consts] = "consts", - [DW_OP_dup] = "dup", - [DW_OP_drop] = "drop", - [DW_OP_over] = "over", - [DW_OP_pick] = "pick", - [DW_OP_swap] = "swap", - [DW_OP_rot] = "rot", - [DW_OP_xderef] = "xderef", - [DW_OP_abs] = "abs", - [DW_OP_and] = "and", - [DW_OP_div] = "div", - [DW_OP_minus] = "minus", - [DW_OP_mod] = "mod", - [DW_OP_mul] = "mul", - [DW_OP_neg] = "neg", - [DW_OP_not] = "not", - [DW_OP_or] = "or", - [DW_OP_plus] = "plus", - [DW_OP_plus_uconst] = "plus_uconst", - [DW_OP_shl] = "shl", - [DW_OP_shr] = "shr", - [DW_OP_shra] = "shra", - [DW_OP_xor] = "xor", - [DW_OP_bra] = "bra", - [DW_OP_eq] = "eq", - [DW_OP_ge] = "ge", - [DW_OP_gt] = "gt", - [DW_OP_le] = "le", - [DW_OP_lt] = "lt", - [DW_OP_ne] = "ne", - [DW_OP_skip] = "skip", - [DW_OP_lit0] = "lit0", - [DW_OP_lit1] = "lit1", - [DW_OP_lit2] = "lit2", - [DW_OP_lit3] = "lit3", - [DW_OP_lit4] = "lit4", - [DW_OP_lit5] = "lit5", - [DW_OP_lit6] = "lit6", - [DW_OP_lit7] = "lit7", - [DW_OP_lit8] = "lit8", - [DW_OP_lit9] = "lit9", - [DW_OP_lit10] = "lit10", - [DW_OP_lit11] = "lit11", - [DW_OP_lit12] = "lit12", - [DW_OP_lit13] = "lit13", - [DW_OP_lit14] = "lit14", - [DW_OP_lit15] = "lit15", - [DW_OP_lit16] = "lit16", - [DW_OP_lit17] = "lit17", - [DW_OP_lit18] = "lit18", - [DW_OP_lit19] = "lit19", - [DW_OP_lit20] = "lit20", - [DW_OP_lit21] = "lit21", - [DW_OP_lit22] = "lit22", - [DW_OP_lit23] = "lit23", - [DW_OP_lit24] = "lit24", - [DW_OP_lit25] = "lit25", - [DW_OP_lit26] = "lit26", - [DW_OP_lit27] = "lit27", - [DW_OP_lit28] = "lit28", - [DW_OP_lit29] = "lit29", - [DW_OP_lit30] = "lit30", - [DW_OP_lit31] = "lit31", - [DW_OP_reg0] = "reg0", - [DW_OP_reg1] = "reg1", - [DW_OP_reg2] = "reg2", - [DW_OP_reg3] = "reg3", - [DW_OP_reg4] = "reg4", - [DW_OP_reg5] = "reg5", - [DW_OP_reg6] = "reg6", - [DW_OP_reg7] = "reg7", - [DW_OP_reg8] = "reg8", - [DW_OP_reg9] = "reg9", - [DW_OP_reg10] = "reg10", - [DW_OP_reg11] = "reg11", - [DW_OP_reg12] = "reg12", - [DW_OP_reg13] = "reg13", - [DW_OP_reg14] = "reg14", - [DW_OP_reg15] = "reg15", - [DW_OP_reg16] = "reg16", - [DW_OP_reg17] = "reg17", - [DW_OP_reg18] = "reg18", - [DW_OP_reg19] = "reg19", - [DW_OP_reg20] = "reg20", - [DW_OP_reg21] = "reg21", - [DW_OP_reg22] = "reg22", - [DW_OP_reg23] = "reg23", - [DW_OP_reg24] = "reg24", - [DW_OP_reg25] = "reg25", - [DW_OP_reg26] = "reg26", - [DW_OP_reg27] = "reg27", - [DW_OP_reg28] = "reg28", - [DW_OP_reg29] = "reg29", - [DW_OP_reg30] = "reg30", - [DW_OP_reg31] = "reg31", - [DW_OP_breg0] = "breg0", - [DW_OP_breg1] = "breg1", - [DW_OP_breg2] = "breg2", - [DW_OP_breg3] = "breg3", - [DW_OP_breg4] = "breg4", - [DW_OP_breg5] = "breg5", - [DW_OP_breg6] = "breg6", - [DW_OP_breg7] = "breg7", - [DW_OP_breg8] = "breg8", - [DW_OP_breg9] = "breg9", - [DW_OP_breg10] = "breg10", - [DW_OP_breg11] = "breg11", - [DW_OP_breg12] = "breg12", - [DW_OP_breg13] = "breg13", - [DW_OP_breg14] = "breg14", - [DW_OP_breg15] = "breg15", - [DW_OP_breg16] = "breg16", - [DW_OP_breg17] = "breg17", - [DW_OP_breg18] = "breg18", - [DW_OP_breg19] = "breg19", - [DW_OP_breg20] = "breg20", - [DW_OP_breg21] = "breg21", - [DW_OP_breg22] = "breg22", - [DW_OP_breg23] = "breg23", - [DW_OP_breg24] = "breg24", - [DW_OP_breg25] = "breg25", - [DW_OP_breg26] = "breg26", - [DW_OP_breg27] = "breg27", - [DW_OP_breg28] = "breg28", - [DW_OP_breg29] = "breg29", - [DW_OP_breg30] = "breg30", - [DW_OP_breg31] = "breg31", - [DW_OP_regx] = "regx", - [DW_OP_fbreg] = "fbreg", - [DW_OP_bregx] = "bregx", - [DW_OP_piece] = "piece", - [DW_OP_deref_size] = "deref_size", - [DW_OP_xderef_size] = "xderef_size", - [DW_OP_nop] = "nop", - [DW_OP_push_object_address] = "push_object_address", - [DW_OP_call2] = "call2", - [DW_OP_call4] = "call4", - [DW_OP_call_ref] = "call_ref", - }; - - Dwarf_Word offset = 0; - while (len-- > 0) - { - size_t op = *((unsigned char *) data); - ++data; - - switch (op) - { - case DW_OP_call_ref: - case DW_OP_addr:; - /* Address operand. */ - Dwarf_Word addr; - if (addrsize == 4) - addr = read_4ubyte_unaligned (dbg, data); - else - { - assert (addrsize == 8); - addr = read_8ubyte_unaligned (dbg, data); - } - data += addrsize; - len -= addrsize; - - printf (" %*s [%4" PRIuMAX "] %s %" PRIuMAX "\n", - (int) (20 + level * 2), "", (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_pick: - case DW_OP_const1u: - printf (" %*s [%4" PRIuMAX "] %s %" PRIu8 "\n", - (int) (20 + level * 2), "", (uintmax_t) offset, - known[op] ?: "???", *((uint8_t *) data)); - ++data; - --len; - offset += 2; - break; - - case DW_OP_const2u: - printf (" %*s [%4" PRIuMAX "] %s %" PRIu16 "\n", - (int) (20 + level * 2), "", (uintmax_t) offset, - known[op] ?: "???", read_2ubyte_unaligned (dbg, data)); - len -= 2; - data += 2; - offset += 3; - break; - - case DW_OP_const4u: - printf (" %*s [%4" PRIuMAX "] %s %" PRIu32 "\n", - (int) (20 + level * 2), "", (uintmax_t) offset, - known[op] ?: "???", read_4ubyte_unaligned (dbg, data)); - len -= 4; - data += 4; - offset += 5; - break; - - case DW_OP_const8u: - printf (" %*s [%4" PRIuMAX "] %s %" PRIu64 "\n", - (int) (20 + level * 2), "", (uintmax_t) offset, - known[op] ?: "???", read_8ubyte_unaligned (dbg, data)); - len -= 8; - data += 8; - offset += 9; - break; - - case DW_OP_const1s: - printf (" %*s [%4" PRIuMAX "] %s %" PRId8 "\n", - (int) (20 + level * 2), "", (uintmax_t) offset, - known[op] ?: "???", *((int8_t *) data)); - ++data; - --len; - offset += 2; - break; - - case DW_OP_const2s: - printf (" %*s [%4" PRIuMAX "] %s %" PRId16 "\n", - (int) (20 + level * 2), "", (uintmax_t) offset, - known[op] ?: "???", read_2sbyte_unaligned (dbg, data)); - len -= 2; - data += 2; - offset += 3; - break; - - case DW_OP_const4s: - printf (" %*s [%4" PRIuMAX "] %s %" PRId32 "\n", - (int) (20 + level * 2), "", (uintmax_t) offset, - known[op] ?: "???", read_4sbyte_unaligned (dbg, data)); - len -= 4; - data += 4; - offset += 5; - break; - - case DW_OP_const8s: - printf (" %*s [%4" PRIuMAX "] %s %" PRId64 "\n", - (int) (20 + level * 2), "", (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_regx: - case DW_OP_plus_uconst: - case DW_OP_constu:; - 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, - known[op] ?: "???", uleb); - 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, - known[op] ?: "???", sleb); - len -= data - start; - offset += 1 + (data - start); - break; - - case DW_OP_bregx: - 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, - known[op] ?: "???", uleb, sleb); - len -= data - start; - offset += 1 + (data - start); - break; - - case DW_OP_call2: - 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, - known[op] ?: "???", - (uintmax_t) (offset + read_2sbyte_unaligned (dbg, data))); - len -= 2; - data += 2; - offset += 3; - break; - - default: - /* No Operand. */ - printf (" %*s [%4" PRIuMAX "] %s\n", - (int) (20 + level * 2), "", (uintmax_t) offset, - known[op] ?: "???"); - ++offset; - break; - } - } -} - - -static void -print_debug_abbrev_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, - GElf_Shdr *shdr, Dwarf *dbg) -{ - printf (gettext ("\nDWARF section '%s' at offset %#" PRIx64 ":\n" - " [ Code]\n"), - ".debug_abbrev", (uint64_t) shdr->sh_offset); - - Dwarf_Off offset = 0; - while (1) - { - size_t length; - Dwarf_Abbrev abbrev; - - if (dwarf_offabbrev (dbg, offset, &length, &abbrev) != 0) - { - printf (gettext (" *** error while reading abbreviation: %s\n"), - dwarf_errmsg (-1)); - break; - } - - if (length == 1) - /* This is the NUL byte at the end of the section. */ - break; - - /* 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); - - ++cnt; - } - - offset += length; - } -} - - -/* Print content of DWARF .debug_aranges section. We fortunately do - 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, - GElf_Shdr *shdr, Dwarf *dbg) -{ - Dwarf_Aranges *aranges; - size_t cnt; - if (dwarf_getaranges (dbg, &aranges, &cnt) != 0) - { - error (0, 0, gettext ("cannot get .debug_aranges content: %s"), - dwarf_errmsg (-1)); - return; - } - - printf (ngettext ("\ -\nDWARF section '%s' at offset %#" PRIx64 " contains %zu entry:\n", - "\ -\nDWARF section '%s' at offset %#" PRIx64 " contains %zu entries:\n", - cnt), - ".debug_aranges", (uint64_t) shdr->sh_offset, cnt); - - /* Compute floor(log16(cnt)). */ - size_t tmp = cnt; - int digits = 1; - while (tmp >= 16) - { - ++digits; - tmp >>= 4; - } - - for (size_t n = 0; n < cnt; ++n) - { - Dwarf_Arange *runp = dwarf_onearange (aranges, n); - if (runp == NULL) - { - printf ("cannot get arange %zu: %s\n", n, dwarf_errmsg (-1)); - return; - } - - Dwarf_Addr start; - Dwarf_Word length; - Dwarf_Off offset; - - if (dwarf_getarangeinfo (runp, &start, &length, &offset) != 0) - printf (gettext (" [%*zu] ???\n"), digits, n); - else - printf (gettext (" [%*zu] start: %0#*" PRIx64 - ", length: %5" PRIu64 ", CU DIE offset: %6" - PRId64 "\n"), - digits, n, ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 10 : 18, - (uint64_t) start, (uint64_t) length, (int64_t) offset); - } -} - - -static void -print_debug_frame_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, - GElf_Shdr *shdr, Dwarf *dbg) -{ -} - - -struct attrcb_args -{ - Dwarf *dbg; - int level; - unsigned int addrsize; - Dwarf_Off cu_offset; -}; - - -static int -attr_callback (Dwarf_Attribute *attrp, void *arg) -{ - struct attrcb_args *cbargs = (struct attrcb_args *) arg; - const int level = cbargs->level; - - unsigned int attr = dwarf_whatattr (attrp); - if (unlikely (attr == 0)) - { - error (0, 0, gettext ("cannot get attribute code: %s"), - dwarf_errmsg (-1)); - return DWARF_CB_ABORT; - } - - unsigned int form = dwarf_whatform (attrp); - if (unlikely (form == 0)) - { - error (0, 0, gettext ("cannot get attribute form: %s"), - dwarf_errmsg (-1)); - return DWARF_CB_ABORT; - } - - 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); - break; - - case DW_FORM_indirect: - case DW_FORM_strp: - case DW_FORM_string:; - const char *str = dwarf_formstring (attrp); - if (unlikely (str == NULL)) - goto attrval_out; - printf (" %*s%-20s \"%s\"\n", - (int) (level * 2), "", dwarf_attr_string (attr), str); - break; - - case DW_FORM_ref_addr: - case DW_FORM_ref_udata: - case DW_FORM_ref8: - case DW_FORM_ref4: - case DW_FORM_ref2: - case DW_FORM_ref1:; - Dwarf_Off ref; - if (unlikely (dwarf_formref (attrp, &ref) != 0)) - goto attrval_out; - - printf (" %*s%-20s [%6" PRIxMAX "]\n", - (int) (level * 2), "", dwarf_attr_string (attr), - (uintmax_t) (ref + cbargs->cu_offset)); - break; - - case DW_FORM_udata: - case DW_FORM_sdata: - case DW_FORM_data8: - case DW_FORM_data4: - case DW_FORM_data2: - case DW_FORM_data1:; - Dwarf_Word num; - if (unlikely (dwarf_formudata (attrp, &num) != 0)) - goto attrval_out; - - if (attr == DW_AT_language) - { - printf (" %*s%-20s %s (%d)\n", - (int) (level * 2), "", dwarf_attr_string (attr), - dwarf_lang_string (num), (int) num); - break; - } - - printf (" %*s%-20s %" PRIuMAX "\n", - (int) (level * 2), "", dwarf_attr_string (attr), - (uintmax_t) num); - break; - - case DW_FORM_flag:; - bool flag; - if (unlikely (dwarf_formflag (attrp, &flag) != 0)) - goto attrval_out; - - printf (" %*s%-20s %s\n", - (int) (level * 2), "", dwarf_attr_string (attr), - nl_langinfo (flag ? YESSTR : NOSTR)); - break; - - case DW_FORM_block4: - case DW_FORM_block2: - case DW_FORM_block1: - case DW_FORM_block:; - Dwarf_Block block; - if (unlikely (dwarf_formblock (attrp, &block) != 0)) - goto attrval_out; - - printf (" %*s%-20s %" PRIxMAX " byte block\n", - (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); - break; - - default: - printf (" %*s%-20s [form: %d] ???\n", - (int) (level * 2), "", dwarf_attr_string (attr), - (int) form); - break; - } - - return DWARF_CB_OK; -} - - -static void -print_debug_info_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, - GElf_Shdr *shdr, Dwarf *dbg) -{ - printf (gettext ("\ -\nDWARF section '%s' at offset %#" PRIx64 ":\n [Offset]\n"), - ".debug_info", (uint64_t) shdr->sh_offset); - - /* If the section is empty we don't have to do anything. */ - if (shdr->sh_size == 0) - return; - - size_t maxdies = 20; - Dwarf_Die *dies = (Dwarf_Die *) xmalloc (maxdies * sizeof (Dwarf_Die)); - - Dwarf_Off offset = 0; - - /* New compilation unit. */ - size_t cuhl; - //Dwarf_Half version; - Dwarf_Off abbroffset; - uint8_t addrsize; - uint8_t offsize; - Dwarf_Off nextcu; - next_cu: - if (dwarf_nextcu (dbg, offset, &nextcu, &cuhl, &abbroffset, &addrsize, - &offsize) != 0) - goto do_return; - - printf (gettext (" Compilation unit at offset %" PRIu64 ":\n" - " Version: %" PRIu16 ", Abbreviation section offset: %" - PRIu64 ", Address size: %" PRIu8 ", Offset size: %" PRIu8 "\n"), - (uint64_t) offset, /*version*/2, abbroffset, addrsize, offsize); - - - struct attrcb_args args; - args.dbg = dbg; - args.addrsize = addrsize; - args.cu_offset = offset; - - offset += cuhl; - - int level = 0; - - if (unlikely (dwarf_offdie (dbg, offset, &dies[level]) == NULL)) - { - error (0, 0, gettext ("cannot get DIE at offset %" PRIu64 - " in section '%s': %s"), - (uint64_t) offset, ".debug_info", dwarf_errmsg (-1)); - goto do_return; - } - - do - { - offset = dwarf_dieoffset (&dies[level]); - if (offset == -1l) - { - error (0, 0, gettext ("cannot get DIE offset: %s"), - dwarf_errmsg (-1)); - goto do_return; - } - - int tag = dwarf_tag (&dies[level]); - if (tag == DW_TAG_invalid) - { - error (0, 0, gettext ("cannot get tag of DIE at offset %" PRIu64 - " in section '%s': %s"), - (uint64_t) offset, ".debug_info", dwarf_errmsg (-1)); - 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); - - /* Print the attribute values. */ - args.level = level; - (void) dwarf_getattrs (&dies[level], attr_callback, &args, 0); - - /* Make room for the next level's DIE. */ - if (level + 1 == maxdies) - dies = (Dwarf_Die *) xrealloc (dies, - (maxdies += 10) - * sizeof (Dwarf_Die)); - - int res = dwarf_child (&dies[level], &dies[level + 1]); - if (res > 0) - { - while ((res = dwarf_siblingof (&dies[level], &dies[level])) == 1) - if (level-- == 0) - break; - - if (res == -1) - { - error (0, 0, gettext ("cannot get next DIE: %s\n"), - dwarf_errmsg (-1)); - goto do_return; - } - } - else if (unlikely (res < 0)) - { - error (0, 0, gettext ("cannot get next DIE: %s"), - dwarf_errmsg (-1)); - goto do_return; - } - else - ++level; - } - while (level >= 0); - - offset = nextcu; - if (offset != 0) - goto next_cu; - - do_return: - free (dies); -} - - -static void -print_debug_line_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, - GElf_Shdr *shdr, Dwarf *dbg) -{ - printf (gettext ("\ -\nDWARF section '%s' at offset %#" PRIx64 ":\n"), - ".debug_line", (uint64_t) shdr->sh_offset); - - if (shdr->sh_size == 0) - return; - - /* 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) - { - error (0, 0, gettext ("cannot get line data section data: %s"), - elf_errmsg (-1)); - return; - } - - const unsigned char *linep = (const unsigned char *) data->d_buf; - const unsigned char *lineendp; - - while (linep - < (lineendp = (const unsigned char *) data->d_buf + data->d_size)) - { - size_t start_offset = linep - (const unsigned char *) data->d_buf; - - Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep); - unsigned int length = 4; - if (unlikely (unit_length == 0xffffffff)) - { - if (unlikely (linep + 8 > lineendp)) - { - invalid_data: - error (0, 0, gettext ("invalid data in section [%zu] '%s'"), - elf_ndxscn (scn), ".debug_line"); - return; - } - unit_length = read_8ubyte_unaligned_inc (dbg, linep); - length = 8; - } - - /* Check whether we have enough room in the section. */ - if (unit_length < 2 + length + 5 * 1 - || unlikely (linep + unit_length > lineendp)) - goto invalid_data; - lineendp = linep + unit_length; - - /* The next element of the header is the version identifier. */ - uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep); - - /* Next comes the header length. */ - Dwarf_Word header_length; - if (length == 4) - header_length = read_4ubyte_unaligned_inc (dbg, linep); - else - header_length = read_8ubyte_unaligned_inc (dbg, linep); - //const unsigned char *header_start = linep; - - /* Next the minimum instruction length. */ - uint_fast8_t minimum_instr_len = *linep++; - - /* Then the flag determining the default value of the is_stmt - register. */ - uint_fast8_t default_is_stmt = *linep++; - - /* Now the line base. */ - int_fast8_t line_base = *((const int_fast8_t *) linep); - ++linep; - - /* And the line range. */ - uint_fast8_t line_range = *linep++; - - /* The opcode base. */ - uint_fast8_t opcode_base = *linep++; - - /* Print what we got so far. */ - printf (gettext ("\n" - " Length: %" PRIu64 "\n" - " DWARF version: %" PRIuFAST16 "\n" - " Prologue length: %" PRIu64 "\n" - " Minimum instruction length: %" PRIuFAST8 "\n" - " Initial value if '%s': %" PRIuFAST8 "\n" - " Line base: %" PRIdFAST8 "\n" - " Line range: %" PRIuFAST8 "\n" - " Opcode base: %" PRIuFAST8 "\n" - "\n" - "Opcodes:\n"), - (uint64_t) unit_length, version, (uint64_t) header_length, - minimum_instr_len, "is_stmt", default_is_stmt, line_base, - line_range, opcode_base); - - if (unlikely (linep + opcode_base - 1 >= lineendp)) - goto invalid_data; - int opcode_base_l10 = 1; - unsigned int tmp = opcode_base; - while (tmp > 10) - { - tmp /= 10; - ++opcode_base_l10; - } - const uint8_t *standard_opcode_lengths = linep - 1; - for (uint_fast8_t cnt = 1; cnt < opcode_base; ++cnt) - printf (ngettext (" [%*" PRIuFAST8 "] %hhu argument\n", - " [%*" PRIuFAST8 "] %hhu arguments\n", - (int) linep[cnt - 1]), - opcode_base_l10, cnt, linep[cnt - 1]); - linep += opcode_base - 1; - if (unlikely (linep >= lineendp)) - goto invalid_data; - - puts (gettext ("\nDirectory table:")); - while (*linep != 0) - { - unsigned char *endp = memchr (linep, '\0', lineendp - linep); - if (endp == NULL) - goto invalid_data; - - printf (" %s\n", (char *) linep); - - linep = endp + 1; - } - /* Skip the final NUL byte. */ - ++linep; - - if (unlikely (linep >= lineendp)) - goto invalid_data; - puts (gettext ("\nFile name table:\n" - " Entry Dir Time Size Name")); - for (unsigned int cnt = 1; *linep != 0; ++cnt) - { - /* First comes the file name. */ - char *fname = (char *) linep; - unsigned char *endp = memchr (fname, '\0', lineendp - linep); - if (endp == NULL) - goto invalid_data; - linep = endp + 1; - - /* Then the index. */ - unsigned int diridx; - get_uleb128 (diridx, linep); - - /* Next comes the modification time. */ - unsigned int mtime; - get_uleb128 (mtime, linep); - - /* Finally the length of the file. */ - unsigned int fsize; - get_uleb128 (fsize, linep); - - printf (" %-5u %-5u %-9u %-9u %s\n", - cnt, diridx, mtime, fsize, fname); - } - /* Skip the final NUL byte. */ - ++linep; - - puts (gettext ("\nLine number statements:")); - Dwarf_Word address = 0; - size_t line = 1; - uint_fast8_t is_stmt = default_is_stmt; - - /* Default address value, in case we do not find the CU. */ - size_t address_size - = elf_getident (ebl->elf, NULL)[EI_CLASS] == ELFCLASS32 ? 4 : 8; - - /* Determine the CU this block is for. */ - Dwarf_Off cuoffset; - Dwarf_Off ncuoffset = 0; - size_t hsize; - while (dwarf_nextcu (dbg, cuoffset = ncuoffset, &ncuoffset, &hsize, - NULL, NULL, NULL) == 0) - { - Dwarf_Die cudie; - if (dwarf_offdie (dbg, cuoffset + hsize, &cudie) == NULL) - continue; - Dwarf_Attribute stmt_list; - if (dwarf_attr (&cudie, DW_AT_stmt_list, &stmt_list) == NULL) - continue; - Dwarf_Word lineoff; - if (dwarf_formudata (&stmt_list, &lineoff) != 0) - continue; - if (lineoff == start_offset) - { - /* Found the CU. */ - address_size = cudie.cu->address_size; - break; - } - } - - while (linep < lineendp) - { - unsigned int u128; - int s128; - - /* Read the opcode. */ - unsigned int opcode = *linep++; - - /* Is this a special opcode? */ - if (likely (opcode >= opcode_base)) - { - /* Yes. Handling this is quite easy since the opcode value - is computed with - - opcode = (desired line increment - line_base) - + (line_range * address advance) + opcode_base - */ - int line_increment = (line_base - + (opcode - opcode_base) % line_range); - unsigned int address_increment = (minimum_instr_len - * ((opcode - opcode_base) - / line_range)); - - /* Perform the increments. */ - line += line_increment; - address += address_increment; - - printf (gettext ("\ - special opcode %u: address+%u = %#" PRIx64 ", line%+d = %zu\n"), - opcode, address_increment, (uint64_t) address, - line_increment, line); - } - else if (opcode == 0) - { - /* This an extended opcode. */ - if (unlikely (linep + 2 > lineendp)) - goto invalid_data; - - /* The length. */ - unsigned int len = *linep++; - - if (unlikely (linep + len > lineendp)) - goto invalid_data; - - /* The sub-opcode. */ - opcode = *linep++; - - printf (gettext (" extended opcode %u: "), opcode); - - switch (opcode) - { - case DW_LNE_end_sequence: - puts (gettext ("end of sequence")); - - /* Reset the registers we care about. */ - address = 0; - line = 1; - is_stmt = default_is_stmt; - break; - - case DW_LNE_set_address: - if (address_size == 4) - 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); - break; - - case DW_LNE_define_file: - { - char *fname = (char *) linep; - unsigned char *endp = memchr (linep, '\0', - lineendp - linep); - if (endp == NULL) - goto invalid_data; - linep = endp + 1; - - unsigned int diridx; - get_uleb128 (diridx, linep); - Dwarf_Word mtime; - get_uleb128 (mtime, linep); - Dwarf_Word filelength; - get_uleb128 (filelength, linep); - - printf (gettext ("\ -define new file: dir=%u, mtime=%" PRIu64 ", length=%" PRIu64 ", name=%s\n"), - diridx, (uint64_t) mtime, (uint64_t) filelength, - fname); - } - break; - - default: - /* Unknown, ignore it. */ - puts (gettext ("unknown opcode")); - linep += len - 1; - break; - } - } - else if (opcode <= DW_LNS_set_epilog_begin) - { - /* This is a known standard opcode. */ - switch (opcode) - { - case DW_LNS_copy: - /* Takes no argument. */ - puts (gettext (" copy")); - break; - - case DW_LNS_advance_pc: - /* Takes one uleb128 parameter which is added to the - address. */ - get_uleb128 (u128, linep); - address += minimum_instr_len * u128; - printf (gettext ("\ - advance address by %u to %#" PRIx64 "\n"), - u128, (uint64_t) address); - break; - - case DW_LNS_advance_line: - /* Takes one sleb128 parameter which is added to the - line. */ - get_sleb128 (s128, linep); - line += s128; - printf (gettext ("\ - advance line by constant %d to %" PRId64 "\n"), - s128, (int64_t) line); - break; - - case DW_LNS_set_file: - /* Takes one uleb128 parameter which is stored in file. */ - get_uleb128 (u128, linep); - printf (gettext (" set file to %" PRIu64 "\n"), - (uint64_t) u128); - break; - - case DW_LNS_set_column: - /* Takes one uleb128 parameter which is stored in column. */ - if (unlikely (standard_opcode_lengths[opcode] != 1)) - goto invalid_data; - - get_uleb128 (u128, linep); - printf (gettext (" set column to %" PRIu64 "\n"), - (uint64_t) u128); - break; - - case DW_LNS_negate_stmt: - /* Takes no argument. */ - is_stmt = 1 - is_stmt; - printf (gettext (" set '%s' to %" PRIuFAST8 "\n"), - "is_stmt", is_stmt); - break; - - case DW_LNS_set_basic_block: - /* Takes no argument. */ - puts (gettext (" set basic block flag")); - break; - - case DW_LNS_const_add_pc: - /* Takes no argument. */ - 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); - 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; - - u128 = read_2ubyte_unaligned_inc (dbg, linep); - address += u128; - printf (gettext ("\ - advance address by fixed value %u to %#" PRIx64 "\n"), - u128, (uint64_t) address); - break; - - case DW_LNS_set_prologue_end: - /* Takes no argument. */ - puts (gettext (" set prologue end flag")); - break; - - case DW_LNS_set_epilog_begin: - /* Takes no argument. */ - puts (gettext (" set epilogue begin flag")); - break; - } - } - else - { - /* This is a new opcode the generator but not we know about. - Read the parameters associated with it but then discard - everything. Read all the parameters for this opcode. */ - printf (ngettext (" unknown opcode with %" PRIu8 " parameter:", - " unknown opcode with %" PRIu8 " parameters:", - standard_opcode_lengths[opcode]), - standard_opcode_lengths[opcode]); - for (int n = standard_opcode_lengths[opcode]; n > 0; --n) - { - get_uleb128 (u128, linep); - if (n != standard_opcode_lengths[opcode]) - putc_unlocked (',', stdout); - printf (" %u", u128); - } - - /* Next round, ignore this opcode. */ - continue; - } - } - } - - /* There must only be one data block. */ - assert (elf_getdata (scn, data) == NULL); -} - - -static void -print_debug_loc_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, - GElf_Shdr *shdr, Dwarf *dbg) -{ - printf (gettext ("\ -\nDWARF section '%s' at offset %#" PRIx64 ":\n"), - ".debug_loc", (uint64_t) shdr->sh_offset); - - // XXX add something -} - - -struct mac_culist -{ - Dwarf_Die die; - Dwarf_Off offset; - Dwarf_Files *files; - struct mac_culist *next; -}; - - -static int -mac_compare (const void *p1, const void *p2) -{ - struct mac_culist *m1 = (struct mac_culist *) p1; - struct mac_culist *m2 = (struct mac_culist *) p2; - - if (m1->offset < m2->offset) - return -1; - if (m1->offset > m2->offset) - return 1; - return 0; -} - - -static void -print_debug_macinfo_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, - GElf_Shdr *shdr, Dwarf *dbg) -{ - printf (gettext ("\ -\nDWARF section '%s' at offset %#" PRIx64 ":\n"), - ".debug_macinfo", (uint64_t) shdr->sh_offset); - putc_unlocked ('\n', stdout); - - /* 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) - { - error (0, 0, gettext ("cannot get macro information section data: %s"), - elf_errmsg (-1)); - return; - } - - /* Get the source file information for all CUs. */ - Dwarf_Off offset; - Dwarf_Off ncu = 0; - size_t hsize; - struct mac_culist *culist = NULL; - size_t nculist = 0; - while (dwarf_nextcu (dbg, offset = ncu, &ncu, &hsize, NULL, NULL, NULL) == 0) - { - Dwarf_Die cudie; - if (dwarf_offdie (dbg, offset + hsize, &cudie) == NULL) - continue; - - Dwarf_Attribute attr; - if (dwarf_attr (&cudie, DW_AT_macro_info, &attr) == NULL) - continue; - - Dwarf_Word macoff; - if (dwarf_formudata (&attr, &macoff) != 0) - continue; - - struct mac_culist *newp = (struct mac_culist *) alloca (sizeof (*newp)); - newp->die = cudie; - newp->offset = macoff; - newp->files = NULL; - newp->next = culist; - culist = newp; - ++nculist; - } - - /* Convert the list into an array for easier consumption. */ - struct mac_culist *cus = (struct mac_culist *) alloca ((nculist + 1) - * sizeof (*cus)); - /* Add sentinel. */ - cus[nculist].offset = data->d_size; - if (nculist > 0) - { - for (size_t cnt = nculist - 1; culist != NULL; --cnt) - { - assert (cnt < nculist); - cus[cnt] = *culist; - culist = culist->next; - } - - /* Sort the array according to the offset in the .debug_macinfo - section. Note we keep the sentinel at the end. */ - qsort (cus, nculist, sizeof (*cus), mac_compare); - } - - const unsigned char *readp = (const unsigned char *) data->d_buf; - const unsigned char *readendp = readp + data->d_size; - int level = 1; - - while (readp < readendp) - { - unsigned int opcode = *readp++; - unsigned int u128; - unsigned int u128_2; - const unsigned char *endp; - - switch (opcode) - { - case DW_MACINFO_define: - case DW_MACINFO_undef: - case DW_MACINFO_vendor_ext: - /* For the first two opcodes the parameters are - line, string - For the latter - number, string. - We can treat these cases together. */ - get_uleb128 (u128, readp); - - endp = memchr (readp, '\0', readendp - readp); - if (endp == NULL) - { - printf (gettext ("\ -%*s*** non-terminated string at end of section"), - level, ""); - return; - } - - if (opcode == DW_MACINFO_define) - printf ("%*s#define %s, line %u\n", - level, "", (char *) readp, u128); - else if (opcode == DW_MACINFO_undef) - printf ("%*s#undef %s, line %u\n", - level, "", (char *) readp, u128); - else - printf (" #vendor-ext %s, number %u\n", (char *) readp, u128); - - readp = endp + 1; - break; - - case DW_MACINFO_start_file: - /* The two parameters are line and file index, in this order. */ - get_uleb128 (u128, readp); - get_uleb128 (u128_2, readp); - - /* Find the CU DIE for this file. */ - ptrdiff_t macoff = readp - (const unsigned char *) data->d_buf; - const char *fname = "???"; - if (macoff >= cus[0].offset) - { - while (macoff >= cus[1].offset) - ++cus; - - if (cus[0].files == NULL - && dwarf_getsrcfiles (&cus[0].die, &cus[0].files, NULL) != 0) - cus[0].files = (Dwarf_Files *) -1l; - - if (cus[0].files != (Dwarf_Files *) -1l) - fname = (dwarf_filesrc (cus[0].files, u128_2, NULL, NULL) - ?: "???"); - } - - printf ("%*sstart_file %u, [%u] %s\n", - level, "", u128, u128_2, fname); - ++level; - break; - - case DW_MACINFO_end_file: - --level; - printf ("%*send_file\n", level, ""); - /* Nothing more to do. */ - break; - - default: - // XXX gcc seems to generate files with a trailing zero. - if (opcode != 0 || readp != readendp) - printf ("%*s*** invalid opcode %u\n", level, "", opcode); - break; - } - } -} - - -/* Callback for printing global names. */ -static int -print_pubnames (Dwarf *dbg, Dwarf_Global *global, void *arg) -{ - int *np = (int *) arg; - - printf (gettext (" [%5d] DIE offset: %6" PRId64 - ", CU DIE offset: %6" PRId64 ", name: %s\n"), - (*np)++, global->die_offset, global->cu_offset, global->name); - - return 0; -} - - -/* 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, - GElf_Shdr *shdr, Dwarf *dbg) -{ - printf (gettext ("\nDWARF section '%s' at offset %#" PRIx64 ":\n"), - ".debug_pubnames", (uint64_t) shdr->sh_offset); - - int n = 0; - (void) dwarf_getpubnames (dbg, print_pubnames, &n, 0); -} - -/* Print the content of the DWARF string section '.debug_str'. */ -static void -print_debug_str_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, - GElf_Shdr *shdr, Dwarf *dbg) -{ - /* Compute floor(log16(shdr->sh_size)). */ - GElf_Addr tmp = shdr->sh_size; - int digits = 1; - while (tmp >= 16) - { - ++digits; - tmp >>= 4; - } - digits = MAX (4, digits); - - printf (gettext ("\nDWARF section '%s' at offset %#" PRIx64 ":\n" - " %*s String\n"), - ".debug_str", (uint64_t) shdr->sh_offset, - /* TRANS: the debugstr| prefix makes the string unique. */ - digits + 2, sgettext ("debugstr|Offset")); - - Dwarf_Off offset = 0; - while (offset < shdr->sh_size) - { - size_t len; - const char *str = dwarf_getstring (dbg, offset, &len); - if (str == NULL) - { - printf (gettext (" *** error while reading strings: %s\n"), - dwarf_errmsg (-1)); - break; - } - - printf (" [%*" PRIx64 "] \"%s\"\n", digits, (uint64_t) offset, str); - - offset += len + 1; - } -} - - -static void -print_debug (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); - if (dbg == NULL) - { - error (0, 0, gettext ("cannot get debug context descriptor: %s"), - dwarf_errmsg (-1)); - return; - } - - /* 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")); - - 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) - { - static const struct - { - const char *name; - enum section_e bitmask; - void (*fp) (Ebl *, GElf_Ehdr *, Elf_Scn *, GElf_Shdr *, Dwarf *); - } debug_sections[] = - { -#define NEW_SECTION(name) \ - { ".debug_" #name, section_##name, print_debug_##name##_section } - NEW_SECTION (abbrev), - NEW_SECTION (aranges), - NEW_SECTION (frame), - NEW_SECTION (info), - NEW_SECTION (line), - NEW_SECTION (loc), - NEW_SECTION (pubnames), - NEW_SECTION (str), - NEW_SECTION (macinfo), - { ".eh_frame", section_frame, print_debug_frame_section } - }; - const int ndebug_sections = (sizeof (debug_sections) - / sizeof (debug_sections[0])); - const char *name = elf_strptr (ebl->elf, shstrndx, - shdr->sh_name); - int n; - - for (n = 0; n < ndebug_sections; ++n) - 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); - break; - } - } - } - - /* We are done with the DWARF handling. */ - dwarf_end (dbg); -} - - -static void -handle_notes (Ebl *ebl, GElf_Ehdr *ehdr) -{ - int class = gelf_getclass (ebl->elf); - size_t cnt; - - /* 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) - { - GElf_Phdr mem; - GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &mem); - - if (phdr == NULL || phdr->p_type != PT_NOTE) - /* Not what we are looking for. */ - continue; - - printf (gettext ("\ -\nNote segment of %" PRId64 " 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)); - - fputs_unlocked (gettext (" Owner Data size Type\n"), stdout); - - - /* Handle the note section content. It consists of one or more - entries each of which consists of five parts: - - - 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 - - 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)) - - size_t idx = 0; - while (idx < phdr->p_filesz) - { - /* 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; - - 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) - { - if (ehdr->e_type == ET_CORE) - ebl_core_note (ebl, noteentry->name, noteentry->type, - noteentry->descsz, - ¬eentry->name[ALIGNED_LEN (noteentry->namesz)]); - else - ebl_object_note (ebl, noteentry->name, noteentry->type, - noteentry->descsz, - ¬eentry->name[ALIGNED_LEN (noteentry->namesz)]); - } - - /* Move to the next entry. */ - idx += (12 + ALIGNED_LEN (noteentry->namesz) - + ALIGNED_LEN (noteentry->descsz)); - } - - gelf_freechunk (ebl->elf, notemem); - } -} |