gdb/testsuite: use with_cwd where possible
[binutils-gdb.git] / binutils / readelf.c
index cf3168f4a8e16118563527125c3a4317d62db1ff..d45e09207880d0fa7c314108e0f64997feb9dd20 100644 (file)
@@ -1,5 +1,5 @@
 /* readelf.c -- display contents of an ELF format file
-   Copyright (C) 1998-2021 Free Software Foundation, Inc.
+   Copyright (C) 1998-2022 Free Software Foundation, Inc.
 
    Originally developed by Eric Youngdale <eric@andante.jic.com>
    Modifications by Nick Clifton <nickc@redhat.com>
 #include <zlib.h>
 #include <wchar.h>
 
+#if defined HAVE_MSGPACK
+#include <msgpack.h>
+#endif
+
 #if __GNUC__ >= 2
 /* Define BFD64 here, even if our default architecture is 32 bit ELF
    as this will allow us to read in and parse 64bit and 32bit ELF files.
@@ -57,6 +61,7 @@
 #include "bfd.h"
 #include "bucomm.h"
 #include "elfcomm.h"
+#include "demanguse.h"
 #include "dwarf.h"
 #include "ctf-api.h"
 #include "demangle.h"
@@ -91,6 +96,7 @@
 
 #include "elf/aarch64.h"
 #include "elf/alpha.h"
+#include "elf/amdgpu.h"
 #include "elf/arc.h"
 #include "elf/arm.h"
 #include "elf/avr.h"
@@ -238,6 +244,7 @@ static bool decompress_dumps = false;
 static bool do_not_show_symbol_truncation = false;
 static bool do_demangle = false;       /* Pretty print C++ symbol names.  */
 static bool process_links = false;
+static bool dump_any_debugging = false;
 static int demangle_flags = DMGL_ANSI | DMGL_PARAMS;
 static int sym_base = 0;
 
@@ -329,6 +336,26 @@ typedef enum print_mode
 }
 print_mode;
 
+typedef enum unicode_display_type
+{
+  unicode_default = 0,
+  unicode_locale,
+  unicode_escape,
+  unicode_hex,
+  unicode_highlight,
+  unicode_invalid
+} unicode_display_type;
+
+static unicode_display_type unicode_display = unicode_default;
+
+typedef enum
+{
+  reltype_unknown,
+  reltype_rel,
+  reltype_rela,
+  reltype_relr
+} relocation_type;
+
 /* Versioned symbol info.  */
 enum versioned_symbol_info
 {
@@ -656,11 +683,18 @@ print_symbol (signed int width, const char * symbol)
       if (c == 0)
        break;
 
-      /* Do not print control characters directly as they can affect terminal
-        settings.  Such characters usually appear in the names generated
-        by the assembler for local labels.  */
-      if (ISCNTRL (c))
+      if (ISPRINT (c))
+       {
+         putchar (c);
+         width_remaining --;
+         num_printed ++;
+       }
+      else if (ISCNTRL (c))
        {
+         /* Do not print control characters directly as they can affect terminal
+            settings.  Such characters usually appear in the names generated
+            by the assembler for local labels.  */
+
          if (width_remaining < 2)
            break;
 
@@ -668,11 +702,137 @@ print_symbol (signed int width, const char * symbol)
          width_remaining -= 2;
          num_printed += 2;
        }
-      else if (ISPRINT (c))
+      else if (c == 0x7f)
        {
-         putchar (c);
-         width_remaining --;
-         num_printed ++;
+         if (width_remaining < 5)
+           break;
+         printf ("<DEL>");
+         width_remaining -= 5;
+         num_printed += 5;
+       }
+      else if (unicode_display != unicode_locale
+              && unicode_display != unicode_default)
+       {
+         /* Display unicode characters as something else.  */
+         unsigned char bytes[4];
+         bool          is_utf8;
+         unsigned int  nbytes;
+
+         bytes[0] = c;
+
+         if (bytes[0] < 0xc0)
+           {
+             nbytes = 1;
+             is_utf8 = false;
+           }
+         else
+           {
+             bytes[1] = *symbol++;
+
+             if ((bytes[1] & 0xc0) != 0x80)
+               {
+                 is_utf8 = false;
+                 /* Do not consume this character.  It may only
+                    be the first byte in the sequence that was
+                    corrupt.  */
+                 --symbol;
+                 nbytes = 1;
+               }
+             else if ((bytes[0] & 0x20) == 0)
+               {
+                 is_utf8 = true;
+                 nbytes = 2;
+               }
+             else
+               {
+                 bytes[2] = *symbol++;
+
+                 if ((bytes[2] & 0xc0) != 0x80)
+                   {
+                     is_utf8 = false;
+                     symbol -= 2;
+                     nbytes = 1;
+                   }
+                 else if ((bytes[0] & 0x10) == 0)
+                   {
+                     is_utf8 = true;
+                     nbytes = 3;
+                   }
+                 else
+                   {
+                     bytes[3] = *symbol++;
+
+                     nbytes = 4;
+
+                     if ((bytes[3] & 0xc0) != 0x80)
+                       {
+                         is_utf8 = false;
+                         symbol -= 3;
+                         nbytes = 1;
+                       }
+                     else
+                       is_utf8 = true;
+                   }
+               }
+           }
+
+         if (unicode_display == unicode_invalid)
+           is_utf8 = false;
+
+         if (unicode_display == unicode_hex || ! is_utf8)
+           {
+             unsigned int i;
+
+             if (width_remaining < (nbytes * 2) + 2)
+               break;
+         
+             putchar (is_utf8 ? '<' : '{');
+             printf ("0x");
+             for (i = 0; i < nbytes; i++)
+               printf ("%02x", bytes[i]);
+             putchar (is_utf8 ? '>' : '}');
+           }
+         else
+           {
+             if (unicode_display == unicode_highlight && isatty (1))
+               printf ("\x1B[31;47m"); /* Red.  */
+             
+             switch (nbytes)
+               {
+               case 2:
+                 if (width_remaining < 6)
+                   break;
+                 printf ("\\u%02x%02x",
+                         (bytes[0] & 0x1c) >> 2, 
+                         ((bytes[0] & 0x03) << 6) | (bytes[1] & 0x3f));
+                 break;
+               case 3:
+                 if (width_remaining < 6)
+                   break;
+                 printf ("\\u%02x%02x",
+                         ((bytes[0] & 0x0f) << 4) | ((bytes[1] & 0x3c) >> 2),
+                         ((bytes[1] & 0x03) << 6) | (bytes[2] & 0x3f));
+                 break;
+               case 4:
+                 if (width_remaining < 8)
+                   break;
+                 printf ("\\u%02x%02x%02x",
+                         ((bytes[0] & 0x07) << 6) | ((bytes[1] & 0x3c) >> 2),
+                         ((bytes[1] & 0x03) << 6) | ((bytes[2] & 0x3c) >> 2),
+                         ((bytes[2] & 0x03) << 6) | (bytes[3] & 0x3f));
+                 
+                 break;
+               default:
+                 /* URG.  */
+                 break;
+               }
+
+             if (unicode_display == unicode_highlight && isatty (1))
+               printf ("\033[0m"); /* Default colour.  */
+           }
+         
+         if (bytes[nbytes - 1] == 0)
+           break;
        }
       else
        {
@@ -1207,6 +1367,76 @@ slurp_rel_relocs (Filedata *            filedata,
   return true;
 }
 
+static bool
+slurp_relr_relocs (Filedata * filedata,
+                  unsigned long relr_offset,
+                  unsigned long relr_size,
+                  bfd_vma ** relrsp,
+                  unsigned long * nrelrsp)
+{
+  void *relrs;
+  size_t size = 0, nentries, i;
+  bfd_vma base = 0, addr, entry;
+
+  relrs = get_data (NULL, filedata, relr_offset, 1, relr_size,
+                   _("RELR relocation data"));
+  if (!relrs)
+    return false;
+
+  if (is_32bit_elf)
+    nentries = relr_size / sizeof (Elf32_External_Relr);
+  else
+    nentries = relr_size / sizeof (Elf64_External_Relr);
+  for (i = 0; i < nentries; i++)
+    {
+      if (is_32bit_elf)
+       entry = BYTE_GET (((Elf32_External_Relr *)relrs)[i].r_data);
+      else
+       entry = BYTE_GET (((Elf64_External_Relr *)relrs)[i].r_data);
+      if ((entry & 1) == 0)
+       size++;
+      else
+       while ((entry >>= 1) != 0)
+         if ((entry & 1) == 1)
+           size++;
+    }
+
+  *relrsp = (bfd_vma *) xmalloc (size * sizeof (bfd_vma));
+  if (*relrsp == NULL)
+    {
+      free (relrs);
+      error (_("out of memory parsing relocs\n"));
+      return false;
+    }
+
+  size = 0;
+  for (i = 0; i < nentries; i++)
+    {
+      const bfd_vma entry_bytes = is_32bit_elf ? 4 : 8;
+
+      if (is_32bit_elf)
+       entry = BYTE_GET (((Elf32_External_Relr *)relrs)[i].r_data);
+      else
+       entry = BYTE_GET (((Elf64_External_Relr *)relrs)[i].r_data);
+      if ((entry & 1) == 0)
+       {
+         (*relrsp)[size++] = entry;
+         base = entry + entry_bytes;
+       }
+      else
+       {
+         for (addr = base; (entry >>= 1) != 0; addr += entry_bytes)
+           if ((entry & 1) != 0)
+             (*relrsp)[size++] = addr;
+         base += entry_bytes * (entry_bytes * CHAR_BIT - 1);
+       }
+    }
+
+  *nrelrsp = size;
+  free (relrs);
+  return true;
+}
+
 /* Returns the reloc type extracted from the reloc info field.  */
 
 static unsigned int
@@ -1259,30 +1489,46 @@ dump_relocations (Filedata *          filedata,
                  unsigned long       nsyms,
                  char *              strtab,
                  unsigned long       strtablen,
-                 int                 is_rela,
+                 relocation_type     rel_type,
                  bool                is_dynsym)
 {
   unsigned long i;
   Elf_Internal_Rela * rels;
   bool res = true;
 
-  if (is_rela == UNKNOWN)
-    is_rela = guess_is_rela (filedata->file_header.e_machine);
+  if (rel_type == reltype_unknown)
+    rel_type = guess_is_rela (filedata->file_header.e_machine) ? reltype_rela : reltype_rel;
 
-  if (is_rela)
+  if (rel_type == reltype_rela)
     {
       if (!slurp_rela_relocs (filedata, rel_offset, rel_size, &rels, &rel_size))
        return false;
     }
-  else
+  else if (rel_type == reltype_rel)
     {
       if (!slurp_rel_relocs (filedata, rel_offset, rel_size, &rels, &rel_size))
        return false;
     }
+  else if (rel_type == reltype_relr)
+    {
+      bfd_vma * relrs;
+      const char *format
+         = is_32bit_elf ? "%08" BFD_VMA_FMT "x\n" : "%016" BFD_VMA_FMT "x\n";
+
+      if (!slurp_relr_relocs (filedata, rel_offset, rel_size, &relrs,
+                             &rel_size))
+       return false;
+
+      printf (ngettext ("  %lu offset\n", "  %lu offsets\n", rel_size), rel_size);
+      for (i = 0; i < rel_size; i++)
+       printf (format, relrs[i]);
+      free (relrs);
+      return true;
+    }
 
   if (is_32bit_elf)
     {
-      if (is_rela)
+      if (rel_type == reltype_rela)
        {
          if (do_wide)
            printf (_(" Offset     Info    Type                Sym. Value  Symbol's Name + Addend\n"));
@@ -1299,7 +1545,7 @@ dump_relocations (Filedata *          filedata,
     }
   else
     {
-      if (is_rela)
+      if (rel_type == reltype_rela)
        {
          if (do_wide)
            printf (_("    Offset             Info             Type               Symbol's Value  Symbol's Name + Addend\n"));
@@ -1684,6 +1930,9 @@ dump_relocations (Filedata *          filedata,
          rtype = elf_loongarch_reloc_type (type);
          break;
 
+       case EM_AMDGPU:
+         rtype = elf_amdgpu_reloc_type (type);
+         break;
        }
 
       if (rtype == NULL)
@@ -1694,7 +1943,7 @@ dump_relocations (Filedata *          filedata,
       if (filedata->file_header.e_machine == EM_ALPHA
          && rtype != NULL
          && streq (rtype, "R_ALPHA_LITUSE")
-         && is_rela)
+         && rel_type == reltype_rela)
        {
          switch (rels[i].r_addend)
            {
@@ -1788,7 +2037,8 @@ dump_relocations (Filedata *          filedata,
 
                  if (ELF_ST_TYPE (psym->st_info) == STT_SECTION)
                    {
-                     if (psym->st_shndx < filedata->file_header.e_shnum)
+                     if (psym->st_shndx < filedata->file_header.e_shnum
+                         && filedata->section_headers != NULL)
                        sec_name = section_name_print (filedata,
                                                       filedata->section_headers
                                                       + psym->st_shndx);
@@ -1841,7 +2091,7 @@ dump_relocations (Filedata *          filedata,
                            version_string);
                }
 
-             if (is_rela)
+             if (rel_type == reltype_rela)
                {
                  bfd_vma off = rels[i].r_addend;
 
@@ -1852,7 +2102,7 @@ dump_relocations (Filedata *          filedata,
                }
            }
        }
-      else if (is_rela)
+      else if (rel_type == reltype_rela)
        {
          bfd_vma off = rels[i].r_addend;
 
@@ -2201,6 +2451,17 @@ get_solaris_dynamic_type (unsigned long type)
     }
 }
 
+static const char *
+get_riscv_dynamic_type (unsigned long type)
+{
+  switch (type)
+    {
+    case DT_RISCV_VARIANT_CC:  return "RISCV_VARIANT_CC";
+    default:
+      return NULL;
+    }
+}
+
 static const char *
 get_dynamic_type (Filedata * filedata, unsigned long type)
 {
@@ -2326,6 +2587,9 @@ get_dynamic_type (Filedata * filedata, unsigned long type)
            case EM_ALTERA_NIOS2:
              result = get_nios2_dynamic_type (type);
              break;
+           case EM_RISCV:
+             result = get_riscv_dynamic_type (type);
+             break;
            default:
              if (filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_SOLARIS)
                result = get_solaris_dynamic_type (type);
@@ -3309,6 +3573,153 @@ decode_NDS32_machine_flags (unsigned e_flags, char buf[], size_t size)
     r += snprintf (buf + r, size -r, ", L2C");
 }
 
+static void
+decode_AMDGPU_machine_flags (Filedata *filedata, unsigned int e_flags,
+                            char *buf)
+{
+  unsigned char *e_ident = filedata->file_header.e_ident;
+  unsigned char osabi = e_ident[EI_OSABI];
+  unsigned char abiversion = e_ident[EI_ABIVERSION];
+  unsigned int mach;
+
+  /* HSA OS ABI v2 used a different encoding, but we don't need to support it,
+     it has been deprecated for a while.
+
+     The PAL, MESA3D and NONE OS ABIs are not properly versioned, at the time
+     of writing, they use the same flags as HSA v3, so the code below uses that
+     assumption.  */
+  if (osabi == ELFOSABI_AMDGPU_HSA && abiversion < ELFABIVERSION_AMDGPU_HSA_V3)
+    return;
+
+  mach = e_flags & EF_AMDGPU_MACH;
+  switch (mach)
+    {
+#define AMDGPU_CASE(code, string) \
+  case code: strcat (buf, ", " string); break;
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX600, "gfx600")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX601, "gfx601")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX700, "gfx700")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX701, "gfx701")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX702, "gfx702")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX703, "gfx703")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX704, "gfx704")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX801, "gfx801")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX802, "gfx802")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX803, "gfx803")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX810, "gfx810")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX900, "gfx900")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX902, "gfx902")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX904, "gfx904")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX906, "gfx906")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX908, "gfx908")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX909, "gfx909")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX90C, "gfx90c")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX1010, "gfx1010")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX1011, "gfx1011")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX1012, "gfx1012")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX1030, "gfx1030")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX1031, "gfx1031")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX1032, "gfx1032")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX1033, "gfx1033")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX602, "gfx602")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX705, "gfx705")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX805, "gfx805")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX1035, "gfx1035")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX1034, "gfx1034")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX90A, "gfx90a")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX940, "gfx940")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX1013, "gfx1013")
+    AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX1036, "gfx1036")
+    default:
+      sprintf (buf, _(", <unknown AMDGPU GPU type: %#x>"), mach);
+      break;
+#undef AMDGPU_CASE
+    }
+
+  buf += strlen (buf);
+  e_flags &= ~EF_AMDGPU_MACH;
+
+  if ((osabi == ELFOSABI_AMDGPU_HSA
+       && abiversion == ELFABIVERSION_AMDGPU_HSA_V3)
+      || osabi != ELFOSABI_AMDGPU_HSA)
+    {
+      /* For HSA v3 and other OS ABIs.  */
+      if (e_flags & EF_AMDGPU_FEATURE_XNACK_V3)
+       {
+         strcat (buf, ", xnack on");
+         buf += strlen (buf);
+         e_flags &= ~EF_AMDGPU_FEATURE_XNACK_V3;
+       }
+
+      if (e_flags & EF_AMDGPU_FEATURE_SRAMECC_V3)
+       {
+         strcat (buf, ", sramecc on");
+         buf += strlen (buf);
+         e_flags &= ~EF_AMDGPU_FEATURE_SRAMECC_V3;
+       }
+    }
+  else
+    {
+      /* For HSA v4+.  */
+      int xnack, sramecc;
+
+      xnack = e_flags & EF_AMDGPU_FEATURE_XNACK_V4;
+      switch (xnack)
+       {
+       case EF_AMDGPU_FEATURE_XNACK_UNSUPPORTED_V4:
+         break;
+
+       case EF_AMDGPU_FEATURE_XNACK_ANY_V4:
+         strcat (buf, ", xnack any");
+         break;
+
+       case EF_AMDGPU_FEATURE_XNACK_OFF_V4:
+         strcat (buf, ", xnack off");
+         break;
+
+       case EF_AMDGPU_FEATURE_XNACK_ON_V4:
+         strcat (buf, ", xnack on");
+         break;
+
+       default:
+         sprintf (buf, _(", <unknown xnack value: %#x>"), xnack);
+         break;
+       }
+
+      buf += strlen (buf);
+      e_flags &= ~EF_AMDGPU_FEATURE_XNACK_V4;
+
+      sramecc = e_flags & EF_AMDGPU_FEATURE_SRAMECC_V4;
+      switch (sramecc)
+       {
+       case EF_AMDGPU_FEATURE_SRAMECC_UNSUPPORTED_V4:
+         break;
+
+       case EF_AMDGPU_FEATURE_SRAMECC_ANY_V4:
+         strcat (buf, ", sramecc any");
+         break;
+
+       case EF_AMDGPU_FEATURE_SRAMECC_OFF_V4:
+         strcat (buf, ", sramecc off");
+         break;
+
+       case EF_AMDGPU_FEATURE_SRAMECC_ON_V4:
+         strcat (buf, ", sramecc on");
+         break;
+
+       default:
+         sprintf (buf, _(", <unknown sramecc value: %#x>"), sramecc);
+         break;
+       }
+
+      buf += strlen (buf);
+      e_flags &= ~EF_AMDGPU_FEATURE_SRAMECC_V4;
+    }
+
+  if (e_flags != 0)
+    sprintf (buf, _(", unknown flags bits: %#x"), e_flags);
+}
+
 static char *
 get_machine_flags (Filedata * filedata, unsigned e_flags, unsigned e_machine)
 {
@@ -3461,6 +3872,10 @@ get_machine_flags (Filedata * filedata, unsigned e_flags, unsigned e_machine)
            }
          break;
 
+       case EM_AMDGPU:
+         decode_AMDGPU_machine_flags (filedata, e_flags, buf);
+         break;
+
        case EM_CYGNUS_MEP:
          switch (e_flags & EF_MEP_CPU_MASK)
            {
@@ -4028,6 +4443,17 @@ get_osabi_name (Filedata * filedata, unsigned int osabi)
       if (osabi >= 64)
        switch (filedata->file_header.e_machine)
          {
+         case EM_AMDGPU:
+           switch (osabi)
+             {
+             case ELFOSABI_AMDGPU_HSA:    return "AMD HSA";
+             case ELFOSABI_AMDGPU_PAL:    return "AMD PAL";
+             case ELFOSABI_AMDGPU_MESA3D: return "AMD Mesa3D";
+             default:
+               break;
+             }
+           break;
+
          case EM_ARM:
            switch (osabi)
              {
@@ -4731,6 +5157,7 @@ static struct option options[] =
   {"syms",            no_argument, 0, 's'},
   {"silent-truncation",no_argument, 0, 'T'},
   {"section-details",  no_argument, 0, 't'},
+  {"unicode",          required_argument, NULL, 'U'},
   {"unwind",          no_argument, 0, 'u'},
   {"version-info",     no_argument, 0, 'V'},
   {"version",         no_argument, 0, 'v'},
@@ -4796,16 +5223,21 @@ usage (FILE * stream)
                          Force base for symbol sizes.  The options are \n\
                          mixed (the default), octal, decimal, hexadecimal.\n"));
   fprintf (stream, _("\
-  -C --demangle[=STYLE]  Decode low-level symbol names into user-level names\n\
-                          The STYLE, if specified, can be `auto' (the default),\n\
-                          `gnu', `lucid', `arm', `hp', `edg', `gnu-v3', `java'\n\
-                          or `gnat'\n"));
+  -C --demangle[=STYLE]  Decode mangled/processed symbol names\n"));
+  display_demangler_styles (stream, _("\
+                           STYLE can be "));
   fprintf (stream, _("\
      --no-demangle       Do not demangle low-level symbol names.  (default)\n"));
   fprintf (stream, _("\
      --recurse-limit     Enable a demangling recursion limit.  (default)\n"));
   fprintf (stream, _("\
      --no-recurse-limit  Disable a demangling recursion limit\n"));
+  fprintf (stream, _("\
+     -U[dlexhi] --unicode=[default|locale|escape|hex|highlight|invalid]\n\
+                         Display unicode characters as determined by the current locale\n\
+                          (default), escape sequences, \"<hex sequences>\", highlighted\n\
+                          escape sequences, or treat them as invalid and display as\n\
+                          \"{hex sequences}\"\n"));
   fprintf (stream, _("\
   -n --notes             Display the core notes (if present)\n"));
   fprintf (stream, _("\
@@ -4864,6 +5296,14 @@ usage (FILE * stream)
   -wN --debug-dump=no-follow-links\n\
                          Do not follow links to separate debug info files\n\
                           (default)\n"));
+#endif
+#if HAVE_LIBDEBUGINFOD
+  fprintf (stream, _("\
+  -wD --debug-dump=use-debuginfod\n\
+                         When following links, also query debuginfod servers (default)\n"));
+  fprintf (stream, _("\
+  -wE --debug-dump=do-not-use-debuginfod\n\
+                         When following links, do not query debuginfod servers\n"));
 #endif
   fprintf (stream, _("\
   --dwarf-depth=N        Do not display DIEs at depth N or greater\n"));
@@ -4990,7 +5430,7 @@ parse_args (struct dump_data *dumpdata, int argc, char ** argv)
     usage (stderr);
 
   while ((c = getopt_long
-         (argc, argv, "ACDHILNPR:STVWacdeghi:lnp:rstuvw::x:z", options, NULL)) != EOF)
+         (argc, argv, "ACDHILNPR:STU:VWacdeghi:lnp:rstuvw::x:z", options, NULL)) != EOF)
     {
       switch (c)
        {
@@ -5071,6 +5511,7 @@ parse_args (struct dump_data *dumpdata, int argc, char ** argv)
        case 'P':
          process_links = true;
          do_follow_links = true;
+         dump_any_debugging = true;
          break;
        case 'x':
          request_dump (dumpdata, HEX_DUMP);
@@ -5086,6 +5527,7 @@ parse_args (struct dump_data *dumpdata, int argc, char ** argv)
          break;
        case 'w':
          do_dump = true;
+         dump_any_debugging = true;
          if (optarg == NULL)
            {
              do_debugging = true;
@@ -5099,6 +5541,7 @@ parse_args (struct dump_data *dumpdata, int argc, char ** argv)
          break;
        case OPTION_DEBUG_DUMP:
          do_dump = true;
+         dump_any_debugging = true;
          if (optarg == NULL)
            {
              do_debugging = true;
@@ -5192,6 +5635,25 @@ parse_args (struct dump_data *dumpdata, int argc, char ** argv)
          /* Ignored for backward compatibility.  */
          break;
 
+       case 'U':
+         if (optarg == NULL)
+           error (_("Missing arg to -U/--unicode")); /* Can this happen ?  */
+         else if (streq (optarg, "default") || streq (optarg, "d"))
+           unicode_display = unicode_default;
+         else if (streq (optarg, "locale") || streq (optarg, "l"))
+           unicode_display = unicode_locale;
+         else if (streq (optarg, "escape") || streq (optarg, "e"))
+           unicode_display = unicode_escape;
+         else if (streq (optarg, "invalid") || streq (optarg, "i"))
+           unicode_display = unicode_invalid;
+         else if (streq (optarg, "hex") || streq (optarg, "x"))
+           unicode_display = unicode_hex;
+         else if (streq (optarg, "highlight") || streq (optarg, "h"))
+           unicode_display = unicode_highlight;
+         else
+           error (_("invalid argument to -U/--unicode: %s"), optarg);
+         break;
+
        case OPTION_SYM_BASE:
          sym_base = 0;
          if (optarg != NULL)
@@ -5347,10 +5809,7 @@ process_file_header (Filedata * filedata)
       if (filedata->section_headers != NULL
          && header->e_phnum == PN_XNUM
          && filedata->section_headers[0].sh_info != 0)
-       {
-         header->e_phnum = filedata->section_headers[0].sh_info;
-         printf (" (%u)", header->e_phnum);
-       }
+       printf (" (%u)", filedata->section_headers[0].sh_info);
       putc ('\n', stdout);
       printf (_("  Size of section headers:           %u (bytes)\n"),
              header->e_shentsize);
@@ -5383,7 +5842,12 @@ process_file_header (Filedata * filedata)
     {
       if (header->e_phnum == PN_XNUM
          && filedata->section_headers[0].sh_info != 0)
-       header->e_phnum = filedata->section_headers[0].sh_info;
+       {
+         /* Throw away any cached read of PN_XNUM headers.  */
+         free (filedata->program_headers);
+         filedata->program_headers = NULL;
+         header->e_phnum = filedata->section_headers[0].sh_info;
+       }
       if (header->e_shnum == SHN_UNDEF)
        header->e_shnum = filedata->section_headers[0].sh_size;
       if (header->e_shstrndx == (SHN_XINDEX & 0xffff))
@@ -6813,6 +7277,10 @@ process_section_headers (Filedata * filedata)
            warn (_("Section '%s': zero-sized relocation section\n"), name);
          break;
 
+       case SHT_RELR:
+         CHECK_ENTSIZE (section, i, Relr);
+         break;
+
        case SHT_NOTE:
        case SHT_PROGBITS:
          /* Having a zero sized section is not illegal according to the
@@ -7848,13 +8316,14 @@ static struct
   const char * name;
   int reloc;
   int size;
-  int rela;
+  relocation_type rel_type;
 }
   dynamic_relocations [] =
 {
-  { "REL", DT_REL, DT_RELSZ, false },
-  { "RELA", DT_RELA, DT_RELASZ, true },
-  { "PLT", DT_JMPREL, DT_PLTRELSZ, UNKNOWN }
+  { "REL", DT_REL, DT_RELSZ, reltype_rel },
+  { "RELA", DT_RELA, DT_RELASZ, reltype_rela },
+  { "RELR", DT_RELR, DT_RELRSZ, reltype_relr },
+  { "PLT", DT_JMPREL, DT_PLTRELSZ, reltype_unknown }
 };
 
 /* Process the reloc section.  */
@@ -7870,7 +8339,7 @@ process_relocs (Filedata * filedata)
 
   if (do_using_dynamic)
     {
-      int          is_rela;
+      relocation_type rel_type;
       const char * name;
       bool  has_dynamic_reloc;
       unsigned int i;
@@ -7879,7 +8348,7 @@ process_relocs (Filedata * filedata)
 
       for (i = 0; i < ARRAY_SIZE (dynamic_relocations); i++)
        {
-         is_rela = dynamic_relocations [i].rela;
+         rel_type = dynamic_relocations [i].rel_type;
          name = dynamic_relocations [i].name;
          rel_size = filedata->dynamic_info[dynamic_relocations [i].size];
          rel_offset = filedata->dynamic_info[dynamic_relocations [i].reloc];
@@ -7887,16 +8356,16 @@ process_relocs (Filedata * filedata)
          if (rel_size)
            has_dynamic_reloc = true;
 
-         if (is_rela == UNKNOWN)
+         if (rel_type == reltype_unknown)
            {
              if (dynamic_relocations [i].reloc == DT_JMPREL)
                switch (filedata->dynamic_info[DT_PLTREL])
                  {
                  case DT_REL:
-                   is_rela = false;
+                   rel_type = reltype_rel;
                    break;
                  case DT_RELA:
-                   is_rela = true;
+                   rel_type = reltype_rela;
                    break;
                  }
            }
@@ -7919,7 +8388,7 @@ process_relocs (Filedata * filedata)
                                filedata->num_dynamic_syms,
                                filedata->dynamic_strings,
                                filedata->dynamic_strings_length,
-                               is_rela, true /* is_dynamic */);
+                               rel_type, true /* is_dynamic */);
            }
        }
 
@@ -7947,7 +8416,8 @@ process_relocs (Filedata * filedata)
           i++, section++)
        {
          if (   section->sh_type != SHT_RELA
-             && section->sh_type != SHT_REL)
+             && section->sh_type != SHT_REL
+             && section->sh_type != SHT_RELR)
            continue;
 
          rel_offset = section->sh_offset;
@@ -7955,7 +8425,7 @@ process_relocs (Filedata * filedata)
 
          if (rel_size)
            {
-             int is_rela;
+             relocation_type rel_type;
              unsigned long num_rela;
 
              if (filedata->is_separate)
@@ -7975,7 +8445,8 @@ process_relocs (Filedata * filedata)
                                num_rela),
                      rel_offset, num_rela);
 
-             is_rela = section->sh_type == SHT_RELA;
+             rel_type = section->sh_type == SHT_RELA ? reltype_rela :
+               section->sh_type == SHT_REL ? reltype_rel : reltype_relr;
 
              if (section->sh_link != 0
                  && section->sh_link < filedata->file_header.e_shnum)
@@ -7997,15 +8468,14 @@ process_relocs (Filedata * filedata)
 
                  dump_relocations (filedata, rel_offset, rel_size,
                                    symtab, nsyms, strtab, strtablen,
-                                   is_rela,
+                                   rel_type,
                                    symsec->sh_type == SHT_DYNSYM);
                  free (strtab);
                  free (symtab);
                }
              else
                dump_relocations (filedata, rel_offset, rel_size,
-                                 NULL, 0, NULL, 0, is_rela,
-                                 false /* is_dynamic */);
+                                 NULL, 0, NULL, 0, rel_type, false /* is_dynamic */);
 
              found = true;
            }
@@ -11005,12 +11475,12 @@ the .dynstr section doesn't match the DT_STRTAB and DT_STRSZ tags\n"));
                filedata->file_name,
                filedata->dynamic_addr,
                (unsigned long) filedata->dynamic_nent);
-         else
-           printf (ngettext ("\nDynamic section at offset 0x%lx contains %lu entry:\n",
-                             "\nDynamic section at offset 0x%lx contains %lu entries:\n",
-                             (unsigned long) filedata->dynamic_nent),
-                   filedata->dynamic_addr,
-                   (unsigned long) filedata->dynamic_nent);
+      else
+       printf (ngettext ("\nDynamic section at offset 0x%lx contains %lu entry:\n",
+                         "\nDynamic section at offset 0x%lx contains %lu entries:\n",
+                         (unsigned long) filedata->dynamic_nent),
+               filedata->dynamic_addr,
+               (unsigned long) filedata->dynamic_nent);
     }
   if (do_dynamic)
     printf (_("  Tag        Type                         Name/Value\n"));
@@ -11326,6 +11796,7 @@ the .dynstr section doesn't match the DT_STRTAB and DT_STRSZ tags\n"));
        case DT_RPATH   :
        case DT_SYMBOLIC:
        case DT_REL     :
+       case DT_RELR    :
        case DT_DEBUG   :
        case DT_TEXTREL :
        case DT_JMPREL  :
@@ -11382,6 +11853,8 @@ the .dynstr section doesn't match the DT_STRTAB and DT_STRSZ tags\n"));
        case DT_STRSZ   :
        case DT_RELSZ   :
        case DT_RELAENT :
+       case DT_RELRENT :
+       case DT_RELRSZ  :
        case DT_SYMENT  :
        case DT_RELENT  :
          filedata->dynamic_info[entry->d_tag] = entry->d_un.d_val;
@@ -11389,8 +11862,6 @@ the .dynstr section doesn't match the DT_STRTAB and DT_STRSZ tags\n"));
        case DT_PLTPADSZ:
        case DT_MOVEENT :
        case DT_MOVESZ  :
-       case DT_RELRENT :
-       case DT_RELRSZ  :
        case DT_PREINIT_ARRAYSZ:
        case DT_INIT_ARRAYSZ:
        case DT_FINI_ARRAYSZ:
@@ -12374,6 +12845,28 @@ get_ppc64_symbol_other (unsigned int other)
   return NULL;
 }
 
+static const char *
+get_riscv_symbol_other (unsigned int other)
+{
+  static char buf[32];
+  buf[0] = 0;
+
+  if (other & STO_RISCV_VARIANT_CC)
+    {
+      strcat (buf, _(" VARIANT_CC"));
+      other &= ~STO_RISCV_VARIANT_CC;
+    }
+
+  if (other != 0)
+    snprintf (buf, sizeof buf, " %x", other);
+
+
+  if (buf[0] != 0)
+    return buf + 1;
+  else
+    return buf;
+}
+
 static const char *
 get_symbol_other (Filedata * filedata, unsigned int other)
 {
@@ -12400,6 +12893,9 @@ get_symbol_other (Filedata * filedata, unsigned int other)
     case EM_PPC64:
       result = get_ppc64_symbol_other (other);
       break;
+    case EM_RISCV:
+      result = get_riscv_symbol_other (other);
+      break;
     default:
       result = NULL;
       break;
@@ -12689,6 +13185,7 @@ print_dynamic_symbol (Filedata *filedata, unsigned long si,
 
   if (ELF_ST_TYPE (psym->st_info) == STT_SECTION
       && psym->st_shndx < filedata->file_header.e_shnum
+      && filedata->section_headers != NULL
       && psym->st_name == 0)
     {
       is_valid
@@ -13775,7 +14272,7 @@ is_32bit_abs_reloc (Filedata * filedata, unsigned int reloc_type)
     case EM_MT:
       return reloc_type == 2; /* R_MT_32.  */
     case EM_NDS32:
-      return reloc_type == 20; /* R_NDS32_RELA.  */
+      return reloc_type == 20; /* R_NDS32_32_RELA.  */
     case EM_ALTERA_NIOS2:
       return reloc_type == 12; /* R_NIOS2_BFD_RELOC_32.  */
     case EM_NIOS32:
@@ -14087,7 +14584,7 @@ is_16bit_abs_reloc (Filedata * filedata, unsigned int reloc_type)
     case EM_MSP430_OLD:
       return reloc_type == 5; /* R_MSP430_16_BYTE.  */
     case EM_NDS32:
-      return reloc_type == 19; /* R_NDS32_RELA.  */
+      return reloc_type == 19; /* R_NDS32_16_RELA.  */
     case EM_ALTERA_NIOS2:
       return reloc_type == 13; /* R_NIOS2_BFD_RELOC_16.  */
     case EM_NIOS32:
@@ -14348,11 +14845,11 @@ is_none_reloc (Filedata * filedata, unsigned int reloc_type)
     case EM_METAG:
       return reloc_type == 3; /* R_METAG_NONE.  */
     case EM_NDS32:
-      return (reloc_type == 0       /* R_XTENSA_NONE.  */
-             || reloc_type == 204  /* R_NDS32_DIFF8.  */
-             || reloc_type == 205  /* R_NDS32_DIFF16.  */
-             || reloc_type == 206  /* R_NDS32_DIFF32.  */
-             || reloc_type == 207  /* R_NDS32_ULEB128.  */);
+      return (reloc_type == 0       /* R_NDS32_NONE.  */
+             || reloc_type == 205  /* R_NDS32_DIFF8.  */
+             || reloc_type == 206  /* R_NDS32_DIFF16.  */
+             || reloc_type == 207  /* R_NDS32_DIFF32.  */
+             || reloc_type == 208  /* R_NDS32_DIFF_ULEB128.  */);
     case EM_TI_PRU:
       return (reloc_type == 0       /* R_PRU_NONE.  */
              || reloc_type == 65   /* R_PRU_DIFF8.  */
@@ -15600,6 +16097,9 @@ load_debug_section (enum dwarf_section_display_enum debug, void * data)
   Elf_Internal_Shdr * sec;
   Filedata * filedata = (Filedata *) data;
 
+  if (!dump_any_debugging)
+    return false;
+
   /* Without section headers we cannot find any sections.  */
   if (filedata->section_headers == NULL)
     return false;
@@ -18090,7 +18590,6 @@ process_mips_specific (Filedata * filedata)
       Elf_External_Options * eopt;
       size_t offset;
       int cnt;
-      sect = filedata->section_headers;
 
       /* Find the section header so that we get the size.  */
       sect = find_section_by_type (filedata, SHT_MIPS_OPTIONS);
@@ -18880,6 +19379,8 @@ get_note_type (Filedata * filedata, unsigned e_type)
        return _("NT_ARM_HW_BREAK (AArch hardware breakpoint registers)");
       case NT_ARM_HW_WATCH:
        return _("NT_ARM_HW_WATCH (AArch hardware watchpoint registers)");
+      case NT_ARM_SYSTEM_CALL:
+       return _("NT_ARM_SYSTEM_CALL (AArch system call number)");
       case NT_ARM_SVE:
        return _("NT_ARM_SVE (AArch SVE registers)");
       case NT_ARM_PAC_MASK:
@@ -18928,6 +19429,8 @@ get_note_type (Filedata * filedata, unsigned e_type)
        return _("func");
       case NT_GO_BUILDID:
        return _("GO BUILDID");
+      case FDO_PACKAGING_METADATA:
+       return _("FDO_PACKAGING_METADATA");
       default:
        break;
       }
@@ -19230,6 +19733,22 @@ decode_x86_compat_2_isa (unsigned int bitmask)
     }
 }
 
+static const char *
+get_amdgpu_elf_note_type (unsigned int e_type)
+{
+  switch (e_type)
+    {
+    case NT_AMDGPU_METADATA:
+      return _("NT_AMDGPU_METADATA (code object metadata)");
+    default:
+      {
+       static char buf[64];
+       snprintf (buf, sizeof (buf), _("Unknown note type: (0x%08x)"), e_type);
+       return buf;
+      }
+    }
+}
+
 static void
 decode_x86_isa (unsigned int bitmask)
 {
@@ -19931,6 +20450,8 @@ get_freebsd_elfcore_note_type (Filedata * filedata, unsigned e_type)
       return _("NT_PROCSTAT_AUXV (auxv data)");
     case NT_FREEBSD_PTLWPINFO:
       return _("NT_PTLWPINFO (ptrace_lwpinfo structure)");
+    case NT_FREEBSD_X86_SEGBASES:
+      return _("NT_X86_SEGBASES (x86 segment base registers)");
     }
   return get_note_type (filedata, e_type);
 }
@@ -20138,6 +20659,17 @@ print_stapsdt_note (Elf_Internal_Note *pnote)
   return false;
 }
 
+static bool
+print_fdo_note (Elf_Internal_Note * pnote)
+{
+  if (pnote->descsz > 0 && pnote->type == FDO_PACKAGING_METADATA)
+    {
+      printf (_("    Packaging Metadata: %.*s\n"), (int) pnote->descsz, pnote->descdata);
+      return true;
+    }
+  return false;
+}
+
 static const char *
 get_ia64_vms_note_type (unsigned e_type)
 {
@@ -20786,6 +21318,177 @@ print_gnu_build_attribute_name (Elf_Internal_Note * pnote)
   return true;
 }
 
+/* Print the contents of PNOTE as hex.  */
+
+static void
+print_note_contents_hex (Elf_Internal_Note *pnote)
+{
+  if (pnote->descsz)
+    {
+      unsigned long i;
+
+      printf (_("   description data: "));
+      for (i = 0; i < pnote->descsz; i++)
+       printf ("%02x ", pnote->descdata[i] & 0xff);
+      if (!do_wide)
+       printf ("\n");
+    }
+
+  if (do_wide)
+    printf ("\n");
+}
+
+#if defined HAVE_MSGPACK
+
+static void
+print_indents (int n)
+{
+  printf ("    ");
+
+  for (int i = 0; i < n; i++)
+    printf ("  ");
+}
+
+/* Print OBJ in human-readable form.  */
+
+static void
+dump_msgpack_obj (const msgpack_object *obj, int indent)
+{
+  switch (obj->type)
+    {
+    case MSGPACK_OBJECT_NIL:
+      printf ("(nil)");
+      break;
+
+    case MSGPACK_OBJECT_BOOLEAN:
+      printf ("%s", obj->via.boolean ? "true" : "false");
+      break;
+
+    case MSGPACK_OBJECT_POSITIVE_INTEGER:
+      printf ("%" PRIu64, obj->via.u64);
+      break;
+
+    case MSGPACK_OBJECT_NEGATIVE_INTEGER:
+      printf ("%" PRIi64, obj->via.i64);
+      break;
+
+    case MSGPACK_OBJECT_FLOAT32:
+    case MSGPACK_OBJECT_FLOAT64:
+      printf ("%f", obj->via.f64);
+      break;
+
+    case MSGPACK_OBJECT_STR:
+      printf ("\"%.*s\"", obj->via.str.size, obj->via.str.ptr);
+      break;
+
+    case MSGPACK_OBJECT_ARRAY:
+      {
+       const msgpack_object_array *array = &obj->via.array;
+
+       printf ("[\n");
+       ++indent;
+
+       for (uint32_t i = 0; i < array->size; ++i)
+         {
+           const msgpack_object *item = &array->ptr[i];
+
+           print_indents (indent);
+           dump_msgpack_obj (item, indent);
+           printf (",\n");
+         }
+
+       --indent;
+       print_indents (indent);
+       printf ("]");
+       break;
+      }
+      break;
+
+    case MSGPACK_OBJECT_MAP:
+      {
+       const msgpack_object_map *map = &obj->via.map;
+
+       printf ("{\n");
+       ++indent;
+
+       for (uint32_t i = 0; i < map->size; ++i)
+         {
+           const msgpack_object_kv *kv = &map->ptr[i];
+           const msgpack_object *key = &kv->key;
+           const msgpack_object *val = &kv->val;
+
+           print_indents (indent);
+           dump_msgpack_obj (key, indent);
+           printf (": ");
+           dump_msgpack_obj (val, indent);
+
+           printf (",\n");
+         }
+
+       --indent;
+       print_indents (indent);
+       printf ("}");
+
+       break;
+      }
+
+    case MSGPACK_OBJECT_BIN:
+      printf ("(bin)");
+      break;
+
+    case MSGPACK_OBJECT_EXT:
+      printf ("(ext)");
+      break;
+    }
+}
+
+static void
+dump_msgpack (const msgpack_unpacked *msg)
+{
+  print_indents (0);
+  dump_msgpack_obj (&msg->data, 0);
+  printf ("\n");
+}
+
+#endif /* defined HAVE_MSGPACK */
+
+static bool
+print_amdgpu_note (Elf_Internal_Note *pnote)
+{
+#if defined HAVE_MSGPACK
+  /* If msgpack is available, decode and dump the note's content.  */
+  bool ret;
+  msgpack_unpacked msg;
+  msgpack_unpack_return msgpack_ret;
+
+  assert (pnote->type == NT_AMDGPU_METADATA);
+
+  msgpack_unpacked_init (&msg);
+  msgpack_ret = msgpack_unpack_next (&msg, pnote->descdata, pnote->descsz,
+                                    NULL);
+
+  switch (msgpack_ret)
+    {
+    case MSGPACK_UNPACK_SUCCESS:
+      dump_msgpack (&msg);
+      ret = true;
+      break;
+
+    default:
+      error (_("failed to unpack msgpack contents in NT_AMDGPU_METADATA note"));
+      ret = false;
+      break;
+    }
+
+  msgpack_unpacked_destroy (&msg);
+  return ret;
+#else
+  /* msgpack is not available, dump contents as hex.  */
+  print_note_contents_hex (pnote);
+  return true;
+#endif
+}
+
 /* Note that by the ELF standard, the name field is already null byte
    terminated, and namesz includes the terminating null byte.
    I.E. the value of namesz for the name "FSF" is 4.
@@ -20808,6 +21511,10 @@ process_note (Elf_Internal_Note *  pnote,
     /* GNU-specific object file notes.  */
     nt = get_gnu_elf_note_type (pnote->type);
 
+  else if (startswith (pnote->namedata, "AMDGPU"))
+    /* AMDGPU-specific object file notes.  */
+    nt = get_amdgpu_elf_note_type (pnote->type);
+
   else if (startswith (pnote->namedata, "FreeBSD"))
     /* FreeBSD-specific core file notes.  */
     nt = get_freebsd_elfcore_note_type (filedata, pnote->type);
@@ -20871,27 +21578,19 @@ process_note (Elf_Internal_Note *  pnote,
     return print_stapsdt_note (pnote);
   else if (startswith (pnote->namedata, "CORE"))
     return print_core_note (pnote);
+  else if (startswith (pnote->namedata, "FDO"))
+    return print_fdo_note (pnote);
   else if (((startswith (pnote->namedata, "GA")
             && strchr ("*$!+", pnote->namedata[2]) != NULL)
            || strchr ("*$!+", pnote->namedata[0]) != NULL)
           && (pnote->type == NT_GNU_BUILD_ATTRIBUTE_OPEN
               || pnote->type == NT_GNU_BUILD_ATTRIBUTE_FUNC))
     return print_gnu_build_attribute_description (pnote, filedata);
+  else if (startswith (pnote->namedata, "AMDGPU")
+          && pnote->type == NT_AMDGPU_METADATA)
+    return print_amdgpu_note (pnote);
 
-  if (pnote->descsz)
-    {
-      unsigned long i;
-
-      printf (_("   description data: "));
-      for (i = 0; i < pnote->descsz; i++)
-       printf ("%02x ", pnote->descdata[i] & 0xff);
-      if (!do_wide)
-       printf ("\n");
-    }
-
-  if (do_wide)
-    printf ("\n");
-
+  print_note_contents_hex (pnote);
   return true;
 }