MIPS16e2: Add MIPS16e2 ASE support
[deliverable/binutils-gdb.git] / binutils / readelf.c
index ab53473b4336930ddd84fad414d6f4c1077abb9f..7ff29bc8ba162d14147098dc8b231b7bf053a5ea 100644 (file)
@@ -2508,6 +2508,9 @@ decode_ARC_machine_flags (unsigned e_flags, unsigned e_machine, char buf[])
     case E_ARC_OSABI_V3:
       strcat (buf, ", v3 no-legacy-syscalls ABI");
       break;
+    case E_ARC_OSABI_V4:
+      strcat (buf, ", v4 ABI");
+      break;
     default:
       strcat (buf, ", unrecognised ARC OSABI flag");
       break;
@@ -3897,6 +3900,18 @@ get_segment_type (unsigned long p_type)
     }
 }
 
+static const char *
+get_arc_section_type_name (unsigned int sh_type)
+{
+  switch (sh_type)
+    {
+    case SHT_ARC_ATTRIBUTES:      return "ARC_ATTRIBUTES";
+    default:
+      break;
+    }
+  return NULL;
+}
+
 static const char *
 get_mips_section_type_name (unsigned int sh_type)
 {
@@ -4106,6 +4121,11 @@ get_section_type_name (unsigned int sh_type)
        {
          switch (elf_header.e_machine)
            {
+           case EM_ARC:
+           case EM_ARC_COMPACT:
+           case EM_ARC_COMPACT2:
+             result = get_arc_section_type_name (sh_type);
+             break;
            case EM_MIPS:
            case EM_MIPS_RS3_LE:
              result = get_mips_section_type_name (sh_type);
@@ -6215,6 +6235,13 @@ process_section_headers (FILE * file)
          break;
        }
 
+      /* Check the sh_size field.  */
+      if (section->sh_size > current_file_size
+         && section->sh_type != SHT_NOBITS
+         && section->sh_type != SHT_NULL
+         && section->sh_type < SHT_LOOS)
+       warn (_("Size of section %u is larger than the entire file!\n"), i);
+
       printf ("  [%2u] ", i);
       if (do_section_details)
        printf ("%s\n      ", printable_section_name (section));
@@ -10171,8 +10198,9 @@ process_version_sections (FILE * file)
                printf (_("  Index: %d  Cnt: %d  "),
                        ent.vd_ndx, ent.vd_cnt);
 
-               /* Check for overflow.  */
-               if (ent.vd_aux + sizeof (* eaux) > (size_t) (endbuf - vstart))
+               /* Check for overflow and underflow.  */
+               if (ent.vd_aux + sizeof (* eaux) > (size_t) (endbuf - vstart)
+                   || (vstart + ent.vd_aux < vstart))
                  break;
 
                vstart += ent.vd_aux;
@@ -13483,6 +13511,180 @@ display_tag_value (signed int tag,
   return p;
 }
 
+/* ARC ABI attributes section.  */
+
+static unsigned char *
+display_arc_attribute (unsigned char * p,
+                      const unsigned char * const end)
+{
+  unsigned int tag;
+  unsigned int len;
+  unsigned int val;
+
+  tag = read_uleb128 (p, &len, end);
+  p += len;
+
+  switch (tag)
+    {
+    case Tag_ARC_PCS_config:
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      printf ("  Tag_ARC_PCS_config: ");
+      switch (val)
+       {
+       case 0:
+         printf (_("Absent/Non standard\n"));
+         break;
+       case 1:
+         printf (_("Bare metal/mwdt\n"));
+         break;
+       case 2:
+         printf (_("Bare metal/newlib\n"));
+         break;
+       case 3:
+         printf (_("Linux/uclibc\n"));
+         break;
+       case 4:
+         printf (_("Linux/glibc\n"));
+         break;
+       default:
+         printf (_("Unknown\n"));
+         break;
+       }
+      break;
+
+    case Tag_ARC_CPU_base:
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      printf ("  Tag_ARC_CPU_base: ");
+      switch (val)
+       {
+       default:
+       case TAG_CPU_NONE:
+         printf (_("Absent\n"));
+         break;
+       case TAG_CPU_ARC6xx:
+         printf ("ARC6xx\n");
+         break;
+       case TAG_CPU_ARC7xx:
+         printf ("ARC7xx\n");
+         break;
+       case TAG_CPU_ARCEM:
+         printf ("ARCEM\n");
+         break;
+       case TAG_CPU_ARCHS:
+         printf ("ARCHS\n");
+         break;
+       }
+      break;
+
+    case Tag_ARC_CPU_variation:
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      printf ("  Tag_ARC_CPU_variation: ");
+      switch (val)
+       {
+       default:
+         if (val > 0 && val < 16)
+           {
+             printf ("Core%d\n", val);
+             break;
+           }
+       case 0:
+         printf (_("Absent\n"));
+         break;
+       }
+      break;
+
+    case Tag_ARC_CPU_name:
+      printf ("  Tag_ARC_CPU_name: ");
+      p = display_tag_value (-1, p, end);
+      break;
+
+    case Tag_ARC_ABI_rf16:
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      printf ("  Tag_ARC_ABI_rf16: %s\n", val ? _("yes") : _("no"));
+      break;
+
+    case Tag_ARC_ABI_osver:
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      printf ("  Tag_ARC_ABI_osver: v%d\n", val);
+      break;
+
+    case Tag_ARC_ABI_pic:
+    case Tag_ARC_ABI_sda:
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      printf (tag == Tag_ARC_ABI_sda ? "  Tag_ARC_ABI_sda: "
+             : "  Tag_ARC_ABI_pic: ");
+      switch (val)
+       {
+       case 0:
+         printf (_("Absent\n"));
+         break;
+       case 1:
+         printf ("MWDT\n");
+         break;
+       case 2:
+         printf ("GNU\n");
+         break;
+       default:
+         printf (_("Unknown\n"));
+         break;
+       }
+      break;
+
+    case Tag_ARC_ABI_tls:
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      printf ("  Tag_ARC_ABI_tls: %s\n", val ? "r25": "none");
+      break;
+
+    case Tag_ARC_ABI_enumsize:
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      printf ("  Tag_ARC_ABI_enumsize: %s\n", val ? _("default") :
+             _("smallest"));
+      break;
+
+    case Tag_ARC_ABI_exceptions:
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      printf ("  Tag_ARC_ABI_exceptions: %s\n", val ? _("OPTFP")
+             : _("default"));
+      break;
+
+    case Tag_ARC_ABI_double_size:
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      printf ("  Tag_ARC_ABI_double_size: %d\n", val);
+      break;
+
+    case Tag_ARC_ISA_config:
+      printf ("  Tag_ARC_ISA_config: ");
+      p = display_tag_value (-1, p, end);
+      break;
+
+    case Tag_ARC_ISA_apex:
+      printf ("  Tag_ARC_ISA_apex: ");
+      p = display_tag_value (-1, p, end);
+      break;
+
+    case Tag_ARC_ISA_mpy_option:
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      printf ("  Tag_ARC_ISA_mpy_option: %d\n", val);
+      break;
+
+    default:
+      return display_tag_value (tag & 1, p, end);
+    }
+
+  return p;
+}
+
 /* ARM EABI attributes section.  */
 typedef struct
 {
@@ -14841,6 +15043,8 @@ print_mips_ases (unsigned int mask)
     fputs ("\n\tMICROMIPS ASE", stdout);
   if (mask & AFL_ASE_XPA)
     fputs ("\n\tXPA ASE", stdout);
+  if (mask & AFL_ASE_MIPS16E2)
+    fputs ("\n\tMIPS16e2 ASE", stdout);
   if (mask == 0)
     fprintf (stdout, "\n\t%s", _("None"));
   else if ((mask & ~AFL_ASE_MASK) != 0)
@@ -15007,8 +15211,93 @@ process_mips_specific (FILE * file)
 
   /* We have a lot of special sections.  Thanks SGI!  */
   if (dynamic_section == NULL)
-    /* No information available.  */
-    return res;
+    {
+      /* No dynamic information available.  See if there is static GOT.  */
+      sect = find_section (".got");
+      if (sect != NULL)
+       {
+         unsigned char *data_end;
+         unsigned char *data;
+         bfd_vma ent, end;
+         int addr_size;
+
+         pltgot = sect->sh_addr;
+
+         ent = pltgot;
+         addr_size = (is_32bit_elf ? 4 : 8);
+         end = pltgot + sect->sh_size;
+
+         data = (unsigned char *) get_data (NULL, file, sect->sh_offset,
+                                            end - pltgot, 1,
+                                            _("Global Offset Table data"));
+         /* PR 12855: Null data is handled gracefully throughout.  */
+         data_end = data + (end - pltgot);
+
+         printf (_("\nStatic GOT:\n"));
+         printf (_(" Canonical gp value: "));
+         print_vma (ent + 0x7ff0, LONG_HEX);
+         printf ("\n\n");
+
+         /* In a dynamic binary GOT[0] is reserved for the dynamic
+            loader to store the lazy resolver pointer, however in
+            a static binary it may well have been omitted and GOT
+            reduced to a table of addresses.
+            PR 21344: Check for the entry being fully available
+            before fetching it.  */
+         if (data
+             && data + ent - pltgot + addr_size <= data_end
+             && byte_get (data + ent - pltgot, addr_size) == 0)
+           {
+             printf (_(" Reserved entries:\n"));
+             printf (_("  %*s %10s %*s\n"),
+                     addr_size * 2, _("Address"), _("Access"),
+                     addr_size * 2, _("Value"));
+             ent = print_mips_got_entry (data, pltgot, ent, data_end);
+             printf ("\n");
+             if (ent == (bfd_vma) -1)
+               goto sgot_print_fail;
+
+             /* Check for the MSB of GOT[1] being set, identifying a
+                GNU object.  This entry will be used by some runtime
+                loaders, to store the module pointer.  Otherwise this
+                is an ordinary local entry.
+                PR 21344: Check for the entry being fully available
+                before fetching it.  */
+             if (data
+                 && data + ent - pltgot + addr_size <= data_end
+                 && (byte_get (data + ent - pltgot, addr_size)
+                     >> (addr_size * 8 - 1)) != 0)
+               {
+                 ent = print_mips_got_entry (data, pltgot, ent, data_end);
+                 printf ("\n");
+                 if (ent == (bfd_vma) -1)
+                   goto sgot_print_fail;
+               }
+             printf ("\n");
+           }
+
+         if (ent < end)
+           {
+             printf (_(" Local entries:\n"));
+             printf ("  %*s %10s %*s\n",
+                     addr_size * 2, _("Address"), _("Access"),
+                     addr_size * 2, _("Value"));
+             while (ent < end)
+               {
+                 ent = print_mips_got_entry (data, pltgot, ent, data_end);
+                 printf ("\n");
+                 if (ent == (bfd_vma) -1)
+                   goto sgot_print_fail;
+               }
+             printf ("\n");
+           }
+
+       sgot_print_fail:
+         if (data)
+           free (data);
+       }
+      return res;
+    }
 
   for (entry = dynamic_section;
        /* PR 17531 file: 012-50589-0.004.  */
@@ -15483,8 +15772,7 @@ process_mips_specific (FILE * file)
       data = (unsigned char *) get_data (NULL, file, offset,
                                          global_end - pltgot, 1,
                                         _("Global Offset Table data"));
-      if (data == NULL)
-       return FALSE;
+      /* PR 12855: Null data is handled gracefully throughout.  */
       data_end = data + (global_end - pltgot);
 
       printf (_("\nPrimary GOT:\n"));
@@ -15501,24 +15789,20 @@ process_mips_specific (FILE * file)
       if (ent == (bfd_vma) -1)
        goto got_print_fail;
 
-      if (data)
-       {
-         /* PR 21344 */
-         if (data + ent - pltgot > data_end - addr_size)
-           {
-             error (_("Invalid got entry - %#lx - overflows GOT table\n"),
-                    (long) ent);
-             goto got_print_fail;
-           }
-         
-         if (byte_get (data + ent - pltgot, addr_size)
-             >> (addr_size * 8 - 1) != 0)
-           {
-             ent = print_mips_got_entry (data, pltgot, ent, data_end);
-             printf (_(" Module pointer (GNU extension)\n"));
-             if (ent == (bfd_vma) -1)
-               goto got_print_fail;
-           }
+      /* Check for the MSB of GOT[1] being set, denoting a GNU object.
+        This entry will be used by some runtime loaders, to store the
+        module pointer.  Otherwise this is an ordinary local entry.
+        PR 21344: Check for the entry being fully available before
+        fetching it.  */
+      if (data
+         && data + ent - pltgot + addr_size <= data_end
+         && (byte_get (data + ent - pltgot, addr_size)
+             >> (addr_size * 8 - 1)) != 0)
+       {
+         ent = print_mips_got_entry (data, pltgot, ent, data_end);
+         printf (_(" Module pointer (GNU extension)\n"));
+         if (ent == (bfd_vma) -1)
+           goto got_print_fail;
        }
       printf ("\n");
 
@@ -16902,7 +17186,6 @@ print_gnu_build_attribute_name (Elf_Internal_Note * pnote)
       expected_types = bool_expected;
       ++ name;
       break;
-
     default:
       if (ISPRINT (* name))
        {
@@ -16916,9 +17199,11 @@ print_gnu_build_attribute_name (Elf_Internal_Note * pnote)
        }
       else
        {
-         error (_("unexpected character in name field\n"));
-         print_symbol (- left, _("<unknown attribute>"));
-         return 0;
+         static char tmpbuf [128];
+         error (_("unrecognised byte in name field: %d\n"), * name);
+         sprintf (tmpbuf, _("<unknown:_%d>"), * name);
+         text = tmpbuf;
+         name ++;
        }
       expected_types = "*$!+";
       break;
@@ -16948,10 +17233,28 @@ print_gnu_build_attribute_name (Elf_Internal_Note * pnote)
     {
     case GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC:
       {
-       unsigned int   bytes = pnote->namesz - (name - pnote->namedata);
-       unsigned long  val = 0;
-       unsigned int   shift = 0;
-       char *         decoded = NULL;
+       unsigned int        bytes;
+       unsigned long long  val = 0;
+       unsigned int        shift = 0;
+       char *              decoded = NULL;
+
+       bytes = pnote->namesz - (name - pnote->namedata);
+       if (bytes > 0)
+         /* The -1 is because the name field is always 0 terminated, and we
+            want to be able to ensure that the shift in the while loop below
+            will not overflow.  */
+         -- bytes;
+
+       if (bytes > sizeof (val))
+         {
+           fprintf (stderr, "namesz %lx name %p namedata %p\n",
+                    pnote->namesz, name, pnote->namedata);
+           error (_("corrupt numeric name field: too many bytes in the value: %x\n"),
+                  bytes);
+           bytes = sizeof (val);
+         }
+       /* We do not bother to warn if bytes == 0 as this can
+          happen with some early versions of the gcc plugin.  */
 
        while (bytes --)
          {
@@ -16991,13 +17294,21 @@ print_gnu_build_attribute_name (Elf_Internal_Note * pnote)
          }
 
        if (decoded != NULL)
-         print_symbol (-left, decoded);
+         {
+           print_symbol (-left, decoded);
+           left = 0;
+         }
+       else if (val == 0)
+         {
+           printf ("0x0");
+           left -= 3;
+         }
        else
          {
            if (do_wide)
-             left -= printf ("0x%lx", val);
+             left -= printf ("0x%llx", val);
            else
-             left -= printf ("0x%-.*lx", left, val);
+             left -= printf ("0x%-.*llx", left, val);
          }
       }
       break;
@@ -17458,6 +17769,12 @@ process_arch_specific (FILE * file)
 
   switch (elf_header.e_machine)
     {
+    case EM_ARC:
+    case EM_ARC_COMPACT:
+    case EM_ARC_COMPACT2:
+      return process_attributes (file, "ARC", SHT_ARC_ATTRIBUTES,
+                                display_arc_attribute,
+                                display_generic_attribute);
     case EM_ARM:
       return process_attributes (file, "aeabi", SHT_ARM_ATTRIBUTES,
                                 display_arm_attribute,
This page took 0.031317 seconds and 4 git commands to generate.