]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
CHERI-RISC-V: Improve handling of hybrid binaries.
authorJohn Baldwin <jhb@FreeBSD.org>
Fri, 14 Oct 2022 00:58:00 +0000 (17:58 -0700)
committerJohn Baldwin <jhb@FreeBSD.org>
Fri, 14 Oct 2022 00:58:00 +0000 (17:58 -0700)
- Add CHERI to the RISC-V ISA features if an ELF file contains the
  "xcheri" attribute.  This is set in both hybrid and purecap
  ELF files.  This isn't needed for purecap ELF files but does enable
  capability types and the "__capability" keyword on hybrid
  binaries and libraries.

- Add address_class gdbarch methods so that capability pointer types
  are tagged as capabilities in hybrid binaries.  This is a bit gross.
  Ideally riscv_address_class_type_flags would only enable the
  TYPE_INSTANCE_FLAG_CAPABILITY if the passed in byte_size (from
  DW_ATTR_byte_size) was equal to riscv_isa_clen() (aka
  gdbarch_capability_bit()).  However, for some reason this gdbarch
  method doesn't take the gdbarch member.  For now, rely on the fact
  that it is only called if either there is a DW_ATTR_address_space
  attribute on a pointer, or if the byte_size doesn't match the
  default pointer size.  Assuming there is no DW_ATTR_address_space
  defined for RISC-V yet, this means it should only be called for a
  size mismatch, and since we don't allow creating integer pointers in
  purecap, this means it can only be called for capability pointers
  for hybrid binaries.

gdb/riscv-tdep.c

index de59adc69a1252be5b92c4aee153551dfba7f5c9..404cd72bb1c66d5ae74cc632a8d91cf17e52d94f 100644 (file)
@@ -3623,6 +3623,31 @@ riscv_features_from_bfd (const bfd *abfd)
   return features;
 }
 
+/* Returns true if a bfd contains any references to CHERI via the
+   attributes section.  This is true both for hybrid and purecap ELF
+   objects.  */
+
+static bool
+riscv_bfd_has_cheri (bfd *abfd)
+{
+  if (abfd != nullptr && bfd_get_flavour (abfd) == bfd_target_elf_flavour)
+    {
+      const struct elf_backend_data *ebd = get_elf_backend_data (abfd);
+      if (ebd != nullptr)
+       {
+         const char *sec_name = ebd->obj_attrs_section;
+         if (bfd_get_section_by_name (abfd, sec_name) != nullptr)
+           {
+             obj_attribute *attr = elf_known_obj_attributes_proc (abfd);
+
+             if (strstr(attr[Tag_RISCV_arch].s, "xcheri") != nullptr)
+               return true;
+           }
+       }
+    }
+  return false;
+}
+
 /* Find a suitable default target description.  Use the contents of INFO,
    specifically the bfd object being executed, to guide the selection of a
    suitable default target description.  */
@@ -3641,6 +3666,10 @@ riscv_find_default_target_description (const struct gdbarch_info info)
   if (features.xlen == 0)
     features.xlen = info.bfd_arch_info->bits_per_word == 32 ? 4 : 8;
 
+  /* Check for a CHERI hybrid binary.  */
+  if (features.clen == 0 && riscv_bfd_has_cheri (info.abfd))
+    features.clen = features.xlen * 2;
+
   /* Now build a target description based on the feature set.  */
   return riscv_lookup_target_description (features);
 }
@@ -3688,6 +3717,46 @@ riscv_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
   return -1;
 }
 
+/* Implementation of `address_class_type_flags' gdbarch method.  */
+
+static type_instance_flags
+riscv_address_class_type_flags (int byte_size, int dwarf2_addr_class)
+{
+  /* XXX: This should be conditional on byte_size == riscv_isa_clen ().  */
+  return TYPE_INSTANCE_FLAG_CAPABILITY;
+}
+
+/* Implementation of `address_class_type_flags_to_name' gdbarch method.
+
+   Convert a type_instance_flag_value to an address space qualifier.  */
+
+static const char*
+riscv_address_class_type_flags_to_name (struct gdbarch *gdbarch,
+                                       type_instance_flags type_flags)
+{
+    /* No need to display the extra __capability modifier.  GDB already takes
+       cares of this.  */
+    return NULL;
+}
+
+/* Implementation of `address_class_name_to_type_flags' gdbarch method.
+
+   Convert an address space qualifier to a type_instance_flag_value.  */
+
+static bool
+riscv_address_class_name_to_type_flags (struct gdbarch *gdbarch,
+                                       const char* name,
+                                       type_instance_flags *type_flags_ptr)
+{
+  if (strcmp (name, "__capability") == 0)
+    {
+      *type_flags_ptr = TYPE_INSTANCE_FLAG_CAPABILITY;
+      return true;
+    }
+  else
+    return false;
+}
+
 static CORE_ADDR
 riscv_cheri_pointer_to_address (struct gdbarch *gdbarch, struct type *type,
                                const gdb_byte *buf)
@@ -4212,6 +4281,12 @@ riscv_gdbarch_init (struct gdbarch_info info,
   /* Settings for CHERI processors.  */
   if (riscv_has_cheri (gdbarch))
     {
+      set_gdbarch_address_class_type_flags (gdbarch,
+                                           riscv_address_class_type_flags);
+      set_gdbarch_address_class_name_to_type_flags
+       (gdbarch, riscv_address_class_name_to_type_flags);
+      set_gdbarch_address_class_type_flags_to_name
+       (gdbarch, riscv_address_class_type_flags_to_name);
       set_gdbarch_pointer_to_address (gdbarch, riscv_cheri_pointer_to_address);
       set_gdbarch_address_to_pointer (gdbarch, riscv_cheri_address_to_pointer);
       set_gdbarch_integer_to_address (gdbarch, riscv_cheri_integer_to_address);