libdw: Add support for DWARF5 DW_FORM_data16.
[platform/upstream/elfutils.git] / src / readelf.c
index 237975f..2d49af3 100644 (file)
@@ -1,5 +1,5 @@
 /* Print information from ELF file in human-readable form.
-   Copyright (C) 1999-2014 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);
@@ -1315,10 +1400,10 @@ print_phdr (Ebl *ebl, GElf_Ehdr *ehdr)
                {
                  /* Determine the segment this section is part of.  */
                  size_t cnt2;
+                 GElf_Phdr phdr2_mem;
                  GElf_Phdr *phdr2 = NULL;
                  for (cnt2 = 0; cnt2 < phnum; ++cnt2)
                    {
-                     GElf_Phdr phdr2_mem;
                      phdr2 = gelf_getphdr (ebl->elf, cnt2, &phdr2_mem);
 
                      if (phdr2 != NULL && phdr2->p_type == PT_LOAD
@@ -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);
+       }
     }
 }
 
@@ -1582,7 +1682,7 @@ handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
 
   glink = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), &glink_mem);
   if (glink == NULL)
-    error (EXIT_FAILURE, 0, gettext ("invalid sh_link value in section %Zu"),
+    error (EXIT_FAILURE, 0, gettext ("invalid sh_link value in section %zu"),
           elf_ndxscn (scn));
 
   printf (ngettext ("\
@@ -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);
+       }
     }
 }
 
@@ -2205,7 +2332,7 @@ handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
   GElf_Shdr *glink = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
                                   &glink_mem);
   if (glink == NULL)
-    error (EXIT_FAILURE, 0, gettext ("invalid sh_link value in section %Zu"),
+    error (EXIT_FAILURE, 0, gettext ("invalid sh_link value in section %zu"),
           elf_ndxscn (scn));
 
   /* Now we can compute the number of entries in the section.  */
@@ -2463,7 +2590,7 @@ handle_verneed (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
   GElf_Shdr *glink = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
                                   &glink_mem);
   if (glink == NULL)
-    error (EXIT_FAILURE, 0, gettext ("invalid sh_link value in section %Zu"),
+    error (EXIT_FAILURE, 0, gettext ("invalid sh_link value in section %zu"),
           elf_ndxscn (scn));
 
   printf (ngettext ("\
@@ -2539,7 +2666,7 @@ handle_verdef (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
   GElf_Shdr *glink = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
                                   &glink_mem);
   if (glink == NULL)
-    error (EXIT_FAILURE, 0, gettext ("invalid sh_link value in section %Zu"),
+    error (EXIT_FAILURE, 0, gettext ("invalid sh_link value in section %zu"),
           elf_ndxscn (scn));
 
   int class = gelf_getclass (ebl->elf);
@@ -2843,7 +2970,7 @@ handle_versym (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
                                   &glink_mem);
   size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_HALF, 1, EV_CURRENT);
   if (glink == NULL)
-    error (EXIT_FAILURE, 0, gettext ("invalid sh_link value in section %Zu"),
+    error (EXIT_FAILURE, 0, gettext ("invalid sh_link value in section %zu"),
           elf_ndxscn (scn));
 
   /* Print the header.  */
@@ -2917,7 +3044,7 @@ print_hash_info (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx,
                                   &glink_mem);
   if (glink == NULL)
     {
-      error (0, 0, gettext ("invalid sh_link value in section %Zu"),
+      error (0, 0, gettext ("invalid sh_link value in section %zu"),
             elf_ndxscn (scn));
       return;
     }
@@ -3092,6 +3219,7 @@ handle_sysv_hash64 (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
 static void
 handle_gnu_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
 {
+  uint32_t *lengths = NULL;
   Elf_Data *data = elf_getdata (scn, NULL);
   if (unlikely (data == NULL))
     {
@@ -3103,6 +3231,7 @@ handle_gnu_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
   if (unlikely (data->d_size < 4 * sizeof (Elf32_Word)))
     {
     invalid_data:
+      free (lengths);
       error (0, 0, gettext ("invalid data in gnu.hash section %d"),
             (int) elf_ndxscn (scn));
       return;
@@ -3131,7 +3260,7 @@ handle_gnu_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
   if (used_buf > data->d_size)
     goto invalid_data;
 
-  uint32_t *lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t));
+  lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t));
 
   Elf32_Word *bitmask = &((Elf32_Word *) data->d_buf)[4];
   Elf32_Word *bucket = &((Elf32_Word *) data->d_buf)[4 + bitmask_words];
@@ -3150,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);
@@ -3209,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))
@@ -3566,9 +3709,9 @@ dwarf_tag_string (unsigned int tag)
 {
   switch (tag)
     {
-#define ONE_KNOWN_DW_TAG(NAME, CODE) case CODE: return #NAME;
-      ALL_KNOWN_DW_TAG
-#undef ONE_KNOWN_DW_TAG
+#define DWARF_ONE_KNOWN_DW_TAG(NAME, CODE) case CODE: return #NAME;
+      DWARF_ALL_KNOWN_DW_TAG
+#undef DWARF_ONE_KNOWN_DW_TAG
     default:
       return NULL;
     }
@@ -3580,9 +3723,9 @@ dwarf_attr_string (unsigned int attrnum)
 {
   switch (attrnum)
     {
-#define ONE_KNOWN_DW_AT(NAME, CODE) case CODE: return #NAME;
-      ALL_KNOWN_DW_AT
-#undef ONE_KNOWN_DW_AT
+#define DWARF_ONE_KNOWN_DW_AT(NAME, CODE) case CODE: return #NAME;
+      DWARF_ALL_KNOWN_DW_AT
+#undef DWARF_ONE_KNOWN_DW_AT
     default:
       return NULL;
     }
@@ -3594,11 +3737,9 @@ dwarf_form_string (unsigned int form)
 {
   switch (form)
     {
-#define ONE_KNOWN_DW_FORM_DESC(NAME, CODE, DESC) ONE_KNOWN_DW_FORM (NAME, CODE)
-#define ONE_KNOWN_DW_FORM(NAME, CODE) case CODE: return #NAME;
-      ALL_KNOWN_DW_FORM
-#undef ONE_KNOWN_DW_FORM
-#undef ONE_KNOWN_DW_FORM_DESC
+#define DWARF_ONE_KNOWN_DW_FORM(NAME, CODE) case CODE: return #NAME;
+      DWARF_ALL_KNOWN_DW_FORM
+#undef DWARF_ONE_KNOWN_DW_FORM
     default:
       return NULL;
     }
@@ -3610,9 +3751,9 @@ dwarf_lang_string (unsigned int lang)
 {
   switch (lang)
     {
-#define ONE_KNOWN_DW_LANG_DESC(NAME, CODE, DESC) case CODE: return #NAME;
-      ALL_KNOWN_DW_LANG
-#undef ONE_KNOWN_DW_LANG_DESC
+#define DWARF_ONE_KNOWN_DW_LANG(NAME, CODE) case CODE: return #NAME;
+      DWARF_ALL_KNOWN_DW_LANG
+#undef DWARF_ONE_KNOWN_DW_LANG
     default:
       return NULL;
     }
@@ -3624,9 +3765,9 @@ dwarf_inline_string (unsigned int code)
 {
   static const char *const known[] =
     {
-#define ONE_KNOWN_DW_INL(NAME, CODE) [CODE] = #NAME,
-      ALL_KNOWN_DW_INL
-#undef ONE_KNOWN_DW_INL
+#define DWARF_ONE_KNOWN_DW_INL(NAME, CODE) [CODE] = #NAME,
+      DWARF_ALL_KNOWN_DW_INL
+#undef DWARF_ONE_KNOWN_DW_INL
     };
 
   if (likely (code < sizeof (known) / sizeof (known[0])))
@@ -3641,9 +3782,9 @@ dwarf_encoding_string (unsigned int code)
 {
   static const char *const known[] =
     {
-#define ONE_KNOWN_DW_ATE(NAME, CODE) [CODE] = #NAME,
-      ALL_KNOWN_DW_ATE
-#undef ONE_KNOWN_DW_ATE
+#define DWARF_ONE_KNOWN_DW_ATE(NAME, CODE) [CODE] = #NAME,
+      DWARF_ALL_KNOWN_DW_ATE
+#undef DWARF_ONE_KNOWN_DW_ATE
     };
 
   if (likely (code < sizeof (known) / sizeof (known[0])))
@@ -3658,9 +3799,26 @@ dwarf_access_string (unsigned int code)
 {
   static const char *const known[] =
     {
-#define ONE_KNOWN_DW_ACCESS(NAME, CODE) [CODE] = #NAME,
-      ALL_KNOWN_DW_ACCESS
-#undef ONE_KNOWN_DW_ACCESS
+#define DWARF_ONE_KNOWN_DW_ACCESS(NAME, CODE) [CODE] = #NAME,
+      DWARF_ALL_KNOWN_DW_ACCESS
+#undef DWARF_ONE_KNOWN_DW_ACCESS
+    };
+
+  if (likely (code < sizeof (known) / sizeof (known[0])))
+    return known[code];
+
+  return NULL;
+}
+
+
+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])))
@@ -3675,9 +3833,9 @@ dwarf_visibility_string (unsigned int code)
 {
   static const char *const known[] =
     {
-#define ONE_KNOWN_DW_VIS(NAME, CODE) [CODE] = #NAME,
-      ALL_KNOWN_DW_VIS
-#undef ONE_KNOWN_DW_VIS
+#define DWARF_ONE_KNOWN_DW_VIS(NAME, CODE) [CODE] = #NAME,
+      DWARF_ALL_KNOWN_DW_VIS
+#undef DWARF_ONE_KNOWN_DW_VIS
     };
 
   if (likely (code < sizeof (known) / sizeof (known[0])))
@@ -3692,9 +3850,9 @@ dwarf_virtuality_string (unsigned int code)
 {
   static const char *const known[] =
     {
-#define ONE_KNOWN_DW_VIRTUALITY(NAME, CODE) [CODE] = #NAME,
-      ALL_KNOWN_DW_VIRTUALITY
-#undef ONE_KNOWN_DW_VIRTUALITY
+#define DWARF_ONE_KNOWN_DW_VIRTUALITY(NAME, CODE) [CODE] = #NAME,
+      DWARF_ALL_KNOWN_DW_VIRTUALITY
+#undef DWARF_ONE_KNOWN_DW_VIRTUALITY
     };
 
   if (likely (code < sizeof (known) / sizeof (known[0])))
@@ -3709,9 +3867,9 @@ dwarf_identifier_case_string (unsigned int code)
 {
   static const char *const known[] =
     {
-#define ONE_KNOWN_DW_ID(NAME, CODE) [CODE] = #NAME,
-      ALL_KNOWN_DW_ID
-#undef ONE_KNOWN_DW_ID
+#define DWARF_ONE_KNOWN_DW_ID(NAME, CODE) [CODE] = #NAME,
+      DWARF_ALL_KNOWN_DW_ID
+#undef DWARF_ONE_KNOWN_DW_ID
     };
 
   if (likely (code < sizeof (known) / sizeof (known[0])))
@@ -3726,9 +3884,9 @@ dwarf_calling_convention_string (unsigned int code)
 {
   static const char *const known[] =
     {
-#define ONE_KNOWN_DW_CC(NAME, CODE) [CODE] = #NAME,
-      ALL_KNOWN_DW_CC
-#undef ONE_KNOWN_DW_CC
+#define DWARF_ONE_KNOWN_DW_CC(NAME, CODE) [CODE] = #NAME,
+      DWARF_ALL_KNOWN_DW_CC
+#undef DWARF_ONE_KNOWN_DW_CC
     };
 
   if (likely (code < sizeof (known) / sizeof (known[0])))
@@ -3743,9 +3901,9 @@ dwarf_ordering_string (unsigned int code)
 {
   static const char *const known[] =
     {
-#define ONE_KNOWN_DW_ORD(NAME, CODE) [CODE] = #NAME,
-      ALL_KNOWN_DW_ORD
-#undef ONE_KNOWN_DW_ORD
+#define DWARF_ONE_KNOWN_DW_ORD(NAME, CODE) [CODE] = #NAME,
+      DWARF_ALL_KNOWN_DW_ORD
+#undef DWARF_ONE_KNOWN_DW_ORD
     };
 
   if (likely (code < sizeof (known) / sizeof (known[0])))
@@ -3760,9 +3918,9 @@ dwarf_discr_list_string (unsigned int code)
 {
   static const char *const known[] =
     {
-#define ONE_KNOWN_DW_DSC(NAME, CODE) [CODE] = #NAME,
-      ALL_KNOWN_DW_DSC
-#undef ONE_KNOWN_DW_DSC
+#define DWARF_ONE_KNOWN_DW_DSC(NAME, CODE) [CODE] = #NAME,
+      DWARF_ALL_KNOWN_DW_DSC
+#undef DWARF_ONE_KNOWN_DW_DSC
     };
 
   if (likely (code < sizeof (known) / sizeof (known[0])))
@@ -3780,11 +3938,9 @@ dwarf_locexpr_opcode_string (unsigned int code)
       /* Normally we can't affort building huge table of 64K entries,
         most of them zero, just because there are a couple defined
         values at the far end.  In case of opcodes, it's OK.  */
-#define ONE_KNOWN_DW_OP_DESC(NAME, CODE, DESC) ONE_KNOWN_DW_OP (NAME, CODE)
-#define ONE_KNOWN_DW_OP(NAME, CODE) [CODE] = #NAME,
-      ALL_KNOWN_DW_OP
-#undef ONE_KNOWN_DW_OP
-#undef ONE_KNOWN_DW_OP_DESC
+#define DWARF_ONE_KNOWN_DW_OP(NAME, CODE) [CODE] = #NAME,
+      DWARF_ALL_KNOWN_DW_OP
+#undef DWARF_ONE_KNOWN_DW_OP
     };
 
   if (likely (code < sizeof (known) / sizeof (known[0])))
@@ -3794,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,
@@ -3878,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);
@@ -3925,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)
 {
@@ -3989,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);
 
@@ -3997,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.  */
@@ -4007,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;
@@ -4020,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;
@@ -4031,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);
@@ -4042,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);
@@ -4053,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);
@@ -4064,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;
@@ -4075,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);
@@ -4086,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);
@@ -4097,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);
@@ -4113,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);
@@ -4126,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);
@@ -4139,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);
@@ -4151,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);
@@ -4159,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);
@@ -4190,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);
@@ -4214,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);
@@ -4226,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);
@@ -4247,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;
@@ -4265,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);
@@ -4281,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);
@@ -4297,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);
@@ -4310,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;
@@ -4319,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;
@@ -4329,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;
     }
@@ -4569,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;
            }
 
@@ -4607,7 +4798,7 @@ print_decoded_aranges_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
   glink = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), &glink_mem);
   if (glink == NULL)
     {
-      error (0, 0, gettext ("invalid sh_link value in section %Zu"),
+      error (0, 0, gettext ("invalid sh_link value in section %zu"),
             elf_ndxscn (scn));
       return;
     }
@@ -4688,7 +4879,7 @@ print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
       const unsigned char *hdrstart = readp;
       size_t start_offset = hdrstart - (const unsigned char *) data->d_buf;
 
-      printf (gettext ("\nTable at offset %Zu:\n"), start_offset);
+      printf (gettext ("\nTable at offset %zu:\n"), start_offset);
       if (readp + 4 > readendp)
        {
        invalid_data:
@@ -4806,7 +4997,7 @@ print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
       if (readp != nexthdr)
        {
          size_t padding = nexthdr - readp;
-         printf (gettext ("   %Zu padding bytes\n"), padding);
+         printf (gettext ("   %zu padding bytes\n"), padding);
          readp = nexthdr;
        }
     }
@@ -4843,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);
@@ -4876,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;
        }
@@ -4938,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];
@@ -4973,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)
@@ -5315,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)
@@ -5623,8 +5840,8 @@ print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
          struct cieinfo *cie = cies;
          while (cie != NULL)
            if (is_eh_frame
-               ? start - (ptrdiff_t) cie_id == cie->cie_offset
-               : (ptrdiff_t) cie_id == cie->cie_offset)
+               ? ((Dwarf_Off) start - cie_id) == (Dwarf_Off) cie->cie_offset
+               : cie_id == (Dwarf_Off) cie->cie_offset)
              break;
            else
              cie = cie->next;
@@ -5745,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;
     }
 }
@@ -5770,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;
     }
 
@@ -5784,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;
     }
 
@@ -5799,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);
@@ -5854,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:;
@@ -5879,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:
@@ -5928,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;
@@ -5949,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;
@@ -6008,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:
@@ -6016,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:
@@ -6024,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;
@@ -6042,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:
@@ -6079,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;
     }
 
@@ -6109,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 =
@@ -6156,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)
@@ -6187,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;
@@ -6236,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);
@@ -6385,7 +6689,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
     {
       size_t start_offset = linep - (const unsigned char *) data->d_buf;
 
-      printf (gettext ("\nTable at offset %Zu:\n"), start_offset);
+      printf (gettext ("\nTable at offset %zu:\n"), start_offset);
 
       if (unlikely (linep + 4 > lineendp))
        goto invalid_data;
@@ -6903,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);
@@ -6940,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
@@ -6955,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)
            {
@@ -6974,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;
@@ -7241,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;
@@ -7265,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)
        {
@@ -7282,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++;
@@ -7299,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
@@ -7340,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;
@@ -7370,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)
@@ -7385,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)
@@ -7395,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;
@@ -7407,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;
@@ -7419,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)
@@ -7430,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.
@@ -7526,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:
@@ -7912,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"));
        }
 
@@ -8015,9 +8406,16 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
   uint32_t const_off = read_4ubyte_unaligned (dbg, readp);
   printf (gettext (" constant offset: %#" PRIx32 "\n"), const_off);
 
+  if (unlikely ((size_t) (dataend - (const unsigned char *) data->d_buf)
+               < const_off))
+    goto invalid_data;
+
   readp = data->d_buf + cu_off;
 
   const unsigned char *nextp = data->d_buf + tu_off;
+  if (tu_off >= data->d_size)
+    goto invalid_data;
+
   size_t cu_nr = (nextp - readp) / 16;
 
   printf (gettext ("\n CU list at offset %#" PRIx32
@@ -8025,7 +8423,7 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
          cu_off, cu_nr);
 
   size_t n = 0;
-  while (readp + 16 <= dataend && n < cu_nr)
+  while (dataend - readp >= 16 && n < cu_nr)
     {
       uint64_t off = read_8ubyte_unaligned (dbg, readp);
       readp += 8;
@@ -8040,6 +8438,9 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
 
   readp = data->d_buf + tu_off;
   nextp = data->d_buf + addr_off;
+  if (addr_off >= data->d_size)
+    goto invalid_data;
+
   size_t tu_nr = (nextp - readp) / 24;
 
   printf (gettext ("\n TU list at offset %#" PRIx32
@@ -8047,7 +8448,7 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
          tu_off, tu_nr);
 
   n = 0;
-  while (readp + 24 <= dataend && n < tu_nr)
+  while (dataend - readp >= 24 && n < tu_nr)
     {
       uint64_t off = read_8ubyte_unaligned (dbg, readp);
       readp += 8;
@@ -8066,6 +8467,9 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
 
   readp = data->d_buf + addr_off;
   nextp = data->d_buf + sym_off;
+  if (sym_off >= data->d_size)
+    goto invalid_data;
+
   size_t addr_nr = (nextp - readp) / 20;
 
   printf (gettext ("\n Address list at offset %#" PRIx32
@@ -8073,7 +8477,7 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
          addr_off, addr_nr);
 
   n = 0;
-  while (readp + 20 <= dataend && n < addr_nr)
+  while (dataend - readp >= 20 && n < addr_nr)
     {
       uint64_t low = read_8ubyte_unaligned (dbg, readp);
       readp += 8;
@@ -8093,8 +8497,12 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
       n++;
     }
 
+  const unsigned char *const_start = data->d_buf + const_off;
+  if (const_off >= data->d_size)
+    goto invalid_data;
+
   readp = data->d_buf + sym_off;
-  nextp = data->d_buf + const_off;
+  nextp = const_start;
   size_t sym_nr = (nextp - readp) / 8;
 
   printf (gettext ("\n Symbol table at offset %#" PRIx32
@@ -8102,7 +8510,7 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
          addr_off, sym_nr);
 
   n = 0;
-  while (readp + 8 <= dataend && n < sym_nr)
+  while (dataend - readp >= 8 && n < sym_nr)
     {
       uint32_t name = read_4ubyte_unaligned (dbg, readp);
       readp += 4;
@@ -8112,15 +8520,15 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
 
       if (name != 0 || vector != 0)
        {
-         const unsigned char *sym = data->d_buf + const_off + name;
-         if (unlikely (sym > dataend
+         const unsigned char *sym = const_start + name;
+         if (unlikely ((size_t) (dataend - const_start) < name
                        || memchr (sym, '\0', dataend - sym) == NULL))
            goto invalid_data;
 
          printf (" [%4zu] symbol: %s, CUs: ", n, sym);
 
-         const unsigned char *readcus = data->d_buf + const_off + vector;
-         if (unlikely (readcus + 4 > dataend))
+         const unsigned char *readcus = const_start + vector;
+         if (unlikely ((size_t) (dataend - const_start) < vector))
            goto invalid_data;
          uint32_t cus = read_4ubyte_unaligned (dbg, readcus);
          while (cus--)
@@ -8186,8 +8594,6 @@ print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr)
       if ((print_debug_sections & ~section_exception) != 0)
        error (0, 0, gettext ("cannot get debug context descriptor: %s"),
               dwfl_errmsg (-1));
-      if ((print_debug_sections & section_exception) == 0)
-       return;
       dbg = &dummy_dbg;
     }
 
@@ -8246,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)
@@ -8356,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);                            \
@@ -8365,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)
@@ -8400,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
@@ -8416,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
@@ -8461,8 +8873,16 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
            unsigned int w = negate ? ~*i : *i;
            while (w != 0)
              {
-               int n = ffs (w);
-               w >>= n;
+               /* Note that a right shift equal to (or greater than)
+                  the number of bits of w is undefined behaviour.  In
+                  particular when the least significant bit is bit 32
+                  (w = 0x8000000) then w >>= n is undefined.  So
+                  explicitly handle that case separately.  */
+               unsigned int n = ffs (w);
+               if (n < sizeof (w) * 8)
+                 w >>= n;
+               else
+                 w = 0;
                bit += n;
 
                if (lastbit != 0 && lastbit + 1 == bit)
@@ -8498,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
@@ -8529,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':
@@ -8980,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 */
@@ -9089,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))
@@ -9103,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)
@@ -9211,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];
@@ -9265,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
@@ -9334,7 +9754,7 @@ hex_dump (const uint8_t *data, size_t len)
   size_t pos = 0;
   while (pos < len)
     {
-      printf ("  0x%08Zx ", pos);
+      printf ("  0x%08zx ", pos);
 
       const size_t chunk = MIN (len - pos, 16);
 
@@ -9362,20 +9782,48 @@ static void
 dump_data_section (Elf_Scn *scn, const GElf_Shdr *shdr, const char *name)
 {
   if (shdr->sh_size == 0 || shdr->sh_type == SHT_NOBITS)
-    printf (gettext ("\nSection [%Zu] '%s' has no data to dump.\n"),
+    printf (gettext ("\nSection [%zu] '%s' has no data to dump.\n"),
            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"),
+       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);
        }
     }
@@ -9385,20 +9833,48 @@ static void
 print_string_section (Elf_Scn *scn, const GElf_Shdr *shdr, const char *name)
 {
   if (shdr->sh_size == 0 || shdr->sh_type == SHT_NOBITS)
-    printf (gettext ("\nSection [%Zu] '%s' has no strings to dump.\n"),
+    printf (gettext ("\nSection [%zu] '%s' has no strings to dump.\n"),
            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"),
+       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;
@@ -9408,11 +9884,11 @@ print_string_section (Elf_Scn *scn, const GElf_Shdr *shdr, const char *name)
              const size_t pos = start - (const char *) data->d_buf;
              if (unlikely (end == NULL))
                {
-                 printf ("  [%6Zx]- %.*s\n",
+                 printf ("  [%6zx]- %.*s\n",
                          pos, (int) (limit - start), start);
                  break;
                }
-             printf ("  [%6Zx]  %s\n", pos, start);
+             printf ("  [%6zx]  %s\n", pos, start);
              start = end + 1;
            } while (start < limit);
        }
@@ -9536,7 +10012,7 @@ dump_archive_index (Elf *elf, const char *fname)
       return;
     }
 
-  printf (gettext ("\nIndex of archive '%s' has %Zu entries:\n"),
+  printf (gettext ("\nIndex of archive '%s' has %zu entries:\n"),
          fname, narsym);
 
   size_t as_off = 0;
@@ -9546,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))
@@ -9554,7 +10030,7 @@ dump_archive_index (Elf *elf, const char *fname)
            while (1)
 #endif
              error (EXIT_FAILURE, 0,
-                    gettext ("cannot extract member at offset %Zu in '%s': %s"),
+                    gettext ("cannot extract member at offset %zu in '%s': %s"),
                     as_off, fname, elf_errmsg (-1));
 
          const Elf_Arhdr *h = elf_getarhdr (subelf);