diff options
| author | Roland McGrath <[email protected]> | 2009-01-17 14:39:35 -0800 |
|---|---|---|
| committer | Roland McGrath <[email protected]> | 2009-01-17 14:39:35 -0800 |
| commit | 54456d8e63bfe787e2b616993e26aba1c8dffa4d (patch) | |
| tree | aefaaf28c7e03e2fe28413a6ee4fb24d848c7139 | |
| parent | 5513e643d78785900e8e9f723844beb1fc03d537 (diff) | |
| parent | e9c5963d7556ada8c852cb43130982ae53e9a0de (diff) | |
Merge commit 'origin/master' into roland/known-dwarf
Conflicts:
libdw/ChangeLog
| -rw-r--r-- | NEWS | 5 | ||||
| -rw-r--r-- | TODO | 4 | ||||
| -rw-r--r-- | lib/ChangeLog | 5 | ||||
| -rw-r--r-- | lib/system.h | 14 | ||||
| -rw-r--r-- | libdw/ChangeLog | 8 | ||||
| -rw-r--r-- | libdw/Makefile.am | 6 | ||||
| -rw-r--r-- | libdw/dwarf.h | 4 | ||||
| -rw-r--r-- | libdwfl/ChangeLog | 5 | ||||
| -rw-r--r-- | libdwfl/gzip.c | 115 | ||||
| -rw-r--r-- | src/ChangeLog | 58 | ||||
| -rw-r--r-- | src/addr2line.c | 6 | ||||
| -rw-r--r-- | src/ar.c | 5 | ||||
| -rw-r--r-- | src/elfcmp.c | 5 | ||||
| -rw-r--r-- | src/elflint.c | 42 | ||||
| -rw-r--r-- | src/findtextrel.c | 6 | ||||
| -rw-r--r-- | src/ld.c | 4 | ||||
| -rw-r--r-- | src/nm.c | 4 | ||||
| -rw-r--r-- | src/objdump.c | 4 | ||||
| -rw-r--r-- | src/ranlib.c | 4 | ||||
| -rw-r--r-- | src/readelf.c | 724 | ||||
| -rw-r--r-- | src/size.c | 4 | ||||
| -rw-r--r-- | src/strings.c | 4 | ||||
| -rw-r--r-- | src/strip.c | 4 | ||||
| -rw-r--r-- | src/unstrip.c | 5 |
24 files changed, 819 insertions, 226 deletions
@@ -2,7 +2,10 @@ Version 0.139: libcpu: Add Intel SSE4 disassembler support -readelf: Implement call frame information dumping. +readelf: Implement call frame information and exception handling dumping. + Add -e option. Enable it implicitly for -a. + +elflint: Check PT_GNU_EH_FRAME program header entry. libdwfl: Support automatic gzip/bzip2 decompression of ELF files. @@ -1,7 +1,7 @@ ToDo list for elfutils -*-outline-*- ---------------------- -Time-stamp: <2009-01-01 16:56:38 drepper> +Time-stamp: <2009-01-16 20:55:06 drepper> * mkinstalldirs @@ -118,6 +118,8 @@ Time-stamp: <2009-01-01 16:56:38 drepper> check TLS relocation depencies + Check content of .eh_frame_hdr, .eh_frame, .gcc_except_table + *** for x86 check that R_386_TLS_GD is followed by R_386_PLT32 for __tls_get_addr diff --git a/lib/ChangeLog b/lib/ChangeLog index 8791640b..0774524c 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,8 @@ +2009-01-17 Ulrich Drepper <[email protected]> + + * system.h (ARGP_PROGRAM_VERSION_HOOK_DEF): Define. + (ARGP_PROGRAM_BUG_ADDRESS_DEF): Define. + 2009-01-10 Ulrich Drepper <[email protected]> * eu-config.h: Remove tls_key_t, key_create, getspecific, setspecific, diff --git a/lib/system.h b/lib/system.h index 23c666ad..10b4734a 100644 --- a/lib/system.h +++ b/lib/system.h @@ -1,5 +1,5 @@ /* Declarations for common convenience functions. - Copyright (C) 2006 Red Hat, Inc. + Copyright (C) 2006, 2009 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -78,4 +78,16 @@ extern int crc32_file (int fd, uint32_t *resp); #define pread_retry(fd, buf, len, off) \ TEMP_FAILURE_RETRY (pread (fd, buf, len, off)) + +/* We need define two variables, argp_program_version_hook and + argp_program_bug_address, in all programs. argp.h declares these + variables as non-const (which is correct in general). But we can + do better, it is not going to change. So we want to move them into + the .rodata section. Define macros to do the trick. */ +#define ARGP_PROGRAM_VERSION_HOOK_DEF \ + void (*const apvh) (FILE *, struct argp_state *) \ + __asm ("argp_program_version_hook") +#define ARGP_PROGRAM_BUG_ADDRESS_DEF \ + const char *const apba__ __asm ("argp_program_bug_address") + #endif /* system.h */ diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 9b9be90c..51ab6e94 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,4 +1,8 @@ -2009-01-11 Roland McGrath <[email protected]> +2009-01-17 Roland McGrath <[email protected]> + + * Makefile.am (known-dwarf.h): Target renamed, not in $(srcdir). + Make it unconditional. + (BUILT_SOURCES): Updated. * dwarf.h: Add description comments for DW_LANG_* values. @@ -6,6 +10,8 @@ ($(srcdir)/known-dwarf.h): New target. (BUILT_SOURCES): Add it. + * dwarf.h: Add DW_OP_GNU_push_tls_address, DW_OP_GNU_uninit. + 2009-01-10 Ulrich Drepper <[email protected]> * dwarf_error.c: Always use __thread. Remove all !USE_TLS code. diff --git a/libdw/Makefile.am b/libdw/Makefile.am index 6dda8eef..5f84abd8 100644 --- a/libdw/Makefile.am +++ b/libdw/Makefile.am @@ -85,12 +85,10 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \ libdw_visit_scopes.c \ dwarf_entry_breakpoints.c -if MAINTAINER_MODE -BUILT_SOURCES = $(srcdir)/known-dwarf.h -$(srcdir)/known-dwarf.h: $(top_srcdir)/config/known-dwarf.awk $(srcdir)/dwarf.h +BUILT_SOURCES = known-dwarf.h +known-dwarf.h: $(top_srcdir)/config/known-dwarf.awk $(srcdir)/dwarf.h $(AWK) -f $^ > [email protected] mv -f [email protected] $@ -endif if !MUDFLAP libdw_pic_a_SOURCES = diff --git a/libdw/dwarf.h b/libdw/dwarf.h index bdd16d93..cce46304 100644 --- a/libdw/dwarf.h +++ b/libdw/dwarf.h @@ -432,6 +432,10 @@ enum DW_OP_call_frame_cfa = 0x9c,/* CFA as determined by CFI. */ DW_OP_bit_piece = 0x9d, /* ULEB128 size and ULEB128 offset in bits. */ + /* GNU extensions. */ + DW_OP_GNU_push_tls_address = 0xe0, + DW_OP_GNU_uninit = 0xf0, + DW_OP_lo_user = 0xe0, /* Implementation-defined range start. */ DW_OP_hi_user = 0xff /* Implementation-defined range end. */ }; diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog index f0ab1acf..ef00a0cf 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -1,3 +1,8 @@ +2009-01-14 Roland McGrath <[email protected]> + + * gzip.c [!BZLIB] (mapped_zImage): New function. + (unzip) [!BZLIB]: Grok Linux kernel zImage format. + 2009-01-10 Ulrich Drepper <[email protected]> * dwfl_error.c: Always use __thread. Remove all !USE_TLS code. diff --git a/libdwfl/gzip.c b/libdwfl/gzip.c index ed602a66..66445254 100644 --- a/libdwfl/gzip.c +++ b/libdwfl/gzip.c @@ -53,6 +53,7 @@ #ifdef BZLIB # define inflate_groks_header true +# define mapped_zImage(...) false # include <bzlib.h> # define unzip __libdw_bunzip2 # define DWFL_E_ZLIB DWFL_E_BZLIB @@ -66,12 +67,41 @@ # define gzdopen BZ2_bzdopen # define gzread BZ2_bzread # define gzclose BZ2_bzclose +# define gzerror BZ2_bzerror #else # define inflate_groks_header false # include <zlib.h> # define unzip __libdw_gunzip # define MAGIC "\037\213" # define Z(what) Z_##what + +/* We can also handle Linux kernel zImage format in a very hackish way. + If it looks like one, we actually just scan the image for the gzip + magic bytes to figure out where the gzip image starts. */ + +# define LINUX_MAGIC_OFFSET 514 +# define LINUX_MAGIC "HdrS" + +static bool +mapped_zImage (off64_t *start_offset, void **mapped, size_t *mapped_size) +{ + const size_t pos = LINUX_MAGIC_OFFSET + sizeof LINUX_MAGIC; + if (*mapped_size > pos + && !memcmp (*mapped + LINUX_MAGIC_OFFSET, + LINUX_MAGIC, sizeof LINUX_MAGIC - 1)) + { + void *p = memmem (*mapped + pos, *mapped_size - pos, + MAGIC, sizeof MAGIC - 1); + if (p != NULL) + { + *start_offset += p - *mapped; + *mapped_size = *mapped + *mapped_size - p, + *mapped = p; + return true; + } + } + return false; +} #endif /* If this is not a compressed image, return DWFL_E_BADELF. @@ -120,7 +150,8 @@ unzip (int fd, off64_t start_offset, /* If the file is already mapped in, look at the header. */ if (mapped != NULL && (mapped_size <= sizeof MAGIC - || memcmp (mapped, MAGIC, sizeof MAGIC - 1))) + || memcmp (mapped, MAGIC, sizeof MAGIC - 1)) + && !mapped_zImage (&start_offset, &mapped, &mapped_size)) /* Not a compressed file. */ return DWFL_E_BADELF; @@ -165,35 +196,69 @@ unzip (int fd, off64_t start_offset, { /* Let the decompression library read the file directly. */ - int d = dup (fd); - if (unlikely (d < 0)) - return DWFL_E_BADELF; - if (start_offset != 0) - { - off64_t off = lseek (d, start_offset, SEEK_SET); - if (off != start_offset) - { - close (d); - return DWFL_E_BADELF; - } - } - gzFile zf = gzdopen (d, "r"); - if (unlikely (zf == NULL)) - { - close (d); - return zlib_fail (Z (MEM_ERROR)); - } + gzFile zf; + Dwfl_Error open_stream (void) + { + int d = dup (fd); + if (unlikely (d < 0)) + return DWFL_E_BADELF; + if (start_offset != 0) + { + off64_t off = lseek (d, start_offset, SEEK_SET); + if (off != start_offset) + { + close (d); + return DWFL_E_BADELF; + } + } + zf = gzdopen (d, "r"); + if (unlikely (zf == NULL)) + { + close (d); + return zlib_fail (Z (MEM_ERROR)); + } + + /* From here on, zlib will close D. */ + + return DWFL_E_NOERROR; + } - /* From here on, zlib will close D. */ + Dwfl_Error result = open_stream (); #ifndef BZLIB - if (gzdirect (zf)) + if (result == DWFL_E_NOERROR && gzdirect (zf)) { + bool found = false; + char buf[sizeof LINUX_MAGIC - 1]; + gzseek (zf, start_offset + LINUX_MAGIC_OFFSET, SEEK_SET); + int n = gzread (zf, buf, sizeof buf); + if (n == sizeof buf + && !memcmp (buf, LINUX_MAGIC, sizeof LINUX_MAGIC - 1)) + while (gzread (zf, buf, sizeof MAGIC - 1) == sizeof MAGIC - 1) + if (!memcmp (buf, MAGIC, sizeof MAGIC - 1)) + { + start_offset = gztell (zf) - 2; + found = true; + break; + } gzclose (zf); - return DWFL_E_BADELF; + if (found) + { + result = open_stream (); + if (result == DWFL_E_NOERROR && unlikely (gzdirect (zf))) + { + gzclose (zf); + result = DWFL_E_BADELF; + } + } + else + result = DWFL_E_BADELF; } #endif + if (result != DWFL_E_NOERROR) + return result; + ptrdiff_t pos = 0; while (1) { @@ -205,9 +270,9 @@ unzip (int fd, off64_t start_offset, int n = gzread (zf, buffer + pos, size - pos); if (n < 0) { -#ifdef BZLIB int code; - BZ2_bzerror (zf, &code); + gzerror (zf, &code); +#ifdef BZLIB if (code == BZ_DATA_ERROR_MAGIC) { gzclose (zf); @@ -216,7 +281,7 @@ unzip (int fd, off64_t start_offset, } #endif gzclose (zf); - return zlib_fail (Z (DATA_ERROR)); + return zlib_fail (code); } if (n == 0) break; diff --git a/src/ChangeLog b/src/ChangeLog index 854ad699..97fd4495 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,61 @@ +2009-01-17 Ulrich Drepper <[email protected]> + + * addr2line.c: Use ARGP_PROGRAM_VERSION_HOOK_DEF and + ARGP_PROGRAM_BUG_ADDRESS_DEF. + * ar.c: Likewise. + * elfcmp.c: Likewise. + * elflint.c: Likewise. + * findtextrel.c: Likewise. + * ld.c: Likewise. + * nm.c: Likewise. + * objdump.c: Likewise. + * ranlib.c: Likewise. + * readelf.c: Likewise. + * size.c: Likewise. + * strings.c: Likewise. + * strip.c: Likewise. + * unstrip.c: Likewise. + +2009-01-16 Ulrich Drepper <[email protected]> + + * elflint.c (check_program_header): Check that PT_GNU_EH_FRAME entry + matches .eh_frame_hdr section, if it is available. Also check that + the segment is allocated, not writable, not executable. + + * readelf.c: Add -e option. Dump exception and unwind related + sections. Add -e to -a. + (print_encoding_base): Handle DW_EH_PE_omit. + (print_debug_exception_table): Beginning of support. + (print_debug): Hook up print_debug_exception_table for + .gcc_except_table sections. + + * readelf.c (print_debug_frame_section): Some fixes for last change. + +2009-01-15 Ulrich Drepper <[email protected]> + + * readelf.c (print_encoding): Now a toplevel function. + (print_relinfo): Likewise. + (print_encoding_base): Broken out of print_debug_frame_section. + (print_debug_frame_section): Print different header for .eh_frame + sections. Fix recognition of matching CIEs in .debug_frame sections. + Print absolute offset for PC-relative FDE locations. Don't print + table header for FDEs if the table is empty. + (read_encoded): New function. + (print_debug_frame_hdr_section): New function. + (print_debug): Hook up print_debug_frame_hdr_section for .eh_frame_hdr + sections. + + * readelf.c (handle_relocs_rel): Print section number. + (print_debug_abbrev_section): Likewise. + (print_debug_aranges_section): Likewise. + (print_debug_ranges_section): Likewise. + (print_debug_info_section): Likewise. + (print_debug_line_section): Likewise. + (print_debug_loc_section): Likewise. + (print_debug_macinfo_section): Likewise. + (print_debug_pubnames_section): Likewise. + (print_debug_str_section): Likewise. + 2009-01-10 Ulrich Drepper <[email protected]> * strings.c (read_block): Fix typo in error message string. diff --git a/src/addr2line.c b/src/addr2line.c index 7141e269..5a7b0456 100644 --- a/src/addr2line.c +++ b/src/addr2line.c @@ -46,13 +46,15 @@ #include <string.h> #include <unistd.h> +#include <system.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; +ARGP_PROGRAM_VERSION_HOOK_DEF = print_version; /* Bug report address. */ -const char *argp_program_bug_address = PACKAGE_BUGREPORT; +ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; /* Values for the parameters which have no short form. */ @@ -55,7 +55,8 @@ /* 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; +ARGP_PROGRAM_VERSION_HOOK_DEF = print_version; + /* Prototypes for local functions. */ static int do_oper_extract (int oper, const char *arfname, char **argv, int argc, long int instance); @@ -66,7 +67,7 @@ static int do_oper_insert (int oper, const char *arfname, char **argv, /* Bug report address. */ -const char *argp_program_bug_address = PACKAGE_BUGREPORT; +ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; /* Definitions of arguments for argp functions. */ diff --git a/src/elfcmp.c b/src/elfcmp.c index 8903efb1..a1596365 100644 --- a/src/elfcmp.c +++ b/src/elfcmp.c @@ -41,6 +41,7 @@ #include <string.h> #include <unistd.h> +#include <system.h> #include "../libelf/elf-knowledge.h" #include "../libebl/libeblP.h" @@ -53,10 +54,10 @@ static int regioncompare (const void *p1, const void *p2); /* 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; +ARGP_PROGRAM_VERSION_HOOK_DEF = print_version; /* Bug report address. */ -const char *argp_program_bug_address = PACKAGE_BUGREPORT; +ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; /* Values for the parameters which have no short form. */ #define OPT_GAPS 0x100 diff --git a/src/elflint.c b/src/elflint.c index 23b0f496..1c508c47 100644 --- a/src/elflint.c +++ b/src/elflint.c @@ -56,10 +56,10 @@ /* 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; +ARGP_PROGRAM_VERSION_HOOK_DEF = print_version; /* Bug report address. */ -const char *argp_program_bug_address = PACKAGE_BUGREPORT; +ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; #define ARGP_strict 300 #define ARGP_gnuld 301 @@ -67,7 +67,6 @@ const char *argp_program_bug_address = PACKAGE_BUGREPORT; /* Definitions of arguments for argp functions. */ static const struct argp_option options[] = { - { "strict", ARGP_strict, NULL, 0, N_("Be extremely strict, flag level 2 features."), 0 }, { "quiet", 'q', NULL, 0, N_("Do not print anything if successful"), 0 }, @@ -4132,7 +4131,7 @@ more than one GNU_RELRO entry in program header\n")); if ((phdr2->p_flags & PF_W) == 0) ERROR (gettext ("\ loadable segment GNU_RELRO applies to is not writable\n")); - if ((phdr2->p_flags &~ PF_W) != (phdr->p_flags &~ PF_W)) + if ((phdr2->p_flags & ~PF_W) != (phdr->p_flags & ~PF_W)) ERROR (gettext ("\ loadable segment [%u] flags do not match GNU_RELRO [%u] flags\n"), cnt, inner); @@ -4173,6 +4172,41 @@ loadable segment [%u] flags do not match GNU_RELRO [%u] flags\n"), ERROR (gettext ("\ program header offset in ELF header and PHDR entry do not match")); } + else if (phdr->p_type == PT_GNU_EH_FRAME) + { + /* If there is an .eh_frame_hdr section it must be + referenced by this program header entry. */ + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr != NULL && shdr->sh_type == SHT_PROGBITS + && ! strcmp (".eh_frame_hdr", + elf_strptr (ebl->elf, shstrndx, shdr->sh_name))) + { + if (phdr->p_offset != shdr->sh_offset) + ERROR (gettext ("\ +call frame search table reference in program header has wrong offset\n")); + if (phdr->p_memsz != shdr->sh_size) + ERROR (gettext ("\ +call frame search table size mismatch in program and section header\n")); + break; + } + } + + /* The section must be allocated and not be writable and + executable. */ + if ((phdr->p_flags & PF_R) == 0) + ERROR (gettext ("\ +call frame search table must be allocated\n")); + if ((phdr->p_flags & PF_W) != 0) + ERROR (gettext ("\ +call frame search table must not be writable\n")); + if ((phdr->p_flags & PF_X) != 0) + ERROR (gettext ("\ +call frame search table must not be executable\n")); + } if (phdr->p_filesz > phdr->p_memsz && (phdr->p_memsz != 0 || phdr->p_type != PT_NOTE)) diff --git a/src/findtextrel.c b/src/findtextrel.c index 2fd99c96..9d10982f 100644 --- a/src/findtextrel.c +++ b/src/findtextrel.c @@ -44,6 +44,8 @@ #include <string.h> #include <unistd.h> +#include <system.h> + struct segments { @@ -54,10 +56,10 @@ struct segments /* 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; +ARGP_PROGRAM_VERSION_HOOK_DEF = print_version; /* Bug report address. */ -const char *argp_program_bug_address = PACKAGE_BUGREPORT; +ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; /* Values for the parameters which have no short form. */ #define OPT_DEBUGINFO 0x100 @@ -48,10 +48,10 @@ /* 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; +ARGP_PROGRAM_VERSION_HOOK_DEF = print_version; /* Bug report address. */ -const char *argp_program_bug_address = PACKAGE_BUGREPORT; +ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; /* Values for the various options. */ @@ -58,10 +58,10 @@ /* 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; +ARGP_PROGRAM_VERSION_HOOK_DEF = print_version; /* Bug report address. */ -const char *argp_program_bug_address = PACKAGE_BUGREPORT; +ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; /* Values for the parameters which have no short form. */ diff --git a/src/objdump.c b/src/objdump.c index 55d3ae2e..7f639410 100644 --- a/src/objdump.c +++ b/src/objdump.c @@ -49,10 +49,10 @@ /* 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; +ARGP_PROGRAM_VERSION_HOOK_DEF = print_version; /* Bug report address. */ -const char *argp_program_bug_address = PACKAGE_BUGREPORT; +ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; /* Definitions of arguments for argp functions. */ diff --git a/src/ranlib.c b/src/ranlib.c index f456b997..e92dc89b 100644 --- a/src/ranlib.c +++ b/src/ranlib.c @@ -58,10 +58,10 @@ static int handle_file (const char *fname); /* 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; +ARGP_PROGRAM_VERSION_HOOK_DEF = print_version; /* Bug report address. */ -const char *argp_program_bug_address = PACKAGE_BUGREPORT; +ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; /* Definitions of arguments for argp functions. */ diff --git a/src/readelf.c b/src/readelf.c index 2041983d..a3223eb4 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -61,16 +61,16 @@ /* 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; +ARGP_PROGRAM_VERSION_HOOK_DEF = print_version; /* Bug report address. */ -const char *argp_program_bug_address = PACKAGE_BUGREPORT; +ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; /* Definitions of arguments for argp functions. */ static const struct argp_option options[] = { { NULL, 0, NULL, 0, N_("Output selection:"), 0 }, - { "all", 'a', NULL, 0, N_("Equivalent to: -h -l"), 0 }, + { "all", 'a', NULL, 0, N_("Equivalent to: -e -h -l"), 0 }, { "dynamic", 'd', NULL, 0, N_("Display the dynamic segment"), 0 }, { "file-header", 'h', NULL, 0, N_("Display the ELF file header"), 0 }, { "histogram", 'I', NULL, 0, @@ -84,8 +84,8 @@ static const struct argp_option options[] = { "version-info", 'V', NULL, 0, N_("Display versioning information"), 0 }, { "debug-dump", 'w', "SECTION", OPTION_ARG_OPTIONAL, N_("Display DWARF section content. SECTION can be one of abbrev, " - "aranges, frame, info, loc, line, ranges, pubnames, str, or macinfo."), - 0 }, + "aranges, frame, info, loc, line, ranges, pubnames, str, macinfo, " + "or exception"), 0 }, { "notes", 'n', NULL, 0, N_("Display the core notes"), 0 }, { "arch-specific", 'A', NULL, 0, N_("Display architecture specific information (if any)"), 0 }, @@ -96,6 +96,8 @@ static const struct argp_option options[] = { "string-dump", 'p', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 }, { "archive-index", 'c', NULL, 0, N_("Display the symbol index of an archive"), 0 }, + { "exception", 'e', NULL, 0, N_("Display sections for exception handling"), + 0 }, { NULL, 0, NULL, 0, N_("Output control:"), 0 }, @@ -166,20 +168,21 @@ static bool any_control_option; /* 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_ranges = 512, /* .debug_ranges */ + section_abbrev = 1, /* .debug_abbrev */ + section_aranges = 2, /* .debug_aranges */ + section_frame = 4, /* .debug_frame or .eh_frame & al. */ + 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_ranges = 512, /* .debug_ranges */ + section_exception = 1024, /* .eh_frame & al. */ section_all = (section_abbrev | section_aranges | section_frame | section_info | section_line | section_loc | section_pubnames | section_str | section_macinfo - | section_ranges) + | section_ranges | section_exception) } print_debug_sections; /* Select hex dumping of sections. */ @@ -286,6 +289,7 @@ parse_opt (int key, char *arg, print_histogram = true; print_arch = true; print_notes = true; + print_debug_sections |= section_exception; any_control_option = true; break; case 'A': @@ -296,6 +300,10 @@ parse_opt (int key, char *arg, print_dynamic_table = true; any_control_option = true; break; + case 'e': + print_debug_sections |= section_exception; + any_control_option = true; + break; case 'g': print_section_groups = true; any_control_option = true; @@ -358,6 +366,8 @@ parse_opt (int key, char *arg, print_debug_sections |= section_str; else if (strcmp (arg, "macinfo") == 0) print_debug_sections |= section_macinfo; + else if (strcmp (arg, "exception") == 0) + print_debug_sections |= section_exception; else { fprintf (stderr, gettext ("Unknown DWARF debug section `%s'.\n"), @@ -1495,11 +1505,11 @@ handle_relocs_rel (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) 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 [%2zu] '%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", +\nRelocation section [%2zu] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n", nentries), - (unsigned int) elf_ndxscn (scn), + elf_ndxscn (scn), elf_strptr (ebl->elf, shstrndx, shdr->sh_name), (unsigned int) shdr->sh_info, elf_strptr (ebl->elf, shstrndx, destshdr->sh_name), @@ -3962,12 +3972,11 @@ static void print_debug_abbrev_section (Dwfl_Module *dwflmod __attribute__ ((unused)), Ebl *ebl __attribute__ ((unused)), GElf_Ehdr *ehdr __attribute__ ((unused)), - Elf_Scn *scn __attribute__ ((unused)), - GElf_Shdr *shdr, Dwarf *dbg) + Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) { - printf (gettext ("\nDWARF section '%s' at offset %#" PRIx64 ":\n" + printf (gettext ("\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n" " [ Code]\n"), - ".debug_abbrev", (uint64_t) shdr->sh_offset); + elf_ndxscn (scn), ".debug_abbrev", (uint64_t) shdr->sh_offset); Dwarf_Off offset = 0; while (offset < shdr->sh_size) @@ -4033,8 +4042,7 @@ print_debug_abbrev_section (Dwfl_Module *dwflmod __attribute__ ((unused)), static void print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)), Ebl *ebl __attribute__ ((unused)), - GElf_Ehdr *ehdr __attribute__ ((unused)), - Elf_Scn *scn __attribute__ ((unused)), + GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) { Dwarf_Aranges *aranges; @@ -4047,11 +4055,11 @@ print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)), } printf (ngettext ("\ -\nDWARF section '%s' at offset %#" PRIx64 " contains %zu entry:\n", +\nDWARF section [%2zu] '%s' at offset %#" PRIx64 " contains %zu entry:\n", "\ -\nDWARF section '%s' at offset %#" PRIx64 " contains %zu entries:\n", +\nDWARF section [%2zu] '%s' at offset %#" PRIx64 " contains %zu entries:\n", cnt), - ".debug_aranges", (uint64_t) shdr->sh_offset, cnt); + elf_ndxscn (scn), ".debug_aranges", (uint64_t) shdr->sh_offset, cnt); /* Compute floor(log16(cnt)). */ size_t tmp = cnt; @@ -4103,8 +4111,8 @@ print_debug_ranges_section (Dwfl_Module *dwflmod, } printf (gettext ("\ -\nDWARF section '%s' at offset %#" PRIx64 ":\n"), - ".debug_ranges", (uint64_t) shdr->sh_offset); +\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"), + elf_ndxscn (scn), ".debug_ranges", (uint64_t) shdr->sh_offset); size_t address_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; @@ -4381,6 +4389,159 @@ encoded_ptr_size (int encoding, unsigned int ptr_size) } +static unsigned int +print_encoding (unsigned int val) +{ + switch (val & 0xf) + { + case DW_EH_PE_absptr: + fputs ("absptr", stdout); + break; + case DW_EH_PE_uleb128: + fputs ("uleb128", stdout); + break; + case DW_EH_PE_udata2: + fputs ("udata2", stdout); + break; + case DW_EH_PE_udata4: + fputs ("udata4", stdout); + break; + case DW_EH_PE_udata8: + fputs ("udata8", stdout); + break; + case DW_EH_PE_sleb128: + fputs ("sleb128", stdout); + break; + case DW_EH_PE_sdata2: + fputs ("sdata2", stdout); + break; + case DW_EH_PE_sdata4: + fputs ("sdata4", stdout); + break; + case DW_EH_PE_sdata8: + fputs ("sdata8", stdout); + break; + default: + /* We did not use any of the bits after all. */ + return val; + } + + return val & ~0xf; +} + + +static unsigned int +print_relinfo (unsigned int val) +{ + switch (val & 0x70) + { + case DW_EH_PE_pcrel: + fputs ("pcrel", stdout); + break; + case DW_EH_PE_textrel: + fputs ("textrel", stdout); + break; + case DW_EH_PE_datarel: + fputs ("datarel", stdout); + break; + case DW_EH_PE_funcrel: + fputs ("funcrel", stdout); + break; + case DW_EH_PE_aligned: + fputs ("aligned", stdout); + break; + default: + return val; + } + + return val & ~0x70; +} + + +static void +print_encoding_base (const char *pfx, unsigned int fde_encoding) +{ + printf ("(%s", pfx); + + if (fde_encoding == DW_EH_PE_omit) + puts ("omit)"); + else + { + unsigned int w = fde_encoding; + + if (w & 0xf) + w = print_encoding (w); + + if (w & 0x70) + { + if (w != fde_encoding) + fputc_unlocked (' ', stdout); + + w = print_relinfo (w); + } + + if (w != 0) + printf ("%s%x", w != fde_encoding ? " " : "", w); + + puts (")"); + } +} + + +static const unsigned char * +read_encoded (unsigned int encoding, const unsigned char *readp, + const unsigned char *const endp, uint64_t *res, Dwarf *dbg) +{ + switch (encoding & 0xf) + { + case DW_EH_PE_uleb128: + // XXX buffer overrun check + get_uleb128 (*res, readp); + break; + case DW_EH_PE_sleb128: + // XXX buffer overrun check + get_sleb128 (*res, readp); + break; + case DW_EH_PE_udata2: + if (readp + 2 > endp) + goto invalid; + *res = read_2ubyte_unaligned_inc (dbg, readp); + break; + case DW_EH_PE_udata4: + if (readp + 4 > endp) + goto invalid; + *res = read_4ubyte_unaligned_inc (dbg, readp); + break; + case DW_EH_PE_udata8: + if (readp + 8 > endp) + goto invalid; + *res = read_8ubyte_unaligned_inc (dbg, readp); + break; + case DW_EH_PE_sdata2: + if (readp + 2 > endp) + goto invalid; + *res = read_2sbyte_unaligned_inc (dbg, readp); + break; + case DW_EH_PE_sdata4: + if (readp + 4 > endp) + goto invalid; + *res = read_4sbyte_unaligned_inc (dbg, readp); + break; + case DW_EH_PE_sdata8: + if (readp + 8 > endp) + goto invalid; + *res = read_8sbyte_unaligned_inc (dbg, readp); + break; + default: + invalid: + error (1, 0, + gettext ("invalid encoding")); + } + + return readp; +} + + static void print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) @@ -4398,10 +4559,16 @@ print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, scnname, elf_errmsg (-1)); return; } + bool is_eh_frame = strcmp (scnname, ".eh_frame") == 0; - printf (gettext ("\ -\nDWARF section '%s' at offset %#" PRIx64 ":\n"), - scnname, (uint64_t) shdr->sh_offset); + if (is_eh_frame) + printf (gettext ("\ +\nCall frame information section [%2zu] '%s' at offset %#" PRIx64 ":\n"), + elf_ndxscn (scn), scnname, (uint64_t) shdr->sh_offset); + else + printf (gettext ("\ +\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"), + elf_ndxscn (scn), scnname, (uint64_t) shdr->sh_offset); struct cieinfo { @@ -4410,20 +4577,16 @@ print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, unsigned int code_alignment_factor; unsigned int data_alignment_factor; unsigned int fde_encoding; + unsigned int lsda_encoding; struct cieinfo *next; } *cies = NULL; const unsigned char *readp = data->d_buf; const unsigned char *const dataend = ((unsigned char *) data->d_buf + data->d_size); - bool is_eh_frame = strcmp (scnname, ".eh_frame") == 0; while (readp < dataend) { - /* At the beginning there must be a CIE. There can be multiple, - hence we test tis in a loop. */ - ptrdiff_t offset = readp - (unsigned char *) data->d_buf; - - if (unlikely (readp + 12 > dataend)) + if (unlikely (readp + 4 > dataend)) { invalid_data: error (0, 0, gettext ("invalid data in section [%zu] '%s'"), @@ -4431,21 +4594,32 @@ print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, return; } - unsigned int ptr_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; + /* At the beginning there must be a CIE. There can be multiple, + hence we test tis in a loop. */ + ptrdiff_t offset = readp - (unsigned char *) data->d_buf; Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, readp); unsigned int length = 4; if (unlikely (unit_length == 0xffffffff)) { + if (unlikely (readp + 8 > dataend)) + goto invalid_data; + unit_length = read_8ubyte_unaligned_inc (dbg, readp); length = 8; + } - if (unlikely (readp + 12 > dataend)) - goto invalid_data; + if (unlikely (unit_length == 0)) + { + printf (gettext ("\n [%6jx] Zero terminator\n"), offset); + continue; } + + unsigned int ptr_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; + ptrdiff_t start = readp - (unsigned char *) data->d_buf; const unsigned char *const cieend = readp + unit_length; - if (unlikely (cieend > dataend)) + if (unlikely (cieend > dataend || readp + 8 > dataend)) goto invalid_data; Dwarf_Word cie_id; @@ -4457,10 +4631,10 @@ print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, unsigned int code_alignment_factor; int data_alignment_factor; unsigned int fde_encoding = 0; + unsigned int lsda_encoding = 0; Dwarf_Word initial_location = 0; - if ((is_eh_frame && cie_id == 0) - || (! is_eh_frame && cie_id == DW_CIE_ID)) + if (cie_id == (is_eh_frame ? 0 : DW_CIE_ID)) { uint_fast8_t version = *readp++; const char *const augmentation = (const char *) readp; @@ -4484,7 +4658,7 @@ print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, // XXX Check overflow get_uleb128 (return_address_register, readp); - printf (" [%6jx] CIE length=%" PRIu64 "\n" + printf ("\n [%6jx] CIE length=%" PRIu64 "\n" " CIE_id: %" PRIu64 "\n" " version: %u\n" " augmentation: \"%s\"\n" @@ -4497,71 +4671,6 @@ print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, if (augmentation[0] == 'z') { - unsigned int print_encoding (unsigned int val) - { - switch (val & 0xf) - { - case DW_EH_PE_absptr: - fputs ("absptr", stdout); - break; - case DW_EH_PE_uleb128: - fputs ("uleb128", stdout); - break; - case DW_EH_PE_udata2: - fputs ("udata2", stdout); - break; - case DW_EH_PE_udata4: - fputs ("udata4", stdout); - break; - case DW_EH_PE_udata8: - fputs ("udata8", stdout); - break; - case DW_EH_PE_sleb128: - fputs ("sleb128", stdout); - break; - case DW_EH_PE_sdata2: - fputs ("sdata2", stdout); - break; - case DW_EH_PE_sdata4: - fputs ("sdata4", stdout); - break; - case DW_EH_PE_sdata8: - fputs ("sdata8", stdout); - break; - default: - /* We did not use any of the bits after all. */ - return val; - } - - return val & ~0xf; - } - - unsigned int print_relinfo (unsigned int val) - { - switch (val & 0x70) - { - case DW_EH_PE_pcrel: - fputs ("pcrel", stdout); - break; - case DW_EH_PE_textrel: - fputs ("textrel", stdout); - break; - case DW_EH_PE_datarel: - fputs ("datarel", stdout); - break; - case DW_EH_PE_funcrel: - fputs ("funcrel", stdout); - break; - case DW_EH_PE_aligned: - fputs ("aligned", stdout); - break; - default: - return val; - } - - return val & ~0x70; - } - unsigned int augmentationlen; get_uleb128 (augmentationlen, readp); @@ -4574,28 +4683,20 @@ print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, if (*cp == 'R') { - putchar_unlocked ('('); - - unsigned int w = fde_encoding = *readp++; - - if (w & 0xf) - w = print_encoding (w); - - if (w & 0x70) - { - if (w != fde_encoding) - fputc_unlocked (' ', stdout); - - w = print_relinfo (w); - } - - if (w != 0) - printf ("(%s%x", w != fde_encoding ? " " : "", w); - - puts (")"); + fde_encoding = *readp++; + print_encoding_base (gettext ("FDE address encoding: "), + fde_encoding); + } + else if (*cp == 'L') + { + lsda_encoding = *readp++; + print_encoding_base (gettext ("LSDA pointer encoding: "), + lsda_encoding); } else if (*cp == 'P') { + /* Personality. This field usually has a relocation + attached pointing to __gcc_personality_v0. */ const unsigned char *startp = readp; unsigned int encoding = *readp++; uint64_t val = 0; @@ -4654,13 +4755,13 @@ print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, ++cp; } - readp += augmentationlen; } struct cieinfo *newp = alloca (sizeof (*newp)); newp->cie_offset = offset; newp->augmentation = augmentation; newp->fde_encoding = fde_encoding; + newp->lsda_encoding = lsda_encoding; newp->code_alignment_factor = code_alignment_factor; newp->data_alignment_factor = data_alignment_factor; newp->next = cies; @@ -4670,7 +4771,9 @@ print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, { struct cieinfo *cie = cies; while (cie != NULL) - if (start - (ptrdiff_t) cie_id == cie->cie_offset) + if (is_eh_frame + ? start - (ptrdiff_t) cie_id == cie->cie_offset + : (ptrdiff_t) cie_id == cie->cie_offset) break; else cie = cie->next; @@ -4681,35 +4784,72 @@ print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, } /* Initialize from CIE data. */ - ptr_size = encoded_ptr_size (cie->fde_encoding, ptr_size); + fde_encoding = cie->fde_encoding; + lsda_encoding = cie->lsda_encoding; + ptr_size = encoded_ptr_size (fde_encoding, ptr_size); code_alignment_factor = cie->code_alignment_factor; data_alignment_factor = cie->data_alignment_factor; - fde_encoding = cie->fde_encoding; + const unsigned char *base = readp; + // XXX There are sometimes relocations for this value initial_location = read_ubyte_unaligned_inc (ptr_size, dbg, readp); Dwarf_Word address_range = read_ubyte_unaligned_inc (ptr_size, dbg, readp); printf ("\n [%6jx] FDE length=%" PRIu64 " cie=[%6jx]\n" " CIE_pointer: %" PRIu64 "\n" - " initial_location: %#" PRIx64 "\n" - " address_range: %#" PRIx64 "\n", + " initial_location: %#" PRIx64, offset, (uint64_t) unit_length, cie->cie_offset, (uint64_t) cie_id, - (uint64_t) initial_location, (uint64_t) address_range); + (uint64_t) initial_location); + if ((fde_encoding & 0x70) == DW_EH_PE_pcrel) + printf (gettext (" (offset: %#" PRIx64 ")"), + ((uint64_t) shdr->sh_offset + + (base - (const unsigned char *) data->d_buf) + + (uint64_t) initial_location) + & (ptr_size == 4 + ? UINT64_C (0xffffffff) + : UINT64_C (0xffffffffffffffff))); + + printf ("\n address_range: %#" PRIx64 "\n", + (uint64_t) address_range); if (cie->augmentation[0] == 'z') { unsigned int augmentationlen; get_uleb128 (augmentationlen, readp); - const char *hdr = "Augmentation data:"; - const char *cp = cie->augmentation + 1; - for (unsigned int u = 0; u < augmentationlen; ++cp, ++u) + if (augmentationlen > 0) { - printf (" %-26s%#x (", hdr, readp[u]); - hdr = ""; + const char *hdr = "Augmentation data:"; + const char *cp = cie->augmentation + 1; + unsigned int u = 0; + while (*cp != '\0') + { + if (*cp == 'L') + { + uint64_t lsda_pointer; + const unsigned char *p + = read_encoded (lsda_encoding, &readp[u], + &readp[augmentationlen], + &lsda_pointer, dbg); + u = p - readp; + printf (gettext ("\ + %-26sLSDA pointer: %#" PRIx64 "\n"), + hdr, lsda_pointer); + hdr = ""; + } + ++cp; + } + + while (u < augmentationlen) + { + printf (" %-26s%#x\n", hdr, readp[u++]); + hdr = ""; + } } + + readp += augmentationlen; } } @@ -4947,12 +5087,12 @@ static void print_debug_info_section (Dwfl_Module *dwflmod, Ebl *ebl __attribute__ ((unused)), GElf_Ehdr *ehdr __attribute__ ((unused)), - Elf_Scn *scn __attribute__ ((unused)), + 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); +\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n [Offset]\n"), + elf_ndxscn (scn), ".debug_info", (uint64_t) shdr->sh_offset); /* If the section is empty we don't have to do anything. */ if (shdr->sh_size == 0) @@ -5072,8 +5212,8 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) { printf (gettext ("\ -\nDWARF section '%s' at offset %#" PRIx64 ":\n"), - ".debug_line", (uint64_t) shdr->sh_offset); +\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"), + elf_ndxscn (scn), ".debug_line", (uint64_t) shdr->sh_offset); if (shdr->sh_size == 0) return; @@ -5504,11 +5644,8 @@ advance address by fixed value %u to %s\n"), static void print_debug_loc_section (Dwfl_Module *dwflmod, - Ebl *ebl __attribute__ ((unused)), - GElf_Ehdr *ehdr __attribute__ ((unused)), - Elf_Scn *scn __attribute__ ((unused)), - GElf_Shdr *shdr, - Dwarf *dbg __attribute__ ((unused))) + Ebl *ebl __attribute__ ((unused)), GElf_Ehdr *ehdr, + Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) { Elf_Data *data = elf_rawdata (scn, NULL); @@ -5520,8 +5657,8 @@ print_debug_loc_section (Dwfl_Module *dwflmod, } printf (gettext ("\ -\nDWARF section '%s' at offset %#" PRIx64 ":\n"), - ".debug_loc", (uint64_t) shdr->sh_offset); +\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"), + elf_ndxscn (scn), ".debug_loc", (uint64_t) shdr->sh_offset); size_t address_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; @@ -5615,8 +5752,8 @@ print_debug_macinfo_section (Dwfl_Module *dwflmod __attribute__ ((unused)), Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) { printf (gettext ("\ -\nDWARF section '%s' at offset %#" PRIx64 ":\n"), - ".debug_macinfo", (uint64_t) shdr->sh_offset); +\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"), + elf_ndxscn (scn), ".debug_macinfo", (uint64_t) shdr->sh_offset); putc_unlocked ('\n', stdout); /* There is no function in libdw to iterate over the raw content of @@ -5784,11 +5921,10 @@ static void print_debug_pubnames_section (Dwfl_Module *dwflmod __attribute__ ((unused)), Ebl *ebl __attribute__ ((unused)), GElf_Ehdr *ehdr __attribute__ ((unused)), - Elf_Scn *scn __attribute__ ((unused)), - GElf_Shdr *shdr, Dwarf *dbg) + Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) { - printf (gettext ("\nDWARF section '%s' at offset %#" PRIx64 ":\n"), - ".debug_pubnames", (uint64_t) shdr->sh_offset); + printf (gettext ("\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"), + elf_ndxscn (scn), ".debug_pubnames", (uint64_t) shdr->sh_offset); int n = 0; (void) dwarf_getpubnames (dbg, print_pubnames, &n, 0); @@ -5799,8 +5935,7 @@ static void print_debug_str_section (Dwfl_Module *dwflmod __attribute__ ((unused)), Ebl *ebl __attribute__ ((unused)), GElf_Ehdr *ehdr __attribute__ ((unused)), - Elf_Scn *scn __attribute__ ((unused)), - GElf_Shdr *shdr, Dwarf *dbg) + Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) { /* Compute floor(log16(shdr->sh_size)). */ GElf_Addr tmp = shdr->sh_size; @@ -5812,8 +5947,9 @@ print_debug_str_section (Dwfl_Module *dwflmod __attribute__ ((unused)), } digits = MAX (4, digits); - printf (gettext ("\nDWARF section '%s' at offset %#" PRIx64 ":\n" + printf (gettext ("\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n" " %*s String\n"), + elf_ndxscn (scn), ".debug_str", (uint64_t) shdr->sh_offset, /* TRANS: the debugstr| prefix makes the string unique. */ digits + 2, sgettext ("debugstr|Offset")); @@ -5836,6 +5972,261 @@ print_debug_str_section (Dwfl_Module *dwflmod __attribute__ ((unused)), } } + +/* Print the content of the call frame search table section + '.eh_frame_hdr'. */ +static void +print_debug_frame_hdr_section (Dwfl_Module *dwflmod __attribute__ ((unused)), + Ebl *ebl __attribute__ ((unused)), + GElf_Ehdr *ehdr __attribute__ ((unused)), + Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) +{ + printf (gettext ("\ +\nCall frame search table section [%2zu] '.eh_frame_hdr':\n"), + elf_ndxscn (scn)); + + Elf_Data *data = elf_rawdata (scn, NULL); + + if (unlikely (data == NULL)) + { + error (0, 0, gettext ("cannot get %s content: %s"), + ".eh_frame_hdr", elf_errmsg (-1)); + return; + } + + const unsigned char *readp = data->d_buf; + const unsigned char *const dataend = ((unsigned char *) data->d_buf + + data->d_size); + + if (unlikely (readp + 4 > dataend)) + { + invalid_data: + error (0, 0, gettext ("invalid data")); + return; + } + + unsigned int version = *readp++; + unsigned int eh_frame_ptr_enc = *readp++; + unsigned int fde_count_enc = *readp++; + unsigned int table_enc = *readp++; + + printf (" version: %u\n" + " eh_frame_ptr_enc: %#x ", + version, eh_frame_ptr_enc); + print_encoding_base ("", eh_frame_ptr_enc); + printf (" fde_count_enc: %#x ", fde_count_enc); + print_encoding_base ("", fde_count_enc); + printf (" table_enc: %#x ", table_enc); + print_encoding_base ("", table_enc); + + uint64_t eh_frame_ptr = 0; + if (eh_frame_ptr_enc != DW_EH_PE_omit) + { + readp = read_encoded (eh_frame_ptr_enc, readp, dataend, &eh_frame_ptr, + dbg); + if (unlikely (readp == NULL)) + goto invalid_data; + + printf (" eh_frame_ptr: %#" PRIx64, eh_frame_ptr); + if ((eh_frame_ptr_enc & 0x70) == DW_EH_PE_pcrel) + printf (" (offset: %#" PRIx64 ")", + /* +4 because of the 4 byte header of the section. */ + (uint64_t) shdr->sh_offset + 4 + eh_frame_ptr); + + putchar_unlocked ('\n'); + } + + uint64_t fde_count = 0; + if (fde_count_enc != DW_EH_PE_omit) + { + readp = read_encoded (fde_count_enc, readp, dataend, &fde_count, dbg); + if (unlikely (readp == NULL)) + goto invalid_data; + + printf (" fde_count: %" PRIu64 "\n", fde_count); + } + + if (fde_count == 0 || table_enc == DW_EH_PE_omit) + return; + + puts (" Table:"); + + /* Optimize for the most common case. */ + if (table_enc == (DW_EH_PE_datarel | DW_EH_PE_sdata4)) + while (fde_count > 0 && readp + 8 <= dataend) + { + int32_t initial_location = read_4sbyte_unaligned_inc (dbg, readp); + uint64_t initial_offset = ((uint64_t) shdr->sh_offset + + (int64_t) initial_location); + int32_t address = read_4sbyte_unaligned_inc (dbg, readp); + // XXX Possibly print symbol name or section offset for initial_offset + printf (" %#" PRIx32 " (offset: %#6" PRIx64 ") -> %#" PRIx32 + " fde=[%6" PRIx64 "]\n", + initial_location, initial_offset, + address, address - (eh_frame_ptr + 4)); + } + else + while (0 && readp < dataend) + { + + } +} + + +/* Print the content of the exception handling table section + '.eh_frame_hdr'. */ +static void +print_debug_exception_table (Dwfl_Module *dwflmod __attribute__ ((unused)), + Ebl *ebl __attribute__ ((unused)), + GElf_Ehdr *ehdr __attribute__ ((unused)), + Elf_Scn *scn, + GElf_Shdr *shdr __attribute__ ((unused)), + Dwarf *dbg __attribute__ ((unused))) +{ + printf (gettext ("\ +\nException handling table section [%2zu] '.gcc_except_table':\n"), + elf_ndxscn (scn)); + + Elf_Data *data = elf_rawdata (scn, NULL); + + if (unlikely (data == NULL)) + { + error (0, 0, gettext ("cannot get %s content: %s"), + ".gcc_except_table", elf_errmsg (-1)); + return; + } + + const unsigned char *readp = data->d_buf; + const unsigned char *const dataend = readp + data->d_size; + + if (unlikely (readp + 1 > dataend)) + { + invalid_data: + error (0, 0, gettext ("invalid data")); + return; + } + unsigned int lpstart_encoding = *readp++; + printf (gettext (" LPStart encoding: %#x "), lpstart_encoding); + print_encoding_base ("", lpstart_encoding); + if (lpstart_encoding != DW_EH_PE_omit) + { + uint64_t lpstart; + readp = read_encoded (lpstart_encoding, readp, dataend, &lpstart, dbg); + printf (" LPStart: %#" PRIx64 "\n", lpstart); + } + + if (unlikely (readp + 1 > dataend)) + goto invalid_data; + unsigned int ttype_encoding = *readp++; + printf (gettext (" TType encoding: %#x "), ttype_encoding); + print_encoding_base ("", ttype_encoding); + const unsigned char *ttype_base = NULL; + if (ttype_encoding != DW_EH_PE_omit) + { + unsigned int ttype_base_offset; + get_uleb128 (ttype_base_offset, readp); + printf (" TType base offset: %#x\n", ttype_base_offset); + ttype_base = readp + ttype_base_offset; + } + + if (unlikely (readp + 1 > dataend)) + goto invalid_data; + unsigned int call_site_encoding = *readp++; + printf (gettext (" Call site encoding: %#x "), call_site_encoding); + print_encoding_base ("", call_site_encoding); + unsigned int call_site_table_len; + get_uleb128 (call_site_table_len, readp); + + const unsigned char *const action_table = readp + call_site_table_len; + if (unlikely (action_table > dataend)) + goto invalid_data; + unsigned int u = 0; + unsigned int max_action = 0; + while (readp < action_table) + { + if (u == 0) + puts (gettext ("\n Call site table:")); + + uint64_t call_site_start; + readp = read_encoded (call_site_encoding, readp, dataend, + &call_site_start, dbg); + uint64_t call_site_length; + readp = read_encoded (call_site_encoding, readp, dataend, + &call_site_length, dbg); + uint64_t landing_pad; + readp = read_encoded (call_site_encoding, readp, dataend, + &landing_pad, dbg); + unsigned int action; + get_uleb128 (action, readp); + max_action = MAX (action, max_action); + printf (gettext (" [%4u] Call site start: %#" PRIx64 "\n" + " Call site length: %" PRIu64 "\n" + " Landing pad: %#" PRIx64 "\n" + " Action: %u\n"), + u++, call_site_start, call_site_length, landing_pad, action); + } + assert (readp == action_table); + + unsigned int max_ar_filter = 0; + if (max_action > 0) + { + puts ("\n Action table:"); + + const unsigned char *const action_table_end + = action_table + max_action + 1; + + u = 0; + do + { + int ar_filter; + get_sleb128 (ar_filter, readp); + if (ar_filter > 0 && (unsigned int) ar_filter > max_ar_filter) + max_ar_filter = ar_filter; + int ar_disp; + get_sleb128 (ar_disp, readp); + + printf (" [%4u] ar_filter: %d\n" + " ar_disp: %d\n", + u++, ar_filter, ar_disp); + } + while (readp < action_table_end); + } + + if (max_ar_filter > 0) + { + puts ("\n TType table:"); + + // XXX Not *4, size of encoding; + switch (ttype_encoding & 7) + { + case DW_EH_PE_udata2: + case DW_EH_PE_sdata2: + readp = ttype_base - max_ar_filter * 2; + break; + case DW_EH_PE_udata4: + case DW_EH_PE_sdata4: + readp = ttype_base - max_ar_filter * 4; + break; + case DW_EH_PE_udata8: + case DW_EH_PE_sdata8: + readp = ttype_base - max_ar_filter * 8; + break; + default: + error (1, 0, gettext ("invalid TType encoding")); + } + + do + { + uint64_t ttype; + readp = read_encoded (ttype_encoding, readp, ttype_base, &ttype, + dbg); + printf (" [%4u] %#" PRIx64 "\n", max_ar_filter--, ttype); + } + while (readp < ttype_base); + } +} + + static void print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr) { @@ -5884,7 +6275,12 @@ print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr) NEW_SECTION (str), NEW_SECTION (macinfo), NEW_SECTION (ranges), - { ".eh_frame", section_frame, print_debug_frame_section } + { ".eh_frame", section_frame | section_exception, + print_debug_frame_section }, + { ".eh_frame_hdr", section_frame | section_exception, + print_debug_frame_hdr_section }, + { ".gcc_except_table", section_frame | section_exception, + print_debug_exception_table } }; const int ndebug_sections = (sizeof (debug_sections) / sizeof (debug_sections[0])); @@ -50,10 +50,10 @@ /* 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; +ARGP_PROGRAM_VERSION_HOOK_DEF = print_version; /* Bug report address. */ -const char *argp_program_bug_address = PACKAGE_BUGREPORT; +ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; /* Values for the parameters which have no short form. */ diff --git a/src/strings.c b/src/strings.c index aebf07bd..b69f2ad2 100644 --- a/src/strings.c +++ b/src/strings.c @@ -59,10 +59,10 @@ static int read_elf (Elf *elf, int fd, const char *fname, off64_t fdlen); /* 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; +ARGP_PROGRAM_VERSION_HOOK_DEF = print_version; /* Bug report address. */ -const char *argp_program_bug_address = PACKAGE_BUGREPORT; +ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; /* Definitions of arguments for argp functions. */ static const struct argp_option options[] = diff --git a/src/strip.c b/src/strip.c index 3ca047af..1958bb51 100644 --- a/src/strip.c +++ b/src/strip.c @@ -55,10 +55,10 @@ /* 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; +ARGP_PROGRAM_VERSION_HOOK_DEF = print_version; /* Bug report address. */ -const char *argp_program_bug_address = PACKAGE_BUGREPORT; +ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; /* Values for the parameters which have no short form. */ diff --git a/src/unstrip.c b/src/unstrip.c index 4a6fd197..97b73c6f 100644 --- a/src/unstrip.c +++ b/src/unstrip.c @@ -64,11 +64,10 @@ /* 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; +ARGP_PROGRAM_VERSION_HOOK_DEF = print_version; /* Bug report address. */ -const char *argp_program_bug_address = PACKAGE_BUGREPORT; +ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; /* Definitions of arguments for argp functions. */ static const struct argp_option options[] = |
