return tags;
 }
 
+/* AArch64 Linux implementation of the
+   gdbarch_use_target_description_from_corefile_notes hook.  */
+
+static bool
+aarch64_use_target_description_from_corefile_notes (gdbarch *gdbarch,
+                                                   bfd *obfd)
+{
+  /* Sanity check.  */
+  gdb_assert (obfd != nullptr);
+
+  /* If the corefile contains any SVE or SME register data, we don't want to
+     use the target description note, as it may be incorrect.
+
+     Currently the target description note contains a potentially incorrect
+     target description if the originating program changed the SVE or SME
+     vector lengths mid-execution.
+
+     Once we support per-thread target description notes in the corefiles, we
+     can always trust those notes whenever they are available.  */
+  if (bfd_get_section_by_name (obfd, ".reg-aarch-sve") != nullptr
+      || bfd_get_section_by_name (obfd, ".reg-aarch-za") != nullptr
+      || bfd_get_section_by_name (obfd, ".reg-aarch-zt") != nullptr)
+    return false;
+
+  return true;
+}
+
 static void
 aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
                                            aarch64_displaced_step_hw_singlestep);
 
   set_gdbarch_gcc_target_options (gdbarch, aarch64_linux_gcc_target_options);
+
+  /* Hook to decide if the target description should be obtained from
+     corefile target description note(s) or inferred from the corefile
+     sections.  */
+  set_gdbarch_use_target_description_from_corefile_notes (gdbarch,
+                           aarch64_use_target_description_from_corefile_notes);
 }
 
 #if GDB_SELF_TEST
 
 {
 }
 
+/* See arch-utils.h.  */
+bool
+default_use_target_description_from_corefile_notes (struct gdbarch *gdbarch,
+                                                   struct bfd *corefile_bfd)
+{
+  /* Always trust the corefile target description contained in the target
+     description note.  */
+  return true;
+}
+
 CORE_ADDR
 default_get_return_buf_addr (struct type *val_type, frame_info_ptr cur_frame)
 {
 
    read_core_file_mappings_pre_loop_ftype pre_loop_cb,
    read_core_file_mappings_loop_ftype loop_cb);
 
+/* Default implementation of gdbarch
+   use_target_description_from_corefile_notes.  */
+extern bool default_use_target_description_from_corefile_notes
+  (struct gdbarch *gdbarch,
+  struct bfd *corefile_bfd);
+
 /* Default implementation of gdbarch default_get_return_buf_addr method.  */
 extern CORE_ADDR default_get_return_buf_addr (struct type *val_typegdbarch,
                                              frame_info_ptr cur_frame);
 
 const struct target_desc *
 core_target::read_description ()
 {
-  /* If the core file contains a target description note then we will use
-     that in preference to anything else.  */
-  bfd_size_type tdesc_note_size = 0;
-  struct bfd_section *tdesc_note_section
-    = bfd_get_section_by_name (core_bfd, ".gdb-tdesc");
-  if (tdesc_note_section != nullptr)
-    tdesc_note_size = bfd_section_size (tdesc_note_section);
-  if (tdesc_note_size > 0)
+  /* First check whether the target wants us to use the corefile target
+     description notes.  */
+  if (gdbarch_use_target_description_from_corefile_notes (m_core_gdbarch,
+                                                         core_bfd))
     {
-      gdb::char_vector contents (tdesc_note_size + 1);
-      if (bfd_get_section_contents (core_bfd, tdesc_note_section,
-                                   contents.data (), (file_ptr) 0,
-                                   tdesc_note_size))
+      /* If the core file contains a target description note then go ahead and
+        use that.  */
+      bfd_size_type tdesc_note_size = 0;
+      struct bfd_section *tdesc_note_section
+       = bfd_get_section_by_name (core_bfd, ".gdb-tdesc");
+      if (tdesc_note_section != nullptr)
+       tdesc_note_size = bfd_section_size (tdesc_note_section);
+      if (tdesc_note_size > 0)
        {
-         /* Ensure we have a null terminator.  */
-         contents[tdesc_note_size] = '\0';
-         const struct target_desc *result
-           = string_read_description_xml (contents.data ());
-         if (result != nullptr)
-           return result;
+         gdb::char_vector contents (tdesc_note_size + 1);
+         if (bfd_get_section_contents (core_bfd, tdesc_note_section,
+                                       contents.data (), (file_ptr) 0,
+                                       tdesc_note_size))
+           {
+             /* Ensure we have a null terminator.  */
+             contents[tdesc_note_size] = '\0';
+             const struct target_desc *result
+               = string_read_description_xml (contents.data ());
+             if (result != nullptr)
+               return result;
+           }
        }
     }
 
+  /* If the architecture provides a corefile target description hook, use
+     it now.  Even if the core file contains a target description in a note
+     section, it is not useful for targets that can potentially have distinct
+     descriptions for each thread.  One example is AArch64's SVE/SME
+     extensions that allow per-thread vector length changes, resulting in
+     registers with different sizes.  */
   if (m_core_gdbarch && gdbarch_core_read_description_p (m_core_gdbarch))
     {
       const struct target_desc *result;
 
       result = gdbarch_core_read_description (m_core_gdbarch, this, core_bfd);
-      if (result != NULL)
+      if (result != nullptr)
        return result;
     }
 
 
 typedef void (gdbarch_read_core_file_mappings_ftype) (struct gdbarch *gdbarch, struct bfd *cbfd, read_core_file_mappings_pre_loop_ftype pre_loop_cb, read_core_file_mappings_loop_ftype loop_cb);
 extern void gdbarch_read_core_file_mappings (struct gdbarch *gdbarch, struct bfd *cbfd, read_core_file_mappings_pre_loop_ftype pre_loop_cb, read_core_file_mappings_loop_ftype loop_cb);
 extern void set_gdbarch_read_core_file_mappings (struct gdbarch *gdbarch, gdbarch_read_core_file_mappings_ftype *read_core_file_mappings);
+
+/* Return true if the target description for all threads should be read from the
+   target description core file note(s).  Return false if the target description
+   for all threads should be inferred from the core file contents/sections.
+
+   The corefile's bfd is passed through COREFILE_BFD. */
+
+typedef bool (gdbarch_use_target_description_from_corefile_notes_ftype) (struct gdbarch *gdbarch, struct bfd *corefile_bfd);
+extern bool gdbarch_use_target_description_from_corefile_notes (struct gdbarch *gdbarch, struct bfd *corefile_bfd);
+extern void set_gdbarch_use_target_description_from_corefile_notes (struct gdbarch *gdbarch, gdbarch_use_target_description_from_corefile_notes_ftype *use_target_description_from_corefile_notes);
 
   gdbarch_type_align_ftype *type_align = default_type_align;
   gdbarch_get_pc_address_flags_ftype *get_pc_address_flags = default_get_pc_address_flags;
   gdbarch_read_core_file_mappings_ftype *read_core_file_mappings = default_read_core_file_mappings;
+  gdbarch_use_target_description_from_corefile_notes_ftype *use_target_description_from_corefile_notes = default_use_target_description_from_corefile_notes;
 };
 
 /* Create a new ``struct gdbarch'' based on information provided by
   /* Skip verify of type_align, invalid_p == 0 */
   /* Skip verify of get_pc_address_flags, invalid_p == 0 */
   /* Skip verify of read_core_file_mappings, invalid_p == 0 */
+  /* Skip verify of use_target_description_from_corefile_notes, invalid_p == 0 */
   if (!log.empty ())
     internal_error (_("verify_gdbarch: the following are invalid ...%s"),
                    log.c_str ());
   gdb_printf (file,
              "gdbarch_dump: read_core_file_mappings = <%s>\n",
              host_address_to_string (gdbarch->read_core_file_mappings));
+  gdb_printf (file,
+             "gdbarch_dump: use_target_description_from_corefile_notes = <%s>\n",
+             host_address_to_string (gdbarch->use_target_description_from_corefile_notes));
   if (gdbarch->dump_tdep != NULL)
     gdbarch->dump_tdep (gdbarch, file);
 }
 {
   gdbarch->read_core_file_mappings = read_core_file_mappings;
 }
+
+bool
+gdbarch_use_target_description_from_corefile_notes (struct gdbarch *gdbarch, struct bfd *corefile_bfd)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->use_target_description_from_corefile_notes != NULL);
+  if (gdbarch_debug >= 2)
+    gdb_printf (gdb_stdlog, "gdbarch_use_target_description_from_corefile_notes called\n");
+  return gdbarch->use_target_description_from_corefile_notes (gdbarch, corefile_bfd);
+}
+
+void
+set_gdbarch_use_target_description_from_corefile_notes (struct gdbarch *gdbarch,
+                                                       gdbarch_use_target_description_from_corefile_notes_ftype use_target_description_from_corefile_notes)
+{
+  gdbarch->use_target_description_from_corefile_notes = use_target_description_from_corefile_notes;
+}
 
     predefault="default_read_core_file_mappings",
     invalid=False,
 )
+
+Method(
+    comment="""
+Return true if the target description for all threads should be read from the
+target description core file note(s).  Return false if the target description
+for all threads should be inferred from the core file contents/sections.
+
+The corefile's bfd is passed through COREFILE_BFD.
+""",
+    type="bool",
+    name="use_target_description_from_corefile_notes",
+    params=[("struct bfd *", "corefile_bfd")],
+    predefault="default_use_target_description_from_corefile_notes",
+    invalid=False,
+)