libdw: Add support for DWARF5 DW_FORM_data16.
[platform/upstream/elfutils.git] / src / readelf.c
index 8e64400..2d49af3 100644 (file)
@@ -1,5 +1,5 @@
 /* Print information from ELF file in human-readable form.
-   Copyright (C) 1999-2015 Red Hat, Inc.
+   Copyright (C) 1999-2017 Red Hat, Inc.
    This file is part of elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 1999.
 
 #include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
+#include <strings.h>
 #include <time.h>
 #include <unistd.h>
-#include <sys/param.h>
 #include <sys/stat.h>
 #include <signal.h>
 
+#include <libeu.h>
 #include <system.h>
+#include <printversion.h>
 #include "../libelf/libelfP.h"
 #include "../libelf/common.h"
 #include "../libebl/libeblP.h"
+#include "../libdwelf/libdwelf.h"
 #include "../libdw/libdwP.h"
 #include "../libdwfl/libdwflP.h"
 #include "../libdw/memory-access.h"
 
 #include "../libdw/known-dwarf.h"
 
+#ifdef __linux__
+#define CORE_SIGILL  SIGILL
+#define CORE_SIGBUS  SIGBUS
+#define CORE_SIGFPE  SIGFPE
+#define CORE_SIGSEGV SIGSEGV
+#define CORE_SI_USER SI_USER
+#else
+/* We want the linux version of those as that is what shows up in the core files. */
+#define CORE_SIGILL  4  /* Illegal instruction (ANSI).  */
+#define CORE_SIGBUS  7  /* BUS error (4.2 BSD).  */
+#define CORE_SIGFPE  8  /* Floating-point exception (ANSI).  */
+#define CORE_SIGSEGV 11 /* Segmentation violation (ANSI).  */
+#define CORE_SI_USER 0  /* Sent by kill, sigsend.  */
+#endif
 
 /* Name and version of program.  */
-static void print_version (FILE *stream, struct argp_state *state);
 ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
 
 /* Bug report address.  */
@@ -82,9 +98,11 @@ static const struct argp_option options[] =
   { "program-headers", 'l', NULL, 0, N_("Display the program headers"), 0 },
   { "segments", 'l', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 },
   { "relocs", 'r', NULL, 0, N_("Display relocations"), 0 },
+  { "section-groups", 'g', NULL, 0, N_("Display the section groups"), 0 },
   { "section-headers", 'S', NULL, 0, N_("Display the sections' headers"), 0 },
   { "sections", 'S', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 },
-  { "symbols", 's', NULL, 0, N_("Display the symbol table"), 0 },
+  { "symbols", 's', "SECTION", OPTION_ARG_OPTIONAL,
+    N_("Display the symbol table sections"), 0 },
   { "version-info", 'V', NULL, 0, N_("Display versioning information"), 0 },
   { "notes", 'n', NULL, 0, N_("Display the ELF notes"), 0 },
   { "arch-specific", 'A', NULL, 0,
@@ -112,6 +130,8 @@ static const struct argp_option options[] =
     N_("Display just offsets instead of resolving values to addresses in DWARF data"), 0 },
   { "wide", 'W', NULL, 0,
     N_("Ignored for compatibility (lines always wide)"), 0 },
+  { "decompress", 'z', NULL, 0,
+    N_("Show compression information for compressed sections (when used with -S); decompress section before dumping data (when used with -p or -x)"), 0 },
   { NULL, 0, NULL, 0, NULL, 0 }
 };
 
@@ -154,6 +174,9 @@ static bool print_section_header;
 /* True if the symbol table should be printed.  */
 static bool print_symbol_table;
 
+/* A specific section name, or NULL to print all symbol tables.  */
+static char *symbol_table_section;
+
 /* True if the version information should be printed.  */
 static bool print_version_info;
 
@@ -190,6 +213,9 @@ static bool decodedaranges = false;
 /* True if we should print the .debug_aranges section using libdw.  */
 static bool decodedline = false;
 
+/* True if we want to show more information about compressed sections.  */
+static bool print_decompress = false;
+
 /* Select printing of debugging sections.  */
 static enum section_e
 {
@@ -383,6 +409,7 @@ parse_opt (int key, char *arg,
     case 's':
       print_symbol_table = true;
       any_control_option = true;
+      symbol_table_section = arg;
       break;
     case 'V':
       print_version_info = true;
@@ -453,7 +480,7 @@ parse_opt (int key, char *arg,
          print_string_sections = true;
          break;
        }
-      /* Fall through.  */
+      FALLTHROUGH;
     case 'x':
       add_dump_section (arg, false);
       any_control_option = true;
@@ -479,6 +506,9 @@ parse_opt (int key, char *arg,
       break;
     case 'W':                  /* Ignored.  */
       break;
+    case 'z':
+      print_decompress = true;
+      break;
     case ELF_INPUT_SECTION:
       if (arg == NULL)
        elf_input_section = ".gnu_debugdata";
@@ -492,20 +522,6 @@ parse_opt (int key, char *arg,
 }
 
 
-/* Print the version information.  */
-static void
-print_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
-{
-  fprintf (stream, "readelf (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
-  fprintf (stream, gettext ("\
-Copyright (C) %s Red Hat, Inc.\n\
-This is free software; see the source for copying conditions.  There is NO\n\
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
-"), "2012");
-  fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
-}
-
-
 /* Create a file descriptor to read the data from the
    elf_input_section given a file descriptor to an ELF file.  */
 static int
@@ -764,8 +780,8 @@ process_file (int fd, const char *fname, bool only_one)
     dwfl->offline_next_address = 0;
   if (dwfl_report_offline (dwfl, fname, fname, dwfl_fd) == NULL)
     {
-      struct stat64 st;
-      if (fstat64 (dwfl_fd, &st) != 0)
+      struct stat st;
+      if (fstat (dwfl_fd, &st) != 0)
        error (0, errno, gettext ("cannot stat input file"));
       else if (unlikely (st.st_size == 0))
        error (0, 0, gettext ("input file is empty"));
@@ -797,6 +813,20 @@ process_file (int fd, const char *fname, bool only_one)
     close (fd);
 }
 
+/* Check whether there are any compressed sections in the ELF file.  */
+static bool
+elf_contains_chdrs (Elf *elf)
+{
+  Elf_Scn *scn = NULL;
+  while ((scn = elf_nextscn (elf, scn)) != NULL)
+    {
+      GElf_Shdr shdr_mem;
+      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+      if (shdr != NULL && (shdr->sh_flags & SHF_COMPRESSED) != 0)
+       return true;
+    }
+  return false;
+}
 
 /* Process one ELF file.  */
 static void
@@ -835,20 +865,24 @@ process_elf_file (Dwfl_Module *dwflmod, int fd)
           gettext ("cannot determine number of program headers: %s"),
           elf_errmsg (-1));
 
-  /* For an ET_REL file, libdwfl has adjusted the in-core shdrs
-     and may have applied relocation to some sections.
-     So we need to get a fresh Elf handle on the file to display those.  */
-  bool print_unrelocated = (print_section_header
-                           || print_relocations
-                           || dump_data_sections != NULL
-                           || print_notes);
+  /* For an ET_REL file, libdwfl has adjusted the in-core shdrs and
+     may have applied relocation to some sections.  If there are any
+     compressed sections, any pass (or libdw/libdwfl) might have
+     uncompressed them.  So we need to get a fresh Elf handle on the
+     file to display those.  */
+  bool print_unchanged = ((print_section_header
+                          || print_relocations
+                          || dump_data_sections != NULL
+                          || print_notes)
+                         && (ehdr->e_type == ET_REL
+                             || elf_contains_chdrs (ebl->elf)));
 
   Elf *pure_elf = NULL;
   Ebl *pure_ebl = ebl;
-  if (ehdr->e_type == ET_REL && print_unrelocated)
+  if (print_unchanged)
     {
       /* Read the file afresh.  */
-      off64_t aroff = elf_getaroff (elf);
+      off_t aroff = elf_getaroff (elf);
       pure_elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
       if (aroff > 0)
        {
@@ -1065,6 +1099,17 @@ get_visibility_type (int value)
     }
 }
 
+static const char *
+elf_ch_type_name (unsigned int code)
+{
+  if (code == 0)
+    return "NONE";
+
+  if (code == ELFCOMPRESS_ZLIB)
+    return "ZLIB";
+
+  return "UNKNOWN";
+}
 
 /* Print the section headers.  */
 static void
@@ -1091,6 +1136,14 @@ There are %d section headers, starting at offset %#" PRIx64 ":\n\
   else
     puts (gettext ("[Nr] Name                 Type         Addr             Off      Size     ES Flags Lk Inf Al"));
 
+  if (print_decompress)
+    {
+      if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
+       puts (gettext ("     [Compression  Size   Al]"));
+      else
+       puts (gettext ("     [Compression  Size     Al]"));
+    }
+
   for (cnt = 0; cnt < shnum; ++cnt)
     {
       Elf_Scn *scn = elf_getscn (ebl->elf, cnt);
@@ -1128,25 +1181,57 @@ There are %d section headers, starting at offset %#" PRIx64 ":\n\
        *cp++ = 'G';
       if (shdr->sh_flags & SHF_TLS)
        *cp++ = 'T';
+      if (shdr->sh_flags & SHF_COMPRESSED)
+       *cp++ = 'C';
       if (shdr->sh_flags & SHF_ORDERED)
        *cp++ = 'O';
       if (shdr->sh_flags & SHF_EXCLUDE)
        *cp++ = 'E';
       *cp = '\0';
 
+      const char *sname;
       char buf[128];
+      sname = elf_strptr (ebl->elf, shstrndx, shdr->sh_name) ?: "<corrupt>";
       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>",
+             cnt, sname,
              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);
+
+      if (print_decompress)
+       {
+         if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+           {
+             GElf_Chdr chdr;
+             if (gelf_getchdr (scn, &chdr) != NULL)
+               printf ("     [ELF %s (%" PRId32 ") %0*" PRIx64
+                       " %2" PRId64 "]\n",
+                       elf_ch_type_name (chdr.ch_type),
+                       chdr.ch_type,
+                       ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 6 : 8,
+                       chdr.ch_size, chdr.ch_addralign);
+             else
+               error (0, 0,
+                      gettext ("bad compression header for section %zd: %s"),
+                      elf_ndxscn (scn), elf_errmsg (-1));
+           }
+         else if (strncmp(".zdebug", sname, strlen (".zdebug")) == 0)
+           {
+             ssize_t size;
+             if ((size = dwelf_scn_gnu_compressed_size (scn)) >= 0)
+               printf ("     [GNU ZLIB     %0*zx   ]\n",
+                       ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 6 : 8, size);
+             else
+               error (0, 0,
+                      gettext ("bad gnu compressed size for section %zd: %s"),
+                      elf_ndxscn (scn), elf_errmsg (-1));
+           }
+       }
     }
 
   fputc_unlocked ('\n', stdout);
@@ -1443,7 +1528,22 @@ print_scngrp (Ebl *ebl)
       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
 
       if (shdr != NULL && shdr->sh_type == SHT_GROUP)
-       handle_scngrp (ebl, scn, shdr);
+       {
+         if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+           {
+             if (elf_compress (scn, 0, 0) < 0)
+               printf ("WARNING: %s [%zd]\n",
+                       gettext ("Couldn't uncompress section"),
+                       elf_ndxscn (scn));
+             shdr = gelf_getshdr (scn, &shdr_mem);
+             if (unlikely (shdr == NULL))
+               error (EXIT_FAILURE, 0,
+                      gettext ("cannot get section [%zd] header: %s"),
+                      elf_ndxscn (scn),
+                      elf_errmsg (-1));
+           }
+         handle_scngrp (ebl, scn, shdr);
+       }
     }
 }
 
@@ -2142,7 +2242,34 @@ print_symtab (Ebl *ebl, int type)
       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
 
       if (shdr != NULL && shdr->sh_type == (GElf_Word) type)
-       handle_symtab (ebl, scn, shdr);
+       {
+         if (symbol_table_section != NULL)
+           {
+             /* Get the section header string table index.  */
+             size_t shstrndx;
+             const char *sname;
+             if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
+               error (EXIT_FAILURE, 0,
+                      gettext ("cannot get section header string table index"));
+             sname = elf_strptr (ebl->elf, shstrndx, shdr->sh_name);
+             if (sname == NULL || strcmp (sname, symbol_table_section) != 0)
+               continue;
+           }
+
+         if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+           {
+             if (elf_compress (scn, 0, 0) < 0)
+               printf ("WARNING: %s [%zd]\n",
+                       gettext ("Couldn't uncompress section"),
+                       elf_ndxscn (scn));
+             shdr = gelf_getshdr (scn, &shdr_mem);
+             if (unlikely (shdr == NULL))
+               error (EXIT_FAILURE, 0,
+                      gettext ("cannot get section [%zd] header: %s"),
+                      elf_ndxscn (scn), elf_errmsg (-1));
+           }
+         handle_symtab (ebl, scn, shdr);
+       }
     }
 }
 
@@ -3152,7 +3279,7 @@ handle_gnu_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
            ++nsyms;
            if (maxlength < ++lengths[cnt])
              ++maxlength;
-           if (inner > max_nsyms)
+           if (inner >= max_nsyms)
              goto invalid_data;
          }
        while ((chain[inner++] & 1) == 0);
@@ -3211,6 +3338,20 @@ handle_hash (Ebl *ebl)
 
       if (likely (shdr != NULL))
        {
+         if ((shdr->sh_type == SHT_HASH || shdr->sh_type == SHT_GNU_HASH)
+             && (shdr->sh_flags & SHF_COMPRESSED) != 0)
+           {
+             if (elf_compress (scn, 0, 0) < 0)
+               printf ("WARNING: %s [%zd]\n",
+                       gettext ("Couldn't uncompress section"),
+                       elf_ndxscn (scn));
+             shdr = gelf_getshdr (scn, &shdr_mem);
+             if (unlikely (shdr == NULL))
+               error (EXIT_FAILURE, 0,
+                      gettext ("cannot get section [%zd] header: %s"),
+                      elf_ndxscn (scn), elf_errmsg (-1));
+           }
+
          if (shdr->sh_type == SHT_HASH)
            {
              if (ebl_sysvhash_entrysize (ebl) == sizeof (Elf64_Xword))
@@ -3671,6 +3812,23 @@ dwarf_access_string (unsigned int code)
 
 
 static const char *
+dwarf_defaulted_string (unsigned int code)
+{
+  static const char *const known[] =
+    {
+#define DWARF_ONE_KNOWN_DW_DEFAULTED(NAME, CODE) [CODE] = #NAME,
+      DWARF_ALL_KNOWN_DW_DEFAULTED
+#undef DWARF_ONE_KNOWN_DW_DEFAULTED
+    };
+
+  if (likely (code < sizeof (known) / sizeof (known[0])))
+    return known[code];
+
+  return NULL;
+}
+
+
+static const char *
 dwarf_visibility_string (unsigned int code)
 {
   static const char *const known[] =
@@ -3792,6 +3950,20 @@ dwarf_locexpr_opcode_string (unsigned int code)
 }
 
 
+static const char *
+dwarf_unit_string (unsigned int type)
+{
+  switch (type)
+    {
+#define DWARF_ONE_KNOWN_DW_UT(NAME, CODE) case CODE: return #NAME;
+      DWARF_ALL_KNOWN_DW_UT
+#undef DWARF_ONE_KNOWN_DW_UT
+    default:
+      return NULL;
+    }
+}
+
+
 /* Used by all dwarf_foo_name functions.  */
 static const char *
 string_or_unknown (const char *known, unsigned int code,
@@ -3876,6 +4048,14 @@ dwarf_access_name (unsigned int code)
 
 
 static const char *
+dwarf_defaulted_name (unsigned int code)
+{
+  const char *ret = dwarf_defaulted_string (code);
+  return string_or_unknown (ret, code, 0, 0, false);
+}
+
+
+static const char *
 dwarf_visibility_name (unsigned int code)
 {
   const char *ret = dwarf_visibility_string (code);
@@ -3923,6 +4103,14 @@ dwarf_discr_list_name (unsigned int code)
 }
 
 
+static const char *
+dwarf_unit_name (unsigned int type)
+{
+  const char *ret = dwarf_unit_string (type);
+  return string_or_unknown (ret, type, DW_UT_lo_user, DW_UT_hi_user, true);
+}
+
+
 static void
 print_block (size_t n, const void *block)
 {
@@ -3987,7 +4175,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
          CONSUME (addrsize);
 
          char *a = format_dwarf_addr (dwflmod, 0, addr, addr);
-         printf ("%*s[%4" PRIuMAX "] %s %s\n",
+         printf ("%*s[%2" PRIuMAX "] %s %s\n",
                  indent, "", (uintmax_t) offset, op_name, a);
          free (a);
 
@@ -3995,6 +4183,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
          break;
 
        case DW_OP_call_ref:
+       case DW_OP_GNU_variable_value:
          /* Offset operand.  */
          if (ref_size != 4 && ref_size != 8)
            goto invalid; /* Cannot be used in CFA.  */
@@ -4005,8 +4194,8 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
            addr = read_8ubyte_unaligned (dbg, data);
          data += ref_size;
          CONSUME (ref_size);
-
-         printf ("%*s[%4" PRIuMAX "] %s %#" PRIxMAX "\n",
+         /* addr is a DIE offset, so format it as one.  */
+         printf ("%*s[%2" PRIuMAX "] %s [%6" PRIxMAX "]\n",
                  indent, "", (uintmax_t) offset,
                  op_name, (uintmax_t) addr);
          offset += 1 + ref_size;
@@ -4018,7 +4207,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
        case DW_OP_const1u:
          // XXX value might be modified by relocation
          NEED (1);
-         printf ("%*s[%4" PRIuMAX "] %s %" PRIu8 "\n",
+         printf ("%*s[%2" PRIuMAX "] %s %" PRIu8 "\n",
                  indent, "", (uintmax_t) offset,
                  op_name, *((uint8_t *) data));
          ++data;
@@ -4029,7 +4218,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
        case DW_OP_const2u:
          NEED (2);
          // XXX value might be modified by relocation
-         printf ("%*s[%4" PRIuMAX "] %s %" PRIu16 "\n",
+         printf ("%*s[%2" PRIuMAX "] %s %" PRIu16 "\n",
                  indent, "", (uintmax_t) offset,
                  op_name, read_2ubyte_unaligned (dbg, data));
          CONSUME (2);
@@ -4040,7 +4229,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
        case DW_OP_const4u:
          NEED (4);
          // XXX value might be modified by relocation
-         printf ("%*s[%4" PRIuMAX "] %s %" PRIu32 "\n",
+         printf ("%*s[%2" PRIuMAX "] %s %" PRIu32 "\n",
                  indent, "", (uintmax_t) offset,
                  op_name, read_4ubyte_unaligned (dbg, data));
          CONSUME (4);
@@ -4051,7 +4240,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
        case DW_OP_const8u:
          NEED (8);
          // XXX value might be modified by relocation
-         printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 "\n",
+         printf ("%*s[%2" PRIuMAX "] %s %" PRIu64 "\n",
                  indent, "", (uintmax_t) offset,
                  op_name, (uint64_t) read_8ubyte_unaligned (dbg, data));
          CONSUME (8);
@@ -4062,7 +4251,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
        case DW_OP_const1s:
          NEED (1);
          // XXX value might be modified by relocation
-         printf ("%*s[%4" PRIuMAX "] %s %" PRId8 "\n",
+         printf ("%*s[%2" PRIuMAX "] %s %" PRId8 "\n",
                  indent, "", (uintmax_t) offset,
                  op_name, *((int8_t *) data));
          ++data;
@@ -4073,7 +4262,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
        case DW_OP_const2s:
          NEED (2);
          // XXX value might be modified by relocation
-         printf ("%*s[%4" PRIuMAX "] %s %" PRId16 "\n",
+         printf ("%*s[%2" PRIuMAX "] %s %" PRId16 "\n",
                  indent, "", (uintmax_t) offset,
                  op_name, read_2sbyte_unaligned (dbg, data));
          CONSUME (2);
@@ -4084,7 +4273,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
        case DW_OP_const4s:
          NEED (4);
          // XXX value might be modified by relocation
-         printf ("%*s[%4" PRIuMAX "] %s %" PRId32 "\n",
+         printf ("%*s[%2" PRIuMAX "] %s %" PRId32 "\n",
                  indent, "", (uintmax_t) offset,
                  op_name, read_4sbyte_unaligned (dbg, data));
          CONSUME (4);
@@ -4095,7 +4284,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
        case DW_OP_const8s:
          NEED (8);
          // XXX value might be modified by relocation
-         printf ("%*s[%4" PRIuMAX "] %s %" PRId64 "\n",
+         printf ("%*s[%2" PRIuMAX "] %s %" PRId64 "\n",
                  indent, "", (uintmax_t) offset,
                  op_name, read_8sbyte_unaligned (dbg, data));
          CONSUME (8);
@@ -4111,7 +4300,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
          uint64_t uleb;
          NEED (1);
          get_uleb128 (uleb, data, data + len);
-         printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 "\n",
+         printf ("%*s[%2" PRIuMAX "] %s %" PRIu64 "\n",
                  indent, "", (uintmax_t) offset, op_name, uleb);
          CONSUME (data - start);
          offset += 1 + (data - start);
@@ -4124,7 +4313,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
          get_uleb128 (uleb, data, data + len);
          NEED (1);
          get_uleb128 (uleb2, data, data + len);
-         printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 ", %" PRIu64 "\n",
+         printf ("%*s[%2" PRIuMAX "] %s %" PRIu64 ", %" PRIu64 "\n",
                  indent, "", (uintmax_t) offset, op_name, uleb, uleb2);
          CONSUME (data - start);
          offset += 1 + (data - start);
@@ -4137,7 +4326,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
          int64_t sleb;
          NEED (1);
          get_sleb128 (sleb, data, data + len);
-         printf ("%*s[%4" PRIuMAX "] %s %" PRId64 "\n",
+         printf ("%*s[%2" PRIuMAX "] %s %" PRId64 "\n",
                  indent, "", (uintmax_t) offset, op_name, sleb);
          CONSUME (data - start);
          offset += 1 + (data - start);
@@ -4149,7 +4338,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
          get_uleb128 (uleb, data, data + len);
          NEED (1);
          get_sleb128 (sleb, data, data + len);
-         printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 " %" PRId64 "\n",
+         printf ("%*s[%2" PRIuMAX "] %s %" PRIu64 " %" PRId64 "\n",
                  indent, "", (uintmax_t) offset, op_name, uleb, sleb);
          CONSUME (data - start);
          offset += 1 + (data - start);
@@ -4157,26 +4346,28 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
 
        case DW_OP_call2:
          NEED (2);
-         printf ("%*s[%4" PRIuMAX "] %s %" PRIu16 "\n",
+         printf ("%*s[%2" PRIuMAX "] %s [%6" PRIx16 "]\n",
                  indent, "", (uintmax_t) offset, op_name,
                  read_2ubyte_unaligned (dbg, data));
          CONSUME (2);
+         data += 2;
          offset += 3;
          break;
 
        case DW_OP_call4:
          NEED (4);
-         printf ("%*s[%4" PRIuMAX "] %s %" PRIu32 "\n",
+         printf ("%*s[%2" PRIuMAX "] %s [%6" PRIx32 "]\n",
                  indent, "", (uintmax_t) offset, op_name,
                  read_4ubyte_unaligned (dbg, data));
          CONSUME (4);
+         data += 4;
          offset += 5;
          break;
 
        case DW_OP_skip:
        case DW_OP_bra:
          NEED (2);
-         printf ("%*s[%4" PRIuMAX "] %s %" PRIuMAX "\n",
+         printf ("%*s[%2" PRIuMAX "] %s %" PRIuMAX "\n",
                  indent, "", (uintmax_t) offset, op_name,
                  (uintmax_t) (offset + read_2sbyte_unaligned (dbg, data) + 3));
          CONSUME (2);
@@ -4188,7 +4379,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
          start = data;
          NEED (1);
          get_uleb128 (uleb, data, data + len);
-         printf ("%*s[%4" PRIuMAX "] %s: ",
+         printf ("%*s[%2" PRIuMAX "] %s: ",
                  indent, "", (uintmax_t) offset, op_name);
          NEED (uleb);
          print_block (uleb, data);
@@ -4212,7 +4403,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
          NEED (1);
          get_sleb128 (sleb, data, data + len);
 
-         printf ("%*s[%4" PRIuMAX "] %s [%6" PRIxMAX "] %+" PRId64 "\n",
+         printf ("%*s[%2" PRIuMAX "] %s [%6" PRIxMAX "] %+" PRId64 "\n",
                  indent, "", (intmax_t) offset,
                  op_name, (uintmax_t) addr, sleb);
          CONSUME (data - start);
@@ -4224,10 +4415,10 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
          start = data;
          NEED (1);
          get_uleb128 (uleb, data, data + len);
-         printf ("%*s[%4" PRIuMAX "] %s:\n",
+         printf ("%*s[%2" PRIuMAX "] %s:\n",
                  indent, "", (uintmax_t) offset, op_name);
          NEED (uleb);
-         print_ops (dwflmod, dbg, indent + 6, indent + 6, vers,
+         print_ops (dwflmod, dbg, indent + 5, indent + 5, vers,
                     addrsize, offset_size, cu, uleb, data);
          data += uleb;
          CONSUME (data - start);
@@ -4245,7 +4436,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
          NEED (1);
          uint8_t usize = *(uint8_t *) data++;
          NEED (usize);
-         printf ("%*s[%4" PRIuMAX "] %s [%6" PRIxMAX "] ",
+         printf ("%*s[%2" PRIuMAX "] %s [%6" PRIxMAX "] ",
                  indent, "", (uintmax_t) offset, op_name, uleb);
          print_block (usize, data);
          data += usize;
@@ -4263,7 +4454,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
          get_uleb128 (uleb2, data, data + len);
          if (! print_unresolved_addresses && cu != NULL)
            uleb2 += cu->start;
-         printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 " [%6" PRIx64 "]\n",
+         printf ("%*s[%2" PRIuMAX "] %s %" PRIu64 " [%6" PRIx64 "]\n",
                  indent, "", (uintmax_t) offset, op_name, uleb, uleb2);
          CONSUME (data - start);
          offset += 1 + (data - start);
@@ -4279,7 +4470,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
          get_uleb128 (uleb, data, data + len);
          if (! print_unresolved_addresses && cu != NULL)
            uleb += cu->start;
-         printf ("%*s[%4" PRIuMAX "] %s %" PRIu8 " [%6" PRIxMAX "]\n",
+         printf ("%*s[%2" PRIuMAX "] %s %" PRIu8 " [%6" PRIxMAX "]\n",
                  indent, "", (uintmax_t) offset,
                  op_name, usize, uleb);
          CONSUME (data - start);
@@ -4295,7 +4486,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
          get_uleb128 (uleb, data, data + len);
          if (uleb != 0 && ! print_unresolved_addresses && cu != NULL)
            uleb += cu->start;
-         printf ("%*s[%4" PRIuMAX "] %s [%6" PRIxMAX "]\n",
+         printf ("%*s[%2" PRIuMAX "] %s [%6" PRIxMAX "]\n",
                  indent, "", (uintmax_t) offset, op_name, uleb);
          CONSUME (data - start);
          offset += 1 + (data - start);
@@ -4308,7 +4499,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
          uintmax_t param_off = (uintmax_t) read_4ubyte_unaligned (dbg, data);
          if (! print_unresolved_addresses && cu != NULL)
            param_off += cu->start;
-         printf ("%*s[%4" PRIuMAX "] %s [%6" PRIxMAX "]\n",
+         printf ("%*s[%2" PRIuMAX "] %s [%6" PRIxMAX "]\n",
                  indent, "", (uintmax_t) offset, op_name, param_off);
          CONSUME (4);
          data += 4;
@@ -4317,7 +4508,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
 
        default:
          /* No Operand.  */
-         printf ("%*s[%4" PRIuMAX "] %s\n",
+         printf ("%*s[%2" PRIuMAX "] %s\n",
                  indent, "", (uintmax_t) offset, op_name);
          ++offset;
          break;
@@ -4327,7 +4518,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
       continue;
 
     invalid:
-      printf (gettext ("%*s[%4" PRIuMAX "] %s  <TRUNCATED>\n"),
+      printf (gettext ("%*s[%2" PRIuMAX "] %s  <TRUNCATED>\n"),
              indent, "", (uintmax_t) offset, op_name);
       break;
     }
@@ -4567,14 +4758,16 @@ print_debug_abbrev_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
          size_t cnt = 0;
          unsigned int name;
          unsigned int form;
+         Dwarf_Sword data;
          Dwarf_Off enoffset;
-         while (dwarf_getabbrevattr (&abbrev, cnt,
-                                     &name, &form, &enoffset) == 0)
+         while (dwarf_getabbrevattr_data (&abbrev, cnt, &name, &form,
+                                          &data, &enoffset) == 0)
            {
-             printf ("          attr: %s, form: %s, offset: %#" PRIx64 "\n",
-                     dwarf_attr_name (name), dwarf_form_name (form),
-                     (uint64_t) enoffset);
-
+             printf ("          attr: %s, form: %s",
+                     dwarf_attr_name (name), dwarf_form_name (form));
+             if (form == DW_FORM_implicit_const)
+               printf (" (%" PRId64 ")", data);
+             printf (", offset: %#" PRIx64 "\n", (uint64_t) enoffset);
              ++cnt;
            }
 
@@ -4841,15 +5034,33 @@ print_debug_ranges_section (Dwfl_Module *dwflmod,
   Dwarf_Addr base = 0;
   unsigned char *const endp = (unsigned char *) data->d_buf + data->d_size;
   unsigned char *readp = data->d_buf;
+  Dwarf_CU *last_cu = NULL;
   while (readp < endp)
     {
       ptrdiff_t offset = readp - (unsigned char *) data->d_buf;
+      Dwarf_CU *cu = last_cu;
 
       if (first && skip_listptr_hole (&known_rangelistptr, &listptr_idx,
-                                     &address_size, NULL, &base, NULL,
+                                     &address_size, NULL, &base, &cu,
                                      offset, &readp, endp))
        continue;
 
+      if (last_cu != cu)
+       {
+         char *basestr = format_dwarf_addr (dwflmod, address_size,
+                                            base, base);
+         Dwarf_Die cudie;
+         if (dwarf_cu_die (cu, &cudie,
+                           NULL, NULL, NULL, NULL,
+                           NULL, NULL) == NULL)
+           printf (gettext ("\n Unknown CU base: %s\n"), basestr);
+         else
+           printf (gettext ("\n CU [%6" PRIx64 "] base: %s\n"),
+                   dwarf_dieoffset (&cudie), basestr);
+         free (basestr);
+       }
+      last_cu = cu;
+
       if (unlikely (data->d_size - offset < (size_t) address_size * 2))
        {
          printf (gettext (" [%6tx]  <INVALID DATA>\n"), offset);
@@ -4874,29 +5085,36 @@ print_debug_ranges_section (Dwfl_Module *dwflmod,
       if (begin == (Dwarf_Addr) -1l) /* Base address entry.  */
        {
          char *b = format_dwarf_addr (dwflmod, address_size, end, end);
-         printf (gettext (" [%6tx]  base address %s\n"), offset, b);
+         printf (gettext (" [%6tx] base address\n          %s\n"), offset, b);
          free (b);
          base = end;
        }
       else if (begin == 0 && end == 0) /* End of list entry.  */
        {
          if (first)
-           printf (gettext (" [%6tx]  empty list\n"), offset);
+           printf (gettext (" [%6tx] empty list\n"), offset);
          first = true;
        }
       else
        {
-         char *b = format_dwarf_addr (dwflmod, address_size, base + begin,
-                                      begin);
-         char *e = format_dwarf_addr (dwflmod, address_size, base + end,
-                                      end);
          /* We have an address range entry.  */
          if (first)            /* First address range entry in a list.  */
-           printf (gettext (" [%6tx]  %s..%s\n"), offset, b, e);
+           printf (" [%6tx] ", offset);
          else
-           printf (gettext ("           %s..%s\n"), b, e);
-         free (b);
-         free (e);
+           printf ("          ");
+
+         printf ("range %" PRIx64 ", %" PRIx64 "\n", begin, end);
+         if (! print_unresolved_addresses)
+           {
+             char *b = format_dwarf_addr (dwflmod, address_size, base + begin,
+                                          base + begin);
+             char *e = format_dwarf_addr (dwflmod, address_size,
+                                          base + end - 1, base + end);
+             printf ("          %s..\n", b);
+             printf ("          %s\n", e);
+             free (b);
+             free (e);
+           }
 
          first = false;
        }
@@ -4936,11 +5154,68 @@ register_info (Ebl *ebl, unsigned int regno, const Ebl_Register_Location *loc,
   return set;
 }
 
+static const unsigned char *
+read_encoded (unsigned int encoding, const unsigned char *readp,
+             const unsigned char *const endp, uint64_t *res, Dwarf *dbg)
+{
+  if ((encoding & 0xf) == DW_EH_PE_absptr)
+    encoding = gelf_getclass (dbg->elf) == ELFCLASS32
+      ? DW_EH_PE_udata4 : DW_EH_PE_udata8;
+
+  switch (encoding & 0xf)
+    {
+    case DW_EH_PE_uleb128:
+      get_uleb128 (*res, readp, endp);
+      break;
+    case DW_EH_PE_sleb128:
+      get_sleb128 (*res, readp, endp);
+      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_cfa_program (const unsigned char *readp, const unsigned char *const endp,
                   Dwarf_Word vma_base, unsigned int code_align,
                   int data_align,
                   unsigned int version, unsigned int ptr_size,
+                  unsigned int encoding,
                   Dwfl_Module *dwflmod, Ebl *ebl, Dwarf *dbg)
 {
   char regnamebuf[REGNAMESZ];
@@ -4971,9 +5246,9 @@ print_cfa_program (const unsigned char *readp, const unsigned char *const endp,
          case DW_CFA_set_loc:
            if ((uint64_t) (endp - readp) < 1)
              goto invalid;
-           get_uleb128 (op1, readp, endp);
-           op1 += vma_base;
-           printf ("     set_loc %" PRIu64 "\n", op1 * code_align);
+           readp = read_encoded (encoding, readp, endp, &op1, dbg);
+           printf ("     set_loc %#" PRIx64 " to %#" PRIx64 "\n",
+                   op1, pc = vma_base + op1);
            break;
          case DW_CFA_advance_loc1:
            if ((uint64_t) (endp - readp) < 1)
@@ -5313,62 +5588,6 @@ print_encoding_base (const char *pfx, unsigned int fde_encoding)
 }
 
 
-static const unsigned char *
-read_encoded (unsigned int encoding, const unsigned char *readp,
-             const unsigned char *const endp, uint64_t *res, Dwarf *dbg)
-{
-  if ((encoding & 0xf) == DW_EH_PE_absptr)
-    encoding = gelf_getclass (dbg->elf) == ELFCLASS32
-      ? DW_EH_PE_udata4 : DW_EH_PE_udata8;
-
-  switch (encoding & 0xf)
-    {
-    case DW_EH_PE_uleb128:
-      get_uleb128 (*res, readp, endp);
-      break;
-    case DW_EH_PE_sleb128:
-      get_sleb128 (*res, readp, endp);
-      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)
@@ -5743,7 +5962,7 @@ print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
       else
        print_cfa_program (readp, cieend, vma_base, code_alignment_factor,
                           data_alignment_factor, version, ptr_size,
-                          dwflmod, ebl, dbg);
+                          fde_encoding, dwflmod, ebl, dbg);
       readp = cieend;
     }
 }
@@ -5768,13 +5987,15 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
 {
   struct attrcb_args *cbargs = (struct attrcb_args *) arg;
   const int level = cbargs->level;
+  Dwarf_Die *die = cbargs->die;
 
   unsigned int attr = dwarf_whatattr (attrp);
   if (unlikely (attr == 0))
     {
       if (!cbargs->silent)
-       error (0, 0, gettext ("cannot get attribute code: %s"),
-              dwarf_errmsg (-1));
+       error (0, 0, gettext ("DIE [%" PRIx64 "] "
+                             "cannot get attribute code: %s"),
+              dwarf_dieoffset (die), dwarf_errmsg (-1));
       return DWARF_CB_ABORT;
     }
 
@@ -5782,8 +6003,9 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
   if (unlikely (form == 0))
     {
       if (!cbargs->silent)
-       error (0, 0, gettext ("cannot get attribute form: %s"),
-              dwarf_errmsg (-1));
+       error (0, 0, gettext ("DIE [%" PRIx64 "] "
+                             "cannot get attribute form: %s"),
+              dwarf_dieoffset (die), dwarf_errmsg (-1));
       return DWARF_CB_ABORT;
     }
 
@@ -5797,9 +6019,15 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
            {
            attrval_out:
              if (!cbargs->silent)
-               error (0, 0, gettext ("cannot get attribute value: %s"),
+               error (0, 0, gettext ("DIE [%" PRIx64 "] "
+                                     "cannot get attribute '%s' (%s) value: "
+                                     "%s"),
+                      dwarf_dieoffset (die),
+                      dwarf_attr_name (attr),
+                      dwarf_form_name (form),
                       dwarf_errmsg (-1));
-             return DWARF_CB_ABORT;
+             /* Don't ABORT, it might be other attributes can be resolved.  */
+             return DWARF_CB_OK;
            }
          char *a = format_dwarf_addr (cbargs->dwflmod, cbargs->addrsize,
                                       addr, addr);
@@ -5852,9 +6080,10 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
       break;
 
     case DW_FORM_sec_offset:
+    case DW_FORM_implicit_const:
     case DW_FORM_udata:
     case DW_FORM_sdata:
-    case DW_FORM_data8:
+    case DW_FORM_data8: /* Note no data16 here, we see that as block. */
     case DW_FORM_data4:
     case DW_FORM_data2:
     case DW_FORM_data1:;
@@ -5877,7 +6106,7 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
                        dwarf_form_name (form), (uintmax_t) num);
              return DWARF_CB_OK;
            }
-         /* else fallthrough */
+         FALLTHROUGH;
 
        /* These cases always take a loclistptr and no constant. */
        case DW_AT_location:
@@ -5926,6 +6155,9 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
        case DW_AT_accessibility:
          valuestr = dwarf_access_name (num);
          break;
+       case DW_AT_defaulted:
+         valuestr = dwarf_defaulted_name (num);
+         break;
        case DW_AT_visibility:
          valuestr = dwarf_visibility_name (num);
          break;
@@ -5947,6 +6179,28 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
        case DW_AT_discr_list:
          valuestr = dwarf_discr_list_name (num);
          break;
+       case DW_AT_decl_file:
+       case DW_AT_call_file:
+         {
+           /* Try to get the actual file, the current interface only
+              gives us full paths, but we only want to show the file
+              name for now.  */
+           Dwarf_Die cudie;
+           if (dwarf_cu_die (cbargs->cu, &cudie,
+                             NULL, NULL, NULL, NULL, NULL, NULL) != NULL)
+             {
+               Dwarf_Files *files;
+               size_t nfiles;
+               if (dwarf_getsrcfiles (&cudie, &files, &nfiles) == 0)
+                 {
+                   valuestr = dwarf_filesrc (files, num, NULL, NULL);
+                   char *filename = strrchr (valuestr, '/');
+                   if (filename != NULL)
+                     valuestr = filename + 1;
+                 }
+             }
+         }
+         break;
        default:
          /* Nothing.  */
          break;
@@ -6006,7 +6260,7 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
 
       printf ("           %*s%-20s (%s) %s\n",
              (int) (level * 2), "", dwarf_attr_name (attr),
-             dwarf_form_name (form), nl_langinfo (flag ? YESSTR : NOSTR));
+             dwarf_form_name (form), flag ? gettext ("yes") : gettext ("no"));
       break;
 
     case DW_FORM_flag_present:
@@ -6014,7 +6268,7 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
        break;
       printf ("           %*s%-20s (%s) %s\n",
              (int) (level * 2), "", dwarf_attr_name (attr),
-             dwarf_form_name (form), nl_langinfo (YESSTR));
+             dwarf_form_name (form), gettext ("yes"));
       break;
 
     case DW_FORM_exprloc:
@@ -6022,6 +6276,7 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
     case DW_FORM_block2:
     case DW_FORM_block1:
     case DW_FORM_block:
+    case DW_FORM_data16: /* DWARF5 calls this a constant class.  */
       if (cbargs->silent)
        break;
       Dwarf_Block block;
@@ -6040,7 +6295,7 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
              print_block (block.length, block.data);
              break;
            }
-         /* Fall through.  */
+         FALLTHROUGH;
 
        case DW_AT_location:
        case DW_AT_data_location:
@@ -6077,9 +6332,9 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
     default:
       if (cbargs->silent)
        break;
-      printf ("           %*s%-20s (form: %#x) ???\n",
+      printf ("           %*s%-20s (%s) ???\n",
              (int) (level * 2), "", dwarf_attr_name (attr),
-             (int) form);
+             dwarf_form_name (form));
       break;
     }
 
@@ -6107,41 +6362,102 @@ print_debug_units (Dwfl_Module *dwflmod,
   int 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_Die result;
   Dwarf_Off abbroffset;
   uint8_t addrsize;
   uint8_t offsize;
-  Dwarf_Off nextcu;
-  uint64_t typesig;
-  Dwarf_Off typeoff;
+  uint64_t unit_id;
+  Dwarf_Off subdie_off;
+
+  int unit_res;
+  Dwarf_CU *cu;
+  Dwarf_CU cu_mem;
+  uint8_t unit_type;
+  Dwarf_Die cudie;
+  Dwarf_Die subdie;
+
+  /* We cheat a little because we want to see only the CUs from .debug_info
+     or .debug_types.  We know the Dwarf_CU struct layout.  Set it up at
+     the end of .debug_info if we want .debug_types only.  Check the returned
+     Dwarf_CU is still in the expected section.  */
+  if (debug_types)
+    {
+      cu_mem.dbg = dbg;
+      cu_mem.end = dbg->sectiondata[IDX_debug_info]->d_size;
+      cu_mem.sec_idx = IDX_debug_info;
+      cu = &cu_mem;
+    }
+  else
+    cu = NULL;
+
  next_cu:
-  if (dwarf_next_unit (dbg, offset, &nextcu, &cuhl, &version,
-                      &abbroffset, &addrsize, &offsize,
-                      debug_types ? &typesig : NULL,
-                      debug_types ? &typeoff : NULL) != 0)
+  unit_res = dwarf_get_units (dbg, cu, &cu, &version, &unit_type,
+                             &cudie, &subdie);
+  if (unit_res == 1)
+    goto do_return;
+
+  if (unit_res == -1)
+    {
+      if (!silent)
+       error (0, 0, gettext ("cannot get next unit: %s"), dwarf_errmsg (-1));
+      goto do_return;
+    }
+
+  if (cu->sec_idx != (size_t) (debug_types ? IDX_debug_types : IDX_debug_info))
     goto do_return;
 
+  dwarf_cu_die (cu, &result, NULL, &abbroffset, &addrsize, &offsize,
+               &unit_id, &subdie_off);
+
   if (!silent)
     {
-      if (debug_types)
+      Dwarf_Off offset = cu->start;
+      if (debug_types && version < 5)
        printf (gettext (" Type unit at offset %" PRIu64 ":\n"
                         " Version: %" PRIu16 ", Abbreviation section offset: %"
                         PRIu64 ", Address size: %" PRIu8
                         ", Offset size: %" PRIu8
                         "\n Type signature: %#" PRIx64
-                        ", Type offset: %#" PRIx64 "\n"),
+                        ", Type offset: %#" PRIx64 " [%" PRIx64 "]\n"),
                (uint64_t) offset, version, abbroffset, addrsize, offsize,
-               typesig, (uint64_t) typeoff);
+               unit_id, (uint64_t) subdie_off, dwarf_dieoffset (&subdie));
       else
-       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, abbroffset, addrsize, offsize);
+       {
+         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, abbroffset, addrsize, offsize);
+
+         if (version >= 5)
+           {
+             printf (gettext (" Unit type: %s (%" PRIu8 ")"),
+                              dwarf_unit_name (unit_type), unit_type);
+             if (unit_type == DW_UT_type
+                 || unit_type == DW_UT_skeleton
+                 || unit_type == DW_UT_split_compile
+                 || unit_type == DW_UT_split_type)
+               printf (", Unit id: 0x%.16" PRIx64 "", unit_id);
+             if (unit_type == DW_UT_type
+                 || unit_type == DW_UT_split_type)
+               printf (", Unit DIE off: %#" PRIx64 " [%" PRIx64 "]",
+                       subdie_off, dwarf_dieoffset (&subdie));
+             printf ("\n");
+           }
+       }
+    }
+
+  if (version < 2 || version > 5
+      || unit_type < DW_UT_compile || unit_type > DW_UT_split_type)
+    {
+      if (!silent)
+       error (0, 0, gettext ("unknown version (%d) or unit type (%d)"),
+              version, unit_type);
+      goto next_cu;
     }
 
   struct attrcb_args args =
@@ -6154,25 +6470,13 @@ print_debug_units (Dwfl_Module *dwflmod,
       .offset_size = offsize
     };
 
-  offset += cuhl;
-
   int level = 0;
-
-  if (unlikely ((debug_types ? dwarf_offdie_types : dwarf_offdie)
-               (dbg, offset, &dies[level]) == NULL))
-    {
-      if (!silent)
-       error (0, 0, gettext ("cannot get DIE at offset %" PRIu64
-                             " in section '%s': %s"),
-              (uint64_t) offset, secname, dwarf_errmsg (-1));
-      goto do_return;
-    }
-
+  dies[0] = cudie;
   args.cu = dies[0].cu;
 
   do
     {
-      offset = dwarf_dieoffset (&dies[level]);
+      Dwarf_Off offset = dwarf_dieoffset (&dies[level]);
       if (unlikely (offset == ~0ul))
        {
          if (!silent)
@@ -6185,16 +6489,19 @@ print_debug_units (Dwfl_Module *dwflmod,
       if (unlikely (tag == DW_TAG_invalid))
        {
          if (!silent)
-           error (0, 0, gettext ("cannot get tag of DIE at offset %" PRIu64
-                                 " in section '%s': %s"),
+           error (0, 0, gettext ("cannot get tag of DIE at offset [%" PRIx64
+                                 "] in section '%s': %s"),
                   (uint64_t) offset, secname, dwarf_errmsg (-1));
          goto do_return;
        }
 
       if (!silent)
-       printf (" [%6" PRIx64 "]  %*s%s\n",
-               (uint64_t) offset, (int) (level * 2), "",
-               dwarf_tag_name (tag));
+       {
+         unsigned int code = dwarf_getabbrevcode (dies[level].abbrev);
+         printf (" [%6" PRIx64 "]  %*s%-20s abbrev: %u\n",
+                 (uint64_t) offset, (int) (level * 2), "",
+                 dwarf_tag_name (tag), code);
+       }
 
       /* Print the attribute values.  */
       args.level = level;
@@ -6234,9 +6541,8 @@ print_debug_units (Dwfl_Module *dwflmod,
     }
   while (level >= 0);
 
-  offset = nextcu;
-  if (offset != 0)
-     goto next_cu;
+  /* And again... */
+  goto next_cu;
 
  do_return:
   free (dies);
@@ -6901,19 +7207,36 @@ print_debug_loc_section (Dwfl_Module *dwflmod,
   uint_fast8_t offset_size = 4;
 
   bool first = true;
-  struct Dwarf_CU *cu = NULL;
   Dwarf_Addr base = 0;
   unsigned char *readp = data->d_buf;
   unsigned char *const endp = (unsigned char *) data->d_buf + data->d_size;
+  Dwarf_CU *last_cu = NULL;
   while (readp < endp)
     {
       ptrdiff_t offset = readp - (unsigned char *) data->d_buf;
+      Dwarf_CU *cu = last_cu;
 
       if (first && skip_listptr_hole (&known_loclistptr, &listptr_idx,
                                      &address_size, &offset_size, &base,
                                      &cu, offset, &readp, endp))
        continue;
 
+      if (last_cu != cu)
+       {
+       char *basestr = format_dwarf_addr (dwflmod, address_size,
+                                          base, base);
+       Dwarf_Die cudie;
+       if (dwarf_cu_die (cu, &cudie,
+                         NULL, NULL, NULL, NULL,
+                         NULL, NULL) == NULL)
+         printf (gettext ("\n Unknown CU base: %s\n"), basestr);
+       else
+         printf (gettext ("\n CU [%6" PRIx64 "] base: %s\n"),
+                 dwarf_dieoffset (&cudie), basestr);
+       free (basestr);
+       }
+      last_cu = cu;
+
       if (unlikely (data->d_size - offset < (size_t) address_size * 2))
        {
          printf (gettext (" [%6tx]  <INVALID DATA>\n"), offset);
@@ -6938,14 +7261,14 @@ print_debug_loc_section (Dwfl_Module *dwflmod,
       if (begin == (Dwarf_Addr) -1l) /* Base address entry.  */
        {
          char *b = format_dwarf_addr (dwflmod, address_size, end, end);
-         printf (gettext (" [%6tx]  base address %s\n"), offset, b);
+         printf (gettext (" [%6tx] base address\n          %s\n"), offset, b);
          free (b);
          base = end;
        }
       else if (begin == 0 && end == 0) /* End of list entry.  */
        {
          if (first)
-           printf (gettext (" [%6tx]  empty list\n"), offset);
+           printf (gettext (" [%6tx] empty list\n"), offset);
          first = true;
        }
       else
@@ -6953,18 +7276,23 @@ print_debug_loc_section (Dwfl_Module *dwflmod,
          /* We have a location expression entry.  */
          uint_fast16_t len = read_2ubyte_unaligned_inc (dbg, readp);
 
-         char *b = format_dwarf_addr (dwflmod, address_size, base + begin,
-                                      begin);
-         char *e = format_dwarf_addr (dwflmod, address_size, base + end,
-                                      end);
-
          if (first)            /* First entry in a list.  */
-           printf (gettext (" [%6tx]  %s..%s"), offset, b, e);
+           printf (" [%6tx] ", offset);
          else
-           printf (gettext ("           %s..%s"), b, e);
+           printf ("          ");
 
-         free (b);
-         free (e);
+         printf ("range %" PRIx64 ", %" PRIx64 "\n", begin, end);
+         if (! print_unresolved_addresses)
+           {
+             char *b = format_dwarf_addr (dwflmod, address_size, base + begin,
+                                          base + begin);
+             char *e = format_dwarf_addr (dwflmod, address_size,
+                                          base + end - 1, base + end);
+             printf ("          %s..\n", b);
+             printf ("          %s\n", e);
+             free (b);
+             free (e);
+           }
 
          if (endp - readp <= (ptrdiff_t) len)
            {
@@ -6972,8 +7300,9 @@ print_debug_loc_section (Dwfl_Module *dwflmod,
              break;
            }
 
-         print_ops (dwflmod, dbg, 1, 18 + (address_size * 4),
-                    3 /*XXX*/, address_size, offset_size, cu, len, readp);
+         print_ops (dwflmod, dbg, 11, 11,
+                    cu != NULL ? cu->version : 3,
+                    address_size, offset_size, cu, len, readp);
 
          first = false;
          readp += len;
@@ -7239,7 +7568,7 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
 
       // Version 4 is the GNU extension for DWARF4.  DWARF5 will use version
       // 5 when it gets standardized.
-      if (vers != 4)
+      if (vers != 4 && vers != 5)
        {
          printf (gettext ("  unknown version, cannot parse section\n"));
          return;
@@ -7263,7 +7592,7 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
                  line_offset);
        }
 
-      const unsigned char *vendor[DW_MACRO_GNU_hi_user - DW_MACRO_GNU_lo_user];
+      const unsigned char *vendor[DW_MACRO_hi_user - DW_MACRO_lo_user];
       memset (vendor, 0, sizeof vendor);
       if (flag & 0x04)
        {
@@ -7280,12 +7609,12 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
                goto invalid_data;
              unsigned int opcode = *readp++;
              printf (gettext ("    [%" PRIx8 "]"), opcode);
-             if (opcode < DW_MACRO_GNU_lo_user
-                 || opcode > DW_MACRO_GNU_hi_user)
+             if (opcode < DW_MACRO_lo_user
+                 || opcode > DW_MACRO_hi_user)
                goto invalid_data;
              // Record the start of description for this vendor opcode.
              // uleb128 nr args, 1 byte per arg form.
-             vendor[opcode - DW_MACRO_GNU_lo_user] = readp;
+             vendor[opcode - DW_MACRO_lo_user] = readp;
              if (readp + 1 > readendp)
                goto invalid_data;
              unsigned int args = *readp++;
@@ -7297,7 +7626,7 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
                      if (readp + 1 > readendp)
                        goto invalid_data;
                      unsigned int form = *readp++;
-                     printf (" %s", dwarf_form_string (form));
+                     printf (" %s", dwarf_form_name (form));
                      if (form != DW_FORM_data1
                          && form != DW_FORM_data2
                          && form != DW_FORM_data4
@@ -7338,7 +7667,7 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
 
           switch (opcode)
             {
-            case DW_MACRO_GNU_start_file:
+            case DW_MACRO_start_file:
              get_uleb128 (u128, readp, readendp);
              if (readp >= readendp)
                goto invalid_data;
@@ -7368,12 +7697,12 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
              ++level;
              break;
 
-           case DW_MACRO_GNU_end_file:
+           case DW_MACRO_end_file:
              --level;
              printf ("%*send_file\n", level, "");
              break;
 
-           case DW_MACRO_GNU_define:
+           case DW_MACRO_define:
              get_uleb128 (u128, readp, readendp);
              endp = memchr (readp, '\0', readendp - readp);
              if (endp == NULL)
@@ -7383,7 +7712,7 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
              readp = endp + 1;
              break;
 
-           case DW_MACRO_GNU_undef:
+           case DW_MACRO_undef:
              get_uleb128 (u128, readp, readendp);
              endp = memchr (readp, '\0', readendp - readp);
              if (endp == NULL)
@@ -7393,7 +7722,7 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
              readp = endp + 1;
              break;
 
-           case DW_MACRO_GNU_define_indirect:
+           case DW_MACRO_define_strp:
              get_uleb128 (u128, readp, readendp);
              if (readp + offset_len > readendp)
                goto invalid_data;
@@ -7405,7 +7734,7 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
                      level, "", dwarf_getstring (dbg, off, NULL), u128);
              break;
 
-           case DW_MACRO_GNU_undef_indirect:
+           case DW_MACRO_undef_strp:
              get_uleb128 (u128, readp, readendp);
              if (readp + offset_len > readendp)
                goto invalid_data;
@@ -7417,7 +7746,7 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
                      level, "", dwarf_getstring (dbg, off, NULL), u128);
              break;
 
-           case DW_MACRO_GNU_transparent_include:
+           case DW_MACRO_import:
              if (readp + offset_len > readendp)
                goto invalid_data;
              if (offset_len == 8)
@@ -7428,15 +7757,78 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
                      level, "", off);
              break;
 
+           case DW_MACRO_define_sup:
+             get_uleb128 (u128, readp, readendp);
+             if (readp + offset_len > readendp)
+               goto invalid_data;
+             if (offset_len == 8)
+               off = read_8ubyte_unaligned_inc (dbg, readp);
+             else
+               off = read_4ubyte_unaligned_inc (dbg, readp);
+             // Needs support for reading from supplementary object file.
+             printf ("%*s#define <str-at-0x%" PRIx64 ">, line %u (sup)\n",
+                     level, "", off, u128);
+             break;
+
+           case DW_MACRO_undef_sup:
+             get_uleb128 (u128, readp, readendp);
+             if (readp + offset_len > readendp)
+               goto invalid_data;
+             if (offset_len == 8)
+               off = read_8ubyte_unaligned_inc (dbg, readp);
+             else
+               off = read_4ubyte_unaligned_inc (dbg, readp);
+             // Needs support for reading from supplementary object file.
+             printf ("%*s#undef <str-at-0x%" PRIx64 ">, line %u (sup)\n",
+                     level, "", off, u128);
+             break;
+
+           case DW_MACRO_import_sup:
+             if (readp + offset_len > readendp)
+               goto invalid_data;
+             if (offset_len == 8)
+               off = read_8ubyte_unaligned_inc (dbg, readp);
+             else
+               off = read_4ubyte_unaligned_inc (dbg, readp);
+             printf ("%*s#include offset 0x%" PRIx64 " (sup)\n",
+                     level, "", off);
+             break;
+
+           case DW_MACRO_define_strx:
+             get_uleb128 (u128, readp, readendp);
+             if (readp + offset_len > readendp)
+               goto invalid_data;
+             if (offset_len == 8)
+               off = read_8ubyte_unaligned_inc (dbg, readp);
+             else
+               off = read_4ubyte_unaligned_inc (dbg, readp);
+             // Needs support for reading indirect string offset table
+             printf ("%*s#define <str-at-0x%" PRIx64 ">, line %u (strx)\n",
+                     level, "", off, u128);
+             break;
+
+           case DW_MACRO_undef_strx:
+             get_uleb128 (u128, readp, readendp);
+             if (readp + offset_len > readendp)
+               goto invalid_data;
+             if (offset_len == 8)
+               off = read_8ubyte_unaligned_inc (dbg, readp);
+             else
+               off = read_4ubyte_unaligned_inc (dbg, readp);
+             // Needs support for reading indirect string offset table.
+             printf ("%*s#undef <str-at-0x%" PRIx64 ">, line %u (strx)\n",
+                     level, "", off, u128);
+             break;
+
            default:
              printf ("%*svendor opcode 0x%" PRIx8, level, "", opcode);
-             if (opcode < DW_MACRO_GNU_lo_user
-                 || opcode > DW_MACRO_GNU_lo_user
-                 || vendor[opcode - DW_MACRO_GNU_lo_user] == NULL)
+             if (opcode < DW_MACRO_lo_user
+                 || opcode > DW_MACRO_lo_user
+                 || vendor[opcode - DW_MACRO_lo_user] == NULL)
                goto invalid_data;
 
              const unsigned char *op_desc;
-             op_desc = vendor[opcode - DW_MACRO_GNU_lo_user];
+             op_desc = vendor[opcode - DW_MACRO_lo_user];
 
              // Just skip the arguments, we cannot really interpret them,
              // but print as much as we can.
@@ -7524,7 +7916,7 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
                      if (readp + 1 > readendp)
                        goto invalid_data;
                      val = *readp++;
-                     printf (" %s", nl_langinfo (val != 0 ? YESSTR : NOSTR));
+                     printf (" %s", val != 0 ? gettext ("yes") : gettext ("no"));
                      break;
 
                    case DW_FORM_string:
@@ -7910,6 +8302,7 @@ print_debug_exception_table (Dwfl_Module *dwflmod __attribute__ ((unused)),
          dsize = 8;
          break;
        default:
+         dsize = 0;
          error (1, 0, gettext ("invalid TType encoding"));
        }
 
@@ -8259,11 +8652,9 @@ print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr)
          int n;
          for (n = 0; n < ndebug_sections; ++n)
            if (strcmp (name, debug_sections[n].name) == 0
-#if USE_ZLIB
                || (name[0] == '.' && name[1] == 'z'
                    && debug_sections[n].name[1] == 'd'
                    && strcmp (&name[2], &debug_sections[n].name[1]) == 0)
-#endif
                )
              {
                if ((print_debug_sections | implicit_debug_sections)
@@ -8369,6 +8760,9 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
                  unsigned int colno, size_t *repeated_size)
 {
   uint_fast16_t count = item->count ?: 1;
+  /* Ebl_Core_Item count is always a small number.
+     Make sure the backend didn't put in some large bogus value.  */
+  assert (count < 128);
 
 #define TYPES                                                                \
   DO_TYPE (BYTE, Byte, "0x%.2" PRIx8, "%" PRId8);                            \
@@ -8378,11 +8772,16 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
   DO_TYPE (XWORD, Xword, "0x%.16" PRIx64, "%" PRId64);                       \
   DO_TYPE (SXWORD, Sxword, "%" PRId64, "%" PRId64)
 
-#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name[count]
-  union { TYPES; } value;
+#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name
+  typedef union { TYPES; } value_t;
+  void *data = alloca (count * sizeof (value_t));
+#undef DO_TYPE
+
+#define DO_TYPE(NAME, Name, hex, dec) \
+    GElf_##Name *value_##Name __attribute__((unused)) = data
+  TYPES;
 #undef DO_TYPE
 
-  void *data = &value;
   size_t size = gelf_fsize (core, item->type, count, EV_CURRENT);
   size_t convsize = size;
   if (repeated_size != NULL)
@@ -8413,7 +8812,7 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 #define DO_TYPE(NAME, Name, hex, dec)                                        \
          case ELF_T_##NAME:                                                  \
            colno = print_core_item (colno, ',', WRAP_COLUMN,                 \
-                                    0, item->name, dec, value.Name[0]); \
+                                    0, item->name, dec, value_##Name[0]); \
            break
          TYPES;
 #undef DO_TYPE
@@ -8429,7 +8828,7 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 #define DO_TYPE(NAME, Name, hex, dec)                                        \
          case ELF_T_##NAME:                                                  \
            colno = print_core_item (colno, ',', WRAP_COLUMN,                 \
-                                    0, item->name, hex, value.Name[0]);      \
+                                    0, item->name, hex, value_##Name[0]);      \
            break
          TYPES;
 #undef DO_TYPE
@@ -8519,8 +8918,8 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
        {
 #define DO_TYPE(NAME, Name, hex, dec)                                        \
          case ELF_T_##NAME:                                                  \
-           sec = value.Name[0];                                              \
-           usec = value.Name[1];                                             \
+           sec = value_##Name[0];                                            \
+           usec = value_##Name[1];                                           \
            break
          TYPES;
 #undef DO_TYPE
@@ -8550,12 +8949,12 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
     case 'c':
       assert (count == 1);
       colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
-                              "%c", value.Byte[0]);
+                              "%c", value_Byte[0]);
       break;
 
     case 's':
       colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
-                              "%.*s", (int) count, value.Byte);
+                              "%.*s", (int) count, value_Byte);
       break;
 
     case '\n':
@@ -9001,7 +9400,7 @@ handle_auxv_note (Ebl *ebl, Elf *core, GElf_Word descsz, GElf_Off desc_pos)
                printf ("    %s\n", name);
                break;
              }
-           /* Fall through */
+           FALLTHROUGH;
          case 'x':             /* hex */
          case 'p':             /* address */
          case 's':             /* address of string */
@@ -9110,10 +9509,10 @@ handle_siginfo_note (Elf *core, GElf_Word descsz, GElf_Off desc_pos)
   if (si_code > 0)
     switch (si_signo)
       {
-      case SIGILL:
-      case SIGFPE:
-      case SIGSEGV:
-      case SIGBUS:
+      case CORE_SIGILL:
+      case CORE_SIGFPE:
+      case CORE_SIGSEGV:
+      case CORE_SIGBUS:
        {
          uint64_t addr;
          if (! buf_read_ulong (core, &ptr, end, &addr))
@@ -9124,7 +9523,7 @@ handle_siginfo_note (Elf *core, GElf_Word descsz, GElf_Off desc_pos)
       default:
        ;
       }
-  else if (si_code == SI_USER)
+  else if (si_code == CORE_SI_USER)
     {
       int pid, uid;
       if (! buf_read_int (core, &ptr, end, &pid)
@@ -9232,7 +9631,7 @@ handle_notes_data (Ebl *ebl, const GElf_Ehdr *ehdr,
         && (offset = gelf_getnote (data, offset,
                                    &nhdr, &name_offset, &desc_offset)) > 0)
     {
-      const char *name = data->d_buf + name_offset;
+      const char *name = nhdr.n_namesz == 0 ? "" : data->d_buf + name_offset;
       const char *desc = data->d_buf + desc_offset;
 
       char buf[100];
@@ -9286,9 +9685,9 @@ handle_notes_data (Ebl *ebl, const GElf_Ehdr *ehdr,
     return;
 
  bad_note:
-  error (EXIT_FAILURE, 0,
-        gettext ("cannot get content of note section: %s"),
-        elf_errmsg (-1));
+  error (0, 0,
+        gettext ("cannot get content of note: %s"),
+        data != NULL ? "garbage data" : elf_errmsg (-1));
 }
 
 static void
@@ -9387,16 +9786,44 @@ dump_data_section (Elf_Scn *scn, const GElf_Shdr *shdr, const char *name)
            elf_ndxscn (scn), name);
   else
     {
+      if (print_decompress)
+       {
+         /* We try to decompress the section, but keep the old shdr around
+            so we can show both the original shdr size and the uncompressed
+            data size.   */
+         if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+           {
+             if (elf_compress (scn, 0, 0) < 0)
+               printf ("WARNING: %s [%zd]\n",
+                       gettext ("Couldn't uncompress section"),
+                       elf_ndxscn (scn));
+           }
+         else if (strncmp (name, ".zdebug", strlen (".zdebug")) == 0)
+           {
+             if (elf_compress_gnu (scn, 0, 0) < 0)
+               printf ("WARNING: %s [%zd]\n",
+                       gettext ("Couldn't uncompress section"),
+                       elf_ndxscn (scn));
+           }
+       }
+
       Elf_Data *data = elf_rawdata (scn, NULL);
       if (data == NULL)
        error (0, 0, gettext ("cannot get data for section [%zu] '%s': %s"),
               elf_ndxscn (scn), name, elf_errmsg (-1));
       else
        {
-         printf (gettext ("\nHex dump of section [%zu] '%s', %" PRIu64
-                          " bytes at offset %#0" PRIx64 ":\n"),
-                 elf_ndxscn (scn), name,
-                 shdr->sh_size, shdr->sh_offset);
+         if (data->d_size == shdr->sh_size)
+           printf (gettext ("\nHex dump of section [%zu] '%s', %" PRIu64
+                            " bytes at offset %#0" PRIx64 ":\n"),
+                   elf_ndxscn (scn), name,
+                   shdr->sh_size, shdr->sh_offset);
+         else
+           printf (gettext ("\nHex dump of section [%zu] '%s', %" PRIu64
+                            " bytes (%zd uncompressed) at offset %#0"
+                            PRIx64 ":\n"),
+                   elf_ndxscn (scn), name,
+                   shdr->sh_size, data->d_size, shdr->sh_offset);
          hex_dump (data->d_buf, data->d_size);
        }
     }
@@ -9410,16 +9837,44 @@ print_string_section (Elf_Scn *scn, const GElf_Shdr *shdr, const char *name)
            elf_ndxscn (scn), name);
   else
     {
+      if (print_decompress)
+       {
+         /* We try to decompress the section, but keep the old shdr around
+            so we can show both the original shdr size and the uncompressed
+            data size.  */
+         if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+           {
+             if (elf_compress (scn, 0, 0) < 0)
+               printf ("WARNING: %s [%zd]\n",
+                       gettext ("Couldn't uncompress section"),
+                       elf_ndxscn (scn));
+           }
+         else if (strncmp (name, ".zdebug", strlen (".zdebug")) == 0)
+           {
+             if (elf_compress_gnu (scn, 0, 0) < 0)
+               printf ("WARNING: %s [%zd]\n",
+                       gettext ("Couldn't uncompress section"),
+                       elf_ndxscn (scn));
+           }
+       }
+
       Elf_Data *data = elf_rawdata (scn, NULL);
       if (data == NULL)
        error (0, 0, gettext ("cannot get data for section [%zu] '%s': %s"),
               elf_ndxscn (scn), name, elf_errmsg (-1));
       else
        {
-         printf (gettext ("\nString section [%zu] '%s' contains %" PRIu64
-                          " bytes at offset %#0" PRIx64 ":\n"),
-                 elf_ndxscn (scn), name,
-                 shdr->sh_size, shdr->sh_offset);
+         if (data->d_size == shdr->sh_size)
+           printf (gettext ("\nString section [%zu] '%s' contains %" PRIu64
+                            " bytes at offset %#0" PRIx64 ":\n"),
+                   elf_ndxscn (scn), name,
+                   shdr->sh_size, shdr->sh_offset);
+         else
+           printf (gettext ("\nString section [%zu] '%s' contains %" PRIu64
+                            " bytes (%zd uncompressed) at offset %#0"
+                            PRIx64 ":\n"),
+                   elf_ndxscn (scn), name,
+                   shdr->sh_size, data->d_size, shdr->sh_offset);
 
          const char *start = data->d_buf;
          const char *const limit = start + data->d_size;
@@ -9567,7 +10022,7 @@ dump_archive_index (Elf *elf, const char *fname)
        {
          as_off = s->as_off;
 
-         Elf *subelf;
+         Elf *subelf = NULL;
          if (unlikely (elf_rand (elf, as_off) == 0)
              || unlikely ((subelf = elf_begin (-1, ELF_C_READ_MMAP, elf))
                           == NULL))