Handle array- and string-like values in no-op pretty printers
[binutils-gdb.git] / bfd / elf64-bpf.c
index beabad79aff1ba3b9bc9588be03ace441758b492..aefad7da5ac0708797f7a0d55a88199eb719e984 100644 (file)
@@ -1,5 +1,5 @@
 /* Linux bpf specific support for 64-bit ELF
 /* Linux bpf specific support for 64-bit ELF
-   Copyright (C) 2019-2021 Free Software Foundation, Inc.
+   Copyright (C) 2019-2023 Free Software Foundation, Inc.
    Contributed by Oracle Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
    Contributed by Oracle Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 static bfd_reloc_status_type bpf_elf_generic_reloc
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
 
 static bfd_reloc_status_type bpf_elf_generic_reloc
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
 
+#undef BPF_HOWTO
+#define BPF_HOWTO(type, right, size, bits, pcrel, left, ovf, func, name,   \
+                 inplace, src_mask, dst_mask, pcrel_off)                  \
+       type##_IDX,
+enum bpf_reloc_index {
+  R_BPF_INVALID_IDX = -1,
+#include "bpf-reloc.def"
+  R_BPF_SIZE
+};
+#undef BPF_HOWTO
+
 /* Relocation tables.  */
 /* Relocation tables.  */
+#define BPF_HOWTO(...) HOWTO(__VA_ARGS__),
 static reloc_howto_type bpf_elf_howto_table [] =
 {
 static reloc_howto_type bpf_elf_howto_table [] =
 {
-  /* This reloc does nothing.  */
-  HOWTO (R_BPF_NONE,           /* type */
-        0,                     /* rightshift */
-        3,                     /* size (0 = byte, 1 = short, 2 = long) */
-        0,                     /* bitsize */
-        false,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        bpf_elf_generic_reloc, /* special_function */
-        "R_BPF_NONE",          /* name */
-        false,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
-        false),                /* pcrel_offset */
-
-  /* 64-immediate in LDDW instruction.  */
-  HOWTO (R_BPF_INSN_64,                /* type */
-        0,                     /* rightshift */
-        4,                     /* size (0 = byte, 1 = short, 2 = long) */
-        64,                    /* bitsize */
-        false,                 /* pc_relative */
-        32,                    /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bpf_elf_generic_reloc, /* special_function */
-        "R_BPF_INSN_64",       /* name */
-        true,                  /* partial_inplace */
-        MINUS_ONE,             /* src_mask */
-        MINUS_ONE,             /* dst_mask */
-        true),                 /* pcrel_offset */
-
-  /* 32-immediate in many instructions.  */
-  HOWTO (R_BPF_INSN_32,                /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        false,                 /* pc_relative */
-        32,                    /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bpf_elf_generic_reloc, /* special_function */
-        "R_BPF_INSN_32",       /* name */
-        true,                  /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        true),                 /* pcrel_offset */
-
-  /* 16-bit offsets in instructions.  */
-  HOWTO (R_BPF_INSN_16,                /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        false,                 /* pc_relative */
-        16,                    /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bpf_elf_generic_reloc, /* special_function */
-        "R_BPF_INSN_16",       /* name */
-        true,                  /* partial_inplace */
-        0x0000ffff,            /* src_mask */
-        0x0000ffff,            /* dst_mask */
-        true),                 /* pcrel_offset */
-
-  /* 16-bit PC-relative address in jump instructions.  */
-  HOWTO (R_BPF_INSN_DISP16,    /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        true,                  /* pc_relative */
-        16,                    /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bpf_elf_generic_reloc, /* special_function */
-        "R_BPF_INSN_DISP16",   /* name */
-        true,                  /* partial_inplace */
-        0xffff,                /* src_mask */
-        0xffff,                /* dst_mask */
-        true),                 /* pcrel_offset */
-
-  HOWTO (R_BPF_DATA_8_PCREL,
-        0,                     /* rightshift */
-        0,                     /* size (0 = byte, 1 = short, 2 = long) */
-        8,                     /* bitsize */
-        true,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bpf_elf_generic_reloc, /* special_function */
-        "R_BPF_8_PCREL",       /* name */
-        true,                  /* partial_inplace */
-        0xff,                  /* src_mask */
-        0xff,                  /* dst_mask */
-        true),                 /* pcrel_offset */
-
-  HOWTO (R_BPF_DATA_16_PCREL,
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        true,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bpf_elf_generic_reloc, /* special_function */
-        "R_BPF_16_PCREL",      /* name */
-        false,                 /* partial_inplace */
-        0xffff,                /* src_mask */
-        0xffff,                /* dst_mask */
-        true),                 /* pcrel_offset */
-
-  HOWTO (R_BPF_DATA_32_PCREL,
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        true,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bpf_elf_generic_reloc, /* special_function */
-        "R_BPF_32_PCREL",      /* name */
-        false,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        true),                 /* pcrel_offset */
-
-  HOWTO (R_BPF_DATA_8,
-        0,                     /* rightshift */
-        0,                     /* size (0 = byte, 1 = short, 2 = long) */
-        8,                     /* bitsize */
-        false,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_unsigned, /* complain_on_overflow */
-        bpf_elf_generic_reloc, /* special_function */
-        "R_BPF_DATA_8",        /* name */
-        true,                  /* partial_inplace */
-        0xff,                  /* src_mask */
-        0xff,                  /* dst_mask */
-        false),                /* pcrel_offset */
-
-  HOWTO (R_BPF_DATA_16,
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        false,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_unsigned, /* complain_on_overflow */
-        bpf_elf_generic_reloc, /* special_function */
-        "R_BPF_DATA_16",       /* name */
-        false,                 /* partial_inplace */
-        0xffff,                /* src_mask */
-        0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
-
-  /* 32-bit PC-relative address in call instructions.  */
-  HOWTO (R_BPF_INSN_DISP32,    /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        true,                  /* pc_relative */
-        32,                    /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bpf_elf_generic_reloc, /* special_function */
-        "R_BPF_INSN_DISP32",   /* name */
-        true,                  /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        true),                 /* pcrel_offset */
-
-  /* 32-bit data.  */
-  HOWTO (R_BPF_DATA_32,                /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        false,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
-        bpf_elf_generic_reloc, /* special_function */
-        "R_BPF_DATA_32",       /* name */
-        false,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        true),                 /* pcrel_offset */
-
-  /* 64-bit data.  */
-  HOWTO (R_BPF_DATA_64,                /* type */
-        0,                     /* rightshift */
-        4,                     /* size (0 = byte, 1 = short, 2 = long) */
-        64,                    /* bitsize */
-        false,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
-        bpf_elf_generic_reloc, /* special_function */
-        "R_BPF_DATA_64",       /* name */
-        false,                 /* partial_inplace */
-        0,                     /* src_mask */
-        MINUS_ONE,             /* dst_mask */
-        true),                 /* pcrel_offset */
-
-  HOWTO (R_BPF_DATA_64_PCREL,
-        0,                     /* rightshift */
-        4,                     /* size (0 = byte, 1 = short, 2 = long) */
-        64,                    /* bitsize */
-        true,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bpf_elf_generic_reloc, /* special_function */
-        "R_BPF_64_PCREL",      /* name */
-        false,                 /* partial_inplace */
-        MINUS_ONE,             /* src_mask */
-        MINUS_ONE,             /* dst_mask */
-        true),                 /* pcrel_offset */
+  #include "bpf-reloc.def"
 };
 #undef AHOW
 };
 #undef AHOW
+#undef BPF_HOWTO
+
+#define BPF_HOWTO(type, right, size, bits, pcrel, left, ovf, func, name,   \
+                 inplace, src_mask, dst_mask, pcrel_off)                  \
+    case type: { return type##_IDX; }
+static enum bpf_reloc_index
+bpf_index_for_rtype(unsigned int r_type)
+{
+  switch(r_type) {
+#include "bpf-reloc.def"
+    default:
+      /* Unreachable code. */
+      BFD_ASSERT(0);
+      return -1;
+  };
+}
 
 /* Map BFD reloc types to bpf ELF reloc types.  */
 
 
 /* Map BFD reloc types to bpf ELF reloc types.  */
 
@@ -249,44 +75,23 @@ static reloc_howto_type *
 bpf_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
                         bfd_reloc_code_real_type code)
 {
 bpf_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
                         bfd_reloc_code_real_type code)
 {
-  /* Note that the bpf_elf_howto_table is indexed by the R_ constants.
-     Thus, the order that the howto records appear in the table *must*
-     match the order of the relocation types defined in
-     include/elf/bpf.h.  */
-
   switch (code)
     {
     case BFD_RELOC_NONE:
   switch (code)
     {
     case BFD_RELOC_NONE:
-      return &bpf_elf_howto_table[ (int) R_BPF_NONE];
-
-    case BFD_RELOC_8_PCREL:
-      return &bpf_elf_howto_table[ (int) R_BPF_DATA_8_PCREL];
-    case BFD_RELOC_16_PCREL:
-      return &bpf_elf_howto_table[ (int) R_BPF_DATA_16_PCREL];
-    case BFD_RELOC_32_PCREL:
-      return &bpf_elf_howto_table[ (int) R_BPF_DATA_32_PCREL];
-    case BFD_RELOC_64_PCREL:
-      return &bpf_elf_howto_table[ (int) R_BPF_DATA_64_PCREL];
-
-    case BFD_RELOC_8:
-      return &bpf_elf_howto_table[ (int) R_BPF_DATA_8];
-    case BFD_RELOC_16:
-      return &bpf_elf_howto_table[ (int) R_BPF_DATA_16];
+      return &bpf_elf_howto_table[ (int) R_BPF_NONE_IDX];
+
     case BFD_RELOC_32:
     case BFD_RELOC_32:
-      return &bpf_elf_howto_table[ (int) R_BPF_DATA_32];
+      return &bpf_elf_howto_table[ (int) R_BPF_64_ABS32_IDX];
     case BFD_RELOC_64:
     case BFD_RELOC_64:
-      return &bpf_elf_howto_table[ (int) R_BPF_DATA_64];
+      return &bpf_elf_howto_table[ (int) R_BPF_64_ABS64_IDX];
 
     case BFD_RELOC_BPF_64:
 
     case BFD_RELOC_BPF_64:
-      return &bpf_elf_howto_table[ (int) R_BPF_INSN_64];
-    case BFD_RELOC_BPF_32:
-      return &bpf_elf_howto_table[ (int) R_BPF_INSN_32];
-    case BFD_RELOC_BPF_16:
-      return &bpf_elf_howto_table[ (int) R_BPF_INSN_16];
-    case BFD_RELOC_BPF_DISP16:
-      return &bpf_elf_howto_table[ (int) R_BPF_INSN_DISP16];
+      return &bpf_elf_howto_table[ (int) R_BPF_64_64_IDX];
     case BFD_RELOC_BPF_DISP32:
     case BFD_RELOC_BPF_DISP32:
-      return &bpf_elf_howto_table[ (int) R_BPF_INSN_DISP32];
+    case BFD_RELOC_BPF_DISPCALL32:
+      return &bpf_elf_howto_table[ (int) R_BPF_64_32_IDX];
+    case BFD_RELOC_BPF_DISP16:
+      return &bpf_elf_howto_table[ (int) R_BPF_GNU_64_16_IDX];
 
     default:
       /* Pacify gcc -Wall.  */
 
     default:
       /* Pacify gcc -Wall.  */
@@ -302,7 +107,7 @@ bpf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
 {
   unsigned int i;
 
 {
   unsigned int i;
 
-  for (i = 0; i < ARRAY_SIZE (bpf_elf_howto_table); i++)
+  for (i = 0; i < R_BPF_SIZE; i++)
     if (bpf_elf_howto_table[i].name != NULL
        && strcasecmp (bpf_elf_howto_table[i].name, r_name) == 0)
       return &bpf_elf_howto_table[i];
     if (bpf_elf_howto_table[i].name != NULL
        && strcasecmp (bpf_elf_howto_table[i].name, r_name) == 0)
       return &bpf_elf_howto_table[i];
@@ -317,9 +122,11 @@ bpf_info_to_howto (bfd *abfd, arelent *bfd_reloc,
                     Elf_Internal_Rela *elf_reloc)
 {
   unsigned int r_type;
                     Elf_Internal_Rela *elf_reloc)
 {
   unsigned int r_type;
-
+  unsigned int i;
   r_type = ELF64_R_TYPE (elf_reloc->r_info);
   r_type = ELF64_R_TYPE (elf_reloc->r_info);
-  if (r_type >= (unsigned int) R_BPF_max)
+
+  i = bpf_index_for_rtype(r_type);
+  if (i == (unsigned int) -1)
     {
       /* xgettext:c-format */
       _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
     {
       /* xgettext:c-format */
       _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
@@ -328,7 +135,7 @@ bpf_info_to_howto (bfd *abfd, arelent *bfd_reloc,
       return false;
     }
 
       return false;
     }
 
-  bfd_reloc->howto = &bpf_elf_howto_table [r_type];
+  bfd_reloc->howto = &bpf_elf_howto_table [i];
   return true;
 }
 
   return true;
 }
 
@@ -386,6 +193,7 @@ bpf_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
   for (rel = relocs; rel < relend; rel ++)
     {
       reloc_howto_type *          howto;
   for (rel = relocs; rel < relend; rel ++)
     {
       reloc_howto_type *          howto;
+      unsigned int                howto_index;
       unsigned long               r_symndx;
       Elf_Internal_Sym *          sym;
       asection *                  sec;
       unsigned long               r_symndx;
       Elf_Internal_Sym *          sym;
       asection *                  sec;
@@ -399,7 +207,9 @@ bpf_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
 
       r_type = ELF64_R_TYPE (rel->r_info);
       r_symndx = ELF64_R_SYM (rel->r_info);
 
       r_type = ELF64_R_TYPE (rel->r_info);
       r_symndx = ELF64_R_SYM (rel->r_info);
-      howto  = bpf_elf_howto_table + ELF64_R_TYPE (rel->r_info);
+
+      howto_index = bpf_index_for_rtype (ELF64_R_TYPE (rel->r_info));
+      howto  = &bpf_elf_howto_table[howto_index];
       h      = NULL;
       sym    = NULL;
       sec    = NULL;
       h      = NULL;
       sym    = NULL;
       sec    = NULL;
@@ -438,8 +248,7 @@ bpf_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
 
       switch (howto->type)
         {
 
       switch (howto->type)
         {
-        case R_BPF_INSN_DISP16:
-        case R_BPF_INSN_DISP32:
+       case R_BPF_64_32:
           {
             /* Make the relocation PC-relative, and change its unit to
                64-bit words.  Note we need *signed* arithmetic
           {
             /* Make the relocation PC-relative, and change its unit to
                64-bit words.  Note we need *signed* arithmetic
@@ -465,10 +274,8 @@ bpf_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
             r = bfd_reloc_ok;
             break;
           }
             r = bfd_reloc_ok;
             break;
           }
-       case R_BPF_DATA_8:
-       case R_BPF_DATA_16:
-       case R_BPF_DATA_32:
-       case R_BPF_DATA_64:
+       case R_BPF_64_ABS64:
+       case R_BPF_64_ABS32:
          {
            addend = bfd_get (howto->bitsize, input_bfd, where);
            relocation += addend;
          {
            addend = bfd_get (howto->bitsize, input_bfd, where);
            relocation += addend;
@@ -477,28 +284,7 @@ bpf_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
            r = bfd_reloc_ok;
            break;
          }
            r = bfd_reloc_ok;
            break;
          }
-       case R_BPF_INSN_16:
-         {
-
-           addend = bfd_get_16 (input_bfd, where + 2);
-           relocation += addend;
-           bfd_put_16 (input_bfd, relocation, where + 2);
-
-           r = bfd_reloc_ok;
-           break;
-         }
-        case R_BPF_INSN_32:
-          {
-            /*  Write relocated value */
-
-           addend = bfd_get_32 (input_bfd, where + 4);
-           relocation += addend;
-            bfd_put_32 (input_bfd, relocation, where + 4);
-
-            r = bfd_reloc_ok;
-            break;
-          }
-        case R_BPF_INSN_64:
+       case R_BPF_64_64:
           {
             /*
                 LDDW instructions are 128 bits long, with a 64-bit immediate.
           {
             /*
                 LDDW instructions are 128 bits long, with a 64-bit immediate.
@@ -608,15 +394,16 @@ bpf_elf_generic_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
   bfd_byte *where;
 
   /* Sanity check that the address is in range.  */
   bfd_byte *where;
 
   /* Sanity check that the address is in range.  */
-  if (reloc_entry->howto->type == R_BPF_INSN_64)
-    {
-      bfd_size_type end = bfd_get_section_limit_octets (abfd, input_section);
-      if (reloc_entry->address > end
-         || end - reloc_entry->address < 16)
-       return bfd_reloc_outofrange;
-    }
-  else if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd, input_section,
-                                      reloc_entry->address))
+  bfd_size_type end = bfd_get_section_limit_octets (abfd, input_section);
+  bfd_size_type reloc_size;
+  if (reloc_entry->howto->type == R_BPF_64_64)
+    reloc_size = 16;
+  else
+    reloc_size = (reloc_entry->howto->bitsize
+                 + reloc_entry->howto->bitpos) / 8;
+
+  if (reloc_entry->address > end
+      || end - reloc_entry->address < reloc_size)
     return bfd_reloc_outofrange;
 
   /*  Get the symbol value.  */
     return bfd_reloc_outofrange;
 
   /*  Get the symbol value.  */
@@ -641,7 +428,7 @@ bpf_elf_generic_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
     return status;
 
   /* Now finally install the relocation.  */
     return status;
 
   /* Now finally install the relocation.  */
-  if (reloc_entry->howto->type == R_BPF_INSN_64)
+  if (reloc_entry->howto->type == R_BPF_64_64)
     {
       /* lddw is a 128-bit (!) instruction that allows loading a 64-bit
         immediate into a register. the immediate is split in half, with the
     {
       /* lddw is a 128-bit (!) instruction that allows loading a 64-bit
         immediate into a register. the immediate is split in half, with the