Add .note.gnu.property runtime verification and merge support
[external/binutils.git] / binutils / readelf.c
index 5bfbac9..7f22c58 100644 (file)
@@ -232,6 +232,7 @@ static unsigned int dynamic_syminfo_nent;
 static char program_interpreter[PATH_MAX];
 static bfd_vma dynamic_info[DT_ENCODING];
 static bfd_vma dynamic_info_DT_GNU_HASH;
+static bfd_vma dynamic_info_DT_MIPS_XHASH;
 static bfd_vma version_info[16];
 static Elf_Internal_Dyn *  dynamic_section;
 static elf_section_list * symtab_shndx_list;
@@ -335,6 +336,10 @@ static const char * get_symbol_version_string
        (ADDR) &= ~1;                           \
     }                                          \
   while (0)
+
+/* Get the correct GNU hash section name.  */
+#define GNU_HASH_SECTION_NAME                  \
+  dynamic_info_DT_MIPS_XHASH ? ".MIPS.xhash" : ".gnu.hash"
 \f
 /* Print a BFD_VMA to an internal buffer, for use in error messages.
    BFD_FMA_FMT can't be used in translated strings.  */
@@ -1872,6 +1877,7 @@ get_mips_dynamic_type (unsigned long type)
     case DT_MIPS_AUX_DYNAMIC: return "MIPS_AUX_DYNAMIC";
     case DT_MIPS_PLTGOT: return "MIPS_PLTGOT";
     case DT_MIPS_RWPLT: return "MIPS_RWPLT";
+    case DT_MIPS_XHASH: return "MIPS_XHASH";
     default:
       return NULL;
     }
@@ -4113,6 +4119,7 @@ get_mips_section_type_name (unsigned int sh_type)
     case SHT_MIPS_XLATE_OLD:    return "MIPS_XLATE_OLD";
     case SHT_MIPS_PDR_EXCEPTION: return "MIPS_PDR_EXCEPTION";
     case SHT_MIPS_ABIFLAGS:     return "MIPS_ABIFLAGS";
+    case SHT_MIPS_XHASH:        return "MIPS_XHASH";
     default:
       break;
     }
@@ -5094,6 +5101,9 @@ process_program_headers (Filedata * filedata)
   unsigned int i;
   Elf_Internal_Phdr * previous_load = NULL;
 
+  dynamic_addr = 0;
+  dynamic_size = 0;
+
   if (filedata->file_header.e_phnum == 0)
     {
       /* PR binutils/12467.  */
@@ -5144,9 +5154,6 @@ process_program_headers (Filedata * filedata)
        }
     }
 
-  dynamic_addr = 0;
-  dynamic_size = 0;
-
   for (i = 0, segment = filedata->program_headers;
        i < filedata->file_header.e_phnum;
        i++, segment++)
@@ -9525,6 +9532,11 @@ dynamic_section_mips_val (Elf_Internal_Dyn * entry)
       print_vma (entry->d_un.d_val, DEC);
       break;
 
+    case DT_MIPS_XHASH:
+      dynamic_info_DT_MIPS_XHASH = entry->d_un.d_val;
+      dynamic_info_DT_GNU_HASH = entry->d_un.d_val;
+      /* Falls through.  */
+
     default:
       print_vma (entry->d_un.d_ptr, PREFIX_HEX);
     }
@@ -11516,6 +11528,7 @@ get_symbol_version_string (Filedata *                   filedata,
   if ((vers_data & VERSYM_HIDDEN) == 0 && vers_data == 0)
     return NULL;
 
+  *sym_info = (vers_data & VERSYM_HIDDEN) != 0 ? symbol_hidden : symbol_public;
   max_vd_ndx = 0;
 
   /* Usually we'd only see verdef for defined symbols, and verneed for
@@ -11581,12 +11594,8 @@ get_symbol_version_string (Filedata *                   filedata,
              ivda.vda_name = BYTE_GET (evda.vda_name);
 
              if (psym->st_name != ivda.vda_name)
-               {
-                 *sym_info = ((vers_data & VERSYM_HIDDEN) != 0
-                              ? symbol_hidden : symbol_public);
-                 return (ivda.vda_name < strtab_size
-                         ? strtab + ivda.vda_name : _("<corrupt>"));
-               }
+               return (ivda.vda_name < strtab_size
+                       ? strtab + ivda.vda_name : _("<corrupt>"));
            }
        }
     }
@@ -11673,6 +11682,7 @@ process_symbol_table (Filedata * filedata)
   bfd_vma ngnubuckets = 0;
   bfd_vma * gnubuckets = NULL;
   bfd_vma * gnuchains = NULL;
+  bfd_vma * mipsxlat = NULL;
   bfd_vma gnusymidx = 0;
   bfd_size_type ngnuchains = 0;
 
@@ -11838,7 +11848,31 @@ process_symbol_table (Filedata * filedata)
       gnuchains = get_dynamic_data (filedata, maxchain, 4);
       ngnuchains = maxchain;
 
+      if (gnuchains == NULL)
+       goto no_gnu_hash;
+
+      if (dynamic_info_DT_MIPS_XHASH)
+       {
+         if (fseek (filedata->handle,
+                    (archive_file_offset
+                     + offset_from_vma (filedata, (buckets_vma
+                                                   + 4 * (ngnubuckets
+                                                          + maxchain)), 4)),
+                    SEEK_SET))
+           {
+             error (_("Unable to seek to start of dynamic information\n"));
+             goto no_gnu_hash;
+           }
+
+         mipsxlat = get_dynamic_data (filedata, maxchain, 4);
+       }
+
     no_gnu_hash:
+      if (dynamic_info_DT_MIPS_XHASH && mipsxlat == NULL)
+       {
+         free (gnuchains);
+         gnuchains = NULL;
+       }
       if (gnuchains == NULL)
        {
          free (gnubuckets);
@@ -11888,7 +11922,8 @@ process_symbol_table (Filedata * filedata)
 
       if (dynamic_info_DT_GNU_HASH)
        {
-         printf (_("\nSymbol table of `.gnu.hash' for image:\n"));
+         printf (_("\nSymbol table of `%s' for image:\n"),
+                 GNU_HASH_SECTION_NAME);
          if (is_32bit_elf)
            printf (_("  Num Buc:    Value  Size   Type   Bind Vis      Ndx Name\n"));
          else
@@ -11902,7 +11937,10 @@ process_symbol_table (Filedata * filedata)
 
                do
                  {
-                   print_dynamic_symbol (filedata, si, hn);
+                   if (dynamic_info_DT_MIPS_XHASH)
+                     print_dynamic_symbol (filedata, mipsxlat[off], hn);
+                   else
+                     print_dynamic_symbol (filedata, si, hn);
                    si++;
                  }
                while (off < ngnuchains && (gnuchains[off++] & 1) == 0);
@@ -12125,11 +12163,12 @@ process_symbol_table (Filedata * filedata)
       unsigned long nzero_counts = 0;
       unsigned long nsyms = 0;
 
-      printf (ngettext ("\nHistogram for `.gnu.hash' bucket list length "
+      printf (ngettext ("\nHistogram for `%s' bucket list length "
                        "(total of %lu bucket):\n",
-                       "\nHistogram for `.gnu.hash' bucket list length "
+                       "\nHistogram for `%s' bucket list length "
                        "(total of %lu buckets):\n",
                        (unsigned long) ngnubuckets),
+             GNU_HASH_SECTION_NAME,
              (unsigned long) ngnubuckets);
 
       lengths = (unsigned long *) calloc (ngnubuckets, sizeof (*lengths));
@@ -12186,6 +12225,7 @@ process_symbol_table (Filedata * filedata)
       free (lengths);
       free (gnubuckets);
       free (gnuchains);
+      free (mipsxlat);
     }
 
   return TRUE;
@@ -17710,6 +17750,20 @@ decode_aarch64_feature_1_and (unsigned int bitmask)
 }
 
 static void
+decode_compiler_flags_notes (unsigned long bitmask)
+{
+  printf("%#lx [", bitmask);
+
+  printf("%c%ccxx11, ", bitmask & GNU_PROPERTY_USECXX_VALIDATION ? '=' : '~',
+        bitmask & GNU_PROPERTY_USECXX11_ABI ? '+' : '!');
+
+  printf("%c%casan", bitmask & GNU_PROPERTY_SANITIZE_VALIDATION ? '=' : '~',
+        bitmask & GNU_PROPERTY_SANITIZE_ADDRESS ? '+' : '!');
+
+  printf("]");
+}
+
+static void
 print_gnu_property_note (Filedata * filedata, Elf_Internal_Note * pnote)
 {
   unsigned char * ptr = (unsigned char *) pnote->descdata;
@@ -17874,6 +17928,18 @@ print_gnu_property_note (Filedata * filedata, Elf_Internal_Note * pnote)
                printf (_("<corrupt length: %#x> "), datasz);
              goto next;
 
+           case GNU_PROPERTY_COMPILER_FLAGS:
+             printf ("compilations flags: ");
+             if ((datasz != 4) && (datasz != 8))
+               printf (_("<corrupt length: %#x> "), datasz);
+             else
+               {
+                 unsigned long bitmask_flags;
+                 bitmask_flags = (unsigned long) byte_get (ptr, size);
+                 decode_compiler_flags_notes (bitmask_flags);
+               }
+             goto next;
+
            default:
              break;
            }
@@ -19744,6 +19810,7 @@ process_object (Filedata * filedata)
   for (i = ARRAY_SIZE (dynamic_info); i--;)
     dynamic_info[i] = 0;
   dynamic_info_DT_GNU_HASH = 0;
+  dynamic_info_DT_MIPS_XHASH = 0;
 
   /* Process the file.  */
   if (show_name)