]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - binutils/readelf.c
2004-09-02 Paolo Bonzini <bonzini@gnu.org>
[thirdparty/binutils-gdb.git] / binutils / readelf.c
index 3cd6ffb1cf29c9619ccbbf700685e827565cdb58..eb9b451181ecdf20f776d4667d5e21a69010f9c3 100644 (file)
 #include "elf/vax.h"
 #include "elf/x86-64.h"
 #include "elf/xstormy16.h"
+#include "elf/crx.h"
 #include "elf/iq2000.h"
 #include "elf/xtensa.h"
 
@@ -206,8 +207,6 @@ print_mode;
 static bfd_vma (*byte_get) (unsigned char *, int);
 static void (*byte_put) (unsigned char *, bfd_vma, int);
 
-typedef int Elf32_Word;
-
 #define UNKNOWN -1
 
 #define SECTION_NAME(X)        ((X) == NULL ? "<none>" : \
@@ -680,6 +679,7 @@ guess_is_rela (unsigned long e_machine)
     case EM_MSP430:
     case EM_MSP430_OLD:
     case EM_XSTORMY16:
+    case EM_CRX:
     case EM_VAX:
     case EM_IP2K:
     case EM_IP2K_OLD:
@@ -1010,10 +1010,10 @@ dump_relocations (FILE *file,
          rtype = elf_i386_reloc_type (type);
          break;
 
-        case EM_68HC11:
-        case EM_68HC12:
-          rtype = elf_m68hc11_reloc_type (type);
-          break;
+       case EM_68HC11:
+       case EM_68HC12:
+         rtype = elf_m68hc11_reloc_type (type);
+         break;
 
        case EM_68K:
          rtype = elf_m68k_reloc_type (type);
@@ -1073,9 +1073,9 @@ dump_relocations (FILE *file,
          rtype = elf_fr30_reloc_type (type);
          break;
 
-        case EM_CYGNUS_FRV:
-          rtype = elf_frv_reloc_type (type);
-          break;
+       case EM_CYGNUS_FRV:
+         rtype = elf_frv_reloc_type (type);
+         break;
 
        case EM_MCORE:
          rtype = elf_mcore_reloc_type (type);
@@ -1168,6 +1168,10 @@ dump_relocations (FILE *file,
          rtype = elf_xstormy16_reloc_type (type);
          break;
 
+       case EM_CRX:
+         rtype = elf_crx_reloc_type (type);
+         break;
+
        case EM_VAX:
          rtype = elf_vax_reloc_type (type);
          break;
@@ -1221,7 +1225,7 @@ dump_relocations (FILE *file,
 
                      if (psym->st_shndx < SHN_LORESERVE)
                        sec_index = psym->st_shndx;
-                     else if (psym->st_shndx > SHN_LORESERVE)
+                     else if (psym->st_shndx > SHN_HIRESERVE)
                        sec_index = psym->st_shndx - (SHN_HIRESERVE + 1
                                                      - SHN_LORESERVE);
 
@@ -1553,9 +1557,9 @@ get_file_type (unsigned e_type)
     {
     case ET_NONE:      return _("NONE (None)");
     case ET_REL:       return _("REL (Relocatable file)");
-    case ET_EXEC:       return _("EXEC (Executable file)");
-    case ET_DYN:        return _("DYN (Shared object file)");
-    case ET_CORE:       return _("CORE (Core file)");
+    case ET_EXEC:      return _("EXEC (Executable file)");
+    case ET_DYN:       return _("DYN (Shared object file)");
+    case ET_CORE:      return _("CORE (Core file)");
 
     default:
       if ((e_type >= ET_LOPROC) && (e_type <= ET_HIPROC))
@@ -1662,6 +1666,7 @@ get_machine_name (unsigned e_machine)
     case EM_XSTORMY16:         return "Sanyo Xstormy16 CPU core";
     case EM_OPENRISC:
     case EM_OR32:              return "OpenRISC";
+    case EM_CRX:               return "National Semiconductor CRX microprocessor";
     case EM_DLX:               return "OpenDLX";
     case EM_IP2K_OLD:
     case EM_IP2K:              return "Ubicom IP2xxx 8-bit microcontrollers";
@@ -1990,6 +1995,29 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
 
          break;
 
+       case EM_SH:
+         switch ((e_flags & EF_SH_MACH_MASK))
+           {
+           case EF_SH1: strcat (buf, ", sh1"); break;
+           case EF_SH2: strcat (buf, ", sh2"); break;
+           case EF_SH3: strcat (buf, ", sh3"); break;
+           case EF_SH_DSP: strcat (buf, ", sh-dsp"); break;
+           case EF_SH3_DSP: strcat (buf, ", sh3-dsp"); break;
+           case EF_SH4AL_DSP: strcat (buf, ", sh4al-dsp"); break;
+           case EF_SH3E: strcat (buf, ", sh3e"); break;
+           case EF_SH4: strcat (buf, ", sh4"); break;
+           case EF_SH5: strcat (buf, ", sh5"); break;
+           case EF_SH2E: strcat (buf, ", sh2e"); break;
+           case EF_SH4A: strcat (buf, ", sh4a"); break;
+           case EF_SH2A: strcat (buf, ", sh2a"); break;
+           case EF_SH4_NOFPU: strcat (buf, ", sh4-nofpu"); break;
+           case EF_SH4A_NOFPU: strcat (buf, ", sh4a-nofpu"); break;
+           case EF_SH2A_NOFPU: strcat (buf, ", sh2a-nofpu"); break;
+           default: strcat (buf, ", unknown ISA"); break;
+           }
+
+         break;
+         
        case EM_SPARCV9:
          if (e_flags & EF_SPARC_32PLUS)
            strcat (buf, ", v8+");
@@ -2193,7 +2221,7 @@ get_segment_type (unsigned long p_type)
 
     case PT_GNU_EH_FRAME:
                        return "GNU_EH_FRAME";
-    case PT_GNU_STACK: return "STACK";
+    case PT_GNU_STACK: return "GNU_STACK";
     case PT_GNU_RELRO:  return "GNU_RELRO";
 
     default:
@@ -3860,7 +3888,7 @@ process_section_groups (FILE *file)
                  error (_("Bad sh_info in group section `%s'\n"), name);
                  continue;
                }
-             
+
              group_name = SECTION_NAME (section_headers + sec_index);
              strtab = NULL;
            }
@@ -3886,8 +3914,8 @@ process_section_groups (FILE *file)
          if (do_section_groups)
            {
              printf ("\n%s group section `%s' [%s] contains %u sections:\n",
-                     get_group_flags (entry), name, group_name, size); 
-             
+                     get_group_flags (entry), name, group_name, size);
+
              printf (_("   [Index]    Name\n"));
            }
 
@@ -3916,8 +3944,8 @@ process_section_groups (FILE *file)
                  sec = SECTION_HEADER (entry);
                  printf ("   [%5u]   %s\n",
                          entry, SECTION_NAME (sec));
-               } 
-             
+               }
+
              g = xmalloc (sizeof (struct group_list));
              g->section_index = entry;
              g->next = group->root;
@@ -4665,9 +4693,19 @@ get_32bit_dynamic_section (FILE *file)
   if (!edyn)
     return 0;
 
-  dynamic_nent = dynamic_size / sizeof (*ext);
-  dynamic_section = malloc (dynamic_nent * sizeof (*entry));
+/* SGI's ELF has more than one section in the DYNAMIC segment, and we
+   might not have the luxury of section headers.  Look for the DT_NULL
+   terminator to determine the number of entries.  */
+  for (ext = edyn, dynamic_nent = 0;
+       (char *) ext < (char *) edyn + dynamic_size;
+       ext++)
+    {
+      dynamic_nent++;
+      if (BYTE_GET (ext->d_tag) == DT_NULL)
+       break;
+    }
 
+  dynamic_section = malloc (dynamic_nent * sizeof (*entry));
   if (dynamic_section == NULL)
     {
       error (_("Out of memory\n"));
@@ -4676,7 +4714,7 @@ get_32bit_dynamic_section (FILE *file)
     }
 
   for (ext = edyn, entry = dynamic_section;
-       (char *) ext < (char *) edyn + dynamic_size;
+       entry < dynamic_section + dynamic_nent;
        ext++, entry++)
     {
       entry->d_tag      = BYTE_GET (ext->d_tag);
@@ -4699,9 +4737,19 @@ get_64bit_dynamic_section (FILE *file)
   if (!edyn)
     return 0;
 
-  dynamic_nent = dynamic_size / sizeof (*ext);
-  dynamic_section = malloc (dynamic_nent * sizeof (*entry));
+/* SGI's ELF has more than one section in the DYNAMIC segment, and we
+   might not have the luxury of section headers.  Look for the DT_NULL
+   terminator to determine the number of entries.  */
+  for (ext = edyn, dynamic_nent = 0;
+       (char *) ext < (char *) edyn + dynamic_size;
+       ext++)
+    {
+      dynamic_nent++;
+      if (BYTE_GET8 (ext->d_tag) == DT_NULL)
+       break;
+    }
 
+  dynamic_section = malloc (dynamic_nent * sizeof (*entry));
   if (dynamic_section == NULL)
     {
       error (_("Out of memory\n"));
@@ -4710,7 +4758,7 @@ get_64bit_dynamic_section (FILE *file)
     }
 
   for (ext = edyn, entry = dynamic_section;
-       (char *) ext < (char *) edyn + dynamic_size;
+       entry < dynamic_section + dynamic_nent;
        ext++, entry++)
     {
       entry->d_tag      = BYTE_GET8 (ext->d_tag);
@@ -7108,9 +7156,9 @@ get_TAG_name (unsigned long tag)
     case DW_TAG_partial_unit:          return "DW_TAG_partial_unit";
     case DW_TAG_imported_unit:         return "DW_TAG_imported_unit";
       /* UPC values.  */
-    case DW_TAG_upc_shared_type:        return "DW_TAG_upc_shared_type";
-    case DW_TAG_upc_strict_type:        return "DW_TAG_upc_strict_type";
-    case DW_TAG_upc_relaxed_type:       return "DW_TAG_upc_relaxed_type";
+    case DW_TAG_upc_shared_type:       return "DW_TAG_upc_shared_type";
+    case DW_TAG_upc_strict_type:       return "DW_TAG_upc_strict_type";
+    case DW_TAG_upc_relaxed_type:      return "DW_TAG_upc_relaxed_type";
     default:
       {
        static char buffer[100];
@@ -8136,7 +8184,7 @@ read_and_display_attr_value (unsigned long attribute,
          data += offset_size;
        }
       else
-        {
+       {
          error (_("Internal error: DWARF version is not 2 or 3.\n"));
        }
       break;
@@ -8458,6 +8506,88 @@ read_and_display_attr (unsigned long attribute,
   return data;
 }
 
+/* Apply addends of RELA relocations.  */
+
+static int
+debug_apply_rela_addends (FILE *file,
+                         Elf_Internal_Shdr *section,
+                         int reloc_size,
+                         unsigned char *sec_data,
+                         unsigned char *start,
+                         unsigned char *end)
+{
+  Elf_Internal_Shdr *relsec;
+
+  if (end - start < reloc_size)
+    return 1;
+
+  for (relsec = section_headers;
+       relsec < section_headers + elf_header.e_shnum;
+       ++relsec)
+    {
+      unsigned long nrelas;
+      Elf_Internal_Rela *rela, *rp;
+      Elf_Internal_Shdr *symsec;
+      Elf_Internal_Sym *symtab;
+      Elf_Internal_Sym *sym;
+
+      if (relsec->sh_type != SHT_RELA
+         || SECTION_HEADER (relsec->sh_info) != section
+         || relsec->sh_size == 0)
+       continue;
+
+      if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size,
+                             &rela, &nrelas))
+       return 0;
+
+      symsec = SECTION_HEADER (relsec->sh_link);
+      symtab = GET_ELF_SYMBOLS (file, symsec);
+
+      for (rp = rela; rp < rela + nrelas; ++rp)
+       {
+         unsigned char *loc;
+
+         if (rp->r_offset >= (bfd_vma) (start - sec_data)
+             && rp->r_offset < (bfd_vma) (end - sec_data) - reloc_size)
+           loc = sec_data + rp->r_offset;
+         else
+           continue;
+
+         if (is_32bit_elf)
+           {
+             sym = symtab + ELF32_R_SYM (rp->r_info);
+
+             if (ELF32_R_SYM (rp->r_info) != 0
+                 && ELF32_ST_TYPE (sym->st_info) != STT_SECTION)
+               {
+                 warn (_("Skipping unexpected symbol type %u\n"),
+                       ELF32_ST_TYPE (sym->st_info));
+                 continue;
+               }
+           }
+         else
+           {
+             sym = symtab + ELF64_R_SYM (rp->r_info);
+
+             if (ELF64_R_SYM (rp->r_info) != 0
+                 && ELF64_ST_TYPE (sym->st_info) != STT_SECTION)
+               {
+                 warn (_("Skipping unexpected symbol type %u\n"),
+                       ELF64_ST_TYPE (sym->st_info));
+                 continue;
+               }
+           }
+
+         byte_put (loc, rp->r_addend, reloc_size);
+       }
+
+      free (symtab);
+      free (rela);
+      break;
+    }
+  return 1;
+}
+
 static int
 display_debug_info (Elf_Internal_Shdr *section,
                    unsigned char *start,
@@ -8474,7 +8604,6 @@ display_debug_info (Elf_Internal_Shdr *section,
   while (start < end)
     {
       DWARF2_Internal_CompUnit compunit;
-      Elf_Internal_Shdr *relsec;
       unsigned char *hdrptr;
       unsigned char *cu_abbrev_offset_ptr;
       unsigned char *tags;
@@ -8504,71 +8633,13 @@ display_debug_info (Elf_Internal_Shdr *section,
       compunit.cu_version = byte_get (hdrptr, 2);
       hdrptr += 2;
 
-      /* Apply addends of RELA relocations.  */
-      for (relsec = section_headers;
-          relsec < section_headers + elf_header.e_shnum;
-          ++relsec)
-       {
-         unsigned long nrelas;
-         Elf_Internal_Rela *rela, *rp;
-         Elf_Internal_Shdr *symsec;
-         Elf_Internal_Sym *symtab;
-         Elf_Internal_Sym *sym;
-
-         if (relsec->sh_type != SHT_RELA
-             || SECTION_HEADER (relsec->sh_info) != section
-             || relsec->sh_size == 0)
-           continue;
-
-         if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size,
-                                 & rela, & nrelas))
-           return 0;
-
-         symsec = SECTION_HEADER (relsec->sh_link);
-         symtab = GET_ELF_SYMBOLS (file, symsec);
-
-         for (rp = rela; rp < rela + nrelas; ++rp)
-           {
-             unsigned char *loc;
-
-             if (rp->r_offset >= (bfd_vma) (hdrptr - section_begin)
-                 && section->sh_size > (bfd_vma) offset_size
-                 && rp->r_offset <= section->sh_size - offset_size)
-               loc = section_begin + rp->r_offset;
-             else
-               continue;
-
-             if (is_32bit_elf)
-               {
-                 sym = symtab + ELF32_R_SYM (rp->r_info);
-
-                 if (ELF32_R_SYM (rp->r_info) != 0
-                     && ELF32_ST_TYPE (sym->st_info) != STT_SECTION)
-                   {
-                     warn (_("Skipping unexpected symbol type %u\n"),
-                           ELF32_ST_TYPE (sym->st_info));
-                     continue;
-                   }
-               }
-             else
-               {
-                 sym = symtab + ELF64_R_SYM (rp->r_info);
-
-                 if (ELF64_R_SYM (rp->r_info) != 0
-                     && ELF64_ST_TYPE (sym->st_info) != STT_SECTION)
-                   {
-                     warn (_("Skipping unexpected symbol type %u\n"),
-                           ELF64_ST_TYPE (sym->st_info));
-                     continue;
-                   }
-               }
-
-             byte_put (loc, rp->r_addend, offset_size);
-           }
+      cu_offset = start - section_begin;
+      start += compunit.cu_length + initial_length_size;
 
-         free (rela);
-         break;
-       }
+      if (elf_header.e_type == ET_REL
+         && !debug_apply_rela_addends (file, section, offset_size,
+                                       section_begin, hdrptr, start))
+       return 0;
 
       cu_abbrev_offset_ptr = hdrptr;
       compunit.cu_abbrev_offset = byte_get (hdrptr, offset_size);
@@ -8578,8 +8649,6 @@ display_debug_info (Elf_Internal_Shdr *section,
       hdrptr += 1;
 
       tags = hdrptr;
-      cu_offset = start - section_begin;
-      start += compunit.cu_length + initial_length_size;
 
       printf (_("  Compilation Unit @ %lx:\n"), cu_offset);
       printf (_("   Length:        %ld\n"), compunit.cu_length);
@@ -8711,7 +8780,7 @@ display_debug_aranges (Elf_Internal_Shdr *section,
          initial_length_size = 12;
        }
       else
-        {
+       {
          offset_size = 4;
          initial_length_size = 4;
        }
@@ -8969,6 +9038,11 @@ display_debug_frames (Elf_Internal_Shdr *section,
       block_end = saved_start + length + initial_length_size;
       cie_id = byte_get (start, offset_size); start += offset_size;
 
+      if (elf_header.e_type == ET_REL
+         && !debug_apply_rela_addends (file, section, offset_size,
+                                       section_start, start, block_end))
+       return 0;
+
       if (is_eh ? (cie_id == 0) : (cie_id == DW_CIE_ID))
        {
          int version;
@@ -9133,7 +9207,10 @@ display_debug_frames (Elf_Internal_Shdr *section,
            encoded_ptr_size = size_of_encoded_value (fc->fde_encoding);
 
          fc->pc_begin = get_encoded_value (start, fc->fde_encoding);
-         if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel)
+         if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel
+             /* Don't adjust for ET_REL since there's invariably a pcrel
+                reloc here, which we haven't applied.  */
+             && elf_header.e_type != ET_REL)
            fc->pc_begin += section->sh_addr + (start - section_start);
          start += encoded_ptr_size;
          fc->pc_range = byte_get (start, encoded_ptr_size);
@@ -9155,7 +9232,7 @@ display_debug_frames (Elf_Internal_Shdr *section,
              unsigned long i;
              printf ("  Augmentation data:    ");
              for (i = 0; i < augmentation_data_len; ++i)
-               printf (" %02x", augmentation_data[i]);
+               printf (" %02x", augmentation_data[i]);
              putchar ('\n');
              putchar ('\n');
            }
@@ -9185,7 +9262,7 @@ display_debug_frames (Elf_Internal_Shdr *section,
                op &= 0xc0;
 
              /* Warning: if you add any more cases to this switch, be
-                sure to add them to the corresponding switch below.  */
+                sure to add them to the corresponding switch below.  */
              switch (op)
                {
                case DW_CFA_advance_loc:
@@ -9286,7 +9363,7 @@ display_debug_frames (Elf_Internal_Shdr *section,
        }
 
       /* Now we know what registers are used, make a second pass over
-         the chunk, this time actually printing out the info.  */
+        the chunk, this time actually printing out the info.  */
 
       while (start < block_end)
        {
@@ -9332,7 +9409,8 @@ display_debug_frames (Elf_Internal_Shdr *section,
 
            case DW_CFA_set_loc:
              vma = get_encoded_value (start, fc->fde_encoding);
-             if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel)
+             if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel
+                 && elf_header.e_type != ET_REL)
                vma += section->sh_addr + (start - section_start);
              start += encoded_ptr_size;
              if (do_debug_frames_interp)