]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - binutils/readelf.c
Add new Dutch translation.
[thirdparty/binutils-gdb.git] / binutils / readelf.c
index ef36de0058c74e227ae42273cb68546aba330862..5780bfae1f705ba07c55e08fe18ef21082960b14 100644 (file)
 #include "elf/x86-64.h"
 #include "elf/xstormy16.h"
 #include "elf/iq2000.h"
+#include "elf/xtensa.h"
 
 #include "bucomm.h"
 #include "getopt.h"
+#include "libiberty.h"
 
 char *program_name = "readelf";
 unsigned long dynamic_addr;
@@ -104,11 +106,11 @@ Elf_Internal_Syminfo *dynamic_syminfo;
 unsigned long dynamic_syminfo_offset;
 unsigned int dynamic_syminfo_nent;
 char program_interpreter[64];
-long dynamic_info[DT_JMPREL + 1];
-long version_info[16];
-long loadaddr = 0;
+bfd_vma dynamic_info[DT_JMPREL + 1];
+bfd_vma version_info[16];
 Elf_Internal_Ehdr elf_header;
 Elf_Internal_Shdr *section_headers;
+Elf_Internal_Phdr *program_headers;
 Elf_Internal_Dyn *dynamic_segment;
 Elf_Internal_Shdr *symtab_shndx_hdr;
 int show_name;
@@ -171,6 +173,14 @@ static bfd_vma byte_get_little_endian
   PARAMS ((unsigned char *, int));
 static bfd_vma byte_get_big_endian
   PARAMS ((unsigned char *, int));
+static bfd_vma byte_get_signed
+  PARAMS ((unsigned char *, int));
+static void (*byte_put)
+  PARAMS ((unsigned char *, bfd_vma, int));
+static void byte_put_little_endian
+  PARAMS ((unsigned char *, bfd_vma, int));
+static void byte_put_big_endian
+  PARAMS ((unsigned char *, bfd_vma, int));
 static const char *get_mips_dynamic_type
   PARAMS ((unsigned long));
 static const char *get_sparc64_dynamic_type
@@ -179,6 +189,8 @@ static const char *get_ppc64_dynamic_type
   PARAMS ((unsigned long));
 static const char *get_parisc_dynamic_type
   PARAMS ((unsigned long));
+static const char *get_ia64_dynamic_type
+  PARAMS ((unsigned long));
 static const char *get_dynamic_type
   PARAMS ((unsigned long));
 static int slurp_rela_relocs
@@ -240,6 +252,8 @@ static void dynamic_segment_mips_val
   PARAMS ((Elf_Internal_Dyn *));
 static void dynamic_segment_parisc_val
   PARAMS ((Elf_Internal_Dyn *));
+static void dynamic_segment_ia64_val
+  PARAMS ((Elf_Internal_Dyn *));
 static int process_dynamic_segment
   PARAMS ((FILE *));
 static int process_symbol_table
@@ -268,6 +282,8 @@ static int get_32bit_program_headers
   PARAMS ((FILE *, Elf_Internal_Phdr *));
 static int get_64bit_program_headers
   PARAMS ((FILE *, Elf_Internal_Phdr *));
+static int get_program_headers
+  PARAMS ((FILE *));
 static int get_file_header
   PARAMS ((FILE *));
 static Elf_Internal_Sym *get_32bit_elf_symbols
@@ -282,6 +298,8 @@ static int get_32bit_dynamic_segment
   PARAMS ((FILE *));
 static int get_64bit_dynamic_segment
   PARAMS ((FILE *));
+static long offset_from_vma
+  PARAMS ((FILE *, bfd_vma vma, bfd_size_type size));
 #ifdef SUPPORT_DISASSEMBLY
 static int disassemble_section
   PARAMS ((Elf_Internal_Shdr *, FILE *));
@@ -344,10 +362,10 @@ static void add_abbrev_attr
   PARAMS ((unsigned long, unsigned long));
 static unsigned char *read_and_display_attr
   PARAMS ((unsigned long, unsigned long, unsigned char *, unsigned long,
-          unsigned long));
+          unsigned long, unsigned long, int));
 static unsigned char *read_and_display_attr_value
   PARAMS ((unsigned long, unsigned long, unsigned char *, unsigned long,
-          unsigned long));
+          unsigned long, unsigned long, int));
 static unsigned char *display_block
   PARAMS ((unsigned char *, unsigned long));
 static void decode_location_expression
@@ -403,7 +421,7 @@ typedef int Elf32_Word;
 
 #define SECTION_HEADER(I) (section_headers + SECTION_HEADER_INDEX (I))
 
-#define DT_VERSIONTAGIDX(tag)  (DT_VERNEEDNUM - (tag)) /* Reverse order! */
+#define DT_VERSIONTAGIDX(tag)  (DT_VERNEEDNUM - (tag)) /* Reverse order!  */
 
 #define BYTE_GET(field)        byte_get (field, sizeof (field))
 
@@ -467,7 +485,7 @@ get_data (var, file, offset, size, reason)
 
   if (fseek (file, offset, SEEK_SET))
     {
-      error (_("Unable to seek to %x for %s\n"), offset, reason);
+      error (_("Unable to seek to 0x%x for %s\n"), offset, reason);
       return NULL;
     }
 
@@ -478,7 +496,7 @@ get_data (var, file, offset, size, reason)
 
       if (mvar == NULL)
        {
-         error (_("Out of memory allocating %d bytes for %s\n"),
+         error (_("Out of memory allocating 0x%x bytes for %s\n"),
                 size, reason);
          return NULL;
        }
@@ -486,7 +504,7 @@ get_data (var, file, offset, size, reason)
 
   if (fread (mvar, size, 1, file) != 1)
     {
-      error (_("Unable to read in %d bytes of %s\n"), size, reason);
+      error (_("Unable to read in 0x%x bytes of %s\n"), size, reason);
       if (mvar != var)
        free (mvar);
       return NULL;
@@ -544,6 +562,60 @@ byte_get_little_endian (field, size)
     }
 }
 
+static bfd_vma
+byte_get_signed (field, size)
+     unsigned char *field;
+     int size;
+{
+  bfd_vma x = byte_get (field, size);
+
+  switch (size)
+    {
+    case 1:
+      return (x ^ 0x80) - 0x80;
+    case 2:
+      return (x ^ 0x8000) - 0x8000;
+    case 4:
+      return (x ^ 0x80000000) - 0x80000000;
+    case 8:
+    case -8:
+      return x;
+    default:
+      abort ();
+    }
+}
+
+static void
+byte_put_little_endian (field, value, size)
+     unsigned char * field;
+     bfd_vma        value;
+     int             size;
+{
+  switch (size)
+    {
+    case 8:
+      field[7] = (((value >> 24) >> 24) >> 8) & 0xff;
+      field[6] = ((value >> 24) >> 24) & 0xff;
+      field[5] = ((value >> 24) >> 16) & 0xff;
+      field[4] = ((value >> 24) >> 8) & 0xff;
+      /* Fall through.  */
+    case 4:
+      field[3] = (value >> 24) & 0xff;
+      field[2] = (value >> 16) & 0xff;
+      /* Fall through.  */
+    case 2:
+      field[1] = (value >> 8) & 0xff;
+      /* Fall through.  */
+    case 1:
+      field[0] = value & 0xff;
+      break;
+
+    default:
+      error (_("Unhandled data length: %d\n"), size);
+      abort ();
+    }
+}
+
 /* Print a VMA value.  */
 static void
 print_vma (vma, mode)
@@ -556,13 +628,34 @@ print_vma (vma, mode)
     {
       switch (mode)
        {
-       case FULL_HEX: printf ("0x"); /* drop through */
-       case LONG_HEX: printf ("%8.8lx", (unsigned long) vma); break;
-       case PREFIX_HEX: printf ("0x"); /* drop through */
-       case HEX: printf ("%lx", (unsigned long) vma); break;
-       case DEC: printf ("%ld", (unsigned long) vma); break;
-       case DEC_5: printf ("%5ld", (long) vma); break;
-       case UNSIGNED: printf ("%lu", (unsigned long) vma); break;
+       case FULL_HEX:
+         printf ("0x");
+         /* Drop through.  */
+       case LONG_HEX:
+         printf ("%8.8lx", (unsigned long) vma);
+         break;
+
+       case DEC_5:
+         if (vma <= 99999)
+           {
+             printf ("%5ld", (long) vma);
+             break;
+           }
+         /* Drop through.  */
+       case PREFIX_HEX:
+         printf ("0x");
+         /* Drop through.  */
+       case HEX:
+         printf ("%lx", (unsigned long) vma);
+         break;
+
+       case DEC:
+         printf ("%ld", (unsigned long) vma);
+         break;
+
+       case UNSIGNED:
+         printf ("%lu", (unsigned long) vma);
+         break;
        }
     }
 #ifdef BFD64
@@ -572,7 +665,7 @@ print_vma (vma, mode)
        {
        case FULL_HEX:
          printf ("0x");
-         /* drop through */
+         /* Drop through.  */
 
        case LONG_HEX:
          printf_vma (vma);
@@ -580,7 +673,7 @@ print_vma (vma, mode)
 
        case PREFIX_HEX:
          printf ("0x");
-         /* drop through */
+         /* Drop through.  */
 
        case HEX:
 #if BFD_HOST_64BIT_LONG
@@ -607,13 +700,18 @@ print_vma (vma, mode)
 
        case DEC_5:
 #if BFD_HOST_64BIT_LONG
-         printf ("%5ld", vma);
+         if (vma <= 99999)
+           printf ("%5ld", vma);
+         else
+           printf ("%#lx", vma);
 #else
          if (_bfd_int64_high (vma))
            /* ugg */
            printf ("++%ld", _bfd_int64_low (vma));
-         else
+         else if (vma <= 99999)
            printf ("%5ld", _bfd_int64_low (vma));
+         else
+           printf ("%#lx", _bfd_int64_low (vma));
 #endif
          break;
 
@@ -702,6 +800,41 @@ byte_get_big_endian (field, size)
     }
 }
 
+static void
+byte_put_big_endian (field, value, size)
+     unsigned char * field;
+     bfd_vma        value;
+     int             size;
+{
+  switch (size)
+    {
+    case 8:
+      field[7] = value & 0xff;
+      field[6] = (value >> 8) & 0xff;
+      field[5] = (value >> 16) & 0xff;
+      field[4] = (value >> 24) & 0xff;
+      value >>= 16;
+      value >>= 16;
+      /* Fall through.  */
+    case 4:
+      field[3] = value & 0xff;
+      field[2] = (value >> 8) & 0xff;
+      value >>= 16;
+      /* Fall through.  */
+    case 2:
+      field[1] = value & 0xff;
+      value >>= 8;
+      /* Fall through.  */
+    case 1:
+      field[0] = value & 0xff;
+      break;
+
+    default:
+      error (_("Unhandled data length: %d\n"), size);
+      abort ();
+    }
+}
+
 /* Guess the relocation size commonly used by the specific machines.  */
 
 static int
@@ -766,6 +899,8 @@ guess_is_rela (e_machine)
     case EM_IP2K:
     case EM_IP2K_OLD:
     case EM_IQ2000:
+    case EM_XTENSA:
+    case EM_XTENSA_OLD:
       return TRUE;
 
     case EM_MMA:
@@ -940,6 +1075,7 @@ slurp_rel_relocs (file, rel_offset, rel_size, relsp, nrelsp)
 }
 
 /* Display the contents of the relocation data found at the specified offset.  */
+
 static int
 dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, is_rela)
      FILE *file;
@@ -990,14 +1126,14 @@ dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, is_rela)
       if (is_rela)
        {
          if (do_wide)
-           printf (_("    Offset             Info            Type               Symbol's Value  Symbol's Name + Addend\n"));
+           printf (_("    Offset             Info             Type               Symbol's Value  Symbol's Name + Addend\n"));
          else
            printf (_("  Offset          Info           Type           Sym. Value    Sym. Name + Addend\n"));
        }
       else
        {
          if (do_wide)
-           printf (_("    Offset             Info            Type               Symbol's Value  Symbol's Name\n"));
+           printf (_("    Offset             Info             Type               Symbol's Value  Symbol's Name\n"));
          else
            printf (_("  Offset          Info           Type           Sym. Value    Sym. Name\n"));
        }
@@ -1025,8 +1161,22 @@ dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, is_rela)
        }
       else
        {
+         /* The #ifdef BFD64 below is to prevent a compile time warning.
+            We know that if we do not have a 64 bit data type that we
+            will never execute this code anyway.  */
+#ifdef BFD64
          if (elf_header.e_machine == EM_MIPS)
            {
+             /* In little-endian objects, r_info isn't really a 64-bit
+                little-endian value: it has a 32-bit little-endian
+                symbol index followed by four individual byte fields.
+                Reorder INFO accordingly.  */
+             if (elf_header.e_ident[EI_DATA] != ELFDATA2MSB)
+               info = (((info & 0xffffffff) << 32)
+                       | ((info >> 56) & 0xff)
+                       | ((info >> 40) & 0xff00)
+                       | ((info >> 24) & 0xff0000)
+                       | ((info >> 8) & 0xff000000));
              type  = ELF64_MIPS_R_TYPE (info);
              type2 = ELF64_MIPS_R_TYPE2 (info);
              type3 = ELF64_MIPS_R_TYPE3 (info);
@@ -1035,10 +1185,7 @@ dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, is_rela)
            type = ELF64_R_TYPE_ID (info);
          else
            type = ELF64_R_TYPE (info);
-         /* The #ifdef BFD64 below is to prevent a compile time warning.
-            We know that if we do not have a 64 bit data type that we
-            will never execute this code anyway.  */
-#ifdef BFD64
+
          symtab_index = ELF64_R_SYM  (info);
 #endif
        }
@@ -1255,6 +1402,11 @@ dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, is_rela)
        case EM_IQ2000:
          rtype = elf_iq2000_reloc_type (type);
          break;
+
+       case EM_XTENSA_OLD:
+       case EM_XTENSA:
+         rtype = elf_xtensa_reloc_type (type);
+         break;
        }
 
       if (rtype == NULL)
@@ -1264,7 +1416,7 @@ dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, is_rela)
        printf (_("unrecognized: %-7lx"), type);
 #endif
       else
-       printf (do_wide ? "%-21.21s" : "%-17.17s", rtype);
+       printf (do_wide ? "%-22.22s" : "%-17.17s", rtype);
 
       if (symtab_index)
        {
@@ -1468,6 +1620,18 @@ get_parisc_dynamic_type (type)
     }
 }
 
+static const char *
+get_ia64_dynamic_type (type)
+     unsigned long type;
+{
+  switch (type)
+    {
+    case DT_IA_64_PLT_RESERVE: return "IA_64_PLT_RESERVE";
+    default:
+      return NULL;
+    }
+}
+
 static const char *
 get_dynamic_type (type)
      unsigned long type;
@@ -1565,6 +1729,9 @@ get_dynamic_type (type)
            case EM_PPC64:
              result = get_ppc64_dynamic_type (type);
              break;
+           case EM_IA_64:
+             result = get_ia64_dynamic_type (type);
+             break;
            default:
              result = NULL;
              break;
@@ -1658,14 +1825,14 @@ get_machine_name (e_machine)
     case EM_MCORE:             return "MCORE";
     case EM_ARM:               return "ARM";
     case EM_OLD_ALPHA:         return "Digital Alpha (old)";
-    case EM_SH:                        return "Hitachi SH";
+    case EM_SH:                        return "Renesas / SuperH SH";
     case EM_SPARCV9:           return "Sparc v9";
     case EM_TRICORE:           return "Siemens Tricore";
     case EM_ARC:               return "ARC";
-    case EM_H8_300:            return "Hitachi H8/300";
-    case EM_H8_300H:           return "Hitachi H8/300H";
-    case EM_H8S:               return "Hitachi H8S";
-    case EM_H8_500:            return "Hitachi H8/500";
+    case EM_H8_300:            return "Renesas H8/300";
+    case EM_H8_300H:           return "Renesas H8/300H";
+    case EM_H8S:               return "Renesas H8S";
+    case EM_H8_500:            return "Renesas H8/500";
     case EM_IA_64:             return "Intel IA-64";
     case EM_MIPS_X:            return "Stanford MIPS-X";
     case EM_COLDFIRE:          return "Motorola Coldfire";
@@ -1676,7 +1843,7 @@ get_machine_name (e_machine)
     case EM_CYGNUS_D30V:
     case EM_D30V:              return "d30v";
     case EM_CYGNUS_M32R:
-    case EM_M32R:              return "Mitsubishi M32r";
+    case EM_M32R:              return "Renesas M32R (formerly Mitsubishi M32r)";
     case EM_CYGNUS_V850:
     case EM_V850:              return "NEC v850";
     case EM_CYGNUS_MN10300:
@@ -1725,6 +1892,8 @@ get_machine_name (e_machine)
     case EM_IP2K_OLD:
     case EM_IP2K:              return "Ubicom IP2xxx 8-bit microcontrollers";
     case EM_IQ2000:            return "Vitesse IQ2000";
+    case EM_XTENSA_OLD:
+    case EM_XTENSA:            return "Tensilica Xtensa Processor";
     default:
       sprintf (buff, _("<unknown>: %x"), e_machine);
       return buff;
@@ -1862,6 +2031,10 @@ decode_ARM_machine_flags (e_flags, buf)
              strcat (buf, ", software FP");
              break;
 
+           case EF_ARM_MAVERICK_FLOAT:
+             strcat (buf, ", Maverick FP");
+             break;
+
            default:
              unknown = 1;
              break;
@@ -2189,6 +2362,7 @@ get_segment_type (p_type)
 
     case PT_GNU_EH_FRAME:
                        return "GNU_EH_FRAME";
+    case PT_GNU_STACK: return "STACK";
 
     default:
       if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC))
@@ -2316,10 +2490,15 @@ static const char *
 get_ia64_section_type_name (sh_type)
      unsigned int sh_type;
 {
+  /* If the top 8 bits are 0x78 the next 8 are the os/abi ID. */
+  if ((sh_type & 0xFF000000) == SHT_IA_64_LOPSREG)
+    return get_osabi_name ((sh_type & 0x00FF0000) >> 16);
+      
   switch (sh_type)
     {
-    case SHT_IA_64_EXT:                return "IA_64_EXT";
-    case SHT_IA_64_UNWIND:     return "IA_64_UNWIND";
+    case SHT_IA_64_EXT:                  return "IA_64_EXT";
+    case SHT_IA_64_UNWIND:       return "IA_64_UNWIND";
+    case SHT_IA_64_PRIORITY_INIT: return "IA_64_PRIORITY_INIT";
     default:
       break;
     }
@@ -2514,7 +2693,7 @@ parse_args (argc, argv)
     usage ();
 
   while ((c = getopt_long
-         (argc, argv, "ersuahnldSDAIw::x:i:vVW", options, NULL)) != EOF)
+         (argc, argv, "ersuahnldSDAIw::x:i:vVWH", options, NULL)) != EOF)
     {
       char *cp;
       int section;
@@ -2842,6 +3021,7 @@ get_osabi_name (osabi)
 }
 
 /* Decode the data held in 'elf_header'.  */
+
 static int
 process_file_header ()
 {
@@ -3003,13 +3183,45 @@ get_64bit_program_headers (file, program_headers)
   return 1;
 }
 
+/* Returns 1 if the program headers were read into `program_headers'.  */
+
+static int
+get_program_headers (file)
+     FILE *file;
+{
+  Elf_Internal_Phdr *phdrs;
+
+  /* Check cache of prior read.  */
+  if (program_headers != NULL)
+    return 1;
+
+  phdrs = (Elf_Internal_Phdr *) malloc
+    (elf_header.e_phnum * sizeof (Elf_Internal_Phdr));
+
+  if (phdrs == NULL)
+    {
+      error (_("Out of memory\n"));
+      return 0;
+    }
+
+  if (is_32bit_elf
+      ? get_32bit_program_headers (file, phdrs)
+      : get_64bit_program_headers (file, phdrs))
+    {
+      program_headers = phdrs;
+      return 1;
+    }
+
+  free (phdrs);
+  return 0;
+}
+
 /* Returns 1 if the program headers were loaded.  */
 
 static int
 process_program_headers (file)
      FILE *file;
 {
-  Elf_Internal_Phdr *program_headers;
   Elf_Internal_Phdr *segment;
   unsigned int i;
 
@@ -3031,25 +3243,8 @@ process_program_headers (file)
       printf ("\n");
     }
 
-  program_headers = (Elf_Internal_Phdr *) malloc
-    (elf_header.e_phnum * sizeof (Elf_Internal_Phdr));
-
-  if (program_headers == NULL)
-    {
-      error (_("Out of memory\n"));
-      return 0;
-    }
-
-  if (is_32bit_elf)
-    i = get_32bit_program_headers (file, program_headers);
-  else
-    i = get_64bit_program_headers (file, program_headers);
-
-  if (i == 0)
-    {
-      free (program_headers);
+  if (! get_program_headers (file))
       return 0;
-    }
 
   if (do_segments)
     {
@@ -3073,7 +3268,6 @@ process_program_headers (file)
        }
     }
 
-  loadaddr = -1;
   dynamic_addr = 0;
   dynamic_size = 0;
 
@@ -3161,18 +3355,6 @@ process_program_headers (file)
 
       switch (segment->p_type)
        {
-       case PT_LOAD:
-         if (loadaddr == -1)
-           {
-             unsigned long align_mask = -segment->p_align;
-
-             if (align_mask == 0)
-               --align_mask;
-             loadaddr = ((segment->p_vaddr & align_mask)
-                         - (segment->p_offset & align_mask));
-           }
-         break;
-
        case PT_DYNAMIC:
          if (dynamic_addr)
            error (_("more than one dynamic segment\n"));
@@ -3200,12 +3382,6 @@ process_program_headers (file)
        putc ('\n', stdout);
     }
 
-  if (loadaddr == -1)
-    {
-      /* Very strange.  */
-      loadaddr = 0;
-    }
-
   if (do_segments && section_headers != NULL)
     {
       printf (_("\n Section to Segment mapping:\n"));
@@ -3242,12 +3418,44 @@ process_program_headers (file)
        }
     }
 
-  free (program_headers);
-
   return 1;
 }
 
 
+/* Find the file offset corresponding to VMA by using the program headers.  */
+
+static long
+offset_from_vma (file, vma, size)
+     FILE *file;
+     bfd_vma vma;
+     bfd_size_type size;
+{
+  Elf_Internal_Phdr *seg;
+
+  if (! get_program_headers (file))
+    {
+      warn (_("Cannot interpret virtual addresses without program headers.\n"));
+      return (long) vma;
+    }
+
+  for (seg = program_headers;
+       seg < program_headers + elf_header.e_phnum;
+       ++seg)
+    {
+      if (seg->p_type != PT_LOAD)
+       continue;
+
+      if (vma >= (seg->p_vaddr & -seg->p_align)
+         && vma + size <= seg->p_vaddr + seg->p_filesz)
+       return vma - seg->p_vaddr + seg->p_offset;
+    }
+
+  warn (_("Virtual address 0x%lx not located in any PT_LOAD segment.\n"),
+       (long) vma);
+  return (long) vma;
+}
+
+
 static int
 get_32bit_section_headers (file, num)
      FILE *file;
@@ -3559,6 +3767,9 @@ process_section_headers (file)
       string_table = (char *) get_data (NULL, file, section->sh_offset,
                                        section->sh_size, _("string table"));
 
+      if (string_table == NULL)
+       return 0;
+      
       string_table_length = section->sh_size;
     }
 
@@ -3757,6 +3968,19 @@ process_section_headers (file)
   return 1;
 }
 
+struct
+{
+  const char *name;
+  int reloc;
+  int size;
+  int rela;
+} dynamic_relocations [] =
+{
+    { "REL", DT_REL, DT_RELSZ, FALSE },
+    { "RELA", DT_RELA, DT_RELASZ, TRUE },
+    { "PLT", DT_JMPREL, DT_PLTRELSZ, UNKNOWN }
+};
+
 /* Process the reloc section.  */
 static int
 process_relocs (file)
@@ -3771,53 +3995,51 @@ process_relocs (file)
 
   if (do_using_dynamic)
     {
-      int is_rela = FALSE;
-
-      rel_size   = 0;
-      rel_offset = 0;
+      int is_rela;
+      const char *name;
+      int has_dynamic_reloc;
+      unsigned int i;
+      
+      has_dynamic_reloc = 0;
 
-      if (dynamic_info[DT_REL])
+      for (i = 0; i < ARRAY_SIZE (dynamic_relocations); i++)
        {
-         rel_offset = dynamic_info[DT_REL];
-         rel_size   = dynamic_info[DT_RELSZ];
-         is_rela    = FALSE;
-       }
-      else if (dynamic_info[DT_RELA])
-       {
-         rel_offset = dynamic_info[DT_RELA];
-         rel_size   = dynamic_info[DT_RELASZ];
-         is_rela    = TRUE;
-       }
-      else if (dynamic_info[DT_JMPREL])
-       {
-         rel_offset = dynamic_info[DT_JMPREL];
-         rel_size   = dynamic_info[DT_PLTRELSZ];
+         is_rela = dynamic_relocations [i].rela;
+         name = dynamic_relocations [i].name;
+         rel_size = dynamic_info [dynamic_relocations [i].size];
+         rel_offset = dynamic_info [dynamic_relocations [i].reloc];
+
+         has_dynamic_reloc |= rel_size;
 
-         switch (dynamic_info[DT_PLTREL])
+         if (is_rela == UNKNOWN)
            {
-           case DT_REL:
-             is_rela = FALSE;
-             break;
-           case DT_RELA:
-             is_rela = TRUE;
-             break;
-           default:
-             is_rela = UNKNOWN;
-             break;
+             if (dynamic_relocations [i].reloc == DT_JMPREL)
+               switch (dynamic_info[DT_PLTREL])
+                 {
+                 case DT_REL:
+                   is_rela = FALSE;
+                   break;
+                 case DT_RELA:
+                   is_rela = TRUE;
+                   break;
+                 }
            }
-       }
-
-      if (rel_size)
-       {
-         printf
-           (_("\nRelocation section at offset 0x%lx contains %ld bytes:\n"),
-            rel_offset, rel_size);
 
-         dump_relocations (file, rel_offset - loadaddr, rel_size,
-                           dynamic_symbols, num_dynamic_syms, dynamic_strings,
-                           is_rela);
+         if (rel_size)
+           {
+             printf
+               (_("\n'%s' relocation section at offset 0x%lx contains %ld bytes:\n"),
+                name, rel_offset, rel_size);
+
+             dump_relocations (file,
+                               offset_from_vma (file, rel_offset, rel_size),
+                               rel_size,
+                               dynamic_symbols, num_dynamic_syms,
+                               dynamic_strings, is_rela);
+           }
        }
-      else
+
+      if (! has_dynamic_reloc)
        printf (_("\nThere are no dynamic relocations in this file.\n"));
     }
   else
@@ -4037,14 +4259,13 @@ slurp_ia64_unwind_table (file, aux, sec)
      Elf_Internal_Shdr *sec;
 {
   unsigned long size, addr_size, nrelas, i;
-  Elf_Internal_Phdr *prog_hdrs, *seg;
+  Elf_Internal_Phdr *seg;
   struct unw_table_entry *tep;
   Elf_Internal_Shdr *relsec;
   Elf_Internal_Rela *rela, *rp;
   unsigned char *table, *tp;
   Elf_Internal_Sym *sym;
   const char *relname;
-  int result;
 
   addr_size = is_32bit_elf ? 4 : 8;
 
@@ -4053,21 +4274,12 @@ slurp_ia64_unwind_table (file, aux, sec)
 
   if (elf_header.e_phnum)
     {
-      prog_hdrs = (Elf_Internal_Phdr *)
-       xmalloc (elf_header.e_phnum * sizeof (Elf_Internal_Phdr));
-
-      if (is_32bit_elf)
-       result = get_32bit_program_headers (file, prog_hdrs);
-      else
-       result = get_64bit_program_headers (file, prog_hdrs);
-
-      if (!result)
-       {
-         free (prog_hdrs);
+      if (! get_program_headers (file))
          return 0;
-       }
 
-      for (seg = prog_hdrs; seg < prog_hdrs + elf_header.e_phnum; ++seg)
+      for (seg = program_headers;
+          seg < program_headers + elf_header.e_phnum;
+          ++seg)
        {
          if (seg->p_type != PT_LOAD)
            continue;
@@ -4079,8 +4291,6 @@ slurp_ia64_unwind_table (file, aux, sec)
              break;
            }
        }
-
-      free (prog_hdrs);
     }
 
   /* Second, build the unwind table from the contents of the unwind section:  */
@@ -4457,6 +4667,26 @@ dynamic_segment_parisc_val (entry)
   putchar ('\n');
 }
 
+static void
+dynamic_segment_ia64_val (entry)
+     Elf_Internal_Dyn *entry;
+{
+  switch (entry->d_tag)
+    {
+    case DT_IA_64_PLT_RESERVE: 
+      /* First 3 slots reserved.  */
+      print_vma (entry->d_un.d_ptr, PREFIX_HEX);
+      printf (" -- ");
+      print_vma (entry->d_un.d_ptr + (3 * 8), PREFIX_HEX);
+      break;
+
+    default:
+      print_vma (entry->d_un.d_ptr, PREFIX_HEX);
+      break;
+    }
+  putchar ('\n');
+}
+
 static int
 get_32bit_dynamic_segment (file)
      FILE *file;
@@ -4618,7 +4848,7 @@ process_dynamic_segment (file)
             we default to reading in the entire file (!) and
             processing that.  This is overkill, I know, but it
             should work.  */
-         section.sh_offset = entry->d_un.d_val - loadaddr;
+         section.sh_offset = offset_from_vma (file, entry->d_un.d_val, 0);
 
          if (fseek (file, 0, SEEK_END))
            error (_("Unable to seek to end of file!"));
@@ -4660,7 +4890,7 @@ process_dynamic_segment (file)
             processing that.  This is overkill, I know, but it
             should work.  */
 
-         offset = entry->d_un.d_val - loadaddr;
+         offset = offset_from_vma (file, entry->d_un.d_val, 0);
          if (fseek (file, 0, SEEK_END))
            error (_("Unable to seek to end of file\n"));
          str_tab_len = ftell (file) - offset;
@@ -4696,7 +4926,8 @@ process_dynamic_segment (file)
          else if (entry->d_tag == DT_SYMINSZ)
            syminsz = entry->d_un.d_val;
          else if (entry->d_tag == DT_SYMINFO)
-           dynamic_syminfo_offset = entry->d_un.d_val - loadaddr;
+           dynamic_syminfo_offset = offset_from_vma (file, entry->d_un.d_val,
+                                                     syminsz);
        }
 
       if (dynamic_syminfo_offset != 0 && syminsz != 0)
@@ -4945,6 +5176,7 @@ process_dynamic_segment (file)
          break;
 
        case DT_PLTREL:
+         dynamic_info[entry->d_tag] = entry->d_un.d_val;
          if (do_dynamic)
            puts (get_dynamic_type (entry->d_un.d_val));
          break;
@@ -5019,6 +5251,7 @@ process_dynamic_segment (file)
        case DT_RELAENT :
        case DT_SYMENT  :
        case DT_RELENT  :
+         dynamic_info[entry->d_tag] = entry->d_un.d_val;
        case DT_PLTPADSZ:
        case DT_MOVEENT :
        case DT_MOVESZ  :
@@ -5106,6 +5339,9 @@ process_dynamic_segment (file)
                case EM_PARISC:
                  dynamic_segment_parisc_val (entry);
                  break;
+               case EM_IA_64:
+                 dynamic_segment_ia64_val (entry);
+                 break;
                default:
                  print_vma (entry->d_un.d_val, PREFIX_HEX);
                  putchar ('\n');
@@ -5380,7 +5616,9 @@ process_version_sections (file)
            edata =
              ((unsigned char *)
               get_data (NULL, file,
-                        version_info[DT_VERSIONTAGIDX (DT_VERSYM)] - loadaddr,
+                        offset_from_vma
+                        (file, version_info[DT_VERSIONTAGIDX (DT_VERSYM)],
+                         total * sizeof (short)),
                         total * sizeof (short), _("version symbol data")));
            if (!edata)
              {
@@ -5436,8 +5674,9 @@ process_version_sections (file)
                          Elf_Internal_Verneed ivn;
                          unsigned long offset;
 
-                         offset = version_info[DT_VERSIONTAGIDX (DT_VERNEED)]
-                           - loadaddr;
+                         offset = offset_from_vma
+                           (file, version_info[DT_VERSIONTAGIDX (DT_VERNEED)],
+                            sizeof (Elf_External_Verneed));
 
                          do
                            {
@@ -5492,8 +5731,9 @@ process_version_sections (file)
                          Elf_External_Verdef evd;
                          unsigned long offset;
 
-                         offset = (version_info[DT_VERSIONTAGIDX (DT_VERDEF)]
-                                   - loadaddr);
+                         offset = offset_from_vma
+                           (file, version_info[DT_VERSIONTAGIDX (DT_VERDEF)],
+                            sizeof evd);
 
                          do
                            {
@@ -5720,7 +5960,9 @@ process_symbol_table (file)
   if (dynamic_info[DT_HASH] && ((do_using_dynamic && dynamic_strings != NULL)
                                || do_histogram))
     {
-      if (fseek (file, dynamic_info[DT_HASH] - loadaddr, SEEK_SET))
+      if (fseek (file, offset_from_vma (file, dynamic_info[DT_HASH],
+                                       sizeof nb + sizeof nc),
+                SEEK_SET))
        {
          error (_("Unable to seek to start of dynamic information"));
          return 0;
@@ -5851,8 +6093,9 @@ process_symbol_table (file)
                  int is_nobits;
                  int check_def;
 
-                 offset = version_info[DT_VERSIONTAGIDX (DT_VERSYM)]
-                   - loadaddr;
+                 offset = offset_from_vma
+                   (file, version_info[DT_VERSIONTAGIDX (DT_VERSYM)],
+                    sizeof data + si * sizeof (vers_data));
 
                  get_data (&data, file, offset + si * sizeof (vers_data),
                            sizeof (data), _("version data"));
@@ -5874,8 +6117,9 @@ process_symbol_table (file)
                          Elf_Internal_Vernaux ivna;
 
                          /* We must test both.  */
-                         offset = (version_info[DT_VERSIONTAGIDX (DT_VERNEED)]
-                                   - loadaddr);
+                         offset = offset_from_vma
+                           (file, version_info[DT_VERSIONTAGIDX (DT_VERNEED)],
+                            sizeof evn);
 
                          do
                            {
@@ -5935,9 +6179,10 @@ process_symbol_table (file)
                              Elf_External_Verdaux evda;
                              unsigned long offset;
 
-                             offset
-                               = (version_info[DT_VERSIONTAGIDX (DT_VERDEF)]
-                                  - loadaddr);
+                             offset = offset_from_vma
+                               (file,
+                                version_info[DT_VERSIONTAGIDX (DT_VERDEF)],
+                                sizeof (Elf_External_Verdef));
 
                              do
                                {
@@ -6363,31 +6608,42 @@ display_debug_lines (section, start, file)
      unsigned char * start;
      FILE *file ATTRIBUTE_UNUSED;
 {
-  DWARF2_External_LineInfo *external;
+  unsigned char *hdrptr;
   DWARF2_Internal_LineInfo info;
   unsigned char *standard_opcodes;
   unsigned char *data = start;
   unsigned char *end = start + section->sh_size;
   unsigned char *end_of_sequence;
   int i;
+  int offset_size;
+  int initial_length_size;
 
   printf (_("\nDump of debug contents of section %s:\n\n"),
          SECTION_NAME (section));
 
   while (data < end)
     {
-      external = (DWARF2_External_LineInfo *) data;
+      hdrptr = data;
 
       /* Check the length of the block.  */
-      info.li_length = BYTE_GET (external->li_length);
+      info.li_length = byte_get (hdrptr, 4);
+      hdrptr += 4;
 
       if (info.li_length == 0xffffffff)
        {
-         warn (_("64-bit DWARF line info is not supported yet.\n"));
-         break;
+         /* This section is 64-bit DWARF 3.  */
+         info.li_length = byte_get (hdrptr, 8);
+         hdrptr += 8;
+         offset_size = 8;
+         initial_length_size = 12;
+       }
+      else
+       {
+         offset_size = 4;
+         initial_length_size = 4;
        }
 
-      if (info.li_length + sizeof (external->li_length) > section->sh_size)
+      if (info.li_length + initial_length_size > section->sh_size)
        {
          warn
            (_("The line info appears to be corrupt - the section is too small\n"));
@@ -6395,19 +6651,26 @@ display_debug_lines (section, start, file)
        }
 
       /* Check its version number.  */
-      info.li_version = BYTE_GET (external->li_version);
-      if (info.li_version != 2)
+      info.li_version = byte_get (hdrptr, 2);
+      hdrptr += 2;
+      if (info.li_version != 2 && info.li_version != 3)
        {
-         warn (_("Only DWARF version 2 line info is currently supported.\n"));
+         warn (_("Only DWARF version 2 and 3 line info is currently supported.\n"));
          return 0;
        }
 
-      info.li_prologue_length = BYTE_GET (external->li_prologue_length);
-      info.li_min_insn_length = BYTE_GET (external->li_min_insn_length);
-      info.li_default_is_stmt = BYTE_GET (external->li_default_is_stmt);
-      info.li_line_base       = BYTE_GET (external->li_line_base);
-      info.li_line_range      = BYTE_GET (external->li_line_range);
-      info.li_opcode_base     = BYTE_GET (external->li_opcode_base);
+      info.li_prologue_length = byte_get (hdrptr, offset_size);
+      hdrptr += offset_size;
+      info.li_min_insn_length = byte_get (hdrptr, 1);
+      hdrptr++;
+      info.li_default_is_stmt = byte_get (hdrptr, 1);
+      hdrptr++;
+      info.li_line_base = byte_get (hdrptr, 1);
+      hdrptr++;
+      info.li_line_range = byte_get (hdrptr, 1);
+      hdrptr++;
+      info.li_opcode_base = byte_get (hdrptr, 1);
+      hdrptr++;
 
       /* Sign extend the line base field.  */
       info.li_line_base <<= 24;
@@ -6422,12 +6685,12 @@ display_debug_lines (section, start, file)
       printf (_("  Line Range:                  %d\n"), info.li_line_range);
       printf (_("  Opcode Base:                 %d\n"), info.li_opcode_base);
 
-      end_of_sequence = data + info.li_length + sizeof (external->li_length);
+      end_of_sequence = data + info.li_length + initial_length_size;
 
       reset_state_machine (info.li_default_is_stmt);
 
       /* Display the contents of the Opcodes table.  */
-      standard_opcodes = data + sizeof (*external);
+      standard_opcodes = hdrptr;
 
       printf (_("\n Opcodes:\n"));
 
@@ -6620,7 +6883,6 @@ display_debug_pubnames (section, start, file)
      unsigned char *start;
      FILE *file ATTRIBUTE_UNUSED;
 {
-  DWARF2_External_PubNames *external;
   DWARF2_Internal_PubNames pubnames;
   unsigned char *end;
 
@@ -6632,30 +6894,41 @@ display_debug_pubnames (section, start, file)
     {
       unsigned char *data;
       unsigned long offset;
+      int offset_size, initial_length_size;
 
-      external = (DWARF2_External_PubNames *) start;
-
-      pubnames.pn_length  = BYTE_GET (external->pn_length);
-      pubnames.pn_version = BYTE_GET (external->pn_version);
-      pubnames.pn_offset  = BYTE_GET (external->pn_offset);
-      pubnames.pn_size    = BYTE_GET (external->pn_size);
-
-      data   = start + sizeof (*external);
-      start += pubnames.pn_length + sizeof (external->pn_length);
+      data = start;
 
+      pubnames.pn_length = byte_get (data, 4);
+      data += 4;
       if (pubnames.pn_length == 0xffffffff)
        {
-         warn (_("64-bit DWARF pubnames are not supported yet.\n"));
-         break;
+         pubnames.pn_length = byte_get (data, 8);
+         data += 8;
+         offset_size = 8;
+         initial_length_size = 12;
        }
+      else
+       {
+         offset_size = 4;
+         initial_length_size = 4;
+       }
+
+      pubnames.pn_version = byte_get (data, 2);
+      data += 2;
+      pubnames.pn_offset = byte_get (data, offset_size);
+      data += offset_size;
+      pubnames.pn_size = byte_get (data, offset_size);
+      data += offset_size;
+
+      start += pubnames.pn_length + initial_length_size;
 
-      if (pubnames.pn_version != 2)
+      if (pubnames.pn_version != 2 && pubnames.pn_version != 3)
        {
          static int warned = 0;
 
          if (! warned)
            {
-             warn (_("Only DWARF 2 pubnames are currently supported\n"));
+             warn (_("Only DWARF 2 and 3 pubnames are currently supported\n"));
              warned = 1;
            }
 
@@ -6675,11 +6948,11 @@ display_debug_pubnames (section, start, file)
 
       do
        {
-         offset = byte_get (data, 4);
+         offset = byte_get (data, offset_size);
 
          if (offset != 0)
            {
-             data += 4;
+             data += offset_size;
              printf ("    %ld\t\t%s\n", offset, data);
              data += strlen ((char *) data) + 1;
            }
@@ -7546,7 +7819,8 @@ decode_location_expression (data, pointer_size, length)
        }
 
       /* Separate the ops.  */
-      printf ("; ");
+      if (data < end)
+       printf ("; ");
     }
 }
 
@@ -7779,12 +8053,15 @@ display_debug_str (section, start, file)
 }
 
 static unsigned char *
-read_and_display_attr_value (attribute, form, data, cu_offset, pointer_size)
+read_and_display_attr_value (attribute, form, data, cu_offset, pointer_size,
+                             offset_size, dwarf_version)
      unsigned long attribute;
      unsigned long form;
      unsigned char *data;
      unsigned long cu_offset;
      unsigned long pointer_size;
+     unsigned long offset_size;
+     int dwarf_version;
 {
   unsigned long uvalue = 0;
   unsigned char *block_start = NULL;
@@ -7796,14 +8073,30 @@ read_and_display_attr_value (attribute, form, data, cu_offset, pointer_size)
       break;
 
     case DW_FORM_ref_addr:
+      if (dwarf_version == 2)
+       {
+         uvalue = byte_get (data, pointer_size);
+         data += pointer_size;
+       }
+      else if (dwarf_version == 3)
+       {
+         uvalue = byte_get (data, offset_size);
+         data += offset_size;
+       }
+      else
+        {
+         error (_("Internal error: DWARF version is not 2 or 3.\n"));
+       }
+      break;
+
     case DW_FORM_addr:
       uvalue = byte_get (data, pointer_size);
       data += pointer_size;
       break;
 
     case DW_FORM_strp:
-      uvalue = byte_get (data, /* offset_size */ 4);
-      data += /* offset_size */ 4;
+      uvalue = byte_get (data, offset_size);
+      data += offset_size;
       break;
 
     case DW_FORM_ref1:
@@ -7840,7 +8133,8 @@ read_and_display_attr_value (attribute, form, data, cu_offset, pointer_size)
       data += bytes_read;
       printf (" %s", get_FORM_name (form));
       return read_and_display_attr_value (attribute, form, data, cu_offset,
-                                         pointer_size);
+                                         pointer_size, offset_size,
+                                         dwarf_version);
     }
 
   switch (form)
@@ -8080,7 +8374,7 @@ read_and_display_attr_value (attribute, form, data, cu_offset, pointer_size)
          decode_location_expression (block_start, pointer_size, uvalue);
          printf (")");
        }
-      else if (form == DW_FORM_data4)
+      else if (form == DW_FORM_data4 || form == DW_FORM_data8)
        {
          printf ("(");
          printf ("location list");
@@ -8096,16 +8390,19 @@ read_and_display_attr_value (attribute, form, data, cu_offset, pointer_size)
 }
 
 static unsigned char *
-read_and_display_attr (attribute, form, data, cu_offset, pointer_size)
+read_and_display_attr (attribute, form, data, cu_offset, pointer_size,
+                       offset_size, dwarf_version)
      unsigned long attribute;
      unsigned long form;
      unsigned char *data;
      unsigned long cu_offset;
      unsigned long pointer_size;
+     unsigned long offset_size;
+     int dwarf_version;
 {
   printf ("     %-18s:", get_AT_name (attribute));
   data = read_and_display_attr_value (attribute, form, data, cu_offset,
-                                     pointer_size);
+                                     pointer_size, offset_size, dwarf_version);
   printf ("\n");
   return data;
 }
@@ -8126,29 +8423,39 @@ display_debug_info (section, start, file)
 
   while (start < end)
     {
-      DWARF2_External_CompUnit *external;
       DWARF2_Internal_CompUnit compunit;
       Elf_Internal_Shdr *relsec;
+      unsigned char *hdrptr;
+      unsigned char *cu_abbrev_offset_ptr;
       unsigned char *tags;
       unsigned int i;
       int level;
       unsigned long cu_offset;
+      int offset_size;
+      int initial_length_size;
 
-      external = (DWARF2_External_CompUnit *) start;
+      hdrptr = start;
 
-      compunit.cu_length        = BYTE_GET (external->cu_length);
-      compunit.cu_version       = BYTE_GET (external->cu_version);
-      compunit.cu_abbrev_offset = BYTE_GET (external->cu_abbrev_offset);
-      compunit.cu_pointer_size  = BYTE_GET (external->cu_pointer_size);
+      compunit.cu_length = byte_get (hdrptr, 4);
+      hdrptr += 4;
 
       if (compunit.cu_length == 0xffffffff)
        {
-         warn (_("64-bit DWARF debug info is not supported yet.\n"));
-         break;
+         compunit.cu_length = byte_get (hdrptr, 8);
+         hdrptr += 8;
+         offset_size = 8;
+         initial_length_size = 12;
+       }
+      else
+       {
+         offset_size = 4;
+         initial_length_size = 4;
        }
 
-      /* Check for RELA relocations in the
-        abbrev_offset address, and apply them.  */
+      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)
@@ -8173,9 +8480,13 @@ display_debug_info (section, start, file)
 
          for (rp = rela; rp < rela + nrelas; ++rp)
            {
-             if (rp->r_offset
-                 != (bfd_vma) ((unsigned char *) &external->cu_abbrev_offset
-                               - section_begin))
+             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)
@@ -8203,17 +8514,23 @@ display_debug_info (section, start, file)
                    }
                }
 
-             compunit.cu_abbrev_offset = rp->r_addend;
-             break;
+             byte_put (loc, rp->r_addend, offset_size);
            }
 
          free (rela);
          break;
        }
 
-      tags = start + sizeof (*external);
+      cu_abbrev_offset_ptr = hdrptr;
+      compunit.cu_abbrev_offset = byte_get (hdrptr, offset_size);
+      hdrptr += offset_size;
+
+      compunit.cu_pointer_size = byte_get (hdrptr, 1);
+      hdrptr += 1;
+
+      tags = hdrptr;
       cu_offset = start - section_begin;
-      start += compunit.cu_length + sizeof (external->cu_length);
+      start += compunit.cu_length + initial_length_size;
 
       printf (_("  Compilation Unit @ %lx:\n"), cu_offset);
       printf (_("   Length:        %ld\n"), compunit.cu_length);
@@ -8221,9 +8538,9 @@ display_debug_info (section, start, file)
       printf (_("   Abbrev Offset: %ld\n"), compunit.cu_abbrev_offset);
       printf (_("   Pointer Size:  %d\n"), compunit.cu_pointer_size);
 
-      if (compunit.cu_version != 2)
+      if (compunit.cu_version != 2 && compunit.cu_version != 3)
        {
-         warn (_("Only version 2 DWARF debug information is currently supported.\n"));
+         warn (_("Only version 2 and 3 DWARF debug information is currently supported.\n"));
          continue;
        }
 
@@ -8301,7 +8618,9 @@ display_debug_info (section, start, file)
            tags = read_and_display_attr (attr->attribute,
                                          attr->form,
                                          tags, cu_offset,
-                                         compunit.cu_pointer_size);
+                                         compunit.cu_pointer_size,
+                                         offset_size,
+                                         compunit.cu_version);
 
          if (entry->children)
            ++level;
@@ -8328,30 +8647,48 @@ display_debug_aranges (section, start, file)
 
   while (start < end)
     {
-      DWARF2_External_ARange *external;
+      unsigned char *hdrptr;
       DWARF2_Internal_ARange arange;
       unsigned char *ranges;
       unsigned long length;
       unsigned long address;
       int excess;
+      int offset_size;
+      int initial_length_size;
 
-      external = (DWARF2_External_ARange *) start;
+      hdrptr = start;
 
-      arange.ar_length       = BYTE_GET (external->ar_length);
-      arange.ar_version      = BYTE_GET (external->ar_version);
-      arange.ar_info_offset  = BYTE_GET (external->ar_info_offset);
-      arange.ar_pointer_size = BYTE_GET (external->ar_pointer_size);
-      arange.ar_segment_size = BYTE_GET (external->ar_segment_size);
+      arange.ar_length = byte_get (hdrptr, 4);
+      hdrptr += 4;
 
       if (arange.ar_length == 0xffffffff)
        {
-         warn (_("64-bit DWARF aranges are not supported yet.\n"));
-         break;
+         arange.ar_length = byte_get (hdrptr, 8);
+         hdrptr += 8;
+         offset_size = 8;
+         initial_length_size = 12;
        }
+      else
+        {
+         offset_size = 4;
+         initial_length_size = 4;
+       }
+
+      arange.ar_version = byte_get (hdrptr, 2);
+      hdrptr += 2;
+
+      arange.ar_info_offset = byte_get (hdrptr, offset_size);
+      hdrptr += offset_size;
+
+      arange.ar_pointer_size = byte_get (hdrptr, 1);
+      hdrptr += 1;
+
+      arange.ar_segment_size = byte_get (hdrptr, 1);
+      hdrptr += 1;
 
-      if (arange.ar_version != 2)
+      if (arange.ar_version != 2 && arange.ar_version != 3)
        {
-         warn (_("Only DWARF 2 aranges are currently supported.\n"));
+         warn (_("Only DWARF 2 and 3 aranges are currently supported.\n"));
          break;
        }
 
@@ -8363,10 +8700,10 @@ display_debug_aranges (section, start, file)
 
       printf (_("\n    Address  Length\n"));
 
-      ranges = start + sizeof (*external);
+      ranges = hdrptr;
 
       /* Must pad to an alignment boundary that is twice the pointer size.  */
-      excess = sizeof (*external) % (2 * arange.ar_pointer_size);
+      excess = (hdrptr - start) % (2 * arange.ar_pointer_size);
       if (excess)
        ranges += (2 * arange.ar_pointer_size) - excess;
 
@@ -8387,7 +8724,7 @@ display_debug_aranges (section, start, file)
          printf ("    %8.8lx %lu\n", address, length);
        }
 
-      start += arange.ar_length + sizeof (external->ar_length);
+      start += arange.ar_length + initial_length_size;
     }
 
   printf ("\n");
@@ -8412,6 +8749,7 @@ typedef struct Frame_Chunk
   int cfa_offset;
   int ra;
   unsigned char fde_encoding;
+  unsigned char cfa_exp;
 }
 Frame_Chunk;
 
@@ -8422,6 +8760,7 @@ Frame_Chunk;
 static void frame_need_space PARAMS ((Frame_Chunk *, int));
 static void frame_display_row PARAMS ((Frame_Chunk *, int *, int *));
 static int size_of_encoded_value PARAMS ((int));
+static bfd_vma get_encoded_value PARAMS ((unsigned char *, int));
 
 static void
 frame_need_space (fc, reg)
@@ -8478,7 +8817,10 @@ frame_display_row (fc, need_col_headers, max_regs)
     }
 
   printf ("%08lx ", fc->pc_begin);
-  sprintf (tmp, "r%d%+d", fc->cfa_reg, fc->cfa_offset);
+  if (fc->cfa_exp)
+    strcpy (tmp, "exp");
+  else
+    sprintf (tmp, "r%d%+d", fc->cfa_reg, fc->cfa_offset);
   printf ("%-8s ", tmp);
 
   for (r = 0; r < fc->ncols; r++)
@@ -8499,6 +8841,9 @@ frame_display_row (fc, need_col_headers, max_regs)
            case DW_CFA_register:
              sprintf (tmp, "r%d", fc->col_offset[r]);
              break;
+           case DW_CFA_expression:
+             strcpy (tmp, "exp");
+             break;
            default:
              strcpy (tmp, "n/a");
              break;
@@ -8523,6 +8868,18 @@ size_of_encoded_value (encoding)
     }
 }
 
+static bfd_vma
+get_encoded_value (data, encoding)
+     unsigned char *data;
+     int encoding;
+{
+  int size = size_of_encoded_value (encoding);
+  if (encoding & DW_EH_PE_signed)
+    return byte_get_signed (data, size);
+  else
+    return byte_get (data, size);
+}
+
 #define GET(N) byte_get (start, N); start += N
 #define LEB()  read_leb128 (start, & length_return, 0); start += length_return
 #define SLEB() read_leb128 (start, & length_return, 1); start += length_return
@@ -8557,6 +8914,8 @@ display_debug_frames (section, start, file)
       unsigned char *augmentation_data = NULL;
       unsigned long augmentation_data_len = 0;
       int encoded_ptr_size = addr_size;
+      int offset_size;
+      int initial_length_size;
 
       saved_start = start;
       length = byte_get (start, 4); start += 4;
@@ -8570,12 +8929,19 @@ display_debug_frames (section, start, file)
 
       if (length == 0xffffffff)
        {
-         warn (_("64-bit DWARF format frames are not supported yet.\n"));
-         break;
+         length = byte_get (start, 8);
+         start += 8;
+         offset_size = 8;
+         initial_length_size = 12;
+       }
+      else
+       {
+         offset_size = 4;
+         initial_length_size = 4;
        }
 
-      block_end = saved_start + length + 4;
-      cie_id = byte_get (start, 4); start += 4;
+      block_end = saved_start + length + initial_length_size;
+      cie_id = byte_get (start, offset_size); start += offset_size;
 
       if (is_eh ? (cie_id == 0) : (cie_id == DW_CIE_ID))
        {
@@ -8719,7 +9085,7 @@ display_debug_frames (section, start, file)
          if (fc->fde_encoding)
            encoded_ptr_size = size_of_encoded_value (fc->fde_encoding);
 
-         fc->pc_begin = byte_get (start, encoded_ptr_size);
+         fc->pc_begin = get_encoded_value (start, fc->fde_encoding);
          if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel)
            fc->pc_begin += section->sh_addr + (start - section_start);
          start += encoded_ptr_size;
@@ -8750,8 +9116,12 @@ display_debug_frames (section, start, file)
 
       /* At this point, fc is the current chunk, cie (if any) is set, and we're
         about to interpret instructions for the chunk.  */
-
-      if (do_debug_frames_interp)
+      /* ??? At present we need to do this always, since this sizes the
+        fc->col_type and fc->col_offset arrays, which we write into always.
+        We should probably split the interpreted and non-interpreted bits
+        into two different routines, since there's so much that doesn't
+        really overlap between them.  */
+      if (1 || do_debug_frames_interp)
        {
          /* Start by making a pass over the chunk, allocating storage
             and taking note of what registers are used.  */
@@ -8760,7 +9130,7 @@ display_debug_frames (section, start, file)
          while (start < block_end)
            {
              unsigned op, opa;
-             unsigned long reg;
+             unsigned long reg, tmp;
 
              op = *start++;
              opa = op & 0x3f;
@@ -8828,6 +9198,17 @@ display_debug_frames (section, start, file)
                case DW_CFA_def_cfa_offset:
                  LEB ();
                  break;
+               case DW_CFA_def_cfa_expression:
+                 tmp = LEB ();
+                 start += tmp;
+                 break;
+               case DW_CFA_expression:
+                 reg = LEB ();
+                 tmp = LEB ();
+                 start += tmp;
+                 frame_need_space (fc, reg);
+                 fc->col_type[reg] = DW_CFA_undefined;
+                 break;
                case DW_CFA_offset_extended_sf:
                  reg = LEB (); SLEB ();
                  frame_need_space (fc, reg);
@@ -8839,6 +9220,9 @@ display_debug_frames (section, start, file)
                case DW_CFA_def_cfa_offset_sf:
                  SLEB ();
                  break;
+               case DW_CFA_MIPS_advance_loc8:
+                 start += 8;
+                 break;
                case DW_CFA_GNU_args_size:
                  LEB ();
                  break;
@@ -8900,7 +9284,7 @@ display_debug_frames (section, start, file)
              break;
 
            case DW_CFA_set_loc:
-             vma = byte_get (start, encoded_ptr_size);
+             vma = get_encoded_value (start, fc->fde_encoding);
              if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel)
                vma += section->sh_addr + (start - section_start);
              start += encoded_ptr_size;
@@ -8982,7 +9366,7 @@ display_debug_frames (section, start, file)
              reg = LEB ();
              roffs = LEB ();
              if (! do_debug_frames_interp)
-               printf ("  DW_CFA_register: r%ld\n", reg);
+               printf ("  DW_CFA_register: r%ld in r%ld\n", reg, roffs);
              fc->col_type[reg] = DW_CFA_register;
              fc->col_offset[reg] = roffs;
              break;
@@ -9016,6 +9400,7 @@ display_debug_frames (section, start, file)
            case DW_CFA_def_cfa:
              fc->cfa_reg = LEB ();
              fc->cfa_offset = LEB ();
+             fc->cfa_exp = 0;
              if (! do_debug_frames_interp)
                printf ("  DW_CFA_def_cfa: r%d ofs %d\n",
                        fc->cfa_reg, fc->cfa_offset);
@@ -9023,6 +9408,7 @@ display_debug_frames (section, start, file)
 
            case DW_CFA_def_cfa_register:
              fc->cfa_reg = LEB ();
+             fc->cfa_exp = 0;
              if (! do_debug_frames_interp)
                printf ("  DW_CFA_def_cfa_reg: r%d\n", fc->cfa_reg);
              break;
@@ -9038,6 +9424,31 @@ display_debug_frames (section, start, file)
                printf ("  DW_CFA_nop\n");
              break;
 
+           case DW_CFA_def_cfa_expression:
+             ul = LEB ();
+             if (! do_debug_frames_interp)
+               {
+                 printf ("  DW_CFA_def_cfa_expression (");
+                 decode_location_expression (start, addr_size, ul);
+                 printf (")\n");
+               }
+             fc->cfa_exp = 1;
+             start += ul;
+             break;
+
+           case DW_CFA_expression:
+             reg = LEB ();
+             ul = LEB ();
+             if (! do_debug_frames_interp)
+               {
+                 printf ("  DW_CFA_expression: r%ld (", reg);
+                 decode_location_expression (start, addr_size, ul);
+                 printf (")\n");
+               }
+             fc->col_type[reg] = DW_CFA_expression;
+             start += ul;
+             break;
+
            case DW_CFA_offset_extended_sf:
              reg = LEB ();
              l = SLEB ();
@@ -9052,6 +9463,7 @@ display_debug_frames (section, start, file)
            case DW_CFA_def_cfa_sf:
              fc->cfa_reg = LEB ();
              fc->cfa_offset = SLEB ();
+             fc->cfa_exp = 0;
              if (! do_debug_frames_interp)
                printf ("  DW_CFA_def_cfa_sf: r%d ofs %d\n",
                        fc->cfa_reg, fc->cfa_offset);
@@ -9063,6 +9475,17 @@ display_debug_frames (section, start, file)
                printf ("  DW_CFA_def_cfa_offset_sf: %d\n", fc->cfa_offset);
              break;
 
+           case DW_CFA_MIPS_advance_loc8:
+             ofs = byte_get (start, 8); start += 8;
+             if (do_debug_frames_interp)
+               frame_display_row (fc, &need_col_headers, &max_regs);
+             else
+               printf ("  DW_CFA_MIPS_advance_loc8: %ld to %08lx\n",
+                       ofs * fc->code_factor,
+                       fc->pc_begin + ofs * fc->code_factor);
+             fc->pc_begin += ofs * fc->code_factor;
+             break;
+
            case DW_CFA_GNU_window_save:
              if (! do_debug_frames_interp)
                printf ("  DW_CFA_GNU_window_save\n");
@@ -9085,17 +9508,6 @@ display_debug_frames (section, start, file)
              fc->col_offset[reg] = l * fc->data_factor;
              break;
 
-           /* FIXME: How do we handle these? */
-           case DW_CFA_def_cfa_expression:
-             fprintf (stderr, "unsupported DW_CFA_def_cfa_expression\n");
-             start = block_end;
-             break;
-
-           case DW_CFA_expression:
-             fprintf (stderr, "unsupported DW_CFA_expression\n");
-             start = block_end;
-             break;
-
            default:
              fprintf (stderr, "unsupported or unknown DW_CFA_%d\n", op);
              start = block_end;
@@ -9138,11 +9550,41 @@ prescan_debug_info (section, start, file)
      unsigned char *start;
      FILE *file ATTRIBUTE_UNUSED;
 {
-  DWARF2_External_CompUnit *external;
+  unsigned long length;
+
+  /* Read the first 4 bytes.  For a 32-bit DWARF section, this will
+     be the length.  For a 64-bit DWARF section, it'll be the escape
+     code 0xffffffff followed by an 8 byte length.  For the purposes
+     of this prescan, we don't care about the actual length, but the
+     presence of the escape bytes does affect the location of the byte
+     which describes the address size.  */
+  length = byte_get (start, 4);
 
-  external = (DWARF2_External_CompUnit *) start;
+  if (length == 0xffffffff)
+    {
+      /* For 64-bit DWARF, the 1-byte address_size field is 22 bytes
+         from the start of the section.  This is computed as follows:
+
+           unit_length:         12 bytes
+           version:              2 bytes
+           debug_abbrev_offset:  8 bytes
+           -----------------------------
+           Total:               22 bytes  */
+
+      debug_line_pointer_size = byte_get (start + 22, 1);
+    }
+  else
+    {
+      /* For 32-bit DWARF, the 1-byte address_size field is 10 bytes from
+         the start of the section:
+           unit_length:          4 bytes
+           version:              2 bytes
+           debug_abbrev_offset:  4 bytes
+           -----------------------------
+           Total:               10 bytes  */
 
-  debug_line_pointer_size = BYTE_GET (external->cu_pointer_size);
+      debug_line_pointer_size = byte_get (start + 10, 1);
+    }
   return 0;
 }
 
@@ -9331,16 +9773,20 @@ process_mips_specific (file)
     switch (entry->d_tag)
       {
       case DT_MIPS_LIBLIST:
-       liblist_offset = entry->d_un.d_val - loadaddr;
+       liblist_offset
+         = offset_from_vma (file, entry->d_un.d_val,
+                            liblistno * sizeof (Elf32_External_Lib));
        break;
       case DT_MIPS_LIBLISTNO:
        liblistno = entry->d_un.d_val;
        break;
       case DT_MIPS_OPTIONS:
-       options_offset = entry->d_un.d_val - loadaddr;
+       options_offset = offset_from_vma (file, entry->d_un.d_val, 0);
        break;
       case DT_MIPS_CONFLICT:
-       conflicts_offset = entry->d_un.d_val - loadaddr;
+       conflicts_offset
+         = offset_from_vma (file, entry->d_un.d_val,
+                            conflictsno * sizeof (Elf32_External_Conflict));
        break;
       case DT_MIPS_CONFLICTNO:
        conflictsno = entry->d_un.d_val;
@@ -9992,30 +10438,12 @@ static int
 process_corefile_note_segments (file)
      FILE *file;
 {
-  Elf_Internal_Phdr *program_headers;
   Elf_Internal_Phdr *segment;
   unsigned int i;
   int res = 1;
 
-  program_headers = (Elf_Internal_Phdr *) malloc
-    (elf_header.e_phnum * sizeof (Elf_Internal_Phdr));
-
-  if (program_headers == NULL)
-    {
-      error (_("Out of memory\n"));
+  if (! get_program_headers (file))
       return 0;
-    }
-
-  if (is_32bit_elf)
-    i = get_32bit_program_headers (file, program_headers);
-  else
-    i = get_64bit_program_headers (file, program_headers);
-
-  if (i == 0)
-    {
-      free (program_headers);
-      return 0;
-    }
 
   for (i = 0, segment = program_headers;
        i < elf_header.e_phnum;
@@ -10027,8 +10455,6 @@ process_corefile_note_segments (file)
                                              (bfd_vma) segment->p_filesz);
     }
 
-  free (program_headers);
-
   return res;
 }
 
@@ -10086,8 +10512,14 @@ get_file_header (file)
     {
     default: /* fall through */
     case ELFDATANONE: /* fall through */
-    case ELFDATA2LSB: byte_get = byte_get_little_endian; break;
-    case ELFDATA2MSB: byte_get = byte_get_big_endian; break;
+    case ELFDATA2LSB:
+      byte_get = byte_get_little_endian;
+      byte_put = byte_put_little_endian;
+      break;
+    case ELFDATA2MSB:
+      byte_get = byte_get_big_endian;
+      byte_put = byte_put_big_endian;
+      break;
     }
 
   /* For now we only support 32 bit and 64 bit ELF files.  */
@@ -10239,6 +10671,12 @@ process_file (file_name)
 
   fclose (file);
 
+  if (program_headers)
+    {
+      free (program_headers);
+      program_headers = NULL;
+    }
+
   if (section_headers)
     {
       free (section_headers);