gdb/testsuite: use with_cwd where possible
[binutils-gdb.git] / binutils / readelf.c
index e104a7ed2a16b171c0fc692bf7572c702ea60d07..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"
 #include "elf/xstormy16.h"
 #include "elf/xtensa.h"
 #include "elf/z80.h"
+#include "elf/loongarch.h"
 
 #include "getopt.h"
 #include "libiberty.h"
@@ -237,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;
 
@@ -328,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
 {
@@ -342,31 +370,54 @@ static const char * get_symbol_version_string
 
 #define UNKNOWN -1
 
-#define SECTION_NAME(X) \
-  (filedata->string_table + (X)->sh_name)
+static inline const char *
+section_name (const Filedata *filedata, const Elf_Internal_Shdr *hdr)
+{
+  return filedata->string_table + hdr->sh_name;
+}
 
-#define SECTION_NAME_VALID(X) \
-  ((X) != NULL                                                         \
-   && filedata->string_table != NULL                                   \
-   && (X)->sh_name < filedata->string_table_length)
+static inline bool
+section_name_valid (const Filedata *filedata, const Elf_Internal_Shdr *hdr)
+{
+  return (hdr != NULL
+         && filedata->string_table != NULL
+         && hdr->sh_name < filedata->string_table_length);
+}
 
-#define SECTION_NAME_PRINT(X) \
-  ((X) == NULL ? _("<none>")                                           \
-   : filedata->string_table == NULL ? _("<no-strings>")                        \
-   : (X)->sh_name >= filedata->string_table_length ? _("<corrupt>")    \
-   : filedata->string_table + (X)->sh_name)
+static inline const char *
+section_name_print (const Filedata *filedata, const Elf_Internal_Shdr *hdr)
+{
+  if (hdr == NULL)
+    return _("<none>");
+  if (filedata->string_table == NULL)
+    return _("<no-strings>");
+  if (hdr->sh_name >= filedata->string_table_length)
+    return _("<corrupt>");
+  return section_name (filedata, hdr);
+}
 
 #define DT_VERSIONTAGIDX(tag)  (DT_VERNEEDNUM - (tag)) /* Reverse order!  */
 
-#define VALID_SYMBOL_NAME(strtab, strtab_size, offset) \
-   (strtab != NULL && offset < strtab_size)
-#define VALID_DYNAMIC_NAME(filedata, offset) \
-  VALID_SYMBOL_NAME (filedata->dynamic_strings, \
-                    filedata->dynamic_strings_length, offset)
+static inline bool
+valid_symbol_name (const char *strtab, size_t strtab_size, uint64_t offset)
+{
+  return strtab != NULL && offset < strtab_size;
+}
+
+static inline bool
+valid_dynamic_name (const Filedata *filedata, uint64_t offset)
+{
+  return valid_symbol_name (filedata->dynamic_strings,
+                           filedata->dynamic_strings_length, offset);
+}
+
 /* GET_DYNAMIC_NAME asssumes that VALID_DYNAMIC_NAME has
    already been called and verified that the string exists.  */
-#define GET_DYNAMIC_NAME(filedata, offset) \
-  (filedata->dynamic_strings + offset)
+static inline const char *
+get_dynamic_name (const Filedata *filedata, size_t offset)
+{
+  return filedata->dynamic_strings + offset;
+}
 
 #define REMOVE_ARCH_BITS(ADDR)                 \
   do                                           \
@@ -632,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;
 
@@ -644,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
        {
@@ -696,7 +880,7 @@ printable_section_name (Filedata * filedata, const Elf_Internal_Shdr * sec)
 {
 #define MAX_PRINT_SEC_NAME_LEN 256
   static char  sec_name_buf [MAX_PRINT_SEC_NAME_LEN + 1];
-  const char * name = SECTION_NAME_PRINT (sec);
+  const char * name = section_name_print (filedata, sec);
   char *       buf = sec_name_buf;
   char         c;
   unsigned int remaining = MAX_PRINT_SEC_NAME_LEN;
@@ -758,8 +942,9 @@ find_section (Filedata * filedata, const char * name)
     return NULL;
 
   for (i = 0; i < filedata->file_header.e_shnum; i++)
-    if (SECTION_NAME_VALID (filedata->section_headers + i)
-       && streq (SECTION_NAME (filedata->section_headers + i), name))
+    if (section_name_valid (filedata, filedata->section_headers + i)
+       && streq (section_name (filedata, filedata->section_headers + i),
+                 name))
       return filedata->section_headers + i;
 
   return NULL;
@@ -825,8 +1010,9 @@ find_section_in_set (Filedata * filedata, const char * name, unsigned int * set)
          if (i >= filedata->file_header.e_shnum)
            continue; /* FIXME: Should we issue an error message ?  */
 
-         if (SECTION_NAME_VALID (filedata->section_headers + i)
-             && streq (SECTION_NAME (filedata->section_headers + i), name))
+         if (section_name_valid (filedata, filedata->section_headers + i)
+             && streq (section_name (filedata, filedata->section_headers + i),
+                       name))
            return filedata->section_headers + i;
        }
     }
@@ -1181,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
@@ -1233,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"));
@@ -1273,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"));
@@ -1653,6 +1925,14 @@ dump_relocations (Filedata *          filedata,
        case EM_Z80:
          rtype = elf_z80_reloc_type (type);
          break;
+
+       case EM_LOONGARCH:
+         rtype = elf_loongarch_reloc_type (type);
+         break;
+
+       case EM_AMDGPU:
+         rtype = elf_amdgpu_reloc_type (type);
+         break;
        }
 
       if (rtype == NULL)
@@ -1663,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)
            {
@@ -1757,8 +2037,10 @@ dump_relocations (Filedata *          filedata,
 
                  if (ELF_ST_TYPE (psym->st_info) == STT_SECTION)
                    {
-                     if (psym->st_shndx < filedata->file_header.e_shnum)
-                       sec_name = SECTION_NAME_PRINT (filedata->section_headers
+                     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);
                      else if (psym->st_shndx == SHN_ABS)
                        sec_name = "ABS";
@@ -1809,7 +2091,7 @@ dump_relocations (Filedata *          filedata,
                            version_string);
                }
 
-             if (is_rela)
+             if (rel_type == reltype_rela)
                {
                  bfd_vma off = rels[i].r_addend;
 
@@ -1820,7 +2102,7 @@ dump_relocations (Filedata *          filedata,
                }
            }
        }
-      else if (is_rela)
+      else if (rel_type == reltype_rela)
        {
          bfd_vma off = rels[i].r_addend;
 
@@ -2169,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)
 {
@@ -2196,6 +2489,9 @@ get_dynamic_type (Filedata * filedata, unsigned long type)
     case DT_REL:       return "REL";
     case DT_RELSZ:     return "RELSZ";
     case DT_RELENT:    return "RELENT";
+    case DT_RELR:      return "RELR";
+    case DT_RELRSZ:    return "RELRSZ";
+    case DT_RELRENT:   return "RELRENT";
     case DT_PLTREL:    return "PLTREL";
     case DT_DEBUG:     return "DEBUG";
     case DT_TEXTREL:   return "TEXTREL";
@@ -2291,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);
@@ -3274,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)
 {
@@ -3426,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)
            {
@@ -3945,6 +4395,20 @@ get_machine_flags (Filedata * filedata, unsigned e_flags, unsigned e_machine)
              strcat (buf, _(", unknown")); break;
            }
          break;
+       case EM_LOONGARCH:
+         if (EF_LOONGARCH_IS_LP64 (e_flags))
+           strcat (buf, ", LP64");
+         else if (EF_LOONGARCH_IS_ILP32 (e_flags))
+           strcat (buf, ", ILP32");
+
+         if (EF_LOONGARCH_IS_SOFT_FLOAT (e_flags))
+           strcat (buf, ", SOFT-FLOAT");
+         else if (EF_LOONGARCH_IS_SINGLE_FLOAT (e_flags))
+           strcat (buf, ", SINGLE-FLOAT");
+         else if (EF_LOONGARCH_IS_DOUBLE_FLOAT (e_flags))
+           strcat (buf, ", DOUBLE-FLOAT");
+
+         break;
        }
     }
 
@@ -3979,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)
              {
@@ -4094,6 +4569,16 @@ get_tic6x_segment_type (unsigned long type)
     }
 }
 
+static const char *
+get_riscv_segment_type (unsigned long type)
+{
+  switch (type)
+    {
+    case PT_RISCV_ATTRIBUTES: return "RISCV_ATTRIBUTES";
+    default:                  return NULL;
+    }
+}
+
 static const char *
 get_hpux_segment_type (unsigned long type, unsigned e_machine)
 {
@@ -4203,6 +4688,9 @@ get_segment_type (Filedata * filedata, unsigned long p_type)
            case EM_S390_OLD:
              result = get_s390_segment_type (p_type);
              break;
+           case EM_RISCV:
+             result = get_riscv_segment_type (p_type);
+             break;
            default:
              result = NULL;
              break;
@@ -4476,6 +4964,7 @@ get_section_type_name (Filedata * filedata, unsigned int sh_type)
     case SHT_SYMTAB:           return "SYMTAB";
     case SHT_STRTAB:           return "STRTAB";
     case SHT_RELA:             return "RELA";
+    case SHT_RELR:             return "RELR";
     case SHT_HASH:             return "HASH";
     case SHT_DYNAMIC:          return "DYNAMIC";
     case SHT_NOTE:             return "NOTE";
@@ -4668,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'},
@@ -4733,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, _("\
@@ -4801,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"));
@@ -4810,8 +5313,7 @@ usage (FILE * stream)
   fprintf (stream, _("\
   --ctf=<number|name>    Display CTF info from section <number|name>\n"));
   fprintf (stream, _("\
-  --ctf-parent=<number|name>\n\
-                         Use section <number|name> as the CTF parent\n"));
+  --ctf-parent=<name>    Use CTF archive member <name> as the CTF parent\n"));
   fprintf (stream, _("\
   --ctf-symbols=<number|name>\n\
                          Use section <number|name> as the CTF external symtab\n"));
@@ -4928,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)
        {
@@ -5009,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);
@@ -5024,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;
@@ -5037,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;
@@ -5130,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)
@@ -5285,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);
@@ -5321,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))
@@ -6684,7 +7210,7 @@ process_section_headers (Filedata * filedata)
        i < filedata->file_header.e_shnum;
        i++, section++)
     {
-      char * name = SECTION_NAME_PRINT (section);
+      const char *name = section_name_print (filedata, section);
 
       /* Run some sanity checks on the headers and
         possibly fill in some file data as well.  */
@@ -6751,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
@@ -7027,7 +7557,7 @@ process_section_headers (Filedata * filedata)
       if (do_section_details)
        printf ("%s\n      ", printable_section_name (filedata, section));
       else
-       print_symbol (-17, SECTION_NAME_PRINT (section));
+       print_symbol (-17, section_name_print (filedata, section));
 
       printf (do_wide ? " %-15s " : " %-15.15s ",
              get_section_type_name (filedata, section->sh_type));
@@ -7451,7 +7981,8 @@ process_section_groups (Filedata * filedata)
                  continue;
                }
 
-             group_name = SECTION_NAME_PRINT (filedata->section_headers
+             group_name = section_name_print (filedata,
+                                              filedata->section_headers
                                               + sym->st_shndx);
              strtab_sec = NULL;
              free (strtab);
@@ -7785,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.  */
@@ -7807,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;
@@ -7816,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];
@@ -7824,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;
                  }
            }
@@ -7856,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 */);
            }
        }
 
@@ -7884,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;
@@ -7892,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)
@@ -7912,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)
@@ -7934,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;
            }
@@ -8372,7 +8905,7 @@ ia64_process_unwind (Filedata * filedata)
 
   while (unwcount-- > 0)
     {
-      char * suffix;
+      const char *suffix;
       size_t len, len2;
 
       for (i = unwstart, sec = filedata->section_headers + unwstart, unwsec = NULL;
@@ -8405,8 +8938,9 @@ ia64_process_unwind (Filedata * filedata)
                {
                  sec = filedata->section_headers + g->section_index;
 
-                 if (SECTION_NAME_VALID (sec)
-                     && streq (SECTION_NAME (sec), ELF_STRING_ia64_unwind_info))
+                 if (section_name_valid (filedata, sec)
+                     && streq (section_name (filedata, sec),
+                               ELF_STRING_ia64_unwind_info))
                    break;
                }
 
@@ -8414,20 +8948,20 @@ ia64_process_unwind (Filedata * filedata)
                i = filedata->file_header.e_shnum;
            }
        }
-      else if (SECTION_NAME_VALID (unwsec)
-              && startswith (SECTION_NAME (unwsec),
+      else if (section_name_valid (filedata, unwsec)
+              && startswith (section_name (filedata, unwsec),
                              ELF_STRING_ia64_unwind_once))
        {
          /* .gnu.linkonce.ia64unw.FOO -> .gnu.linkonce.ia64unwi.FOO.  */
          len2 = sizeof (ELF_STRING_ia64_unwind_info_once) - 1;
-         suffix = SECTION_NAME (unwsec) + len;
+         suffix = section_name (filedata, unwsec) + len;
          for (i = 0, sec = filedata->section_headers;
               i < filedata->file_header.e_shnum;
               ++i, ++sec)
-           if (SECTION_NAME_VALID (sec)
-               && startswith (SECTION_NAME (sec),
+           if (section_name_valid (filedata, sec)
+               && startswith (section_name (filedata, sec),
                               ELF_STRING_ia64_unwind_info_once)
-               && streq (SECTION_NAME (sec) + len2, suffix))
+               && streq (section_name (filedata, sec) + len2, suffix))
              break;
        }
       else
@@ -8437,15 +8971,17 @@ ia64_process_unwind (Filedata * filedata)
          len = sizeof (ELF_STRING_ia64_unwind) - 1;
          len2 = sizeof (ELF_STRING_ia64_unwind_info) - 1;
          suffix = "";
-         if (SECTION_NAME_VALID (unwsec)
-             && startswith (SECTION_NAME (unwsec), ELF_STRING_ia64_unwind))
-           suffix = SECTION_NAME (unwsec) + len;
+         if (section_name_valid (filedata, unwsec)
+             && startswith (section_name (filedata, unwsec),
+                            ELF_STRING_ia64_unwind))
+           suffix = section_name (filedata, unwsec) + len;
          for (i = 0, sec = filedata->section_headers;
               i < filedata->file_header.e_shnum;
               ++i, ++sec)
-           if (SECTION_NAME_VALID (sec)
-               && startswith (SECTION_NAME (sec), ELF_STRING_ia64_unwind_info)
-               && streq (SECTION_NAME (sec) + len2, suffix))
+           if (section_name_valid (filedata, sec)
+               && startswith (section_name (filedata, sec),
+                              ELF_STRING_ia64_unwind_info)
+               && streq (section_name (filedata, sec) + len2, suffix))
              break;
        }
 
@@ -8827,8 +9363,8 @@ hppa_process_unwind (Filedata * filedata)
                           &aux.strtab, &aux.strtab_size))
            return false;
        }
-      else if (SECTION_NAME_VALID (sec)
-              && streq (SECTION_NAME (sec), ".PARISC.unwind"))
+      else if (section_name_valid (filedata, sec)
+              && streq (section_name (filedata, sec), ".PARISC.unwind"))
        unwsec = sec;
     }
 
@@ -8837,8 +9373,8 @@ hppa_process_unwind (Filedata * filedata)
 
   for (i = 0, sec = filedata->section_headers; i < filedata->file_header.e_shnum; ++i, ++sec)
     {
-      if (SECTION_NAME_VALID (sec)
-         && streq (SECTION_NAME (sec), ".PARISC.unwind"))
+      if (section_name_valid (filedata, sec)
+         && streq (section_name (filedata, sec), ".PARISC.unwind"))
        {
          unsigned long num_unwind = sec->sh_size / 16;
 
@@ -9357,6 +9893,8 @@ decode_arm_unwind_bytecode (Filedata *                 filedata,
            printf ("-D%d", first + last);
          printf ("}");
        }
+      else if (op == 0xb4)
+       printf (_("     pop {ra_auth_code}"));
       else if ((op & 0xf8) == 0xb8 || (op & 0xf8) == 0xd0)
        {
          unsigned int count = op & 0x07;
@@ -10051,9 +10589,9 @@ dynamic_section_mips_val (Filedata * filedata, Elf_Internal_Dyn * entry)
       break;
 
     case DT_MIPS_IVERSION:
-      if (VALID_DYNAMIC_NAME (filedata, entry->d_un.d_val))
+      if (valid_dynamic_name (filedata, entry->d_un.d_val))
        printf (_("Interface Version: %s"),
-               GET_DYNAMIC_NAME (filedata, entry->d_un.d_val));
+               get_dynamic_name (filedata, entry->d_un.d_val));
       else
        {
          char buf[40];
@@ -10930,28 +11468,19 @@ the .dynstr section doesn't match the DT_STRTAB and DT_STRSZ tags\n"));
 
   if (do_dynamic && filedata->dynamic_addr)
     {
-      if (filedata->dynamic_nent == 1)
-       {
-         if (filedata->is_separate)
-           printf (_("\nIn linked file '%s' the dynamic section at offset 0x%lx contains 1 entry:\n"),
-                   filedata->file_name,
-                   filedata->dynamic_addr);
-         else
-           printf (_("\nDynamic section at offset 0x%lx contains 1 entry:\n"),
-                   filedata->dynamic_addr);
-       }
+      if (filedata->is_separate)
+       printf (ngettext ("\nIn linked file '%s' the dynamic section at offset 0x%lx contains %lu entry:\n",
+                         "\nIn linked file '%s' the dynamic section at offset 0x%lx contains %lu entries:\n",
+                         (unsigned long) filedata->dynamic_nent),
+               filedata->file_name,
+               filedata->dynamic_addr,
+               (unsigned long) filedata->dynamic_nent);
       else
-       {
-         if (filedata->is_separate)
-           printf (_("\nIn linked file '%s' the dynamic section at offset 0x%lx contains %lu entries:\n"),
-                   filedata->file_name,
-                   filedata->dynamic_addr,
-                   (unsigned long) filedata->dynamic_nent);
-         else
-           printf (_("\nDynamic section at offset 0x%lx contains %lu entries:\n"),
-                   filedata->dynamic_addr,
-                   (unsigned long) filedata->dynamic_nent);
-       }
+       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"));
@@ -11008,9 +11537,9 @@ the .dynstr section doesn't match the DT_STRTAB and DT_STRSZ tags\n"));
                  break;
                }
 
-             if (VALID_DYNAMIC_NAME (filedata, entry->d_un.d_val))
+             if (valid_dynamic_name (filedata, entry->d_un.d_val))
                printf (": [%s]\n",
-                       GET_DYNAMIC_NAME (filedata, entry->d_un.d_val));
+                       get_dynamic_name (filedata, entry->d_un.d_val));
              else
                {
                  printf (": ");
@@ -11267,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  :
@@ -11275,10 +11805,10 @@ the .dynstr section doesn't match the DT_STRTAB and DT_STRSZ tags\n"));
 
          if (do_dynamic)
            {
-             char * name;
+             const char *name;
 
-             if (VALID_DYNAMIC_NAME (filedata, entry->d_un.d_val))
-               name = GET_DYNAMIC_NAME (filedata, entry->d_un.d_val);
+             if (valid_dynamic_name (filedata, entry->d_un.d_val))
+               name = get_dynamic_name (filedata, entry->d_un.d_val);
              else
                name = NULL;
 
@@ -11323,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;
@@ -11330,6 +11862,7 @@ 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_PREINIT_ARRAYSZ:
        case DT_INIT_ARRAYSZ:
        case DT_FINI_ARRAYSZ:
        case DT_GNU_CONFLICTSZ:
@@ -11361,9 +11894,10 @@ the .dynstr section doesn't match the DT_STRTAB and DT_STRSZ tags\n"));
          if (do_dynamic)
            {
              if (entry->d_tag == DT_USED
-                 && VALID_DYNAMIC_NAME (filedata, entry->d_un.d_val))
+                 && valid_dynamic_name (filedata, entry->d_un.d_val))
                {
-                 char * name = GET_DYNAMIC_NAME (filedata, entry->d_un.d_val);
+                 const char *name
+                   = get_dynamic_name (filedata, entry->d_un.d_val);
 
                  if (*name)
                    {
@@ -11606,9 +12140,9 @@ process_version_sections (Filedata * filedata)
                aux.vda_name = BYTE_GET (eaux->vda_name);
                aux.vda_next = BYTE_GET (eaux->vda_next);
 
-               if (VALID_DYNAMIC_NAME (filedata, aux.vda_name))
+               if (valid_dynamic_name (filedata, aux.vda_name))
                  printf (_("Name: %s\n"),
-                         GET_DYNAMIC_NAME (filedata, aux.vda_name));
+                         get_dynamic_name (filedata, aux.vda_name));
                else
                  printf (_("Name index: %ld\n"), aux.vda_name);
 
@@ -11638,10 +12172,10 @@ process_version_sections (Filedata * filedata)
                    aux.vda_name = BYTE_GET (eaux->vda_name);
                    aux.vda_next = BYTE_GET (eaux->vda_next);
 
-                   if (VALID_DYNAMIC_NAME (filedata, aux.vda_name))
+                   if (valid_dynamic_name (filedata, aux.vda_name))
                      printf (_("  %#06lx: Parent %d: %s\n"),
                              isum, j,
-                             GET_DYNAMIC_NAME (filedata, aux.vda_name));
+                             get_dynamic_name (filedata, aux.vda_name));
                    else
                      printf (_("  %#06lx: Parent %d, name index: %ld\n"),
                              isum, j, aux.vda_name);
@@ -11733,9 +12267,9 @@ process_version_sections (Filedata * filedata)
 
                printf (_("  %#06lx: Version: %d"), idx, ent.vn_version);
 
-               if (VALID_DYNAMIC_NAME (filedata, ent.vn_file))
+               if (valid_dynamic_name (filedata, ent.vn_file))
                  printf (_("  File: %s"),
-                         GET_DYNAMIC_NAME (filedata, ent.vn_file));
+                         get_dynamic_name (filedata, ent.vn_file));
                else
                  printf (_("  File: %lx"), ent.vn_file);
 
@@ -11761,9 +12295,9 @@ process_version_sections (Filedata * filedata)
                    aux.vna_name  = BYTE_GET (eaux->vna_name);
                    aux.vna_next  = BYTE_GET (eaux->vna_next);
 
-                   if (VALID_DYNAMIC_NAME (filedata, aux.vna_name))
+                   if (valid_dynamic_name (filedata, aux.vna_name))
                      printf (_("  %#06lx:   Name: %s"),
-                             isum, GET_DYNAMIC_NAME (filedata, aux.vna_name));
+                             isum, get_dynamic_name (filedata, aux.vna_name));
                    else
                      printf (_("  %#06lx:   Name index: %lx"),
                              isum, aux.vna_name);
@@ -12311,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)
 {
@@ -12337,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;
@@ -12626,16 +13185,20 @@ 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 = SECTION_NAME_VALID (filedata->section_headers + psym->st_shndx);
+      is_valid
+       = section_name_valid (filedata,
+                             filedata->section_headers + psym->st_shndx);
       sstr = is_valid ?
-       SECTION_NAME_PRINT (filedata->section_headers + psym->st_shndx)
+       section_name_print (filedata,
+                           filedata->section_headers + psym->st_shndx)
        : _("<corrupt>");
     }
   else
     {
-      is_valid = VALID_SYMBOL_NAME (strtab, strtab_size, psym->st_name);
+      is_valid = valid_symbol_name (strtab, strtab_size, psym->st_name);
       sstr = is_valid  ? strtab + psym->st_name : _("<corrupt>");
     }
 
@@ -12783,7 +13346,8 @@ display_lto_symtab (Filedata *           filedata,
   char * ext_name = NULL;
 
   if (asprintf (& ext_name, ".gnu.lto_.ext_symtab.%s",
-               SECTION_NAME (section) + sizeof (".gnu.lto_.symtab.") - 1) > 0
+               (section_name (filedata, section)
+                + sizeof (".gnu.lto_.symtab.") - 1)) > 0
       && ext_name != NULL /* Paranoia.  */
       && (ext = find_section (filedata, ext_name)) != NULL)
     {
@@ -12936,8 +13500,8 @@ process_lto_symbol_tables (Filedata * filedata)
   for (i = 0, section = filedata->section_headers;
        i < filedata->file_header.e_shnum;
        i++, section++)
-    if (SECTION_NAME_VALID (section)
-       && startswith (SECTION_NAME (section), ".gnu.lto_.symtab."))
+    if (section_name_valid (filedata, section)
+       && startswith (section_name (filedata, section), ".gnu.lto_.symtab."))
       res &= display_lto_symtab (filedata, section);
 
   return res;
@@ -13286,8 +13850,8 @@ process_syminfo (Filedata * filedata)
       printf ("%4d: ", i);
       if (i >= filedata->num_dynamic_syms)
        printf (_("<corrupt index>"));
-      else if (VALID_DYNAMIC_NAME (filedata, filedata->dynamic_symbols[i].st_name))
-       print_symbol (30, GET_DYNAMIC_NAME (filedata,
+      else if (valid_dynamic_name (filedata, filedata->dynamic_symbols[i].st_name))
+       print_symbol (30, get_dynamic_name (filedata,
                                            filedata->dynamic_symbols[i].st_name));
       else
        printf (_("<corrupt: %19ld>"), filedata->dynamic_symbols[i].st_name);
@@ -13304,10 +13868,10 @@ process_syminfo (Filedata * filedata)
        default:
          if (filedata->dynamic_syminfo[i].si_boundto > 0
              && filedata->dynamic_syminfo[i].si_boundto < filedata->dynamic_nent
-             && VALID_DYNAMIC_NAME (filedata,
+             && valid_dynamic_name (filedata,
                                     filedata->dynamic_section[filedata->dynamic_syminfo[i].si_boundto].d_un.d_val))
            {
-             print_symbol (10, GET_DYNAMIC_NAME (filedata,
+             print_symbol (10, get_dynamic_name (filedata,
                                                  filedata->dynamic_section[filedata->dynamic_syminfo[i].si_boundto].d_un.d_val));
              putchar (' ' );
            }
@@ -13669,6 +14233,8 @@ is_32bit_abs_reloc (Filedata * filedata, unsigned int reloc_type)
       return reloc_type == 2; /* R_IQ2000_32.  */
     case EM_LATTICEMICO32:
       return reloc_type == 3; /* R_LM32_32.  */
+    case EM_LOONGARCH:
+      return reloc_type == 1; /* R_LARCH_32. */
     case EM_M32C_OLD:
     case EM_M32C:
       return reloc_type == 3; /* R_M32C_32.  */
@@ -13706,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:
@@ -13886,6 +14452,8 @@ is_64bit_abs_reloc (Filedata * filedata, unsigned int reloc_type)
     case EM_IA_64:
       return (reloc_type == 0x26    /* R_IA64_DIR64MSB.  */
              || reloc_type == 0x27 /* R_IA64_DIR64LSB.  */);
+    case EM_LOONGARCH:
+      return reloc_type == 2;      /* R_LARCH_64 */
     case EM_PARISC:
       return reloc_type == 80; /* R_PARISC_DIR64.  */
     case EM_PPC64:
@@ -14016,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:
@@ -14277,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.  */
@@ -15056,7 +15624,7 @@ dump_section_as_bytes (Elf_Internal_Shdr *section,
 static ctf_sect_t *
 shdr_to_ctf_sect (ctf_sect_t *buf, Elf_Internal_Shdr *shdr, Filedata *filedata)
 {
-  buf->cts_name = SECTION_NAME_PRINT (shdr);
+  buf->cts_name = section_name_print (filedata, shdr);
   buf->cts_size = shdr->sh_size;
   buf->cts_entsize = shdr->sh_entsize;
 
@@ -15101,30 +15669,27 @@ dump_ctf_errs (ctf_dict_t *fp)
 
 /* Dump one CTF archive member.  */
 
-static int
-dump_ctf_archive_member (ctf_dict_t *ctf, const char *name, void *arg)
+static void
+dump_ctf_archive_member (ctf_dict_t *ctf, const char *name, ctf_dict_t *parent,
+                        size_t member)
 {
-  ctf_dict_t *parent = (ctf_dict_t *) arg;
   const char *things[] = {"Header", "Labels", "Data objects",
                          "Function objects", "Variables", "Types", "Strings",
                          ""};
   const char **thing;
   size_t i;
-  int err = 0;
 
-  /* Only print out the name of non-default-named archive members.
-     The name .ctf appears everywhere, even for things that aren't
-     really archives, so printing it out is liable to be confusing.
+  /* Don't print out the name of the default-named archive member if it appears
+     first in the list.  The name .ctf appears everywhere, even for things that
+     aren't really archives, so printing it out is liable to be confusing; also,
+     the common case by far is for only one archive member to exist, and hiding
+     it in that case seems worthwhile.  */
 
-     The parent, if there is one, is the default-owned archive member:
-     avoid importing it into itself.  (This does no harm, but looks
-     confusing.)  */
+  if (strcmp (name, ".ctf") != 0 || member != 0)
+    printf (_("\nCTF archive member: %s:\n"), name);
 
-  if (strcmp (name, ".ctf") != 0)
-    {
-      printf (_("\nCTF archive member: %s:\n"), name);
-      ctf_import (ctf, parent);
-    }
+  if (ctf_parent_name (ctf) != NULL)
+    ctf_import (ctf, parent);
 
   for (i = 0, thing = things; *thing[0]; thing++, i++)
     {
@@ -15143,33 +15708,31 @@ dump_ctf_archive_member (ctf_dict_t *ctf, const char *name, void *arg)
        {
          error (_("Iteration failed: %s, %s\n"), *thing,
                 ctf_errmsg (ctf_errno (ctf)));
-         err = 1;
-         goto out;
+         break;
        }
     }
 
- out:
   dump_ctf_errs (ctf);
-  return err;
 }
 
 static bool
 dump_section_as_ctf (Elf_Internal_Shdr * section, Filedata * filedata)
 {
-  Elf_Internal_Shdr *  parent_sec = NULL;
   Elf_Internal_Shdr *  symtab_sec = NULL;
   Elf_Internal_Shdr *  strtab_sec = NULL;
   void *              data = NULL;
   void *              symdata = NULL;
   void *              strdata = NULL;
-  void *              parentdata = NULL;
-  ctf_sect_t          ctfsect, symsect, strsect, parentsect;
+  ctf_sect_t          ctfsect, symsect, strsect;
   ctf_sect_t *        symsectp = NULL;
   ctf_sect_t *        strsectp = NULL;
   ctf_archive_t *      ctfa = NULL;
-  ctf_archive_t *      parenta = NULL, *lookparent;
   ctf_dict_t *         parent = NULL;
+  ctf_dict_t *         fp;
 
+  ctf_next_t *i = NULL;
+  const char *name;
+  size_t member = 0;
   int err;
   bool ret = false;
 
@@ -15216,25 +15779,9 @@ dump_section_as_ctf (Elf_Internal_Shdr * section, Filedata * filedata)
       strsect.cts_data = strdata;
     }
 
-  if (dump_ctf_parent_name)
-    {
-      if ((parent_sec = find_section (filedata, dump_ctf_parent_name)) == NULL)
-       {
-         error (_("No CTF parent section named %s\n"), dump_ctf_parent_name);
-         goto fail;
-       }
-      if ((parentdata = (void *) get_data (NULL, filedata,
-                                          parent_sec->sh_offset, 1,
-                                          parent_sec->sh_size,
-                                          _("CTF parent"))) == NULL)
-       goto fail;
-      shdr_to_ctf_sect (&parentsect, parent_sec, filedata);
-      parentsect.cts_data = parentdata;
-    }
-
   /* Load the CTF file and dump it.  It may be a raw CTF section, or an archive:
      libctf papers over the difference, so we can pretend it is always an
-     archive.  Possibly open the parent as well, if one was specified.  */
+     archive.  */
 
   if ((ctfa = ctf_arc_bufopen (&ctfsect, symsectp, strsectp, &err)) == NULL)
     {
@@ -15246,24 +15793,9 @@ dump_section_as_ctf (Elf_Internal_Shdr * section, Filedata * filedata)
   ctf_arc_symsect_endianness (ctfa, filedata->file_header.e_ident[EI_DATA]
                              != ELFDATA2MSB);
 
-  if (parentdata)
-    {
-      if ((parenta = ctf_arc_bufopen (&parentsect, symsectp, strsectp,
-                                     &err)) == NULL)
-       {
-         dump_ctf_errs (NULL);
-         error (_("CTF open failure: %s\n"), ctf_errmsg (err));
-         goto fail;
-       }
-      lookparent = parenta;
-    }
-  else
-    lookparent = ctfa;
-
-  /* Assume that the applicable parent archive member is the default one.
-     (This is what all known implementations are expected to do, if they
-     put CTFs and their parents in archives together.)  */
-  if ((parent = ctf_dict_open (lookparent, NULL, &err)) == NULL)
+  /* Preload the parent dict, since it will need to be imported into every
+     child in turn.  */
+  if ((parent = ctf_dict_open (ctfa, dump_ctf_parent_name, &err)) == NULL)
     {
       dump_ctf_errs (NULL);
       error (_("CTF open failure: %s\n"), ctf_errmsg (err));
@@ -15280,18 +15812,18 @@ dump_section_as_ctf (Elf_Internal_Shdr * section, Filedata * filedata)
     printf (_("\nDump of CTF section '%s':\n"),
            printable_section_name (filedata, section));
 
-  if ((err = ctf_archive_iter (ctfa, dump_ctf_archive_member, parent)) != 0)
-    {
-      dump_ctf_errs (NULL);
-      error (_("CTF member open failure: %s\n"), ctf_errmsg (err));
-      ret = false;
-    }
+ while ((fp = ctf_archive_next (ctfa, &i, &name, 0, &err)) != NULL)
+    dump_ctf_archive_member (fp, name, parent, member++);
+ if (err != ECTF_NEXT_END)
+   {
+     dump_ctf_errs (NULL);
+     error (_("CTF member open failure: %s\n"), ctf_errmsg (err));
+     ret = false;
+   }
 
  fail:
   ctf_dict_close (parent);
   ctf_close (ctfa);
-  ctf_close (parenta);
-  free (parentdata);
   free (data);
   free (symdata);
   free (strdata);
@@ -15565,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;
@@ -15632,8 +16167,9 @@ free_debug_section (enum dwarf_section_display_enum debug)
 static bool
 display_debug_section (int shndx, Elf_Internal_Shdr * section, Filedata * filedata)
 {
-  char * name = SECTION_NAME_VALID (section) ? SECTION_NAME (section) : "";
-  const char * print_name = printable_section_name (filedata, section);
+  const char *name = (section_name_valid (filedata, section)
+                     ? section_name (filedata, section) : "");
+  const char *print_name = printable_section_name (filedata, section);
   bfd_size_type length;
   bool result = true;
   int i;
@@ -15721,8 +16257,9 @@ initialise_dumps_byname (Filedata * filedata)
       bool any = false;
 
       for (i = 0; i < filedata->file_header.e_shnum; i++)
-       if (SECTION_NAME_VALID (filedata->section_headers + i)
-           && streq (SECTION_NAME (filedata->section_headers + i), cur->name))
+       if (section_name_valid (filedata, filedata->section_headers + i)
+           && streq (section_name (filedata, filedata->section_headers + i),
+                     cur->name))
          {
            request_dump_bynumber (&filedata->dump, i, cur->type);
            any = true;
@@ -16068,7 +16605,8 @@ typedef struct
 static const char *const arm_attr_tag_CPU_arch[] =
   {"Pre-v4", "v4", "v4T", "v5T", "v5TE", "v5TEJ", "v6", "v6KZ", "v6T2",
    "v6K", "v7", "v6-M", "v6S-M", "v7E-M", "v8", "v8-R", "v8-M.baseline",
-   "v8-M.mainline", "", "", "", "v8.1-M.mainline"};
+   "v8-M.mainline", "v8.1-A", "v8.2-A", "v8.3-A",
+   "v8.1-M.mainline", "v9"};
 static const char *const arm_attr_tag_ARM_ISA_use[] = {"No", "Yes"};
 static const char *const arm_attr_tag_THUMB_ISA_use[] =
   {"No", "Thumb-1", "Thumb-2", "Yes"};
@@ -16135,6 +16673,24 @@ static const char *const arm_attr_tag_MPextension_use_legacy[] =
 static const char *const arm_attr_tag_MVE_arch[] =
   {"No MVE", "MVE Integer only", "MVE Integer and FP"};
 
+static const char * arm_attr_tag_PAC_extension[] =
+  {"No PAC/AUT instructions",
+   "PAC/AUT instructions permitted in the NOP space",
+   "PAC/AUT instructions permitted in the NOP and in the non-NOP space"};
+
+static const char * arm_attr_tag_BTI_extension[] =
+  {"BTI instructions not permitted",
+   "BTI instructions permitted in the NOP space",
+   "BTI instructions permitted in the NOP and in the non-NOP space"};
+
+static const char * arm_attr_tag_BTI_use[] =
+  {"Compiled without branch target enforcement",
+   "Compiled with branch target enforcement"};
+
+static const char * arm_attr_tag_PACRET_use[] =
+  {"Compiled without return address signing and authentication",
+   "Compiled with return address signing and authentication"};
+
 #define LOOKUP(id, name) \
   {id, #name, 0x80 | ARRAY_SIZE(arm_attr_tag_##name), arm_attr_tag_##name}
 static arm_attr_public_tag arm_attr_public_tags[] =
@@ -16175,6 +16731,10 @@ static arm_attr_public_tag arm_attr_public_tags[] =
   LOOKUP(44, DIV_use),
   LOOKUP(46, DSP_extension),
   LOOKUP(48, MVE_arch),
+  LOOKUP(50, PAC_extension),
+  LOOKUP(52, BTI_extension),
+  LOOKUP(74, BTI_use),
+  LOOKUP(76, PACRET_use),
   {64, "nodefaults", 0, NULL},
   {65, "also_compatible_with", 0, NULL},
   LOOKUP(66, T2EE_use),
@@ -17282,24 +17842,27 @@ display_csky_attribute (unsigned char * p,
       break;
     case Tag_CSKY_FPU_ROUNDING:
       READ_ULEB (val, p, end);
-      if (val == 1) {
-       printf ("  Tag_CSKY_FPU_ROUNDING:\t");
-       printf ("Needed\n");
-      }
+      if (val == 1)
+       {
+         printf ("  Tag_CSKY_FPU_ROUNDING:\t");
+         printf ("Needed\n");
+       }
       break;
     case Tag_CSKY_FPU_DENORMAL:
       READ_ULEB (val, p, end);
-      if (val == 1) {
-       printf ("  Tag_CSKY_FPU_DENORMAL:\t");
-       printf ("Needed\n");
-      }
+      if (val == 1)
+       {
+         printf ("  Tag_CSKY_FPU_DENORMAL:\t");
+         printf ("Needed\n");
+       }
       break;
     case Tag_CSKY_FPU_Exception:
       READ_ULEB (val, p, end);
-      if (val == 1) {
-       printf ("  Tag_CSKY_FPU_Exception:\t");
-       printf ("Needed\n");
-      }
+      if (val == 1)
+       {
+         printf ("  Tag_CSKY_FPU_Exception:\t");
+         printf ("Needed\n");
+       }
       break;
     case Tag_CSKY_FPU_NUMBER_MODULE:
       printf ("  Tag_CSKY_FPU_NUMBER_MODULE:\t");
@@ -17975,8 +18538,8 @@ process_mips_specific (Filedata * filedata)
                        tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
 
              printf ("%3lu: ", (unsigned long) cnt);
-             if (VALID_DYNAMIC_NAME (filedata, liblist.l_name))
-               print_symbol (20, GET_DYNAMIC_NAME (filedata, liblist.l_name));
+             if (valid_dynamic_name (filedata, liblist.l_name))
+               print_symbol (20, get_dynamic_name (filedata, liblist.l_name));
              else
                printf (_("<corrupt: %9ld>"), liblist.l_name);
              printf (" %s %#10lx %-7ld", timebuf, liblist.l_checksum,
@@ -18027,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);
@@ -18355,8 +18917,8 @@ process_mips_specific (Filedata * filedata)
              psym = & filedata->dynamic_symbols[iconf[cnt]];
              print_vma (psym->st_value, FULL_HEX);
              putchar (' ');
-             if (VALID_DYNAMIC_NAME (filedata, psym->st_name))
-               print_symbol (25, GET_DYNAMIC_NAME (filedata, psym->st_name));
+             if (valid_dynamic_name (filedata, psym->st_name))
+               print_symbol (25, get_dynamic_name (filedata, psym->st_name));
              else
                printf (_("<corrupt: %14ld>"), psym->st_name);
            }
@@ -18480,9 +19042,9 @@ process_mips_specific (Filedata * filedata)
                          get_symbol_type (filedata, ELF_ST_TYPE (psym->st_info)),
                          get_symbol_index_type (filedata, psym->st_shndx));
 
-                 if (VALID_DYNAMIC_NAME (filedata, psym->st_name))
+                 if (valid_dynamic_name (filedata, psym->st_name))
                    print_symbol (sym_width,
-                                 GET_DYNAMIC_NAME (filedata, psym->st_name));
+                                 get_dynamic_name (filedata, psym->st_name));
                  else
                    printf (_("<corrupt: %14ld>"), psym->st_name);
                }
@@ -18568,9 +19130,9 @@ process_mips_specific (Filedata * filedata)
              printf (" %-7s %3s ",
                      get_symbol_type (filedata, ELF_ST_TYPE (psym->st_info)),
                      get_symbol_index_type (filedata, psym->st_shndx));
-             if (VALID_DYNAMIC_NAME (filedata, psym->st_name))
+             if (valid_dynamic_name (filedata, psym->st_name))
                print_symbol (sym_width,
-                             GET_DYNAMIC_NAME (filedata, psym->st_name));
+                             get_dynamic_name (filedata, psym->st_name));
              else
                printf (_("<corrupt: %14ld>"), psym->st_name);
            }
@@ -18817,12 +19379,20 @@ 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:
        return _("NT_ARM_PAC_MASK (AArch pointer authentication code masks)");
+      case NT_ARM_PACA_KEYS:
+       return _("NT_ARM_PACA_KEYS (ARM pointer authentication address keys)");
+      case NT_ARM_PACG_KEYS:
+       return _("NT_ARM_PACG_KEYS (ARM pointer authentication generic keys)");
       case NT_ARM_TAGGED_ADDR_CTRL:
        return _("NT_ARM_TAGGED_ADDR_CTRL (AArch tagged address control)");
+      case NT_ARM_PAC_ENABLED_KEYS:
+       return _("NT_ARM_PAC_ENABLED_KEYS (AArch64 pointer authentication enabled keys)");
       case NT_ARC_V2:
        return _("NT_ARC_V2 (ARC HS accumulator/extra registers)");
       case NT_RISCV_CSR:
@@ -18843,8 +19413,6 @@ get_note_type (Filedata * filedata, unsigned e_type)
        return _("NT_SIGINFO (siginfo_t data)");
       case NT_FILE:
        return _("NT_FILE (mapped files)");
-      case NT_MEMTAG:
-       return _("NT_MEMTAG (memory tags)");
       default:
        break;
       }
@@ -18859,6 +19427,10 @@ get_note_type (Filedata * filedata, unsigned e_type)
        return _("OPEN");
       case NT_GNU_BUILD_ATTRIBUTE_FUNC:
        return _("func");
+      case NT_GO_BUILDID:
+       return _("GO BUILDID");
+      case FDO_PACKAGING_METADATA:
+       return _("FDO_PACKAGING_METADATA");
       default:
        break;
       }
@@ -19161,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)
 {
@@ -19317,6 +19905,28 @@ decode_aarch64_feature_1_and (unsigned int bitmask)
     }
 }
 
+static void
+decode_1_needed (unsigned int bitmask)
+{
+  while (bitmask)
+    {
+      unsigned int bit = bitmask & (- bitmask);
+
+      bitmask &= ~ bit;
+      switch (bit)
+       {
+       case GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS:
+         printf ("indirect external access");
+         break;
+       default:
+         printf (_("<unknown: %x>"), bit);
+         break;
+       }
+      if (bitmask)
+       printf (", ");
+    }
+}
+
 static void
 print_gnu_property_note (Filedata * filedata, Elf_Internal_Note * pnote)
 {
@@ -19505,6 +20115,38 @@ print_gnu_property_note (Filedata * filedata, Elf_Internal_Note * pnote)
              goto next;
 
            default:
+             if ((type >= GNU_PROPERTY_UINT32_AND_LO
+                  && type <= GNU_PROPERTY_UINT32_AND_HI)
+                 || (type >= GNU_PROPERTY_UINT32_OR_LO
+                     && type <= GNU_PROPERTY_UINT32_OR_HI))
+               {
+                 switch (type)
+                   {
+                   case GNU_PROPERTY_1_NEEDED:
+                     if (datasz != 4)
+                       printf (_("1_needed: <corrupt length: %#x> "),
+                               datasz);
+                     else
+                       {
+                         unsigned int bitmask = byte_get (ptr, 4);
+                         printf ("1_needed: ");
+                         decode_1_needed (bitmask);
+                       }
+                     goto next;
+
+                   default:
+                     break;
+                   }
+                 if (type <= GNU_PROPERTY_UINT32_AND_HI)
+                   printf (_("UINT32_AND (%#x): "), type);
+                 else
+                   printf (_("UINT32_OR (%#x): "), type);
+                 if (datasz != 4)
+                   printf (_("<corrupt length: %#x> "), datasz);
+                 else
+                   printf ("%#x", (unsigned int) byte_get (ptr, 4));
+                 goto next;
+               }
              break;
            }
        }
@@ -19808,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);
 }
@@ -19900,6 +20544,26 @@ get_netbsd_elfcore_note_type (Filedata * filedata, unsigned e_type)
   return buff;
 }
 
+static const char *
+get_openbsd_elfcore_note_type (Filedata * filedata, unsigned e_type)
+{
+  switch (e_type)
+    {
+    case NT_OPENBSD_PROCINFO:
+      return _("OpenBSD procinfo structure");
+    case NT_OPENBSD_AUXV:
+      return _("OpenBSD ELF auxiliary vector data");
+    case NT_OPENBSD_REGS:
+      return _("OpenBSD regular registers");
+    case NT_OPENBSD_FPREGS:
+      return _("OpenBSD floating point registers");
+    case NT_OPENBSD_WCOOKIE:
+      return _("OpenBSD window cookie");
+    }
+
+  return get_note_type (filedata, e_type);
+}
+
 static const char *
 get_stapsdt_note_type (unsigned e_type)
 {
@@ -19995,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)
 {
@@ -20213,7 +20888,7 @@ get_symbol_for_build_attribute (Filedata *filedata,
        if (ba_cache.strtab[sym->st_name] == 0)
          continue;
 
-       /* The AArch64 and ARM architectures define mapping symbols
+       /* The AArch64, ARM and RISC-V architectures define mapping symbols
           (eg $d, $x, $t) which we want to ignore.  */
        if (ba_cache.strtab[sym->st_name] == '$'
            && ba_cache.strtab[sym->st_name + 1] != 0
@@ -20643,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.
@@ -20665,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);
@@ -20681,6 +21531,10 @@ process_note (Elf_Internal_Note *  pnote,
     /* NetBSD-specific core file notes.  */
     return process_netbsd_elf_note (pnote);
 
+  else if (startswith (pnote->namedata, "OpenBSD"))
+    /* OpenBSD-specific core file notes.  */
+    nt = get_openbsd_elfcore_note_type (filedata, pnote->type);
+
   else if (startswith (pnote->namedata, "SPU/"))
     {
       /* SPU-specific core file notes.  */
@@ -20724,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;
 }
 
@@ -21726,8 +22572,6 @@ process_archive (Filedata * filedata, bool is_thin_archive)
       arch.next_arhdr_offset += sizeof arch.arhdr;
 
       filedata->archive_file_size = strtoul (arch.arhdr.ar_size, NULL, 10);
-      if (filedata->archive_file_size & 01)
-       ++filedata->archive_file_size;
 
       name = get_archive_member_name (&arch, &nested_arch);
       if (name == NULL)
@@ -21775,6 +22619,9 @@ process_archive (Filedata * filedata, bool is_thin_archive)
          filedata->archive_file_offset = arch.nested_member_origin;
          member_filedata->file_name = qualified_name;
 
+         /* The call to process_object() expects the file to be at the beginning.  */
+         rewind (member_filedata->handle);
+
          if (! process_object (member_filedata))
            ret = false;
 
@@ -21828,7 +22675,7 @@ process_archive (Filedata * filedata, bool is_thin_archive)
          filedata->file_name = qualified_name;
          if (! process_object (filedata))
            ret = false;
-         arch.next_arhdr_offset += filedata->archive_file_size;
+         arch.next_arhdr_offset += (filedata->archive_file_size + 1) & -2;
          /* Stop looping with "negative" archive_file_size.  */
          if (arch.next_arhdr_offset < filedata->archive_file_size)
            arch.next_arhdr_offset = -1ul;