ld: elfvers tests: support symbol prefixed targets
[deliverable/binutils-gdb.git] / binutils / dwarf.c
index 117d2a573e5e806c3b7a21adf1b1f36efc814374..dd5ccbc35384567ffdcc06febb3439c081019571 100644 (file)
@@ -1,12 +1,12 @@
 /* dwarf.c -- display DWARF contents of a BFD binary file
-   Copyright 2005, 2006
+   Copyright 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
 
    This file is part of GNU Binutils.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
    02110-1301, USA.  */
 
-#include <stdio.h>
-
+#include "sysdep.h"
+#include "libiberty.h"
+#include "bfd.h"
+#include "bfd_stdint.h"
+#include "bucomm.h"
+#include "elfcomm.h"
+#include "elf/common.h"
+#include "dwarf2.h"
 #include "dwarf.h"
 
-#include "bucomm.h"
-#include "libiberty.h"
+static const char *regname (unsigned int regno, int row);
 
 static int have_frame_base;
 static int need_base_address;
@@ -34,14 +39,17 @@ static int warned_about_missing_comp_units = FALSE;
 
 static unsigned int num_debug_info_entries = 0;
 static debug_info *debug_information = NULL;
+/* Special value for num_debug_info_entries to indicate
+   that the .debug_info section could not be loaded/parsed.  */
+#define DEBUG_INFO_UNAVAILABLE  (unsigned int) -1
 
-dwarf_vma eh_addr_size;
-int is_relocatable;
+int eh_addr_size;
 
 int do_debug_info;
 int do_debug_abbrevs;
 int do_debug_lines;
 int do_debug_pubnames;
+int do_debug_pubtypes;
 int do_debug_aranges;
 int do_debug_ranges;
 int do_debug_frames;
@@ -49,117 +57,73 @@ int do_debug_frames_interp;
 int do_debug_macinfo;
 int do_debug_str;
 int do_debug_loc;
+int do_gdb_index;
+int do_trace_info;
+int do_trace_abbrevs;
+int do_trace_aranges;
+int do_wide;
 
-dwarf_vma (*byte_get) (unsigned char *, int);
+/* Values for do_debug_lines.  */
+#define FLAG_DEBUG_LINES_RAW    1
+#define FLAG_DEBUG_LINES_DECODED 2
 
-dwarf_vma
-byte_get_little_endian (unsigned char *field, int size)
+static int
+size_of_encoded_value (int encoding)
 {
-  switch (size)
+  switch (encoding & 0x7)
     {
-    case 1:
-      return *field;
-
-    case 2:
-      return  ((unsigned int) (field[0]))
-       |    (((unsigned int) (field[1])) << 8);
-
-    case 4:
-      return  ((unsigned long) (field[0]))
-       |    (((unsigned long) (field[1])) << 8)
-       |    (((unsigned long) (field[2])) << 16)
-       |    (((unsigned long) (field[3])) << 24);
-
-    case 8:
-      if (sizeof (dwarf_vma) == 8)
-       return  ((dwarf_vma) (field[0]))
-         |    (((dwarf_vma) (field[1])) << 8)
-         |    (((dwarf_vma) (field[2])) << 16)
-         |    (((dwarf_vma) (field[3])) << 24)
-         |    (((dwarf_vma) (field[4])) << 32)
-         |    (((dwarf_vma) (field[5])) << 40)
-         |    (((dwarf_vma) (field[6])) << 48)
-         |    (((dwarf_vma) (field[7])) << 56);
-      else if (sizeof (dwarf_vma) == 4)
-       /* We want to extract data from an 8 byte wide field and
-          place it into a 4 byte wide field.  Since this is a little
-          endian source we can just use the 4 byte extraction code.  */
-       return  ((unsigned long) (field[0]))
-         |    (((unsigned long) (field[1])) << 8)
-         |    (((unsigned long) (field[2])) << 16)
-         |    (((unsigned long) (field[3])) << 24);
-
-    default:
-      error (_("Unhandled data length: %d\n"), size);
-      abort ();
+    default:   /* ??? */
+    case 0:    return eh_addr_size;
+    case 2:    return 2;
+    case 3:    return 4;
+    case 4:    return 8;
     }
 }
 
-dwarf_vma
-byte_get_big_endian (unsigned char *field, int size)
+static dwarf_vma
+get_encoded_value (unsigned char *data,
+                  int encoding,
+                  struct dwarf_section *section)
 {
-  switch (size)
-    {
-    case 1:
-      return *field;
-
-    case 2:
-      return ((unsigned int) (field[1])) | (((int) (field[0])) << 8);
-
-    case 4:
-      return ((unsigned long) (field[3]))
-       |   (((unsigned long) (field[2])) << 8)
-       |   (((unsigned long) (field[1])) << 16)
-       |   (((unsigned long) (field[0])) << 24);
-
-    case 8:
-      if (sizeof (dwarf_vma) == 8)
-       return ((dwarf_vma) (field[7]))
-         |   (((dwarf_vma) (field[6])) << 8)
-         |   (((dwarf_vma) (field[5])) << 16)
-         |   (((dwarf_vma) (field[4])) << 24)
-         |   (((dwarf_vma) (field[3])) << 32)
-         |   (((dwarf_vma) (field[2])) << 40)
-         |   (((dwarf_vma) (field[1])) << 48)
-         |   (((dwarf_vma) (field[0])) << 56);
-      else if (sizeof (dwarf_vma) == 4)
-       {
-         /* Although we are extracing data from an 8 byte wide field,
-            we are returning only 4 bytes of data.  */
-         field += 4;
-         return ((unsigned long) (field[3]))
-           |   (((unsigned long) (field[2])) << 8)
-           |   (((unsigned long) (field[1])) << 16)
-           |   (((unsigned long) (field[0])) << 24);
-       }
+  int size = size_of_encoded_value (encoding);
+  dwarf_vma val;
 
-    default:
-      error (_("Unhandled data length: %d\n"), size);
-      abort ();
-    }
+  if (encoding & DW_EH_PE_signed)
+    val = byte_get_signed (data, size);
+  else
+    val = byte_get (data, size);
+
+  if ((encoding & 0x70) == DW_EH_PE_pcrel)
+    val += section->address + (data - section->start);
+  return val;
 }
 
-static dwarf_vma
-byte_get_signed (unsigned char *field, int size)
-{
-  dwarf_vma x = byte_get (field, size);
+/* Print a dwarf_vma value (typically an address, offset or length) in
+   hexadecimal format, followed by a space.  The length of the value (and
+   hence the precision displayed) is determined by the byte_size parameter.  */
 
-  switch (size)
-    {
-    case 1:
-      return (x ^ 0x80) - 0x80;
-    case 2:
-      return (x ^ 0x8000) - 0x8000;
-    case 4:
-      return (x ^ 0x80000000) - 0x80000000;
-    case 8:
-      return x;
-    default:
-      abort ();
-    }
+static void
+print_dwarf_vma (dwarf_vma val, unsigned byte_size)
+{
+  static char buff[18];
+
+  /* Printf does not have a way of specifiying a maximum field width for an
+     integer value, so we print the full value into a buffer and then select
+     the precision we need.  */
+#if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
+#ifndef __MSVCRT__
+  snprintf (buff, sizeof (buff), "%16.16llx ", val);
+#else
+  snprintf (buff, sizeof (buff), "%016I64x ", val);
+#endif
+#else
+  snprintf (buff, sizeof (buff), "%16.16lx ", val);
+#endif
+
+  fputs (buff + (byte_size == 4 ? 8 : 0), stdout);
 }
 
-static unsigned long int
+unsigned long int
 read_leb128 (unsigned char *data, unsigned int *length_return, int sign)
 {
   unsigned long int result = 0;
@@ -196,7 +160,8 @@ typedef struct State_Machine_Registers
   unsigned int column;
   int is_stmt;
   int basic_block;
-  int end_sequence;
+  unsigned char op_index;
+  unsigned char end_sequence;
 /* This variable hold the number of the last entry seen
    in the File Table.  */
   unsigned int last_file_entry;
@@ -208,6 +173,7 @@ static void
 reset_state_machine (int is_stmt)
 {
   state_machine_regs.address = 0;
+  state_machine_regs.op_index = 0;
   state_machine_regs.file = 1;
   state_machine_regs.line = 1;
   state_machine_regs.column = 0;
@@ -254,25 +220,70 @@ process_extended_line_op (unsigned char *data, int is_stmt)
       adr = byte_get (data, len - bytes_read - 1);
       printf (_("set Address to 0x%lx\n"), adr);
       state_machine_regs.address = adr;
+      state_machine_regs.op_index = 0;
       break;
 
     case DW_LNE_define_file:
       printf (_("  define new File Table entry\n"));
       printf (_("  Entry\tDir\tTime\tSize\tName\n"));
 
-      printf (_("   %d\t"), ++state_machine_regs.last_file_entry);
+      printf ("   %d\t", ++state_machine_regs.last_file_entry);
       name = data;
       data += strlen ((char *) data) + 1;
-      printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0));
+      printf ("%lu\t", read_leb128 (data, & bytes_read, 0));
       data += bytes_read;
-      printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0));
+      printf ("%lu\t", read_leb128 (data, & bytes_read, 0));
       data += bytes_read;
-      printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0));
-      printf (_("%s\n\n"), name);
+      printf ("%lu\t", read_leb128 (data, & bytes_read, 0));
+      printf ("%s\n\n", name);
+      break;
+
+    case DW_LNE_set_discriminator:
+      printf (_("set Discriminator to %lu\n"),
+              read_leb128 (data, & bytes_read, 0));
+      break;
+
+    /* HP extensions.  */
+    case DW_LNE_HP_negate_is_UV_update:
+      printf ("DW_LNE_HP_negate_is_UV_update\n");
+      break;
+    case DW_LNE_HP_push_context:
+      printf ("DW_LNE_HP_push_context\n");
+      break;
+    case DW_LNE_HP_pop_context:
+      printf ("DW_LNE_HP_pop_context\n");
+      break;
+    case DW_LNE_HP_set_file_line_column:
+      printf ("DW_LNE_HP_set_file_line_column\n");
+      break;
+    case DW_LNE_HP_set_routine_name:
+      printf ("DW_LNE_HP_set_routine_name\n");
+      break;
+    case DW_LNE_HP_set_sequence:
+      printf ("DW_LNE_HP_set_sequence\n");
+      break;
+    case DW_LNE_HP_negate_post_semantics:
+      printf ("DW_LNE_HP_negate_post_semantics\n");
+      break;
+    case DW_LNE_HP_negate_function_exit:
+      printf ("DW_LNE_HP_negate_function_exit\n");
+      break;
+    case DW_LNE_HP_negate_front_end_logical:
+      printf ("DW_LNE_HP_negate_front_end_logical\n");
+      break;
+    case DW_LNE_HP_define_proc:
+      printf ("DW_LNE_HP_define_proc\n");
       break;
 
     default:
-      printf (_("UNKNOWN: length %d\n"), len - bytes_read);
+      if (op_code >= DW_LNE_lo_user
+         /* The test against DW_LNW_hi_user is redundant due to
+            the limited range of the unsigned char data type used
+            for op_code.  */
+         /*&& op_code <= DW_LNE_hi_user*/)
+       printf (_("user defined: length %d\n"), len - bytes_read);
+      else
+       printf (_("UNKNOWN: length %d\n"), len - bytes_read);
       break;
     }
 
@@ -326,23 +337,23 @@ static abbrev_entry *last_abbrev = NULL;
 static void
 free_abbrevs (void)
 {
-  abbrev_entry *abbrev;
+  abbrev_entry *abbrv;
 
-  for (abbrev = first_abbrev; abbrev;)
+  for (abbrv = first_abbrev; abbrv;)
     {
-      abbrev_entry *next = abbrev->next;
+      abbrev_entry *next_abbrev = abbrv->next;
       abbrev_attr *attr;
 
-      for (attr = abbrev->first_attr; attr;)
+      for (attr = abbrv->first_attr; attr;)
        {
-         abbrev_attr *next = attr->next;
+         abbrev_attr *next_attr = attr->next;
 
          free (attr);
-         attr = next;
+         attr = next_attr;
        }
 
-      free (abbrev);
-      abbrev = next;
+      free (abbrv);
+      abbrv = next_abbrev;
     }
 
   last_abbrev = first_abbrev = NULL;
@@ -353,7 +364,7 @@ add_abbrev (unsigned long number, unsigned long tag, int children)
 {
   abbrev_entry *entry;
 
-  entry = malloc (sizeof (*entry));
+  entry = (abbrev_entry *) malloc (sizeof (*entry));
 
   if (entry == NULL)
     /* ugg */
@@ -379,7 +390,7 @@ add_abbrev_attr (unsigned long attribute, unsigned long form)
 {
   abbrev_attr *attr;
 
-  attr = malloc (sizeof (*attr));
+  attr = (abbrev_attr *) malloc (sizeof (*attr));
 
   if (attr == NULL)
     /* ugg */
@@ -517,6 +528,12 @@ get_TAG_name (unsigned long tag)
     case DW_TAG_unspecified_type:      return "DW_TAG_unspecified_type";
     case DW_TAG_partial_unit:          return "DW_TAG_partial_unit";
     case DW_TAG_imported_unit:         return "DW_TAG_imported_unit";
+    case DW_TAG_condition:             return "DW_TAG_condition";
+    case DW_TAG_shared_type:           return "DW_TAG_shared_type";
+      /* DWARF 4 values.  */
+    case DW_TAG_type_unit:             return "DW_TAG_type_unit";
+    case DW_TAG_rvalue_reference_type: return "DW_TAG_rvalue_reference_type";
+    case DW_TAG_template_alias:                return "DW_TAG_template_alias";
       /* 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";
@@ -557,6 +574,11 @@ get_FORM_name (unsigned long form)
     case DW_FORM_ref8:         return "DW_FORM_ref8";
     case DW_FORM_ref_udata:    return "DW_FORM_ref_udata";
     case DW_FORM_indirect:     return "DW_FORM_indirect";
+      /* DWARF 4 values.  */
+    case DW_FORM_sec_offset:   return "DW_FORM_sec_offset";
+    case DW_FORM_exprloc:      return "DW_FORM_exprloc";
+    case DW_FORM_flag_present: return "DW_FORM_flag_present";
+    case DW_FORM_ref_sig8:     return "DW_FORM_ref_sig8";
     default:
       {
        static char buffer[100];
@@ -581,8 +603,11 @@ display_block (unsigned char *data, unsigned long length)
 static int
 decode_location_expression (unsigned char * data,
                            unsigned int pointer_size,
+                           unsigned int offset_size,
+                           int dwarf_version,
                            unsigned long length,
-                           unsigned long cu_offset)
+                           unsigned long cu_offset,
+                           struct dwarf_section * section)
 {
   unsigned op;
   unsigned int bytes_read;
@@ -806,7 +831,8 @@ decode_location_expression (unsigned char * data,
        case DW_OP_reg29:
        case DW_OP_reg30:
        case DW_OP_reg31:
-         printf ("DW_OP_reg%d", op - DW_OP_reg0);
+         printf ("DW_OP_reg%d (%s)", op - DW_OP_reg0,
+                 regname (op - DW_OP_reg0, 1));
          break;
 
        case DW_OP_breg0:
@@ -841,14 +867,16 @@ decode_location_expression (unsigned char * data,
        case DW_OP_breg29:
        case DW_OP_breg30:
        case DW_OP_breg31:
-         printf ("DW_OP_breg%d: %ld", op - DW_OP_breg0,
+         printf ("DW_OP_breg%d (%s): %ld", op - DW_OP_breg0,
+                 regname (op - DW_OP_breg0, 1),
                  read_leb128 (data, &bytes_read, 1));
          data += bytes_read;
          break;
 
        case DW_OP_regx:
-         printf ("DW_OP_regx: %lu", read_leb128 (data, &bytes_read, 0));
+         uvalue = read_leb128 (data, &bytes_read, 0);
          data += bytes_read;
+         printf ("DW_OP_regx: %lu (%s)", uvalue, regname (uvalue, 1));
          break;
        case DW_OP_fbreg:
          need_frame_base = 1;
@@ -858,7 +886,7 @@ decode_location_expression (unsigned char * data,
        case DW_OP_bregx:
          uvalue = read_leb128 (data, &bytes_read, 0);
          data += bytes_read;
-         printf ("DW_OP_bregx: %lu %ld", uvalue,
+         printf ("DW_OP_bregx: %lu (%s) %ld", uvalue, regname (uvalue, 1),
                  read_leb128 (data, &bytes_read, 1));
          data += bytes_read;
          break;
@@ -883,22 +911,143 @@ decode_location_expression (unsigned char * data,
        case DW_OP_call2:
          /* XXX: Strictly speaking for 64-bit DWARF3 files
             this ought to be an 8-byte wide computation.  */
-         printf ("DW_OP_call2: <%lx>", (long) byte_get (data, 2) + cu_offset);
+         printf ("DW_OP_call2: <0x%lx>", (long) byte_get (data, 2) + cu_offset);
          data += 2;
          break;
        case DW_OP_call4:
          /* XXX: Strictly speaking for 64-bit DWARF3 files
             this ought to be an 8-byte wide computation.  */
-         printf ("DW_OP_call4: <%lx>", (long) byte_get (data, 4) + cu_offset);
+         printf ("DW_OP_call4: <0x%lx>", (long) byte_get (data, 4) + cu_offset);
          data += 4;
          break;
        case DW_OP_call_ref:
-         printf ("DW_OP_call_ref");
+         /* XXX: Strictly speaking for 64-bit DWARF3 files
+            this ought to be an 8-byte wide computation.  */
+         if (dwarf_version == -1)
+           {
+             printf (_("(DW_OP_call_ref in frame info)"));
+             /* No way to tell where the next op is, so just bail.  */
+             return need_frame_base;
+           }
+         if (dwarf_version == 2)
+           {
+             printf ("DW_OP_call_ref: <0x%lx>",
+                     (long) byte_get (data, pointer_size));
+             data += pointer_size;
+           }
+         else
+           {
+             printf ("DW_OP_call_ref: <0x%lx>",
+                     (long) byte_get (data, offset_size));
+             data += offset_size;
+           }
+         break;
+       case DW_OP_form_tls_address:
+         printf ("DW_OP_form_tls_address");
+         break;
+       case DW_OP_call_frame_cfa:
+         printf ("DW_OP_call_frame_cfa");
+         break;
+       case DW_OP_bit_piece:
+         printf ("DW_OP_bit_piece: ");
+         printf ("size: %lu ", read_leb128 (data, &bytes_read, 0));
+         data += bytes_read;
+         printf ("offset: %lu ", read_leb128 (data, &bytes_read, 0));
+         data += bytes_read;
+         break;
+
+         /* DWARF 4 extensions.  */
+       case DW_OP_stack_value:
+         printf ("DW_OP_stack_value");
+         break;
+
+       case DW_OP_implicit_value:
+         printf ("DW_OP_implicit_value");
+         uvalue = read_leb128 (data, &bytes_read, 0);
+         data += bytes_read;
+         display_block (data, uvalue);
+         data += uvalue;
          break;
 
          /* GNU extensions.  */
        case DW_OP_GNU_push_tls_address:
-         printf ("DW_OP_GNU_push_tls_address");
+         printf ("DW_OP_GNU_push_tls_address or DW_OP_HP_unknown");
+         break;
+       case DW_OP_GNU_uninit:
+         printf ("DW_OP_GNU_uninit");
+         /* FIXME: Is there data associated with this OP ?  */
+         break;
+       case DW_OP_GNU_encoded_addr:
+         {
+           int encoding;
+           dwarf_vma addr;
+       
+           encoding = *data++;
+           addr = get_encoded_value (data, encoding, section);
+           data += size_of_encoded_value (encoding);
+
+           printf ("DW_OP_GNU_encoded_addr: fmt:%02x addr:", encoding);
+           print_dwarf_vma (addr, pointer_size);
+         }
+         break;
+       case DW_OP_GNU_implicit_pointer:
+         /* XXX: Strictly speaking for 64-bit DWARF3 files
+            this ought to be an 8-byte wide computation.  */
+         if (dwarf_version == -1)
+           {
+             printf (_("(DW_OP_GNU_implicit_pointer in frame info)"));
+             /* No way to tell where the next op is, so just bail.  */
+             return need_frame_base;
+           }
+         if (dwarf_version == 2)
+           {
+             printf ("DW_OP_GNU_implicit_pointer: <0x%lx> %ld",
+                     (long) byte_get (data, pointer_size),
+                     read_leb128 (data + pointer_size, &bytes_read, 1));
+             data += pointer_size + bytes_read;
+           }
+         else
+           {
+             printf ("DW_OP_GNU_implicit_pointer: <0x%lx> %ld",
+                     (long) byte_get (data, offset_size),
+                     read_leb128 (data + offset_size, &bytes_read, 1));
+             data += offset_size + bytes_read;
+           }
+         break;
+
+         /* HP extensions.  */
+       case DW_OP_HP_is_value:
+         printf ("DW_OP_HP_is_value");
+         /* FIXME: Is there data associated with this OP ?  */
+         break;
+       case DW_OP_HP_fltconst4:
+         printf ("DW_OP_HP_fltconst4");
+         /* FIXME: Is there data associated with this OP ?  */
+         break;
+       case DW_OP_HP_fltconst8:
+         printf ("DW_OP_HP_fltconst8");
+         /* FIXME: Is there data associated with this OP ?  */
+         break;
+       case DW_OP_HP_mod_range:
+         printf ("DW_OP_HP_mod_range");
+         /* FIXME: Is there data associated with this OP ?  */
+         break;
+       case DW_OP_HP_unmod_range:
+         printf ("DW_OP_HP_unmod_range");
+         /* FIXME: Is there data associated with this OP ?  */
+         break;
+       case DW_OP_HP_tls:
+         printf ("DW_OP_HP_tls");
+         /* FIXME: Is there data associated with this OP ?  */
+         break;
+
+         /* PGI (STMicroelectronics) extensions.  */
+       case DW_OP_PGI_omp_thread_num:
+         /* Pushes the thread number for the current thread as it would be
+            returned by the standard OpenMP library function:
+            omp_get_thread_num().  The "current thread" is the thread for
+            which the expression is being evaluated.  */
+         printf ("DW_OP_PGI_omp_thread_num");
          break;
 
        default:
@@ -922,16 +1071,18 @@ decode_location_expression (unsigned char * data,
 static unsigned char *
 read_and_display_attr_value (unsigned long attribute,
                             unsigned long form,
-                            unsigned char *data,
+                            unsigned char * data,
                             unsigned long cu_offset,
                             unsigned long pointer_size,
                             unsigned long offset_size,
                             int dwarf_version,
-                            debug_info *debug_info_p,
-                            int do_loc)
+                            debug_info * debug_info_p,
+                            int do_loc,
+                            struct dwarf_section * section)
 {
   unsigned long uvalue = 0;
   unsigned char *block_start = NULL;
+  unsigned char * orig_data = data;
   unsigned int bytes_read;
 
   switch (form)
@@ -945,14 +1096,14 @@ read_and_display_attr_value (unsigned long attribute,
          uvalue = byte_get (data, pointer_size);
          data += pointer_size;
        }
-      else if (dwarf_version == 3)
+      else if (dwarf_version == 3 || dwarf_version == 4)
        {
          uvalue = byte_get (data, offset_size);
          data += offset_size;
        }
       else
        {
-         error (_("Internal error: DWARF version is not 2 or 3.\n"));
+         error (_("Internal error: DWARF version is not 2, 3 or 4.\n"));
        }
       break;
 
@@ -962,10 +1113,15 @@ read_and_display_attr_value (unsigned long attribute,
       break;
 
     case DW_FORM_strp:
+    case DW_FORM_sec_offset:
       uvalue = byte_get (data, offset_size);
       data += offset_size;
       break;
 
+    case DW_FORM_flag_present:
+      uvalue = 1;
+      break;
+
     case DW_FORM_ref1:
     case DW_FORM_flag:
     case DW_FORM_data1:
@@ -1003,14 +1159,15 @@ read_and_display_attr_value (unsigned long attribute,
       return read_and_display_attr_value (attribute, form, data,
                                          cu_offset, pointer_size,
                                          offset_size, dwarf_version,
-                                         debug_info_p, do_loc);
+                                         debug_info_p, do_loc,
+                                         section);
     }
 
   switch (form)
     {
     case DW_FORM_ref_addr:
       if (!do_loc)
-       printf (" <#%lx>", uvalue);
+       printf (" <0x%lx>", uvalue);
       break;
 
     case DW_FORM_ref1:
@@ -1018,15 +1175,17 @@ read_and_display_attr_value (unsigned long attribute,
     case DW_FORM_ref4:
     case DW_FORM_ref_udata:
       if (!do_loc)
-       printf (" <%lx>", uvalue + cu_offset);
+       printf (" <0x%lx>", uvalue + cu_offset);
       break;
 
     case DW_FORM_data4:
     case DW_FORM_addr:
+    case DW_FORM_sec_offset:
       if (!do_loc)
-       printf (" %#lx", uvalue);
+       printf (" 0x%lx", uvalue);
       break;
 
+    case DW_FORM_flag_present:
     case DW_FORM_flag:
     case DW_FORM_data1:
     case DW_FORM_data2:
@@ -1041,8 +1200,8 @@ read_and_display_attr_value (unsigned long attribute,
       if (!do_loc)
        {
          uvalue = byte_get (data, 4);
-         printf (" %lx", uvalue);
-         printf (" %lx", (unsigned long) byte_get (data + 4, 4));
+         printf (" 0x%lx", uvalue);
+         printf (" 0x%lx", (unsigned long) byte_get (data + 4, 4));
        }
       if ((do_loc || do_debug_loc || do_debug_ranges)
          && num_debug_info_entries == 0)
@@ -1062,6 +1221,7 @@ read_and_display_attr_value (unsigned long attribute,
       break;
 
     case DW_FORM_block:
+    case DW_FORM_exprloc:
       uvalue = read_leb128 (data, & bytes_read, 0);
       block_start = data + bytes_read;
       if (do_loc)
@@ -1107,12 +1267,26 @@ read_and_display_attr_value (unsigned long attribute,
       /* Handled above.  */
       break;
 
+    case DW_FORM_ref_sig8:
+      if (!do_loc)
+       {
+         int i;
+         printf (" signature: ");
+         for (i = 0; i < 8; i++)
+           {
+             printf ("%02x", (unsigned) byte_get (data, 1));
+             data += 1;
+           }
+       }
+      else
+        data += 8;
+      break;
+
     default:
       warn (_("Unrecognized form: %lu\n"), form);
       break;
     }
 
-  /* For some attributes we can display further information.  */
   if ((do_loc || do_debug_loc || do_debug_ranges)
       && num_debug_info_entries == 0)
     {
@@ -1121,56 +1295,59 @@ read_and_display_attr_value (unsigned long attribute,
        case DW_AT_frame_base:
          have_frame_base = 1;
        case DW_AT_location:
+       case DW_AT_string_length:
+       case DW_AT_return_addr:
        case DW_AT_data_member_location:
        case DW_AT_vtable_elem_location:
-       case DW_AT_allocated:
-       case DW_AT_associated:
-       case DW_AT_data_location:
-       case DW_AT_stride:
-       case DW_AT_upper_bound:
-       case DW_AT_lower_bound:
-         if (form == DW_FORM_data4 || form == DW_FORM_data8)
+       case DW_AT_segment:
+       case DW_AT_static_link:
+       case DW_AT_use_location:
+         if (form == DW_FORM_data4
+             || form == DW_FORM_data8
+             || form == DW_FORM_sec_offset)
            {
              /* Process location list.  */
-             unsigned int max = debug_info_p->max_loc_offsets;
+             unsigned int lmax = debug_info_p->max_loc_offsets;
              unsigned int num = debug_info_p->num_loc_offsets;
 
-             if (max == 0 || num >= max)
+             if (lmax == 0 || num >= lmax)
                {
-                 max += 1024;
-                 debug_info_p->loc_offsets
-                   = xcrealloc (debug_info_p->loc_offsets,
-                                max, sizeof (*debug_info_p->loc_offsets));
-                 debug_info_p->have_frame_base
-                   = xcrealloc (debug_info_p->have_frame_base,
-                                max, sizeof (*debug_info_p->have_frame_base));
-                 debug_info_p->max_loc_offsets = max;
+                 lmax += 1024;
+                 debug_info_p->loc_offsets = (long unsigned int *)
+                      xcrealloc (debug_info_p->loc_offsets,
+                                lmax, sizeof (*debug_info_p->loc_offsets));
+                 debug_info_p->have_frame_base = (int *)
+                      xcrealloc (debug_info_p->have_frame_base,
+                                lmax, sizeof (*debug_info_p->have_frame_base));
+                 debug_info_p->max_loc_offsets = lmax;
                }
              debug_info_p->loc_offsets [num] = uvalue;
              debug_info_p->have_frame_base [num] = have_frame_base;
              debug_info_p->num_loc_offsets++;
            }
          break;
-       
+
        case DW_AT_low_pc:
          if (need_base_address)
            debug_info_p->base_address = uvalue;
          break;
 
        case DW_AT_ranges:
-         if (form == DW_FORM_data4 || form == DW_FORM_data8)
+         if (form == DW_FORM_data4
+             || form == DW_FORM_data8
+             || form == DW_FORM_sec_offset)
            {
              /* Process range list.  */
-             unsigned int max = debug_info_p->max_range_lists;
+             unsigned int lmax = debug_info_p->max_range_lists;
              unsigned int num = debug_info_p->num_range_lists;
 
-             if (max == 0 || num >= max)
+             if (lmax == 0 || num >= lmax)
                {
-                 max += 1024;
-                 debug_info_p->range_lists
-                   = xcrealloc (debug_info_p->range_lists,
-                                max, sizeof (*debug_info_p->range_lists));
-                 debug_info_p->max_range_lists = max;
+                 lmax += 1024;
+                 debug_info_p->range_lists = (long unsigned int *)
+                      xcrealloc (debug_info_p->range_lists,
+                                lmax, sizeof (*debug_info_p->range_lists));
+                 debug_info_p->max_range_lists = lmax;
                }
              debug_info_p->range_lists [num] = uvalue;
              debug_info_p->num_range_lists++;
@@ -1185,6 +1362,7 @@ read_and_display_attr_value (unsigned long attribute,
   if (do_loc)
     return data;
 
+  /* For some attributes we can display further information.  */
   printf ("\t");
 
   switch (attribute)
@@ -1213,26 +1391,39 @@ read_and_display_attr_value (unsigned long attribute,
     case DW_AT_language:
       switch (uvalue)
        {
-       case DW_LANG_C:                 printf ("(non-ANSI C)"); break;
+         /* Ordered by the numeric value of these constants.  */
        case DW_LANG_C89:               printf ("(ANSI C)"); break;
+       case DW_LANG_C:                 printf ("(non-ANSI C)"); break;
+       case DW_LANG_Ada83:             printf ("(Ada)"); break;
        case DW_LANG_C_plus_plus:       printf ("(C++)"); break;
+       case DW_LANG_Cobol74:           printf ("(Cobol 74)"); break;
+       case DW_LANG_Cobol85:           printf ("(Cobol 85)"); break;
        case DW_LANG_Fortran77:         printf ("(FORTRAN 77)"); break;
        case DW_LANG_Fortran90:         printf ("(Fortran 90)"); break;
-       case DW_LANG_Modula2:           printf ("(Modula 2)"); break;
        case DW_LANG_Pascal83:          printf ("(ANSI Pascal)"); break;
-       case DW_LANG_Ada83:             printf ("(Ada)"); break;
-       case DW_LANG_Cobol74:           printf ("(Cobol 74)"); break;
-       case DW_LANG_Cobol85:           printf ("(Cobol 85)"); break;
+       case DW_LANG_Modula2:           printf ("(Modula 2)"); break;
          /* DWARF 2.1 values.  */
+       case DW_LANG_Java:              printf ("(Java)"); break;
        case DW_LANG_C99:               printf ("(ANSI C99)"); break;
        case DW_LANG_Ada95:             printf ("(ADA 95)"); break;
        case DW_LANG_Fortran95:         printf ("(Fortran 95)"); break;
+         /* DWARF 3 values.  */
+       case DW_LANG_PLI:               printf ("(PLI)"); break;
+       case DW_LANG_ObjC:              printf ("(Objective C)"); break;
+       case DW_LANG_ObjC_plus_plus:    printf ("(Objective C++)"); break;
+       case DW_LANG_UPC:               printf ("(Unified Parallel C)"); break;
+       case DW_LANG_D:                 printf ("(D)"); break;
+         /* DWARF 4 values.  */
+       case DW_LANG_Python:            printf ("(Python)"); break;
          /* MIPS extension.  */
        case DW_LANG_Mips_Assembler:    printf ("(MIPS assembler)"); break;
          /* UPC extension.  */
        case DW_LANG_Upc:               printf ("(Unified Parallel C)"); break;
        default:
-         printf ("(Unknown: %lx)", uvalue);
+         if (uvalue >= DW_LANG_lo_user && uvalue <= DW_LANG_hi_user)
+           printf ("(implementation defined: %lx)", uvalue);
+         else
+           printf ("(Unknown: %lx)", uvalue);
          break;
        }
       break;
@@ -1249,9 +1440,24 @@ read_and_display_attr_value (unsigned long attribute,
        case DW_ATE_signed_char:        printf ("(signed char)"); break;
        case DW_ATE_unsigned:           printf ("(unsigned)"); break;
        case DW_ATE_unsigned_char:      printf ("(unsigned char)"); break;
-         /* DWARF 2.1 value.  */
+         /* DWARF 2.1 values:  */
        case DW_ATE_imaginary_float:    printf ("(imaginary float)"); break;
        case DW_ATE_decimal_float:      printf ("(decimal float)"); break;
+         /* DWARF 3 values:  */
+       case DW_ATE_packed_decimal:     printf ("(packed_decimal)"); break;
+       case DW_ATE_numeric_string:     printf ("(numeric_string)"); break;
+       case DW_ATE_edited:             printf ("(edited)"); break;
+       case DW_ATE_signed_fixed:       printf ("(signed_fixed)"); break;
+       case DW_ATE_unsigned_fixed:     printf ("(unsigned_fixed)"); break;
+         /* HP extensions:  */
+       case DW_ATE_HP_float80:         printf ("(HP_float80)"); break;
+       case DW_ATE_HP_complex_float80: printf ("(HP_complex_float80)"); break;
+       case DW_ATE_HP_float128:        printf ("(HP_float128)"); break;
+       case DW_ATE_HP_complex_float128:printf ("(HP_complex_float128)"); break;
+       case DW_ATE_HP_floathpintel:    printf ("(HP_floathpintel)"); break;
+       case DW_ATE_HP_imaginary_float80:       printf ("(HP_imaginary_float80)"); break;
+       case DW_ATE_HP_imaginary_float128:      printf ("(HP_imaginary_float128)"); break;
+
        default:
          if (uvalue >= DW_ATE_lo_user
              && uvalue <= DW_ATE_hi_user)
@@ -1332,8 +1538,18 @@ read_and_display_attr_value (unsigned long attribute,
     case DW_AT_frame_base:
       have_frame_base = 1;
     case DW_AT_location:
+    case DW_AT_string_length:
+    case DW_AT_return_addr:
     case DW_AT_data_member_location:
     case DW_AT_vtable_elem_location:
+    case DW_AT_segment:
+    case DW_AT_static_link:
+    case DW_AT_use_location:
+      if (form == DW_FORM_data4
+         || form == DW_FORM_data8
+         || form == DW_FORM_sec_offset)
+       printf (_("(location list)"));
+      /* Fall through.  */
     case DW_AT_allocated:
     case DW_AT_associated:
     case DW_AT_data_location:
@@ -1347,15 +1563,45 @@ read_and_display_attr_value (unsigned long attribute,
          printf ("(");
          need_frame_base = decode_location_expression (block_start,
                                                        pointer_size,
+                                                       offset_size,
+                                                       dwarf_version,
                                                        uvalue,
-                                                       cu_offset);
+                                                       cu_offset, section);
          printf (")");
          if (need_frame_base && !have_frame_base)
            printf (_(" [without DW_AT_frame_base]"));
        }
-      else if (form == DW_FORM_data4 || form == DW_FORM_data8)
-       printf (_("(location list)"));
+      break;
 
+    case DW_AT_import:
+      {
+        if (form == DW_FORM_ref_sig8)
+          break;
+
+       if (form == DW_FORM_ref1
+           || form == DW_FORM_ref2
+           || form == DW_FORM_ref4)
+         uvalue += cu_offset;
+
+       if (uvalue >= section->size)
+         warn (_("Offset %lx used as value for DW_AT_import attribute of DIE at offset %lx is too big.\n"),
+               uvalue, (unsigned long) (orig_data - section->start));
+       else
+         {
+           unsigned long abbrev_number;
+           abbrev_entry * entry;
+
+           abbrev_number = read_leb128 (section->start + uvalue, NULL, 0);
+
+           printf ("[Abbrev Number: %ld", abbrev_number);
+           for (entry = first_abbrev; entry != NULL; entry = entry->next)
+             if (entry->entry == abbrev_number)
+               break;
+           if (entry != NULL)
+             printf (" (%s)", get_TAG_name (entry->tag));
+           printf ("]");
+         }
+      }
       break;
 
     default:
@@ -1445,29 +1691,86 @@ get_AT_name (unsigned long attribute)
     case DW_AT_call_column:            return "DW_AT_call_column";
     case DW_AT_call_file:              return "DW_AT_call_file";
     case DW_AT_call_line:              return "DW_AT_call_line";
-      /* SGI/MIPS extensions.  */
-    case DW_AT_MIPS_fde:               return "DW_AT_MIPS_fde";
-    case DW_AT_MIPS_loop_begin:                return "DW_AT_MIPS_loop_begin";
-    case DW_AT_MIPS_tail_loop_begin:   return "DW_AT_MIPS_tail_loop_begin";
-    case DW_AT_MIPS_epilog_begin:      return "DW_AT_MIPS_epilog_begin";
-    case DW_AT_MIPS_loop_unroll_factor: return "DW_AT_MIPS_loop_unroll_factor";
-    case DW_AT_MIPS_software_pipeline_depth:
-      return "DW_AT_MIPS_software_pipeline_depth";
-    case DW_AT_MIPS_linkage_name:      return "DW_AT_MIPS_linkage_name";
-    case DW_AT_MIPS_stride:            return "DW_AT_MIPS_stride";
-    case DW_AT_MIPS_abstract_name:     return "DW_AT_MIPS_abstract_name";
-    case DW_AT_MIPS_clone_origin:      return "DW_AT_MIPS_clone_origin";
-    case DW_AT_MIPS_has_inlines:       return "DW_AT_MIPS_has_inlines";
+    case DW_AT_description:            return "DW_AT_description";
+    case DW_AT_binary_scale:           return "DW_AT_binary_scale";
+    case DW_AT_decimal_scale:          return "DW_AT_decimal_scale";
+    case DW_AT_small:                  return "DW_AT_small";
+    case DW_AT_decimal_sign:           return "DW_AT_decimal_sign";
+    case DW_AT_digit_count:            return "DW_AT_digit_count";
+    case DW_AT_picture_string:         return "DW_AT_picture_string";
+    case DW_AT_mutable:                        return "DW_AT_mutable";
+    case DW_AT_threads_scaled:         return "DW_AT_threads_scaled";
+    case DW_AT_explicit:               return "DW_AT_explicit";
+    case DW_AT_object_pointer:         return "DW_AT_object_pointer";
+    case DW_AT_endianity:              return "DW_AT_endianity";
+    case DW_AT_elemental:              return "DW_AT_elemental";
+    case DW_AT_pure:                   return "DW_AT_pure";
+    case DW_AT_recursive:              return "DW_AT_recursive";
+      /* DWARF 4 values.  */
+    case DW_AT_signature:              return "DW_AT_signature";
+    case DW_AT_main_subprogram:                return "DW_AT_main_subprogram";
+    case DW_AT_data_bit_offset:                return "DW_AT_data_bit_offset";
+    case DW_AT_const_expr:             return "DW_AT_const_expr";
+    case DW_AT_enum_class:             return "DW_AT_enum_class";
+    case DW_AT_linkage_name:           return "DW_AT_linkage_name";
+
+      /* HP and SGI/MIPS extensions.  */
+    case DW_AT_MIPS_loop_begin:                        return "DW_AT_MIPS_loop_begin";
+    case DW_AT_MIPS_tail_loop_begin:           return "DW_AT_MIPS_tail_loop_begin";
+    case DW_AT_MIPS_epilog_begin:              return "DW_AT_MIPS_epilog_begin";
+    case DW_AT_MIPS_loop_unroll_factor:        return "DW_AT_MIPS_loop_unroll_factor";
+    case DW_AT_MIPS_software_pipeline_depth:   return "DW_AT_MIPS_software_pipeline_depth";
+    case DW_AT_MIPS_linkage_name:              return "DW_AT_MIPS_linkage_name";
+    case DW_AT_MIPS_stride:                    return "DW_AT_MIPS_stride";
+    case DW_AT_MIPS_abstract_name:             return "DW_AT_MIPS_abstract_name";
+    case DW_AT_MIPS_clone_origin:              return "DW_AT_MIPS_clone_origin";
+    case DW_AT_MIPS_has_inlines:               return "DW_AT_MIPS_has_inlines";
+
+      /* HP Extensions.  */
+    case DW_AT_HP_block_index:                 return "DW_AT_HP_block_index";
+    case DW_AT_HP_actuals_stmt_list:           return "DW_AT_HP_actuals_stmt_list";
+    case DW_AT_HP_proc_per_section:            return "DW_AT_HP_proc_per_section";
+    case DW_AT_HP_raw_data_ptr:                        return "DW_AT_HP_raw_data_ptr";
+    case DW_AT_HP_pass_by_reference:           return "DW_AT_HP_pass_by_reference";
+    case DW_AT_HP_opt_level:                   return "DW_AT_HP_opt_level";
+    case DW_AT_HP_prof_version_id:             return "DW_AT_HP_prof_version_id";
+    case DW_AT_HP_opt_flags:                   return "DW_AT_HP_opt_flags";
+    case DW_AT_HP_cold_region_low_pc:          return "DW_AT_HP_cold_region_low_pc";
+    case DW_AT_HP_cold_region_high_pc:         return "DW_AT_HP_cold_region_high_pc";
+    case DW_AT_HP_all_variables_modifiable:    return "DW_AT_HP_all_variables_modifiable";
+    case DW_AT_HP_linkage_name:                        return "DW_AT_HP_linkage_name";
+    case DW_AT_HP_prof_flags:                  return "DW_AT_HP_prof_flags";
+
+      /* One value is shared by the MIPS and HP extensions:  */
+    case DW_AT_MIPS_fde:                       return "DW_AT_MIPS_fde or DW_AT_HP_unmodifiable";
+
       /* GNU extensions.  */
-    case DW_AT_sf_names:               return "DW_AT_sf_names";
-    case DW_AT_src_info:               return "DW_AT_src_info";
-    case DW_AT_mac_info:               return "DW_AT_mac_info";
-    case DW_AT_src_coords:             return "DW_AT_src_coords";
-    case DW_AT_body_begin:             return "DW_AT_body_begin";
-    case DW_AT_body_end:               return "DW_AT_body_end";
-    case DW_AT_GNU_vector:             return "DW_AT_GNU_vector";
+    case DW_AT_sf_names:                       return "DW_AT_sf_names";
+    case DW_AT_src_info:                       return "DW_AT_src_info";
+    case DW_AT_mac_info:                       return "DW_AT_mac_info";
+    case DW_AT_src_coords:                     return "DW_AT_src_coords";
+    case DW_AT_body_begin:                     return "DW_AT_body_begin";
+    case DW_AT_body_end:                       return "DW_AT_body_end";
+    case DW_AT_GNU_vector:                     return "DW_AT_GNU_vector";
+    case DW_AT_GNU_guarded_by:                 return "DW_AT_GNU_guarded_by";
+    case DW_AT_GNU_pt_guarded_by:              return "DW_AT_GNU_pt_guarded_by";
+    case DW_AT_GNU_guarded:                    return "DW_AT_GNU_guarded";
+    case DW_AT_GNU_pt_guarded:                 return "DW_AT_GNU_pt_guarded";
+    case DW_AT_GNU_locks_excluded:             return "DW_AT_GNU_locks_excluded";
+    case DW_AT_GNU_exclusive_locks_required:   return "DW_AT_GNU_exclusive_locks_required";
+    case DW_AT_GNU_shared_locks_required:      return "DW_AT_GNU_shared_locks_required";
+    case DW_AT_GNU_odr_signature:              return "DW_AT_GNU_odr_signature";
+    case DW_AT_use_GNAT_descriptive_type:      return "DW_AT_use_GNAT_descriptive_type";
+    case DW_AT_GNAT_descriptive_type:          return "DW_AT_GNAT_descriptive_type";
+
       /* UPC extension.  */
     case DW_AT_upc_threads_scaled:     return "DW_AT_upc_threads_scaled";
+
+    /* PGI (STMicroelectronics) extensions.  */
+    case DW_AT_PGI_lbase:              return "DW_AT_PGI_lbase";
+    case DW_AT_PGI_soffset:            return "DW_AT_PGI_soffset";
+    case DW_AT_PGI_lstride:            return "DW_AT_PGI_lstride";
+
     default:
       {
        static char buffer[100];
@@ -1482,20 +1785,21 @@ get_AT_name (unsigned long attribute)
 static unsigned char *
 read_and_display_attr (unsigned long attribute,
                       unsigned long form,
-                      unsigned char *data,
+                      unsigned char * data,
                       unsigned long cu_offset,
                       unsigned long pointer_size,
                       unsigned long offset_size,
                       int dwarf_version,
-                      debug_info *debug_info_p,
-                      int do_loc)
+                      debug_info * debug_info_p,
+                      int do_loc,
+                      struct dwarf_section * section)
 {
   if (!do_loc)
-    printf ("     %-18s:", get_AT_name (attribute));
+    printf ("   %-18s:", get_AT_name (attribute));
   data = read_and_display_attr_value (attribute, form, data, cu_offset,
                                      pointer_size, offset_size,
                                      dwarf_version, debug_info_p,
-                                     do_loc);
+                                     do_loc, section);
   if (!do_loc)
     printf ("\n");
   return data;
@@ -1504,11 +1808,15 @@ read_and_display_attr (unsigned long attribute,
 
 /* Process the contents of a .debug_info section.  If do_loc is non-zero
    then we are scanning for location lists and we do not want to display
-   anything to the user.  */
+   anything to the user.  If do_types is non-zero, we are processing
+   a .debug_types section instead of a .debug_info section.  */
 
 static int
-process_debug_info (struct dwarf_section *section, void *file,
-                   int do_loc)
+process_debug_info (struct dwarf_section *section,
+                   void *file,
+                    enum dwarf_section_display_enum abbrev_sec,
+                   int do_loc,
+                   int do_types)
 {
   unsigned char *start = section->start;
   unsigned char *end = start + section->size;
@@ -1517,7 +1825,8 @@ process_debug_info (struct dwarf_section *section, void *file,
   unsigned int num_units = 0;
 
   if ((do_loc || do_debug_loc || do_debug_ranges)
-      && num_debug_info_entries == 0)
+      && num_debug_info_entries == 0
+      && ! do_types)
     {
       unsigned long length;
 
@@ -1535,8 +1844,22 @@ process_debug_info (struct dwarf_section *section, void *file,
              length = byte_get (section_begin + 4, 8);
              section_begin += length + 12;
            }
+         else if (length >= 0xfffffff0 && length < 0xffffffff)
+           {
+             warn (_("Reserved length value (%lx) found in section %s\n"), length, section->name);
+             return 0;
+           }
          else
            section_begin += length + 4;
+
+         /* Negative values are illegal, they may even cause infinite
+            looping.  This can happen if we can't accurately apply
+            relocations to an object file.  */
+         if ((signed long) length <= 0)
+           {
+             warn (_("Corrupt unit length (%lx) found in section %s\n"), length, section->name);
+             return 0;
+           }
        }
 
       if (num_units == 0)
@@ -1546,8 +1869,8 @@ process_debug_info (struct dwarf_section *section, void *file,
        }
 
       /* Then allocate an array to hold the information.  */
-      debug_information = cmalloc (num_units,
-                                  sizeof (* debug_information));
+      debug_information = (debug_info *) cmalloc (num_units,
+                                                  sizeof (* debug_information));
       if (debug_information == NULL)
        {
          error (_("Not enough memory for a debug info array of %u entries"),
@@ -1558,16 +1881,16 @@ process_debug_info (struct dwarf_section *section, void *file,
 
   if (!do_loc)
     {
-      printf (_("The section %s contains:\n\n"), section->name);
+      printf (_("Contents of the %s section:\n\n"), section->name);
 
       load_debug_section (str, file);
     }
 
-  load_debug_section (abbrev, file);
-  if (debug_displays [abbrev].section.start == NULL)
+  load_debug_section (abbrev_sec, file);
+  if (debug_displays [abbrev_sec].section.start == NULL)
     {
       warn (_("Unable to locate %s section!\n"),
-           debug_displays [abbrev].section.name);
+           debug_displays [abbrev_sec].section.name);
       return 0;
     }
 
@@ -1575,12 +1898,13 @@ process_debug_info (struct dwarf_section *section, void *file,
     {
       DWARF2_Internal_CompUnit compunit;
       unsigned char *hdrptr;
-      unsigned char *cu_abbrev_offset_ptr;
       unsigned char *tags;
       int level;
       unsigned long cu_offset;
       int offset_size;
       int initial_length_size;
+      unsigned char signature[8] = { 0 };
+      unsigned long type_offset = 0;
 
       hdrptr = start;
 
@@ -1604,20 +1928,36 @@ process_debug_info (struct dwarf_section *section, void *file,
       hdrptr += 2;
 
       cu_offset = start - section_begin;
-      start += compunit.cu_length + initial_length_size;
 
-      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;
+
+      if (do_types)
+        {
+          int i;
+
+          for (i = 0; i < 8; i++)
+            {
+              signature[i] = byte_get (hdrptr, 1);
+              hdrptr += 1;
+            }
+
+          type_offset = byte_get (hdrptr, offset_size);
+          hdrptr += offset_size;
+        }
+
       if ((do_loc || do_debug_loc || do_debug_ranges)
-         && num_debug_info_entries == 0)
+         && num_debug_info_entries == 0
+         && ! do_types)
        {
          debug_information [unit].cu_offset = cu_offset;
          debug_information [unit].pointer_size
            = compunit.cu_pointer_size;
+         debug_information [unit].offset_size = offset_size;
+         debug_information [unit].dwarf_version = compunit.cu_version;
          debug_information [unit].base_address = 0;
          debug_information [unit].loc_offsets = NULL;
          debug_information [unit].have_frame_base = NULL;
@@ -1628,20 +1968,41 @@ process_debug_info (struct dwarf_section *section, void *file,
          debug_information [unit].num_range_lists = 0;
        }
 
-      tags = hdrptr;
-
       if (!do_loc)
        {
          printf (_("  Compilation Unit @ offset 0x%lx:\n"), cu_offset);
-         printf (_("   Length:        %ld\n"), compunit.cu_length);
+         printf (_("   Length:        0x%lx (%s)\n"), compunit.cu_length,
+                 initial_length_size == 8 ? "64-bit" : "32-bit");
          printf (_("   Version:       %d\n"), compunit.cu_version);
          printf (_("   Abbrev Offset: %ld\n"), compunit.cu_abbrev_offset);
          printf (_("   Pointer Size:  %d\n"), compunit.cu_pointer_size);
+         if (do_types)
+           {
+             int i;
+             printf (_("   Signature:     "));
+             for (i = 0; i < 8; i++)
+               printf ("%02x", signature[i]);
+             printf ("\n");
+             printf (_("   Type Offset:   0x%lx\n"), type_offset);
+           }
+       }
+
+      if (cu_offset + compunit.cu_length + initial_length_size
+         > section->size)
+       {
+         warn (_("Debug info is corrupted, length of CU at %lx extends beyond end of section (length = %lx)\n"),
+               cu_offset, compunit.cu_length);
+         break;
        }
+      tags = hdrptr;
+      start += compunit.cu_length + initial_length_size;
 
-      if (compunit.cu_version != 2 && compunit.cu_version != 3)
+      if (compunit.cu_version != 2
+         && compunit.cu_version != 3
+         && compunit.cu_version != 4)
        {
-         warn (_("Only version 2 and 3 DWARF debug information is currently supported.\n"));
+         warn (_("CU at offset %lx contains corrupt or unsupported version number: %d.\n"),
+               cu_offset, compunit.cu_version);
          continue;
        }
 
@@ -1649,30 +2010,68 @@ process_debug_info (struct dwarf_section *section, void *file,
 
       /* Process the abbrevs used by this compilation unit. DWARF
         sections under Mach-O have non-zero addresses.  */
-      process_abbrev_section
-       ((unsigned char *) debug_displays [abbrev].section.start
-        + compunit.cu_abbrev_offset - debug_displays [abbrev].section.address,
-        (unsigned char *) debug_displays [abbrev].section.start
-        + debug_displays [abbrev].section.size);
+      if (compunit.cu_abbrev_offset >= debug_displays [abbrev_sec].section.size)
+       warn (_("Debug info is corrupted, abbrev offset (%lx) is larger than abbrev section size (%lx)\n"),
+             (unsigned long) compunit.cu_abbrev_offset,
+             (unsigned long) debug_displays [abbrev_sec].section.size);
+      else
+       process_abbrev_section
+         ((unsigned char *) debug_displays [abbrev_sec].section.start
+          + compunit.cu_abbrev_offset,
+          (unsigned char *) debug_displays [abbrev_sec].section.start
+          + debug_displays [abbrev_sec].section.size);
 
       level = 0;
       while (tags < start)
        {
          unsigned int bytes_read;
          unsigned long abbrev_number;
+         unsigned long die_offset;
          abbrev_entry *entry;
          abbrev_attr *attr;
 
+         die_offset = tags - section_begin;
+
          abbrev_number = read_leb128 (tags, & bytes_read, 0);
          tags += bytes_read;
 
-         /* A null DIE marks the end of a list of children.  */
+         /* A null DIE marks the end of a list of siblings or it may also be
+            a section padding.  */
          if (abbrev_number == 0)
            {
+             /* Check if it can be a section padding for the last CU.  */
+             if (level == 0 && start == end)
+               {
+                 unsigned char *chk;
+
+                 for (chk = tags; chk < start; chk++)
+                   if (*chk != 0)
+                     break;
+                 if (chk == start)
+                   break;
+               }
+
              --level;
+             if (level < 0)
+               {
+                 static unsigned num_bogus_warns = 0;
+
+                 if (num_bogus_warns < 3)
+                   {
+                     warn (_("Bogus end-of-siblings marker detected at offset %lx in .debug_info section\n"),
+                           die_offset);
+                     num_bogus_warns ++;
+                     if (num_bogus_warns == 3)
+                       warn (_("Further warnings about bogus end-of-sibling markers suppressed\n"));
+                   }
+               }
              continue;
            }
 
+         if (!do_loc)
+           printf (_(" <%d><%lx>: Abbrev Number: %lu"),
+                   level, die_offset, abbrev_number);
+
          /* Scan through the abbreviation list until we reach the
             correct entry.  */
          for (entry = first_abbrev;
@@ -1682,19 +2081,19 @@ process_debug_info (struct dwarf_section *section, void *file,
 
          if (entry == NULL)
            {
-             warn (_("Unable to locate entry %lu in the abbreviation table\n"),
-                   abbrev_number);
+             if (!do_loc)
+               {
+                 printf ("\n");
+                 fflush (stdout);
+               }
+             warn (_("DIE at offset %lx refers to abbreviation number %lu which does not exist\n"),
+                   die_offset, abbrev_number);
              return 0;
            }
 
          if (!do_loc)
-           printf (_(" <%d><%lx>: Abbrev Number: %lu (%s)\n"),
-                   level,
-                   (unsigned long) (tags - section_begin
-                                    - bytes_read),
-                   abbrev_number,
-                   get_TAG_name (entry->tag));
+           printf (" (%s)\n", get_TAG_name (entry->tag));
+
          switch (entry->tag)
            {
            default:
@@ -1704,7 +2103,6 @@ process_debug_info (struct dwarf_section *section, void *file,
              need_base_address = 1;
              break;
            case DW_TAG_entry_point:
-           case DW_TAG_inlined_subroutine:
            case DW_TAG_subprogram:
              need_base_address = 0;
              /* Assuming that there is no DW_AT_frame_base.  */
@@ -1713,31 +2111,38 @@ process_debug_info (struct dwarf_section *section, void *file,
            }
 
          for (attr = entry->first_attr; attr; attr = attr->next)
-           tags = read_and_display_attr (attr->attribute,
-                                         attr->form,
-                                         tags, cu_offset,
-                                         compunit.cu_pointer_size,
-                                         offset_size,
-                                         compunit.cu_version,
-                                         &debug_information [unit],
-                                         do_loc);
+           {
+             if (! do_loc)
+               /* Show the offset from where the tag was extracted.  */
+               printf ("    <%2lx>", (unsigned long)(tags - section_begin));
+
+             tags = read_and_display_attr (attr->attribute,
+                                           attr->form,
+                                           tags, cu_offset,
+                                           compunit.cu_pointer_size,
+                                           offset_size,
+                                           compunit.cu_version,
+                                           debug_information + unit,
+                                           do_loc, section);
+           }
+
          if (entry->children)
            ++level;
        }
     }
+
   /* Set num_debug_info_entries here so that it can be used to check if
      we need to process .debug_loc and .debug_ranges sections.  */
   if ((do_loc || do_debug_loc || do_debug_ranges)
-      && num_debug_info_entries == 0)
+      && num_debug_info_entries == 0
+      && ! do_types)
     num_debug_info_entries = num_units;
-      
+
   if (!do_loc)
     {
       printf ("\n");
     }
+
   return 1;
 }
 
@@ -1755,49 +2160,55 @@ load_debug_info (void * file)
   last_pointer_size = 0;
   warned_about_missing_comp_units = FALSE;
 
+  /* If we have already tried and failed to load the .debug_info
+     section then do not bother to repear the task.  */
+  if (num_debug_info_entries == DEBUG_INFO_UNAVAILABLE)
+    return 0;
+
   /* If we already have the information there is nothing else to do.  */
   if (num_debug_info_entries > 0)
     return num_debug_info_entries;
 
   if (load_debug_section (info, file)
-      && process_debug_info (&debug_displays [info].section, file, 1))
+      && process_debug_info (&debug_displays [info].section, file, abbrev, 1, 0))
     return num_debug_info_entries;
-  else
-    return 0;
+
+  num_debug_info_entries = DEBUG_INFO_UNAVAILABLE;
+  return 0;
 }
 
 static int
-display_debug_lines (struct dwarf_section *section, void *file)
+display_debug_lines_raw (struct dwarf_section *section,
+                        unsigned char *data,
+                         unsigned char *end)
 {
   unsigned char *start = section->start;
-  unsigned char *data = start;
-  unsigned char *end = start + section->size;
 
-  printf (_("\nDump of debug contents of section %s:\n\n"),
-         section->name);
-
-  load_debug_info (file);
+  printf (_("Raw dump of debug contents of section %s:\n\n"),
+          section->name);
 
   while (data < end)
     {
-      DWARF2_Internal_LineInfo info;
+      DWARF2_Internal_LineInfo linfo;
       unsigned char *standard_opcodes;
       unsigned char *end_of_sequence;
       unsigned char *hdrptr;
+      unsigned long hdroff;
       int initial_length_size;
       int offset_size;
       int i;
 
       hdrptr = data;
+      hdroff = hdrptr - start;
 
       /* Check the length of the block.  */
-      info.li_length = byte_get (hdrptr, 4);
+      linfo.li_length = byte_get (hdrptr, 4);
       hdrptr += 4;
 
-      if (info.li_length == 0xffffffff)
+      if (linfo.li_length == 0xffffffff)
        {
          /* This section is 64-bit DWARF 3.  */
-         info.li_length = byte_get (hdrptr, 8);
+         linfo.li_length = byte_get (hdrptr, 8);
          hdrptr += 8;
          offset_size = 8;
          initial_length_size = 12;
@@ -1808,62 +2219,80 @@ display_debug_lines (struct dwarf_section *section, void *file)
          initial_length_size = 4;
        }
 
-      if (info.li_length + initial_length_size > section->size)
+      if (linfo.li_length + initial_length_size > section->size)
        {
          warn
-           (_("The line info appears to be corrupt - the section is too small\n"));
+           (_("The information in section %s appears to be corrupt - the section is too small\n"),
+            section->name);
          return 0;
        }
 
       /* Check its version number.  */
-      info.li_version = byte_get (hdrptr, 2);
+      linfo.li_version = byte_get (hdrptr, 2);
       hdrptr += 2;
-      if (info.li_version != 2 && info.li_version != 3)
+      if (linfo.li_version != 2
+         && linfo.li_version != 3
+         && linfo.li_version != 4)
        {
-         warn (_("Only DWARF version 2 and 3 line info is currently supported.\n"));
+         warn (_("Only DWARF version 2, 3 and 4 line info is currently supported.\n"));
          return 0;
        }
 
-      info.li_prologue_length = byte_get (hdrptr, offset_size);
+      linfo.li_prologue_length = byte_get (hdrptr, offset_size);
       hdrptr += offset_size;
-      info.li_min_insn_length = byte_get (hdrptr, 1);
+      linfo.li_min_insn_length = byte_get (hdrptr, 1);
       hdrptr++;
-      info.li_default_is_stmt = byte_get (hdrptr, 1);
+      if (linfo.li_version >= 4)
+       {
+         linfo.li_max_ops_per_insn = byte_get (hdrptr, 1);
+         hdrptr++;
+         if (linfo.li_max_ops_per_insn == 0)
+           {
+             warn (_("Invalid maximum operations per insn.\n"));
+             return 0;
+           }
+       }
+      else
+       linfo.li_max_ops_per_insn = 1;
+      linfo.li_default_is_stmt = byte_get (hdrptr, 1);
       hdrptr++;
-      info.li_line_base = byte_get (hdrptr, 1);
+      linfo.li_line_base = byte_get (hdrptr, 1);
       hdrptr++;
-      info.li_line_range = byte_get (hdrptr, 1);
+      linfo.li_line_range = byte_get (hdrptr, 1);
       hdrptr++;
-      info.li_opcode_base = byte_get (hdrptr, 1);
+      linfo.li_opcode_base = byte_get (hdrptr, 1);
       hdrptr++;
 
       /* Sign extend the line base field.  */
-      info.li_line_base <<= 24;
-      info.li_line_base >>= 24;
+      linfo.li_line_base <<= 24;
+      linfo.li_line_base >>= 24;
 
-      printf (_("  Length:                      %ld\n"), info.li_length);
-      printf (_("  DWARF Version:               %d\n"), info.li_version);
-      printf (_("  Prologue Length:             %d\n"), info.li_prologue_length);
-      printf (_("  Minimum Instruction Length:  %d\n"), info.li_min_insn_length);
-      printf (_("  Initial value of 'is_stmt':  %d\n"), info.li_default_is_stmt);
-      printf (_("  Line Base:                   %d\n"), info.li_line_base);
-      printf (_("  Line Range:                  %d\n"), info.li_line_range);
-      printf (_("  Opcode Base:                 %d\n"), info.li_opcode_base);
+      printf (_("  Offset:                      0x%lx\n"), hdroff);
+      printf (_("  Length:                      %ld\n"), linfo.li_length);
+      printf (_("  DWARF Version:               %d\n"), linfo.li_version);
+      printf (_("  Prologue Length:             %d\n"), linfo.li_prologue_length);
+      printf (_("  Minimum Instruction Length:  %d\n"), linfo.li_min_insn_length);
+      if (linfo.li_version >= 4)
+       printf (_("  Maximum Ops per Instruction: %d\n"), linfo.li_max_ops_per_insn);
+      printf (_("  Initial value of 'is_stmt':  %d\n"), linfo.li_default_is_stmt);
+      printf (_("  Line Base:                   %d\n"), linfo.li_line_base);
+      printf (_("  Line Range:                  %d\n"), linfo.li_line_range);
+      printf (_("  Opcode Base:                 %d\n"), linfo.li_opcode_base);
 
-      end_of_sequence = data + info.li_length + initial_length_size;
+      end_of_sequence = data + linfo.li_length + initial_length_size;
 
-      reset_state_machine (info.li_default_is_stmt);
+      reset_state_machine (linfo.li_default_is_stmt);
 
       /* Display the contents of the Opcodes table.  */
       standard_opcodes = hdrptr;
 
       printf (_("\n Opcodes:\n"));
 
-      for (i = 1; i < info.li_opcode_base; i++)
+      for (i = 1; i < linfo.li_opcode_base; i++)
        printf (_("  Opcode %d has %d args\n"), i, standard_opcodes[i - 1]);
 
       /* Display the contents of the Directory table.  */
-      data = standard_opcodes + info.li_opcode_base - 1;
+      data = standard_opcodes + linfo.li_opcode_base - 1;
 
       if (*data == 0)
        printf (_("\n The Directory Table is empty.\n"));
@@ -1873,7 +2302,7 @@ display_debug_lines (struct dwarf_section *section, void *file)
 
          while (*data != 0)
            {
-             printf (_("  %s\n"), data);
+             printf ("  %s\n", data);
 
              data += strlen ((char *) data) + 1;
            }
@@ -1895,18 +2324,18 @@ display_debug_lines (struct dwarf_section *section, void *file)
              unsigned char *name;
              unsigned int bytes_read;
 
-             printf (_("  %d\t"), ++state_machine_regs.last_file_entry);
+             printf ("  %d\t", ++state_machine_regs.last_file_entry);
              name = data;
 
              data += strlen ((char *) data) + 1;
 
-             printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0));
+             printf ("%lu\t", read_leb128 (data, & bytes_read, 0));
              data += bytes_read;
-             printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0));
+             printf ("%lu\t", read_leb128 (data, & bytes_read, 0));
              data += bytes_read;
-             printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0));
+             printf ("%lu\t", read_leb128 (data, & bytes_read, 0));
              data += bytes_read;
-             printf (_("%s\n"), name);
+             printf ("%s\n", name);
            }
        }
 
@@ -1925,14 +2354,31 @@ display_debug_lines (struct dwarf_section *section, void *file)
 
          op_code = *data++;
 
-         if (op_code >= info.li_opcode_base)
+         if (op_code >= linfo.li_opcode_base)
            {
-             op_code -= info.li_opcode_base;
-             uladv = (op_code / info.li_line_range) * info.li_min_insn_length;
-             state_machine_regs.address += uladv;
-             printf (_("  Special opcode %d: advance Address by %lu to 0x%lx"),
-                     op_code, uladv, state_machine_regs.address);
-             adv = (op_code % info.li_line_range) + info.li_line_base;
+             op_code -= linfo.li_opcode_base;
+             uladv = (op_code / linfo.li_line_range);
+             if (linfo.li_max_ops_per_insn == 1)
+               {
+                 uladv *= linfo.li_min_insn_length;
+                 state_machine_regs.address += uladv;
+                 printf (_("  Special opcode %d: advance Address by %lu to 0x%lx"),
+                         op_code, uladv, state_machine_regs.address);
+               }
+             else
+               {
+                 state_machine_regs.address
+                   += ((state_machine_regs.op_index + uladv)
+                       / linfo.li_max_ops_per_insn)
+                      * linfo.li_min_insn_length;
+                 state_machine_regs.op_index
+                   = (state_machine_regs.op_index + uladv)
+                     % linfo.li_max_ops_per_insn;
+                 printf (_("  Special opcode %d: advance Address by %lu to 0x%lx[%d]"),
+                         op_code, uladv, state_machine_regs.address,
+                         state_machine_regs.op_index);
+               }
+             adv = (op_code % linfo.li_line_range) + linfo.li_line_base;
              state_machine_regs.line += adv;
              printf (_(" and Line by %d to %d\n"),
                      adv, state_machine_regs.line);
@@ -1940,7 +2386,7 @@ display_debug_lines (struct dwarf_section *section, void *file)
          else switch (op_code)
            {
            case DW_LNS_extended_op:
-             data += process_extended_line_op (data, info.li_default_is_stmt);
+             data += process_extended_line_op (data, linfo.li_default_is_stmt);
              break;
 
            case DW_LNS_copy:
@@ -1949,11 +2395,27 @@ display_debug_lines (struct dwarf_section *section, void *file)
 
            case DW_LNS_advance_pc:
              uladv = read_leb128 (data, & bytes_read, 0);
-             uladv *= info.li_min_insn_length;
              data += bytes_read;
-             state_machine_regs.address += uladv;
-             printf (_("  Advance PC by %lu to 0x%lx\n"), uladv,
-                     state_machine_regs.address);
+             if (linfo.li_max_ops_per_insn == 1)
+               {
+                 uladv *= linfo.li_min_insn_length;
+                 state_machine_regs.address += uladv;
+                 printf (_("  Advance PC by %lu to 0x%lx\n"), uladv,
+                         state_machine_regs.address);
+               }
+             else
+               {
+                 state_machine_regs.address
+                   += ((state_machine_regs.op_index + uladv)
+                       / linfo.li_max_ops_per_insn)
+                      * linfo.li_min_insn_length;
+                 state_machine_regs.op_index
+                   = (state_machine_regs.op_index + uladv)
+                     % linfo.li_max_ops_per_insn;
+                 printf (_("  Advance PC by %lu to 0x%lx[%d]\n"), uladv,
+                         state_machine_regs.address,
+                         state_machine_regs.op_index);
+               }
              break;
 
            case DW_LNS_advance_line:
@@ -1992,17 +2454,34 @@ display_debug_lines (struct dwarf_section *section, void *file)
              break;
 
            case DW_LNS_const_add_pc:
-             uladv = (((255 - info.li_opcode_base) / info.li_line_range)
-                     * info.li_min_insn_length);
-             state_machine_regs.address += uladv;
-             printf (_("  Advance PC by constant %lu to 0x%lx\n"), uladv,
-                     state_machine_regs.address);
+             uladv = ((255 - linfo.li_opcode_base) / linfo.li_line_range);
+             if (linfo.li_max_ops_per_insn)
+               {
+                 uladv *= linfo.li_min_insn_length;
+                 state_machine_regs.address += uladv;
+                 printf (_("  Advance PC by constant %lu to 0x%lx\n"), uladv,
+                         state_machine_regs.address);
+               }
+             else
+               {
+                 state_machine_regs.address
+                   += ((state_machine_regs.op_index + uladv)
+                       / linfo.li_max_ops_per_insn)
+                      * linfo.li_min_insn_length;
+                 state_machine_regs.op_index
+                   = (state_machine_regs.op_index + uladv)
+                     % linfo.li_max_ops_per_insn;
+                 printf (_("  Advance PC by constant %lu to 0x%lx[%d]\n"),
+                         uladv, state_machine_regs.address,
+                         state_machine_regs.op_index);
+               }
              break;
 
            case DW_LNS_fixed_advance_pc:
              uladv = byte_get (data, 2);
              data += 2;
              state_machine_regs.address += uladv;
+             state_machine_regs.op_index = 0;
              printf (_("  Advance PC by fixed size amount %lu to 0x%lx\n"),
                      uladv, state_machine_regs.address);
              break;
@@ -2040,69 +2519,591 @@ display_debug_lines (struct dwarf_section *section, void *file)
   return 1;
 }
 
-static int
-display_debug_pubnames (struct dwarf_section *section,
-                       void *file ATTRIBUTE_UNUSED)
+typedef struct
 {
-  DWARF2_Internal_PubNames pubnames;
-  unsigned char *start = section->start;
-  unsigned char *end = start + section->size;
+    unsigned char *name;
+    unsigned int directory_index;
+    unsigned int modification_date;
+    unsigned int length;
+} File_Entry;
 
-  printf (_("Contents of the %s section:\n\n"), section->name);
+/* Output a decoded representation of the .debug_line section.  */
 
-  while (start < end)
-    {
-      unsigned char *data;
-      unsigned long offset;
-      int offset_size, initial_length_size;
+static int
+display_debug_lines_decoded (struct dwarf_section *section,
+                            unsigned char *data,
+                            unsigned char *end)
+{
+  printf (_("Decoded dump of debug contents of section %s:\n\n"),
+          section->name);
 
-      data = start;
+  while (data < end)
+    {
+      /* This loop amounts to one iteration per compilation unit.  */
+      DWARF2_Internal_LineInfo linfo;
+      unsigned char *standard_opcodes;
+      unsigned char *end_of_sequence;
+      unsigned char *hdrptr;
+      int initial_length_size;
+      int offset_size;
+      int i;
+      File_Entry *file_table = NULL;
+      unsigned char **directory_table = NULL;
 
-      pubnames.pn_length = byte_get (data, 4);
-      data += 4;
-      if (pubnames.pn_length == 0xffffffff)
-       {
-         pubnames.pn_length = byte_get (data, 8);
-         data += 8;
-         offset_size = 8;
-         initial_length_size = 12;
-       }
-      else
-       {
-         offset_size = 4;
-         initial_length_size = 4;
-       }
+      hdrptr = data;
 
-      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;
+      /* Extract information from the Line Number Program Header.
+        (section 6.2.4 in the Dwarf3 doc).  */
 
-      start += pubnames.pn_length + initial_length_size;
+      /* Get the length of this CU's line number information block.  */
+      linfo.li_length = byte_get (hdrptr, 4);
+      hdrptr += 4;
 
-      if (pubnames.pn_version != 2 && pubnames.pn_version != 3)
+      if (linfo.li_length == 0xffffffff)
+        {
+          /* This section is 64-bit DWARF 3.  */
+          linfo.li_length = byte_get (hdrptr, 8);
+          hdrptr += 8;
+          offset_size = 8;
+          initial_length_size = 12;
+        }
+      else
+        {
+          offset_size = 4;
+          initial_length_size = 4;
+        }
+
+      if (linfo.li_length + initial_length_size > section->size)
+        {
+          warn (_("The line info appears to be corrupt - "
+                  "the section is too small\n"));
+          return 0;
+        }
+
+      /* Get this CU's Line Number Block version number.  */
+      linfo.li_version = byte_get (hdrptr, 2);
+      hdrptr += 2;
+      if (linfo.li_version != 2
+         && linfo.li_version != 3
+         && linfo.li_version != 4)
+        {
+          warn (_("Only DWARF version 2, 3 and 4 line info is currently "
+                "supported.\n"));
+          return 0;
+        }
+
+      linfo.li_prologue_length = byte_get (hdrptr, offset_size);
+      hdrptr += offset_size;
+      linfo.li_min_insn_length = byte_get (hdrptr, 1);
+      hdrptr++;
+      if (linfo.li_version >= 4)
        {
-         static int warned = 0;
-
-         if (! warned)
+         linfo.li_max_ops_per_insn = byte_get (hdrptr, 1);
+         hdrptr++;
+         if (linfo.li_max_ops_per_insn == 0)
            {
-             warn (_("Only DWARF 2 and 3 pubnames are currently supported\n"));
-             warned = 1;
+             warn (_("Invalid maximum operations per insn.\n"));
+             return 0;
+           }
+       }
+      else
+       linfo.li_max_ops_per_insn = 1;
+      linfo.li_default_is_stmt = byte_get (hdrptr, 1);
+      hdrptr++;
+      linfo.li_line_base = byte_get (hdrptr, 1);
+      hdrptr++;
+      linfo.li_line_range = byte_get (hdrptr, 1);
+      hdrptr++;
+      linfo.li_opcode_base = byte_get (hdrptr, 1);
+      hdrptr++;
+
+      /* Sign extend the line base field.  */
+      linfo.li_line_base <<= 24;
+      linfo.li_line_base >>= 24;
+
+      /* Find the end of this CU's Line Number Information Block.  */
+      end_of_sequence = data + linfo.li_length + initial_length_size;
+
+      reset_state_machine (linfo.li_default_is_stmt);
+
+      /* Save a pointer to the contents of the Opcodes table.  */
+      standard_opcodes = hdrptr;
+
+      /* Traverse the Directory table just to count entries.  */
+      data = standard_opcodes + linfo.li_opcode_base - 1;
+      if (*data != 0)
+        {
+          unsigned int n_directories = 0;
+          unsigned char *ptr_directory_table = data;
+
+         while (*data != 0)
+           {
+             data += strlen ((char *) data) + 1;
+             n_directories++;
+           }
+
+          /* Go through the directory table again to save the directories.  */
+          directory_table = (unsigned char **)
+              xmalloc (n_directories * sizeof (unsigned char *));
+
+          i = 0;
+          while (*ptr_directory_table != 0)
+            {
+              directory_table[i] = ptr_directory_table;
+              ptr_directory_table += strlen ((char *) ptr_directory_table) + 1;
+              i++;
+            }
+        }
+      /* Skip the NUL at the end of the table.  */
+      data++;
+
+      /* Traverse the File Name table just to count the entries.  */
+      if (*data != 0)
+        {
+          unsigned int n_files = 0;
+          unsigned char *ptr_file_name_table = data;
+
+          while (*data != 0)
+            {
+             unsigned int bytes_read;
+
+              /* Skip Name, directory index, last modification time and length
+                 of file.  */
+              data += strlen ((char *) data) + 1;
+              read_leb128 (data, & bytes_read, 0);
+              data += bytes_read;
+              read_leb128 (data, & bytes_read, 0);
+              data += bytes_read;
+              read_leb128 (data, & bytes_read, 0);
+              data += bytes_read;
+
+              n_files++;
+            }
+
+          /* Go through the file table again to save the strings.  */
+          file_table = (File_Entry *) xmalloc (n_files * sizeof (File_Entry));
+
+          i = 0;
+          while (*ptr_file_name_table != 0)
+            {
+              unsigned int bytes_read;
+
+              file_table[i].name = ptr_file_name_table;
+              ptr_file_name_table += strlen ((char *) ptr_file_name_table) + 1;
+
+              /* We are not interested in directory, time or size.  */
+              file_table[i].directory_index = read_leb128 (ptr_file_name_table,
+                                                           & bytes_read, 0);
+              ptr_file_name_table += bytes_read;
+              file_table[i].modification_date = read_leb128 (ptr_file_name_table,
+                                                            & bytes_read, 0);
+              ptr_file_name_table += bytes_read;
+              file_table[i].length = read_leb128 (ptr_file_name_table, & bytes_read, 0);
+              ptr_file_name_table += bytes_read;
+              i++;
+            }
+          i = 0;
+
+          /* Print the Compilation Unit's name and a header.  */
+          if (directory_table == NULL)
+            {
+              printf (_("CU: %s:\n"), file_table[0].name);
+              printf (_("File name                            Line number    Starting address\n"));
+            }
+          else
+            {
+              if (do_wide || strlen ((char *) directory_table[0]) < 76)
+               printf (_("CU: %s/%s:\n"), directory_table[0],
+                       file_table[0].name);
+              else
+               printf ("%s:\n", file_table[0].name);
+
+              printf (_("File name                            Line number    Starting address\n"));
+            }
+        }
+
+      /* Skip the NUL at the end of the table.  */
+      data++;
+
+      /* This loop iterates through the Dwarf Line Number Program.  */
+      while (data < end_of_sequence)
+        {
+         unsigned char op_code;
+          int adv;
+          unsigned long int uladv;
+          unsigned int bytes_read;
+          int is_special_opcode = 0;
+
+          op_code = *data++;
+
+          if (op_code >= linfo.li_opcode_base)
+           {
+             op_code -= linfo.li_opcode_base;
+             uladv = (op_code / linfo.li_line_range);
+             if (linfo.li_max_ops_per_insn == 1)
+               {
+                 uladv *= linfo.li_min_insn_length;
+                 state_machine_regs.address += uladv;
+               }
+             else
+               {
+                 state_machine_regs.address
+                   += ((state_machine_regs.op_index + uladv)
+                       / linfo.li_max_ops_per_insn)
+                      * linfo.li_min_insn_length;
+                 state_machine_regs.op_index
+                   = (state_machine_regs.op_index + uladv)
+                     % linfo.li_max_ops_per_insn;
+               }
+
+              adv = (op_code % linfo.li_line_range) + linfo.li_line_base;
+              state_machine_regs.line += adv;
+              is_special_opcode = 1;
+            }
+          else switch (op_code)
+            {
+            case DW_LNS_extended_op:
+              {
+                unsigned int ext_op_code_len;
+                unsigned char ext_op_code;
+                unsigned char *op_code_data = data;
+
+                ext_op_code_len = read_leb128 (op_code_data, &bytes_read, 0);
+                op_code_data += bytes_read;
+
+                if (ext_op_code_len == 0)
+                  {
+                    warn (_("badly formed extended line op encountered!\n"));
+                    break;
+                  }
+                ext_op_code_len += bytes_read;
+                ext_op_code = *op_code_data++;
+
+                switch (ext_op_code)
+                  {
+                  case DW_LNE_end_sequence:
+                    reset_state_machine (linfo.li_default_is_stmt);
+                    break;
+                  case DW_LNE_set_address:
+                    state_machine_regs.address =
+                    byte_get (op_code_data, ext_op_code_len - bytes_read - 1);
+                   state_machine_regs.op_index = 0;
+                    break;
+                  case DW_LNE_define_file:
+                    {
+                      unsigned int dir_index = 0;
+
+                      ++state_machine_regs.last_file_entry;
+                      op_code_data += strlen ((char *) op_code_data) + 1;
+                      dir_index = read_leb128 (op_code_data, & bytes_read, 0);
+                      op_code_data += bytes_read;
+                      read_leb128 (op_code_data, & bytes_read, 0);
+                      op_code_data += bytes_read;
+                      read_leb128 (op_code_data, & bytes_read, 0);
+
+                      printf ("%s:\n", directory_table[dir_index]);
+                      break;
+                    }
+                  default:
+                    printf (_("UNKNOWN: length %d\n"), ext_op_code_len - bytes_read);
+                    break;
+                  }
+                data += ext_op_code_len;
+                break;
+              }
+            case DW_LNS_copy:
+              break;
+
+            case DW_LNS_advance_pc:
+              uladv = read_leb128 (data, & bytes_read, 0);
+              data += bytes_read;
+             if (linfo.li_max_ops_per_insn == 1)
+               {
+                 uladv *= linfo.li_min_insn_length;
+                 state_machine_regs.address += uladv;
+               }
+             else
+               {
+                 state_machine_regs.address
+                   += ((state_machine_regs.op_index + uladv)
+                       / linfo.li_max_ops_per_insn)
+                      * linfo.li_min_insn_length;
+                 state_machine_regs.op_index
+                   = (state_machine_regs.op_index + uladv)
+                     % linfo.li_max_ops_per_insn;
+               }
+              break;
+
+            case DW_LNS_advance_line:
+              adv = read_leb128 (data, & bytes_read, 1);
+              data += bytes_read;
+              state_machine_regs.line += adv;
+              break;
+
+            case DW_LNS_set_file:
+              adv = read_leb128 (data, & bytes_read, 0);
+              data += bytes_read;
+              state_machine_regs.file = adv;
+              if (file_table[state_machine_regs.file - 1].directory_index == 0)
+                {
+                  /* If directory index is 0, that means current directory.  */
+                  printf ("\n./%s:[++]\n",
+                          file_table[state_machine_regs.file - 1].name);
+                }
+              else
+                {
+                  /* The directory index starts counting at 1.  */
+                  printf ("\n%s/%s:\n",
+                          directory_table[file_table[state_machine_regs.file - 1].directory_index - 1],
+                          file_table[state_machine_regs.file - 1].name);
+                }
+              break;
+
+            case DW_LNS_set_column:
+              uladv = read_leb128 (data, & bytes_read, 0);
+              data += bytes_read;
+              state_machine_regs.column = uladv;
+              break;
+
+            case DW_LNS_negate_stmt:
+              adv = state_machine_regs.is_stmt;
+              adv = ! adv;
+              state_machine_regs.is_stmt = adv;
+              break;
+
+            case DW_LNS_set_basic_block:
+              state_machine_regs.basic_block = 1;
+              break;
+
+            case DW_LNS_const_add_pc:
+             uladv = ((255 - linfo.li_opcode_base) / linfo.li_line_range);
+             if (linfo.li_max_ops_per_insn == 1)
+               {
+                 uladv *= linfo.li_min_insn_length;
+                 state_machine_regs.address += uladv;
+               }
+             else
+               {
+                 state_machine_regs.address
+                   += ((state_machine_regs.op_index + uladv)
+                       / linfo.li_max_ops_per_insn)
+                      * linfo.li_min_insn_length;
+                 state_machine_regs.op_index
+                   = (state_machine_regs.op_index + uladv)
+                     % linfo.li_max_ops_per_insn;
+               }
+              break;
+
+            case DW_LNS_fixed_advance_pc:
+              uladv = byte_get (data, 2);
+              data += 2;
+              state_machine_regs.address += uladv;
+             state_machine_regs.op_index = 0;
+              break;
+
+            case DW_LNS_set_prologue_end:
+              break;
+
+            case DW_LNS_set_epilogue_begin:
+              break;
+
+            case DW_LNS_set_isa:
+              uladv = read_leb128 (data, & bytes_read, 0);
+              data += bytes_read;
+              printf (_("  Set ISA to %lu\n"), uladv);
+              break;
+
+            default:
+              printf (_("  Unknown opcode %d with operands: "), op_code);
+
+              for (i = standard_opcodes[op_code - 1]; i > 0 ; --i)
+                {
+                  printf ("0x%lx%s", read_leb128 (data, &bytes_read, 0),
+                          i == 1 ? "" : ", ");
+                  data += bytes_read;
+                }
+              putchar ('\n');
+              break;
+            }
+
+          /* Only Special opcodes, DW_LNS_copy and DW_LNE_end_sequence adds a row
+             to the DWARF address/line matrix.  */
+          if ((is_special_opcode) || (op_code == DW_LNE_end_sequence)
+             || (op_code == DW_LNS_copy))
+            {
+              const unsigned int MAX_FILENAME_LENGTH = 35;
+              char *fileName = (char *)file_table[state_machine_regs.file - 1].name;
+              char *newFileName = NULL;
+              size_t fileNameLength = strlen (fileName);
+
+              if ((fileNameLength > MAX_FILENAME_LENGTH) && (!do_wide))
+                {
+                  newFileName = (char *) xmalloc (MAX_FILENAME_LENGTH + 1);
+                  /* Truncate file name */
+                  strncpy (newFileName,
+                           fileName + fileNameLength - MAX_FILENAME_LENGTH,
+                           MAX_FILENAME_LENGTH + 1);
+                }
+              else
+                {
+                  newFileName = (char *) xmalloc (fileNameLength + 1);
+                  strncpy (newFileName, fileName, fileNameLength + 1);
+                }
+
+              if (!do_wide || (fileNameLength <= MAX_FILENAME_LENGTH))
+                {
+                 if (linfo.li_max_ops_per_insn == 1)
+                   printf ("%-35s  %11d  %#18lx\n", newFileName,
+                           state_machine_regs.line,
+                           state_machine_regs.address);
+                 else
+                   printf ("%-35s  %11d  %#18lx[%d]\n", newFileName,
+                           state_machine_regs.line,
+                           state_machine_regs.address,
+                           state_machine_regs.op_index);
+                }
+              else
+                {
+                 if (linfo.li_max_ops_per_insn == 1)
+                   printf ("%s  %11d  %#18lx\n", newFileName,
+                           state_machine_regs.line,
+                           state_machine_regs.address);
+                 else
+                   printf ("%s  %11d  %#18lx[%d]\n", newFileName,
+                           state_machine_regs.line,
+                           state_machine_regs.address,
+                           state_machine_regs.op_index);
+                }
+
+              if (op_code == DW_LNE_end_sequence)
+               printf ("\n");
+
+              free (newFileName);
+            }
+        }
+      free (file_table);
+      file_table = NULL;
+      free (directory_table);
+      directory_table = NULL;
+      putchar ('\n');
+    }
+
+  return 1;
+}
+
+static int
+display_debug_lines (struct dwarf_section *section, void *file ATTRIBUTE_UNUSED)
+{
+  unsigned char *data = section->start;
+  unsigned char *end = data + section->size;
+  int retValRaw = 1;
+  int retValDecoded = 1;
+
+  if (do_debug_lines == 0)
+    do_debug_lines |= FLAG_DEBUG_LINES_RAW;
+
+  if (do_debug_lines & FLAG_DEBUG_LINES_RAW)
+    retValRaw = display_debug_lines_raw (section, data, end);
+
+  if (do_debug_lines & FLAG_DEBUG_LINES_DECODED)
+    retValDecoded = display_debug_lines_decoded (section, data, end);
+
+  if (!retValRaw || !retValDecoded)
+    return 0;
+
+  return 1;
+}
+
+static debug_info *
+find_debug_info_for_offset (unsigned long offset)
+{
+  unsigned int i;
+
+  if (num_debug_info_entries == DEBUG_INFO_UNAVAILABLE)
+    return NULL;
+
+  for (i = 0; i < num_debug_info_entries; i++)
+    if (debug_information[i].cu_offset == offset)
+      return debug_information + i;
+
+  return NULL;
+}
+
+static int
+display_debug_pubnames (struct dwarf_section *section,
+                       void *file ATTRIBUTE_UNUSED)
+{
+  DWARF2_Internal_PubNames names;
+  unsigned char *start = section->start;
+  unsigned char *end = start + section->size;
+
+  /* It does not matter if this load fails,
+     we test for that later on.  */
+  load_debug_info (file);
+
+  printf (_("Contents of the %s section:\n\n"), section->name);
+
+  while (start < end)
+    {
+      unsigned char *data;
+      unsigned long offset;
+      int offset_size, initial_length_size;
+
+      data = start;
+
+      names.pn_length = byte_get (data, 4);
+      data += 4;
+      if (names.pn_length == 0xffffffff)
+       {
+         names.pn_length = byte_get (data, 8);
+         data += 8;
+         offset_size = 8;
+         initial_length_size = 12;
+       }
+      else
+       {
+         offset_size = 4;
+         initial_length_size = 4;
+       }
+
+      names.pn_version = byte_get (data, 2);
+      data += 2;
+
+      names.pn_offset = byte_get (data, offset_size);
+      data += offset_size;
+
+      if (num_debug_info_entries != DEBUG_INFO_UNAVAILABLE
+         && num_debug_info_entries > 0
+         && find_debug_info_for_offset (names.pn_offset) == NULL)
+       warn (_(".debug_info offset of 0x%lx in %s section does not point to a CU header.\n"),
+             names.pn_offset, section->name);
+
+      names.pn_size = byte_get (data, offset_size);
+      data += offset_size;
+
+      start += names.pn_length + initial_length_size;
+
+      if (names.pn_version != 2 && names.pn_version != 3)
+       {
+         static int warned = 0;
+
+         if (! warned)
+           {
+             warn (_("Only DWARF 2 and 3 pubnames are currently supported\n"));
+             warned = 1;
            }
 
          continue;
        }
 
       printf (_("  Length:                              %ld\n"),
-             pubnames.pn_length);
+             names.pn_length);
       printf (_("  Version:                             %d\n"),
-             pubnames.pn_version);
-      printf (_("  Offset into .debug_info section:     %ld\n"),
-             pubnames.pn_offset);
+             names.pn_version);
+      printf (_("  Offset into .debug_info section:     0x%lx\n"),
+             names.pn_offset);
       printf (_("  Size of area in .debug_info section: %ld\n"),
-             pubnames.pn_size);
+             names.pn_size);
 
       printf (_("\n    Offset\tName\n"));
 
@@ -2113,7 +3114,7 @@ display_debug_pubnames (struct dwarf_section *section,
          if (offset != 0)
            {
              data += offset_size;
-             printf ("    %-6ld\t\t%s\n", offset, data);
+             printf ("    %-6lx\t%s\n", offset, data);
              data += strlen ((char *) data) + 1;
            }
        }
@@ -2141,7 +3142,7 @@ display_debug_macinfo (struct dwarf_section *section,
       unsigned int lineno;
       const char *string;
 
-      op = *curr;
+      op = (enum dwarf_macinfo_record_type) *curr;
       curr++;
 
       switch (op)
@@ -2225,13 +3226,13 @@ display_debug_abbrev (struct dwarf_section *section,
        {
          abbrev_attr *attr;
 
-         printf (_("   %ld      %s    [%s]\n"),
+         printf ("   %ld      %s    [%s]\n",
                  entry->entry,
                  get_TAG_name (entry->tag),
                  entry->children ? _("has children") : _("no children"));
 
          for (attr = entry->first_attr; attr; attr = attr->next)
-           printf (_("    %-18s %s\n"),
+           printf ("    %-18s %s\n",
                    get_AT_name (attr->attribute),
                    get_FORM_name (attr->form));
        }
@@ -2268,7 +3269,12 @@ display_debug_loc (struct dwarf_section *section, void *file)
       return 0;
     }
 
-  load_debug_info (file);
+  if (load_debug_info (file) == 0)
+    {
+      warn (_("Unable to load/parse the .debug_info section, so cannot interpret the %s section.\n"),
+           section->name);
+      return 0;
+    }
 
   /* Check the order of location list in .debug_info section. If
      offsets of location lists are in the ascending order, we can
@@ -2326,11 +3332,13 @@ display_debug_loc (struct dwarf_section *section, void *file)
   seen_first_offset = 0;
   for (i = first; i < num_debug_info_entries; i++)
     {
-      unsigned long begin;
-      unsigned long end;
+      dwarf_vma begin;
+      dwarf_vma end;
       unsigned short length;
       unsigned long offset;
       unsigned int pointer_size;
+      unsigned int offset_size;
+      int dwarf_version;
       unsigned long cu_offset;
       unsigned long base_address;
       int need_frame_base;
@@ -2338,12 +3346,14 @@ display_debug_loc (struct dwarf_section *section, void *file)
 
       pointer_size = debug_information [i].pointer_size;
       cu_offset = debug_information [i].cu_offset;
+      offset_size = debug_information [i].offset_size;
+      dwarf_version = debug_information [i].dwarf_version;
 
       for (j = 0; j < debug_information [i].num_loc_offsets; j++)
        {
          has_frame_base = debug_information [i].have_frame_base [j];
          /* DWARF sections under Mach-O have non-zero addresses.  */
-         offset = debug_information [i].loc_offsets [j] - section->address; 
+         offset = debug_information [i].loc_offsets [j] - section->address;
          next = section_begin + offset;
          base_address = debug_information [i].base_address;
 
@@ -2353,10 +3363,12 @@ display_debug_loc (struct dwarf_section *section, void *file)
            {
              if (start < next)
                warn (_("There is a hole [0x%lx - 0x%lx] in .debug_loc section.\n"),
-                     (long)(start - section_begin), (long)(next - section_begin));
+                     (unsigned long) (start - section_begin),
+                     (unsigned long) (next - section_begin));
              else if (start > next)
                warn (_("There is an overlap [0x%lx - 0x%lx] in .debug_loc section.\n"),
-                     (long)(start - section_begin), (long)(next - section_begin));
+                     (unsigned long) (start - section_begin),
+                     (unsigned long) (next - section_begin));
            }
          start = next;
 
@@ -2376,23 +3388,31 @@ display_debug_loc (struct dwarf_section *section, void *file)
                  break;
                }
 
-             begin = byte_get (start, pointer_size);
+             /* Note: we use sign extension here in order to be sure that
+                we can detect the -1 escape value.  Sign extension into the
+                top 32 bits of a 32-bit address will not affect the values
+                that we display since we always show hex values, and always
+                the bottom 32-bits.  */
+             begin = byte_get_signed (start, pointer_size);
              start += pointer_size;
-             end = byte_get (start, pointer_size);
+             end = byte_get_signed (start, pointer_size);
              start += pointer_size;
 
+             printf ("    %8.8lx ", offset);
+
              if (begin == 0 && end == 0)
                {
-                 printf (_("    %8.8lx <End of list>\n"), offset);
+                 printf (_("<End of list>\n"));
                  break;
                }
 
              /* Check base address specifiers.  */
-             if (begin == -1UL && end != -1UL)
+             if (begin == (dwarf_vma) -1 && end != (dwarf_vma) -1)
                {
                  base_address = end;
-                 printf (_("    %8.8lx %8.8lx %8.8lx (base address)\n"),
-                         offset, begin, end);
+                 print_dwarf_vma (begin, pointer_size);
+                 print_dwarf_vma (end, pointer_size);
+                 printf (_("(base address)\n"));
                  continue;
                }
 
@@ -2413,12 +3433,16 @@ display_debug_loc (struct dwarf_section *section, void *file)
                  break;
                }
 
-             printf ("    %8.8lx %8.8lx %8.8lx (",
-                     offset, begin + base_address, end + base_address);
+             print_dwarf_vma (begin + base_address, pointer_size);
+             print_dwarf_vma (end + base_address, pointer_size);
+
+             putchar ('(');
              need_frame_base = decode_location_expression (start,
                                                            pointer_size,
+                                                           offset_size,
+                                                           dwarf_version,
                                                            length,
-                                                           cu_offset);
+                                                           cu_offset, section);
              putchar (')');
 
              if (need_frame_base && !has_frame_base)
@@ -2435,6 +3459,11 @@ display_debug_loc (struct dwarf_section *section, void *file)
            }
        }
     }
+
+  if (start < section_end)
+    warn (_("There are %ld unused bytes at the end of section %s\n"),
+         (long) (section_end - start), section->name);
+  putchar ('\n');
   return 1;
 }
 
@@ -2496,13 +3525,23 @@ display_debug_str (struct dwarf_section *section,
   return 1;
 }
 
-
 static int
 display_debug_info (struct dwarf_section *section, void *file)
 {
-  return process_debug_info (section, file, 0);
+  return process_debug_info (section, file, abbrev, 0, 0);
+}
+
+static int
+display_debug_types (struct dwarf_section *section, void *file)
+{
+  return process_debug_info (section, file, abbrev, 0, 1);
 }
 
+static int
+display_trace_info (struct dwarf_section *section, void *file)
+{
+  return process_debug_info (section, file, trace_abbrev, 0, 0);
+}
 
 static int
 display_debug_aranges (struct dwarf_section *section,
@@ -2511,15 +3550,19 @@ display_debug_aranges (struct dwarf_section *section,
   unsigned char *start = section->start;
   unsigned char *end = start + section->size;
 
-  printf (_("The section %s contains:\n\n"), section->name);
+  printf (_("Contents of the %s section:\n\n"), section->name);
+
+  /* It does not matter if this load fails,
+     we test for that later on.  */
+  load_debug_info (file);
 
   while (start < end)
     {
       unsigned char *hdrptr;
       DWARF2_Internal_ARange arange;
-      unsigned char *ranges;
-      unsigned long length;
-      unsigned long address;
+      unsigned char *addr_ranges;
+      dwarf_vma length;
+      dwarf_vma address;
       unsigned char address_size;
       int excess;
       int offset_size;
@@ -2549,6 +3592,12 @@ display_debug_aranges (struct dwarf_section *section,
       arange.ar_info_offset = byte_get (hdrptr, offset_size);
       hdrptr += offset_size;
 
+      if (num_debug_info_entries != DEBUG_INFO_UNAVAILABLE
+         && num_debug_info_entries > 0
+         && find_debug_info_for_offset (arange.ar_info_offset) == NULL)
+       warn (_(".debug_info offset of 0x%lx in %s section does not point to a CU header.\n"),
+             arange.ar_info_offset, section->name);
+
       arange.ar_pointer_size = byte_get (hdrptr, 1);
       hdrptr += 1;
 
@@ -2563,7 +3612,7 @@ display_debug_aranges (struct dwarf_section *section,
 
       printf (_("  Length:                   %ld\n"), arange.ar_length);
       printf (_("  Version:                  %d\n"), arange.ar_version);
-      printf (_("  Offset into .debug_info:  %lx\n"), arange.ar_info_offset);
+      printf (_("  Offset into .debug_info:  0x%lx\n"), arange.ar_info_offset);
       printf (_("  Pointer Size:             %d\n"), arange.ar_pointer_size);
       printf (_("  Segment Size:             %d\n"), arange.ar_segment_size);
 
@@ -2577,35 +3626,35 @@ display_debug_aranges (struct dwarf_section *section,
          warn (_("Pointer size + Segment size is not a power of two.\n"));
          break;
        }
-      
+
       if (address_size > 4)
        printf (_("\n    Address            Length\n"));
       else
        printf (_("\n    Address    Length\n"));
 
-      ranges = hdrptr;
+      addr_ranges = hdrptr;
 
       /* Must pad to an alignment boundary that is twice the address size.  */
       excess = (hdrptr - start) % (2 * address_size);
       if (excess)
-       ranges += (2 * address_size) - excess;
+       addr_ranges += (2 * address_size) - excess;
 
       start += arange.ar_length + initial_length_size;
 
-      while (ranges + 2 * address_size <= start)
+      while (addr_ranges + 2 * address_size <= start)
        {
-         address = byte_get (ranges, address_size);
+         address = byte_get (addr_ranges, address_size);
 
-         ranges += address_size;
+         addr_ranges += address_size;
 
-         length  = byte_get (ranges, address_size);
+         length  = byte_get (addr_ranges, address_size);
 
-         ranges += address_size;
+         addr_ranges += address_size;
 
-         if (address_size > 4)
-           printf ("    0x%16.16lx 0x%lx\n", address, length);
-         else
-           printf ("    0x%8.8lx 0x%lx\n", address, length);       
+         printf ("    ");
+         print_dwarf_vma (address, address_size);
+         print_dwarf_vma (length, address_size);
+         putchar ('\n');
        }
     }
 
@@ -2614,25 +3663,42 @@ display_debug_aranges (struct dwarf_section *section,
   return 1;
 }
 
+/* Each debug_information[x].range_lists[y] gets this representation for
+   sorting purposes.  */
+
+struct range_entry
+  {
+    /* The debug_information[x].range_lists[y] value.  */
+    unsigned long ranges_offset;
+
+    /* Original debug_information to find parameters of the data.  */
+    debug_info *debug_info_p;
+  };
+
+/* Sort struct range_entry in ascending order of its RANGES_OFFSET.  */
+
+static int
+range_entry_compar (const void *ap, const void *bp)
+{
+  const struct range_entry *a_re = (const struct range_entry *) ap;
+  const struct range_entry *b_re = (const struct range_entry *) bp;
+  const unsigned long a = a_re->ranges_offset;
+  const unsigned long b = b_re->ranges_offset;
+
+  return (a > b) - (b > a);
+}
+
 static int
 display_debug_ranges (struct dwarf_section *section,
                      void *file ATTRIBUTE_UNUSED)
 {
   unsigned char *start = section->start;
-  unsigned char *section_end;
   unsigned long bytes;
   unsigned char *section_begin = start;
-  unsigned int num_range_list = 0;
-  unsigned long last_offset = 0;
-  unsigned int first = 0;
-  unsigned int i;
-  unsigned int j;
-  int seen_first_offset = 0;
-  int use_debug_info = 1;
-  unsigned char *next;
+  unsigned int num_range_list, i;
+  struct range_entry *range_entries, *range_entry_fill;
 
   bytes = section->size;
-  section_end = start + bytes;
 
   if (bytes == 0)
     {
@@ -2640,129 +3706,125 @@ display_debug_ranges (struct dwarf_section *section,
       return 0;
     }
 
-  load_debug_info (file);
+  if (load_debug_info (file) == 0)
+    {
+      warn (_("Unable to load/parse the .debug_info section, so cannot interpret the %s section.\n"),
+           section->name);
+      return 0;
+    }
 
-  /* Check the order of range list in .debug_info section. If
-     offsets of range lists are in the ascending order, we can
-     use `debug_information' directly.  */
+  num_range_list = 0;
   for (i = 0; i < num_debug_info_entries; i++)
-    {
-      unsigned int num;
+    num_range_list += debug_information [i].num_range_lists;
 
-      num = debug_information [i].num_range_lists;
-      num_range_list += num;
+  if (num_range_list == 0)
+    error (_("No range lists in .debug_info section!\n"));
 
-      /* Check if we can use `debug_information' directly.  */
-      if (use_debug_info && num != 0)
-       {
-         if (!seen_first_offset)
-           {
-             /* This is the first range list.  */
-             last_offset = debug_information [i].range_lists [0];
-             first = i;
-             seen_first_offset = 1;
-             j = 1;
-           }
-         else
-           j = 0;
+  range_entries = (struct range_entry *)
+      xmalloc (sizeof (*range_entries) * num_range_list);
+  range_entry_fill = range_entries;
 
-         for (; j < num; j++)
-           {
-             if (last_offset >
-                 debug_information [i].range_lists [j])
-               {
-                 use_debug_info = 0;
-                 break;
-               }
-             last_offset = debug_information [i].range_lists [j];
-           }
+  for (i = 0; i < num_debug_info_entries; i++)
+    {
+      debug_info *debug_info_p = &debug_information[i];
+      unsigned int j;
+
+      for (j = 0; j < debug_info_p->num_range_lists; j++)
+       {
+         range_entry_fill->ranges_offset = debug_info_p->range_lists[j];
+         range_entry_fill->debug_info_p = debug_info_p;
+         range_entry_fill++;
        }
     }
 
-  if (!use_debug_info)
-    /* FIXME: Should we handle this case?  */
-    error (_("Range lists in .debug_info section aren't in ascending order!\n"));
-
-  if (!seen_first_offset)
-    error (_("No range lists in .debug_info section!\n"));
+  qsort (range_entries, num_range_list, sizeof (*range_entries),
+        range_entry_compar);
 
   /* DWARF sections under Mach-O have non-zero addresses.  */
-  if (debug_information [first].num_range_lists > 0
-      && debug_information [first].range_lists [0] != section->address)
+  if (range_entries[0].ranges_offset != section->address)
     warn (_("Range lists in %s section start at 0x%lx\n"),
-         section->name, debug_information [first].range_lists [0]);
+         section->name, range_entries[0].ranges_offset);
 
   printf (_("Contents of the %s section:\n\n"), section->name);
   printf (_("    Offset   Begin    End\n"));
 
-  seen_first_offset = 0;
-  for (i = first; i < num_debug_info_entries; i++)
+  for (i = 0; i < num_range_list; i++)
     {
-      unsigned long begin;
-      unsigned long end;
-      unsigned long offset;
+      struct range_entry *range_entry = &range_entries[i];
+      debug_info *debug_info_p = range_entry->debug_info_p;
       unsigned int pointer_size;
+      unsigned long offset;
+      unsigned char *next;
       unsigned long base_address;
 
-      pointer_size = debug_information [i].pointer_size;
+      pointer_size = debug_info_p->pointer_size;
 
-      for (j = 0; j < debug_information [i].num_range_lists; j++)
+      /* DWARF sections under Mach-O have non-zero addresses.  */
+      offset = range_entry->ranges_offset - section->address;
+      next = section_begin + offset;
+      base_address = debug_info_p->base_address;
+
+      if (i > 0)
        {
-         /* DWARF sections under Mach-O have non-zero addresses.  */
-         offset = debug_information [i].range_lists [j] - section->address;
-         next = section_begin + offset;
-         base_address = debug_information [i].base_address;
+         if (start < next)
+           warn (_("There is a hole [0x%lx - 0x%lx] in %s section.\n"),
+                 (unsigned long) (start - section_begin),
+                 (unsigned long) (next - section_begin), section->name);
+         else if (start > next)
+           warn (_("There is an overlap [0x%lx - 0x%lx] in %s section.\n"),
+                 (unsigned long) (start - section_begin),
+                 (unsigned long) (next - section_begin), section->name);
+       }
+      start = next;
 
-         if (!seen_first_offset)
-           seen_first_offset = 1;
-         else
+      while (1)
+       {
+         dwarf_vma begin;
+         dwarf_vma end;
+
+         /* Note: we use sign extension here in order to be sure that
+            we can detect the -1 escape value.  Sign extension into the
+            top 32 bits of a 32-bit address will not affect the values
+            that we display since we always show hex values, and always
+            the bottom 32-bits.  */
+         begin = byte_get_signed (start, pointer_size);
+         start += pointer_size;
+         end = byte_get_signed (start, pointer_size);
+         start += pointer_size;
+
+         printf ("    %8.8lx ", offset);
+
+         if (begin == 0 && end == 0)
            {
-             if (start < next)
-               warn (_("There is a hole [0x%lx - 0x%lx] in %s section.\n"),
-                     (long)(start - section_begin),
-                     (long)(next - section_begin), section->name);
-             else if (start > next)
-               warn (_("There is an overlap [0x%lx - 0x%lx] in %s section.\n"),
-                     (long)(start - section_begin),
-                     (long)(next - section_begin), section->name);
+             printf (_("<End of list>\n"));
+             break;
            }
-         start = next;
 
-         while (1)
+         /* Check base address specifiers.  */
+         if (begin == (dwarf_vma) -1 && end != (dwarf_vma) -1)
            {
-             begin = byte_get (start, pointer_size);
-             start += pointer_size;
-             end = byte_get (start, pointer_size);
-             start += pointer_size;
-
-             if (begin == 0 && end == 0)
-               {
-                 printf (_("    %8.8lx <End of list>\n"), offset);
-                 break;
-               }
-
-             /* Check base address specifiers.  */
-             if (begin == -1UL && end != -1UL)
-               {
-                 base_address = end;
-                 printf ("    %8.8lx %8.8lx %8.8lx (base address)\n",
-                         offset, begin, end);
-                 continue;
-               }
+             base_address = end;
+             print_dwarf_vma (begin, pointer_size);
+             print_dwarf_vma (end, pointer_size);
+             printf ("(base address)\n");
+             continue;
+           }
 
-             printf ("    %8.8lx %8.8lx %8.8lx",
-                     offset, begin + base_address, end + base_address);
+         print_dwarf_vma (begin + base_address, pointer_size);
+         print_dwarf_vma (end + base_address, pointer_size);
 
-             if (begin == end)
-               fputs (_(" (start == end)"), stdout);
-             else if (begin > end)
-               fputs (_(" (start > end)"), stdout);
+         if (begin == end)
+           fputs (_("(start == end)"), stdout);
+         else if (begin > end)
+           fputs (_("(start > end)"), stdout);
 
-             putchar ('\n');
-           }
+         putchar ('\n');
        }
     }
   putchar ('\n');
+
+  free (range_entries);
+
   return 1;
 }
 
@@ -2784,24 +3846,37 @@ typedef struct Frame_Chunk
   int ra;
   unsigned char fde_encoding;
   unsigned char cfa_exp;
+  unsigned char ptr_size;
+  unsigned char segment_size;
 }
 Frame_Chunk;
 
+static const char *const *dwarf_regnames;
+static unsigned int dwarf_regnames_count;
+
 /* A marker for a col_type that means this column was never referenced
    in the frame info.  */
 #define DW_CFA_unreferenced (-1)
 
-static void
-frame_need_space (Frame_Chunk *fc, int reg)
+/* Return 0 if not more space is needed, 1 if more space is needed,
+   -1 for invalid reg.  */
+
+static int
+frame_need_space (Frame_Chunk *fc, unsigned int reg)
 {
   int prev = fc->ncols;
 
-  if (reg < fc->ncols)
-    return;
+  if (reg < (unsigned int) fc->ncols)
+    return 0;
+
+  if (dwarf_regnames_count
+      && reg > dwarf_regnames_count)
+    return -1;
 
   fc->ncols = reg + 1;
-  fc->col_type = xcrealloc (fc->col_type, fc->ncols, sizeof (short int));
-  fc->col_offset = xcrealloc (fc->col_offset, fc->ncols, sizeof (int));
+  fc->col_type = (short int *) xcrealloc (fc->col_type, fc->ncols,
+                                          sizeof (short int));
+  fc->col_offset = (int *) xcrealloc (fc->col_offset, fc->ncols, sizeof (int));
 
   while (prev < fc->ncols)
     {
@@ -2809,6 +3884,98 @@ frame_need_space (Frame_Chunk *fc, int reg)
       fc->col_offset[prev] = 0;
       prev++;
     }
+  return 1;
+}
+
+static const char *const dwarf_regnames_i386[] =
+{
+  "eax", "ecx", "edx", "ebx",
+  "esp", "ebp", "esi", "edi",
+  "eip", "eflags", NULL,
+  "st0", "st1", "st2", "st3",
+  "st4", "st5", "st6", "st7",
+  NULL, NULL,
+  "xmm0", "xmm1", "xmm2", "xmm3",
+  "xmm4", "xmm5", "xmm6", "xmm7",
+  "mm0", "mm1", "mm2", "mm3",
+  "mm4", "mm5", "mm6", "mm7",
+  "fcw", "fsw", "mxcsr",
+  "es", "cs", "ss", "ds", "fs", "gs", NULL, NULL,
+  "tr", "ldtr"
+};
+
+void
+init_dwarf_regnames_i386 (void)
+{
+  dwarf_regnames = dwarf_regnames_i386;
+  dwarf_regnames_count = ARRAY_SIZE (dwarf_regnames_i386);
+}
+
+static const char *const dwarf_regnames_x86_64[] =
+{
+  "rax", "rdx", "rcx", "rbx",
+  "rsi", "rdi", "rbp", "rsp",
+  "r8",  "r9",  "r10", "r11",
+  "r12", "r13", "r14", "r15",
+  "rip",
+  "xmm0",  "xmm1",  "xmm2",  "xmm3",
+  "xmm4",  "xmm5",  "xmm6",  "xmm7",
+  "xmm8",  "xmm9",  "xmm10", "xmm11",
+  "xmm12", "xmm13", "xmm14", "xmm15",
+  "st0", "st1", "st2", "st3",
+  "st4", "st5", "st6", "st7",
+  "mm0", "mm1", "mm2", "mm3",
+  "mm4", "mm5", "mm6", "mm7",
+  "rflags",
+  "es", "cs", "ss", "ds", "fs", "gs", NULL, NULL,
+  "fs.base", "gs.base", NULL, NULL,
+  "tr", "ldtr",
+  "mxcsr", "fcw", "fsw"
+};
+
+void
+init_dwarf_regnames_x86_64 (void)
+{
+  dwarf_regnames = dwarf_regnames_x86_64;
+  dwarf_regnames_count = ARRAY_SIZE (dwarf_regnames_x86_64);
+}
+
+void
+init_dwarf_regnames (unsigned int e_machine)
+{
+  switch (e_machine)
+    {
+    case EM_386:
+    case EM_486:
+      init_dwarf_regnames_i386 ();
+      break;
+
+    case EM_X86_64:
+    case EM_L1OM:
+      init_dwarf_regnames_x86_64 ();
+      break;
+
+    default:
+      break;
+    }
+}
+
+static const char *
+regname (unsigned int regno, int row)
+{
+  static char reg[64];
+  if (dwarf_regnames
+      && regno < dwarf_regnames_count
+      && dwarf_regnames [regno] != NULL)
+    {
+      if (row)
+       return dwarf_regnames [regno];
+      snprintf (reg, sizeof (reg), "r%d (%s)", regno,
+               dwarf_regnames [regno]);
+    }
+  else
+    snprintf (reg, sizeof (reg), "r%d", regno);
+  return reg;
 }
 
 static void
@@ -2822,27 +3989,29 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, int *max_regs)
 
   if (*need_col_headers)
     {
+      static const char *sloc = "   LOC";
+
       *need_col_headers = 0;
 
-      printf ("   LOC   CFA      ");
+      printf ("%-*s CFA      ", eh_addr_size * 2, sloc);
 
       for (r = 0; r < *max_regs; r++)
        if (fc->col_type[r] != DW_CFA_unreferenced)
          {
            if (r == fc->ra)
-             printf ("ra   ");
+             printf ("ra      ");
            else
-             printf ("r%-4d", r);
+             printf ("%-5s ", regname (r, 1));
          }
 
       printf ("\n");
     }
 
-  printf ("%08lx ", fc->pc_begin);
+  printf ("%0*lx ", eh_addr_size * 2, fc->pc_begin);
   if (fc->cfa_exp)
     strcpy (tmp, "exp");
   else
-    sprintf (tmp, "r%d%+d", fc->cfa_reg, fc->cfa_offset);
+    sprintf (tmp, "%s%+d", regname (fc->cfa_reg, 1), fc->cfa_offset);
   printf ("%-8s ", tmp);
 
   for (r = 0; r < fc->ncols; r++)
@@ -2864,7 +4033,7 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, int *max_regs)
              sprintf (tmp, "v%+d", fc->col_offset[r]);
              break;
            case DW_CFA_register:
-             sprintf (tmp, "r%d", fc->col_offset[r]);
+             sprintf (tmp, "%s", regname (fc->col_offset[r], 0));
              break;
            case DW_CFA_expression:
              strcpy (tmp, "exp");
@@ -2876,36 +4045,12 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, int *max_regs)
              strcpy (tmp, "n/a");
              break;
            }
-         printf ("%-5s", tmp);
+         printf ("%-5s ", tmp);
        }
     }
   printf ("\n");
 }
 
-static int
-size_of_encoded_value (int encoding)
-{
-  switch (encoding & 0x7)
-    {
-    default:   /* ??? */
-    case 0:    return eh_addr_size;
-    case 2:    return 2;
-    case 3:    return 4;
-    case 4:    return 8;
-    }
-}
-
-static dwarf_vma
-get_encoded_value (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
@@ -2923,8 +4068,10 @@ display_debug_frames (struct dwarf_section *section,
   int is_eh = strcmp (section->name, ".eh_frame") == 0;
   unsigned int length_return;
   int max_regs = 0;
+  const char *bad_reg = _("bad register: ");
+  int saved_eh_addr_size = eh_addr_size;
 
-  printf (_("The section %s contains:\n"), section->name);
+  printf (_("Contents of the %s section:\n"), section->name);
 
   while (start < end)
     {
@@ -2937,7 +4084,7 @@ display_debug_frames (struct dwarf_section *section,
       int need_col_headers = 1;
       unsigned char *augmentation_data = NULL;
       unsigned long augmentation_data_len = 0;
-      int encoded_ptr_size = eh_addr_size;
+      int encoded_ptr_size = saved_eh_addr_size;
       int offset_size;
       int initial_length_size;
 
@@ -2977,64 +4124,52 @@ display_debug_frames (struct dwarf_section *section,
        {
          int version;
 
-         fc = xmalloc (sizeof (Frame_Chunk));
+         fc = (Frame_Chunk *) xmalloc (sizeof (Frame_Chunk));
          memset (fc, 0, sizeof (Frame_Chunk));
 
          fc->next = chunks;
          chunks = fc;
          fc->chunk_start = saved_start;
          fc->ncols = 0;
-         fc->col_type = xmalloc (sizeof (short int));
-         fc->col_offset = xmalloc (sizeof (int));
-         frame_need_space (fc, max_regs-1);
+         fc->col_type = (short int *) xmalloc (sizeof (short int));
+         fc->col_offset = (int *) xmalloc (sizeof (int));
+         frame_need_space (fc, max_regs - 1);
 
          version = *start++;
 
          fc->augmentation = (char *) start;
          start = (unsigned char *) strchr ((char *) start, '\0') + 1;
 
-         if (fc->augmentation[0] == 'z')
+         if (strcmp (fc->augmentation, "eh") == 0)
+           start += eh_addr_size;
+
+         if (version >= 4)
            {
-             fc->code_factor = LEB ();
-             fc->data_factor = SLEB ();
-             if (version == 1)
-               {
-                 fc->ra = GET (1);
-               }
-             else
-               {
-                 fc->ra = LEB ();
-               }
-             augmentation_data_len = LEB ();
-             augmentation_data = start;
-             start += augmentation_data_len;
+             fc->ptr_size = GET (1);
+             fc->segment_size = GET (1);
+             eh_addr_size = fc->ptr_size;
            }
-         else if (strcmp (fc->augmentation, "eh") == 0)
+         else
            {
-             start += eh_addr_size;
-             fc->code_factor = LEB ();
-             fc->data_factor = SLEB ();
-             if (version == 1)
-               {
-                 fc->ra = GET (1);
-               }
-             else
-               {
-                 fc->ra = LEB ();
-               }
+             fc->ptr_size = eh_addr_size;
+             fc->segment_size = 0;
+           }
+         fc->code_factor = LEB ();
+         fc->data_factor = SLEB ();
+         if (version == 1)
+           {
+             fc->ra = GET (1);
            }
          else
            {
-             fc->code_factor = LEB ();
-             fc->data_factor = SLEB ();
-             if (version == 1)
-               {
-                 fc->ra = GET (1);
-               }
-             else
-               {
-                 fc->ra = LEB ();
-               }
+             fc->ra = LEB ();
+           }
+
+         if (fc->augmentation[0] == 'z')
+           {
+             augmentation_data_len = LEB ();
+             augmentation_data = start;
+             start += augmentation_data_len;
            }
          cie = fc;
 
@@ -3049,6 +4184,11 @@ display_debug_frames (struct dwarf_section *section,
                      (unsigned long)(saved_start - section_start), length, cie_id);
              printf ("  Version:               %d\n", version);
              printf ("  Augmentation:          \"%s\"\n", fc->augmentation);
+             if (version >= 4)
+               {
+                 printf ("  Pointer Size:          %u\n", fc->ptr_size);
+                 printf ("  Segment Size:          %u\n", fc->segment_size);
+               }
              printf ("  Code alignment factor: %u\n", fc->code_factor);
              printf ("  Data alignment factor: %d\n", fc->data_factor);
              printf ("  Return address column: %d\n", fc->ra);
@@ -3078,6 +4218,8 @@ display_debug_frames (struct dwarf_section *section,
                    q += 1 + size_of_encoded_value (*q);
                  else if (*p == 'R')
                    fc->fde_encoding = *q++;
+                 else if (*p == 'S')
+                   ;
                  else
                    break;
                  p++;
@@ -3093,6 +4235,7 @@ display_debug_frames (struct dwarf_section *section,
        {
          unsigned char *look_for;
          static Frame_Chunk fde_fc;
+         unsigned long segment_selector;
 
          fc = & fde_fc;
          memset (fc, 0, sizeof (Frame_Chunk));
@@ -3108,40 +4251,45 @@ display_debug_frames (struct dwarf_section *section,
              warn ("Invalid CIE pointer %#08lx in FDE at %#08lx\n",
                    cie_id, (unsigned long)(saved_start - section_start));
              fc->ncols = 0;
-             fc->col_type = xmalloc (sizeof (short int));
-             fc->col_offset = xmalloc (sizeof (int));
+             fc->col_type = (short int *) xmalloc (sizeof (short int));
+             fc->col_offset = (int *) xmalloc (sizeof (int));
              frame_need_space (fc, max_regs - 1);
              cie = fc;
              fc->augmentation = "";
              fc->fde_encoding = 0;
+             fc->ptr_size = eh_addr_size;
+             fc->segment_size = 0;
            }
          else
            {
              fc->ncols = cie->ncols;
-             fc->col_type = xcmalloc (fc->ncols, sizeof (short int));
-             fc->col_offset = xcmalloc (fc->ncols, sizeof (int));
+             fc->col_type = (short int *) xcmalloc (fc->ncols, sizeof (short int));
+             fc->col_offset =  (int *) xcmalloc (fc->ncols, sizeof (int));
              memcpy (fc->col_type, cie->col_type, fc->ncols * sizeof (short int));
              memcpy (fc->col_offset, cie->col_offset, fc->ncols * sizeof (int));
              fc->augmentation = cie->augmentation;
+             fc->ptr_size = cie->ptr_size;
+             eh_addr_size = cie->ptr_size;
+             fc->segment_size = cie->segment_size;
              fc->code_factor = cie->code_factor;
              fc->data_factor = cie->data_factor;
              fc->cfa_reg = cie->cfa_reg;
              fc->cfa_offset = cie->cfa_offset;
              fc->ra = cie->ra;
-             frame_need_space (fc, max_regs-1);
+             frame_need_space (fc, max_regs - 1);
              fc->fde_encoding = cie->fde_encoding;
            }
 
          if (fc->fde_encoding)
            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
-             /* Don't adjust for relocatable file since there's
-                invariably a pcrel reloc here, which we haven't
-                applied.  */
-             && !is_relocatable)
-           fc->pc_begin += section->address + (start - section_start);
+         segment_selector = 0;
+         if (fc->segment_size)
+           {
+             segment_selector = byte_get (start, fc->segment_size);
+             start += fc->segment_size;
+           }
+         fc->pc_begin = get_encoded_value (start, fc->fde_encoding, section);
          start += encoded_ptr_size;
          fc->pc_range = byte_get (start, encoded_ptr_size);
          start += encoded_ptr_size;
@@ -3153,10 +4301,12 @@ display_debug_frames (struct dwarf_section *section,
              start += augmentation_data_len;
            }
 
-         printf ("\n%08lx %08lx %08lx FDE cie=%08lx pc=%08lx..%08lx\n",
+         printf ("\n%08lx %08lx %08lx FDE cie=%08lx pc=",
                  (unsigned long)(saved_start - section_start), length, cie_id,
-                 (unsigned long)(cie->chunk_start - section_start),
-                 fc->pc_begin, fc->pc_begin + fc->pc_range);
+                 (unsigned long)(cie->chunk_start - section_start));
+         if (fc->segment_size)
+           printf ("%04lx:", segment_selector);
+         printf ("%08lx..%08lx\n", fc->pc_begin, fc->pc_begin + fc->pc_range);
          if (! do_debug_frames_interp && augmentation_data_len)
            {
              unsigned long i;
@@ -3185,7 +4335,7 @@ display_debug_frames (struct dwarf_section *section,
          while (start < block_end)
            {
              unsigned op, opa;
-             unsigned long reg, tmp;
+             unsigned long reg, temp;
 
              op = *start++;
              opa = op & 0x3f;
@@ -3200,12 +4350,12 @@ display_debug_frames (struct dwarf_section *section,
                  break;
                case DW_CFA_offset:
                  LEB ();
-                 frame_need_space (fc, opa);
-                 fc->col_type[opa] = DW_CFA_undefined;
+                 if (frame_need_space (fc, opa) >= 0)
+                   fc->col_type[opa] = DW_CFA_undefined;
                  break;
                case DW_CFA_restore:
-                 frame_need_space (fc, opa);
-                 fc->col_type[opa] = DW_CFA_undefined;
+                 if (frame_need_space (fc, opa) >= 0)
+                   fc->col_type[opa] = DW_CFA_undefined;
                  break;
                case DW_CFA_set_loc:
                  start += encoded_ptr_size;
@@ -3222,28 +4372,29 @@ display_debug_frames (struct dwarf_section *section,
                case DW_CFA_offset_extended:
                case DW_CFA_val_offset:
                  reg = LEB (); LEB ();
-                 frame_need_space (fc, reg);
-                 fc->col_type[reg] = DW_CFA_undefined;
+                 if (frame_need_space (fc, reg) >= 0)
+                   fc->col_type[reg] = DW_CFA_undefined;
                  break;
                case DW_CFA_restore_extended:
                  reg = LEB ();
                  frame_need_space (fc, reg);
-                 fc->col_type[reg] = DW_CFA_undefined;
+                 if (frame_need_space (fc, reg) >= 0)
+                   fc->col_type[reg] = DW_CFA_undefined;
                  break;
                case DW_CFA_undefined:
                  reg = LEB ();
-                 frame_need_space (fc, reg);
-                 fc->col_type[reg] = DW_CFA_undefined;
+                 if (frame_need_space (fc, reg) >= 0)
+                   fc->col_type[reg] = DW_CFA_undefined;
                  break;
                case DW_CFA_same_value:
                  reg = LEB ();
-                 frame_need_space (fc, reg);
-                 fc->col_type[reg] = DW_CFA_undefined;
+                 if (frame_need_space (fc, reg) >= 0)
+                   fc->col_type[reg] = DW_CFA_undefined;
                  break;
                case DW_CFA_register:
                  reg = LEB (); LEB ();
-                 frame_need_space (fc, reg);
-                 fc->col_type[reg] = DW_CFA_undefined;
+                 if (frame_need_space (fc, reg) >= 0)
+                   fc->col_type[reg] = DW_CFA_undefined;
                  break;
                case DW_CFA_def_cfa:
                  LEB (); LEB ();
@@ -3255,22 +4406,22 @@ display_debug_frames (struct dwarf_section *section,
                  LEB ();
                  break;
                case DW_CFA_def_cfa_expression:
-                 tmp = LEB ();
-                 start += tmp;
+                 temp = LEB ();
+                 start += temp;
                  break;
                case DW_CFA_expression:
                case DW_CFA_val_expression:
                  reg = LEB ();
-                 tmp = LEB ();
-                 start += tmp;
-                 frame_need_space (fc, reg);
-                 fc->col_type[reg] = DW_CFA_undefined;
+                 temp = LEB ();
+                 start += temp;
+                 if (frame_need_space (fc, reg) >= 0)
+                   fc->col_type[reg] = DW_CFA_undefined;
                  break;
                case DW_CFA_offset_extended_sf:
                case DW_CFA_val_offset_sf:
                  reg = LEB (); SLEB ();
-                 frame_need_space (fc, reg);
-                 fc->col_type[reg] = DW_CFA_undefined;
+                 if (frame_need_space (fc, reg) >= 0)
+                   fc->col_type[reg] = DW_CFA_undefined;
                  break;
                case DW_CFA_def_cfa_sf:
                  LEB (); SLEB ();
@@ -3286,9 +4437,9 @@ display_debug_frames (struct dwarf_section *section,
                  break;
                case DW_CFA_GNU_negative_offset_extended:
                  reg = LEB (); LEB ();
-                 frame_need_space (fc, reg);
-                 fc->col_type[reg] = DW_CFA_undefined;
-
+                 if (frame_need_space (fc, reg) >= 0)
+                   fc->col_type[reg] = DW_CFA_undefined;
+                 break;
                default:
                  break;
                }
@@ -3305,6 +4456,7 @@ display_debug_frames (struct dwarf_section *section,
          unsigned long ul, reg, roffs;
          long l, ofs;
          dwarf_vma vma;
+         const char *reg_prefix = "";
 
          op = *start++;
          opa = op & 0x3f;
@@ -3327,25 +4479,35 @@ display_debug_frames (struct dwarf_section *section,
 
            case DW_CFA_offset:
              roffs = LEB ();
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_offset: r%d at cfa%+ld\n",
-                       opa, roffs * fc->data_factor);
-             fc->col_type[opa] = DW_CFA_offset;
-             fc->col_offset[opa] = roffs * fc->data_factor;
+             if (opa >= (unsigned int) fc->ncols)
+               reg_prefix = bad_reg;
+             if (! do_debug_frames_interp || *reg_prefix != '\0')
+               printf ("  DW_CFA_offset: %s%s at cfa%+ld\n",
+                       reg_prefix, regname (opa, 0),
+                       roffs * fc->data_factor);
+             if (*reg_prefix == '\0')
+               {
+                 fc->col_type[opa] = DW_CFA_offset;
+                 fc->col_offset[opa] = roffs * fc->data_factor;
+               }
              break;
 
            case DW_CFA_restore:
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_restore: r%d\n", opa);
-             fc->col_type[opa] = cie->col_type[opa];
-             fc->col_offset[opa] = cie->col_offset[opa];
+             if (opa >= (unsigned int) cie->ncols
+                 || opa >= (unsigned int) fc->ncols)
+               reg_prefix = bad_reg;
+             if (! do_debug_frames_interp || *reg_prefix != '\0')
+               printf ("  DW_CFA_restore: %s%s\n",
+                       reg_prefix, regname (opa, 0));
+             if (*reg_prefix == '\0')
+               {
+                 fc->col_type[opa] = cie->col_type[opa];
+                 fc->col_offset[opa] = cie->col_offset[opa];
+               }
              break;
 
            case DW_CFA_set_loc:
-             vma = get_encoded_value (start, fc->fde_encoding);
-             if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel
-                 && !is_relocatable)
-               vma += section->address + (start - section_start);
+             vma = get_encoded_value (start, fc->fde_encoding, section);
              start += encoded_ptr_size;
              if (do_debug_frames_interp)
                frame_display_row (fc, &need_col_headers, &max_regs);
@@ -3390,63 +4552,104 @@ display_debug_frames (struct dwarf_section *section,
            case DW_CFA_offset_extended:
              reg = LEB ();
              roffs = LEB ();
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_offset_extended: r%ld at cfa%+ld\n",
-                       reg, roffs * fc->data_factor);
-             fc->col_type[reg] = DW_CFA_offset;
-             fc->col_offset[reg] = roffs * fc->data_factor;
+             if (reg >= (unsigned int) fc->ncols)
+               reg_prefix = bad_reg;
+             if (! do_debug_frames_interp || *reg_prefix != '\0')
+               printf ("  DW_CFA_offset_extended: %s%s at cfa%+ld\n",
+                       reg_prefix, regname (reg, 0),
+                       roffs * fc->data_factor);
+             if (*reg_prefix == '\0')
+               {
+                 fc->col_type[reg] = DW_CFA_offset;
+                 fc->col_offset[reg] = roffs * fc->data_factor;
+               }
              break;
 
            case DW_CFA_val_offset:
              reg = LEB ();
              roffs = LEB ();
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_val_offset: r%ld at cfa%+ld\n",
-                       reg, roffs * fc->data_factor);
-             fc->col_type[reg] = DW_CFA_val_offset;
-             fc->col_offset[reg] = roffs * fc->data_factor;
+             if (reg >= (unsigned int) fc->ncols)
+               reg_prefix = bad_reg;
+             if (! do_debug_frames_interp || *reg_prefix != '\0')
+               printf ("  DW_CFA_val_offset: %s%s at cfa%+ld\n",
+                       reg_prefix, regname (reg, 0),
+                       roffs * fc->data_factor);
+             if (*reg_prefix == '\0')
+               {
+                 fc->col_type[reg] = DW_CFA_val_offset;
+                 fc->col_offset[reg] = roffs * fc->data_factor;
+               }
              break;
 
            case DW_CFA_restore_extended:
              reg = LEB ();
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_restore_extended: r%ld\n", reg);
-             fc->col_type[reg] = cie->col_type[reg];
-             fc->col_offset[reg] = cie->col_offset[reg];
+             if (reg >= (unsigned int) cie->ncols
+                 || reg >= (unsigned int) fc->ncols)
+               reg_prefix = bad_reg;
+             if (! do_debug_frames_interp || *reg_prefix != '\0')
+               printf ("  DW_CFA_restore_extended: %s%s\n",
+                       reg_prefix, regname (reg, 0));
+             if (*reg_prefix == '\0')
+               {
+                 fc->col_type[reg] = cie->col_type[reg];
+                 fc->col_offset[reg] = cie->col_offset[reg];
+               }
              break;
 
            case DW_CFA_undefined:
              reg = LEB ();
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_undefined: r%ld\n", reg);
-             fc->col_type[reg] = DW_CFA_undefined;
-             fc->col_offset[reg] = 0;
+             if (reg >= (unsigned int) fc->ncols)
+               reg_prefix = bad_reg;
+             if (! do_debug_frames_interp || *reg_prefix != '\0')
+               printf ("  DW_CFA_undefined: %s%s\n",
+                       reg_prefix, regname (reg, 0));
+             if (*reg_prefix == '\0')
+               {
+                 fc->col_type[reg] = DW_CFA_undefined;
+                 fc->col_offset[reg] = 0;
+               }
              break;
 
            case DW_CFA_same_value:
              reg = LEB ();
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_same_value: r%ld\n", reg);
-             fc->col_type[reg] = DW_CFA_same_value;
-             fc->col_offset[reg] = 0;
+             if (reg >= (unsigned int) fc->ncols)
+               reg_prefix = bad_reg;
+             if (! do_debug_frames_interp || *reg_prefix != '\0')
+               printf ("  DW_CFA_same_value: %s%s\n",
+                       reg_prefix, regname (reg, 0));
+             if (*reg_prefix == '\0')
+               {
+                 fc->col_type[reg] = DW_CFA_same_value;
+                 fc->col_offset[reg] = 0;
+               }
              break;
 
            case DW_CFA_register:
              reg = LEB ();
              roffs = LEB ();
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_register: r%ld in r%ld\n", reg, roffs);
-             fc->col_type[reg] = DW_CFA_register;
-             fc->col_offset[reg] = roffs;
+             if (reg >= (unsigned int) fc->ncols)
+               reg_prefix = bad_reg;
+             if (! do_debug_frames_interp || *reg_prefix != '\0')
+               {
+                 printf ("  DW_CFA_register: %s%s in ",
+                         reg_prefix, regname (reg, 0));
+                 puts (regname (roffs, 0));
+               }
+             if (*reg_prefix == '\0')
+               {
+                 fc->col_type[reg] = DW_CFA_register;
+                 fc->col_offset[reg] = roffs;
+               }
              break;
 
            case DW_CFA_remember_state:
              if (! do_debug_frames_interp)
                printf ("  DW_CFA_remember_state\n");
-             rs = xmalloc (sizeof (Frame_Chunk));
+             rs = (Frame_Chunk *) xmalloc (sizeof (Frame_Chunk));
              rs->ncols = fc->ncols;
-             rs->col_type = xcmalloc (rs->ncols, sizeof (short int));
-             rs->col_offset = xcmalloc (rs->ncols, sizeof (int));
+             rs->col_type = (short int *) xcmalloc (rs->ncols,
+                                                     sizeof (short int));
+             rs->col_offset = (int *) xcmalloc (rs->ncols, sizeof (int));
              memcpy (rs->col_type, fc->col_type, rs->ncols);
              memcpy (rs->col_offset, fc->col_offset, rs->ncols * sizeof (int));
              rs->next = remembered_state;
@@ -3460,7 +4663,7 @@ display_debug_frames (struct dwarf_section *section,
              if (rs)
                {
                  remembered_state = rs->next;
-                 frame_need_space (fc, rs->ncols-1);
+                 frame_need_space (fc, rs->ncols - 1);
                  memcpy (fc->col_type, rs->col_type, rs->ncols);
                  memcpy (fc->col_offset, rs->col_offset,
                          rs->ncols * sizeof (int));
@@ -3477,15 +4680,16 @@ display_debug_frames (struct dwarf_section *section,
              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);
+               printf ("  DW_CFA_def_cfa: %s ofs %d\n",
+                       regname (fc->cfa_reg, 0), fc->cfa_offset);
              break;
 
            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);
+               printf ("  DW_CFA_def_cfa_register: %s\n",
+                       regname (fc->cfa_reg, 0));
              break;
 
            case DW_CFA_def_cfa_offset:
@@ -3504,7 +4708,8 @@ display_debug_frames (struct dwarf_section *section,
              if (! do_debug_frames_interp)
                {
                  printf ("  DW_CFA_def_cfa_expression (");
-                 decode_location_expression (start, eh_addr_size, ul, 0);
+                 decode_location_expression (start, eh_addr_size, 0, -1,
+                                             ul, 0, section);
                  printf (")\n");
                }
              fc->cfa_exp = 1;
@@ -3514,49 +4719,69 @@ display_debug_frames (struct dwarf_section *section,
            case DW_CFA_expression:
              reg = LEB ();
              ul = LEB ();
-             if (! do_debug_frames_interp)
+             if (reg >= (unsigned int) fc->ncols)
+               reg_prefix = bad_reg;
+             if (! do_debug_frames_interp || *reg_prefix != '\0')
                {
-                 printf ("  DW_CFA_expression: r%ld (", reg);
-                 decode_location_expression (start, eh_addr_size, ul, 0);
+                 printf ("  DW_CFA_expression: %s%s (",
+                         reg_prefix, regname (reg, 0));
+                 decode_location_expression (start, eh_addr_size, 0, -1,
+                                             ul, 0, section);
                  printf (")\n");
                }
-             fc->col_type[reg] = DW_CFA_expression;
+             if (*reg_prefix == '\0')
+               fc->col_type[reg] = DW_CFA_expression;
              start += ul;
              break;
 
            case DW_CFA_val_expression:
              reg = LEB ();
              ul = LEB ();
-             if (! do_debug_frames_interp)
+             if (reg >= (unsigned int) fc->ncols)
+               reg_prefix = bad_reg;
+             if (! do_debug_frames_interp || *reg_prefix != '\0')
                {
-                 printf ("  DW_CFA_val_expression: r%ld (", reg);
-                 decode_location_expression (start, eh_addr_size, ul, 0);
+                 printf ("  DW_CFA_val_expression: %s%s (",
+                         reg_prefix, regname (reg, 0));
+                 decode_location_expression (start, eh_addr_size, 0, -1,
+                                             ul, 0, section);
                  printf (")\n");
                }
-             fc->col_type[reg] = DW_CFA_val_expression;
+             if (*reg_prefix == '\0')
+               fc->col_type[reg] = DW_CFA_val_expression;
              start += ul;
              break;
 
            case DW_CFA_offset_extended_sf:
              reg = LEB ();
              l = SLEB ();
-             frame_need_space (fc, reg);
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_offset_extended_sf: r%ld at cfa%+ld\n",
-                       reg, l * fc->data_factor);
-             fc->col_type[reg] = DW_CFA_offset;
-             fc->col_offset[reg] = l * fc->data_factor;
+             if (frame_need_space (fc, reg) < 0)
+               reg_prefix = bad_reg;
+             if (! do_debug_frames_interp || *reg_prefix != '\0')
+               printf ("  DW_CFA_offset_extended_sf: %s%s at cfa%+ld\n",
+                       reg_prefix, regname (reg, 0),
+                       l * fc->data_factor);
+             if (*reg_prefix == '\0')
+               {
+                 fc->col_type[reg] = DW_CFA_offset;
+                 fc->col_offset[reg] = l * fc->data_factor;
+               }
              break;
 
            case DW_CFA_val_offset_sf:
              reg = LEB ();
              l = SLEB ();
-             frame_need_space (fc, reg);
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_val_offset_sf: r%ld at cfa%+ld\n",
-                       reg, l * fc->data_factor);
-             fc->col_type[reg] = DW_CFA_val_offset;
-             fc->col_offset[reg] = l * fc->data_factor;
+             if (frame_need_space (fc, reg) < 0)
+               reg_prefix = bad_reg;
+             if (! do_debug_frames_interp || *reg_prefix != '\0')
+               printf ("  DW_CFA_val_offset_sf: %s%s at cfa%+ld\n",
+                       reg_prefix, regname (reg, 0),
+                       l * fc->data_factor);
+             if (*reg_prefix == '\0')
+               {
+                 fc->col_type[reg] = DW_CFA_val_offset;
+                 fc->col_offset[reg] = l * fc->data_factor;
+               }
              break;
 
            case DW_CFA_def_cfa_sf:
@@ -3565,8 +4790,8 @@ display_debug_frames (struct dwarf_section *section,
              fc->cfa_offset = fc->cfa_offset * fc->data_factor;
              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);
+               printf ("  DW_CFA_def_cfa_sf: %s ofs %d\n",
+                       regname (fc->cfa_reg, 0), fc->cfa_offset);
              break;
 
            case DW_CFA_def_cfa_offset_sf:
@@ -3601,19 +4826,24 @@ display_debug_frames (struct dwarf_section *section,
            case DW_CFA_GNU_negative_offset_extended:
              reg = LEB ();
              l = - LEB ();
-             frame_need_space (fc, reg);
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_GNU_negative_offset_extended: r%ld at cfa%+ld\n",
-                       reg, l * fc->data_factor);
-             fc->col_type[reg] = DW_CFA_offset;
-             fc->col_offset[reg] = l * fc->data_factor;
+             if (frame_need_space (fc, reg) < 0)
+               reg_prefix = bad_reg;
+             if (! do_debug_frames_interp || *reg_prefix != '\0')
+               printf ("  DW_CFA_GNU_negative_offset_extended: %s%s at cfa%+ld\n",
+                       reg_prefix, regname (reg, 0),
+                       l * fc->data_factor);
+             if (*reg_prefix == '\0')
+               {
+                 fc->col_type[reg] = DW_CFA_offset;
+                 fc->col_offset[reg] = l * fc->data_factor;
+               }
              break;
 
            default:
              if (op >= DW_CFA_lo_user && op <= DW_CFA_hi_user)
                printf (_("  DW_CFA_??? (User defined call frame op: %#x)\n"), op);
              else
-               warn (_("unsupported or unknown Dwarf Call Frame Instruction number: %#x\n"), op);              
+               warn (_("unsupported or unknown Dwarf Call Frame Instruction number: %#x\n"), op);
              start = block_end;
            }
        }
@@ -3622,6 +4852,7 @@ display_debug_frames (struct dwarf_section *section,
        frame_display_row (fc, &need_col_headers, &max_regs);
 
       start = block_end;
+      eh_addr_size = saved_eh_addr_size;
     }
 
   printf ("\n");
@@ -3633,6 +4864,135 @@ display_debug_frames (struct dwarf_section *section,
 #undef LEB
 #undef SLEB
 
+static int
+display_gdb_index (struct dwarf_section *section,
+                  void *file ATTRIBUTE_UNUSED)
+{
+  unsigned char *start = section->start;
+  uint32_t version;
+  uint32_t cu_list_offset, tu_list_offset;
+  uint32_t address_table_offset, symbol_table_offset, constant_pool_offset;
+  unsigned int cu_list_elements, tu_list_elements;
+  unsigned int address_table_size, symbol_table_slots;
+  unsigned char *cu_list, *tu_list;
+  unsigned char *address_table, *symbol_table, *constant_pool;
+  unsigned int i;
+
+  /* The documentation for the format of this file is in gdb/dwarf2read.c.  */
+
+  printf (_("Contents of the %s section:\n"), section->name);
+
+  if (section->size < 6 * sizeof (uint32_t))
+    {
+      warn (_("Truncated header in the %s section.\n"), section->name);
+      return 0;
+    }
+
+  version = byte_get_little_endian (start, 4);
+  printf (_("Version %d\n"), version);
+
+  /* Prior versions are obsolete, and future versions may not be
+     backwards compatible.  */
+  if (version != 3)
+    {
+      warn (_("Unsupported version %u.\n"), version);
+      return 0;
+    }
+
+  cu_list_offset = byte_get_little_endian (start + 4, 4);
+  tu_list_offset = byte_get_little_endian (start + 8, 4);
+  address_table_offset = byte_get_little_endian (start + 12, 4);
+  symbol_table_offset = byte_get_little_endian (start + 16, 4);
+  constant_pool_offset = byte_get_little_endian (start + 20, 4);
+
+  if (cu_list_offset > section->size
+      || tu_list_offset > section->size
+      || address_table_offset > section->size
+      || symbol_table_offset > section->size
+      || constant_pool_offset > section->size)
+    {
+      warn (_("Corrupt header in the %s section.\n"), section->name);
+      return 0;
+    }
+
+  cu_list_elements = (tu_list_offset - cu_list_offset) / 8;
+  tu_list_elements = (address_table_offset - tu_list_offset) / 8;
+  address_table_size = symbol_table_offset - address_table_offset;
+  symbol_table_slots = (constant_pool_offset - symbol_table_offset) / 8;
+
+  cu_list = start + cu_list_offset;
+  tu_list = start + tu_list_offset;
+  address_table = start + address_table_offset;
+  symbol_table = start + symbol_table_offset;
+  constant_pool = start + constant_pool_offset;
+
+  printf (_("\nCU table:\n"));
+  for (i = 0; i < cu_list_elements; i += 2)
+    {
+      uint64_t cu_offset = byte_get_little_endian (cu_list + i * 8, 8);
+      uint64_t cu_length = byte_get_little_endian (cu_list + i * 8 + 8, 8);
+
+      printf (_("[%3u] 0x%lx - 0x%lx\n"), i / 2,
+             (unsigned long) cu_offset,
+             (unsigned long) (cu_offset + cu_length - 1));
+    }
+
+  printf (_("\nTU table:\n"));
+  for (i = 0; i < tu_list_elements; i += 3)
+    {
+      uint64_t tu_offset = byte_get_little_endian (tu_list + i * 8, 8);
+      uint64_t type_offset = byte_get_little_endian (tu_list + i * 8 + 8, 8);
+      uint64_t signature = byte_get_little_endian (tu_list + i * 8 + 16, 8);
+
+      printf (_("[%3u] 0x%lx 0x%lx "), i / 3,
+             (unsigned long) tu_offset,
+             (unsigned long) type_offset);
+      print_dwarf_vma (signature, 8);
+      printf ("\n");
+    }
+
+  printf (_("\nAddress table:\n"));
+  for (i = 0; i < address_table_size; i += 2 * 8 + 4)
+    {
+      uint64_t low = byte_get_little_endian (address_table + i, 8);
+      uint64_t high = byte_get_little_endian (address_table + i + 8, 8);
+      uint32_t cu_index = byte_get_little_endian (address_table + i + 16, 4);
+
+      print_dwarf_vma (low, 8);
+      print_dwarf_vma (high, 8);
+      printf (_("%u\n"), cu_index);
+    }
+
+  printf (_("\nSymbol table:\n"));
+  for (i = 0; i < symbol_table_slots; ++i)
+    {
+      uint32_t name_offset = byte_get_little_endian (symbol_table + i * 8, 4);
+      uint32_t cu_vector_offset = byte_get_little_endian (symbol_table + i * 8 + 4, 4);
+      uint32_t num_cus, cu;
+
+      if (name_offset != 0
+         || cu_vector_offset != 0)
+       {
+         unsigned int j;
+
+         printf ("[%3u] %s:", i, constant_pool + name_offset);
+         num_cus = byte_get_little_endian (constant_pool + cu_vector_offset, 4);
+         for (j = 0; j < num_cus; ++j)
+           {
+             cu = byte_get_little_endian (constant_pool + cu_vector_offset + 4 + j * 4, 4);
+             /* Convert to TU number if it's for a type unit.  */
+             if (cu >= cu_list_elements)
+               printf (" T%u", cu - cu_list_elements);
+             else
+               printf (" %u", cu);
+           }
+         printf ("\n");
+       }
+    }
+
+  return 1;
+}
+
 static int
 display_debug_not_supported (struct dwarf_section *section,
                             void *file ATTRIBUTE_UNUSED)
@@ -3673,89 +5033,241 @@ xcrealloc (void *ptr, size_t nmemb, size_t size)
     return xrealloc (ptr, nmemb * size);
 }
 
-void
-error (const char *message, ...)
-{
-  va_list args;
-
-  va_start (args, message);
-  fprintf (stderr, _("%s: Error: "), program_name);
-  vfprintf (stderr, message, args);
-  va_end (args);
-}
-
-void
-warn (const char *message, ...)
-{
-  va_list args;
-
-  va_start (args, message);
-  fprintf (stderr, _("%s: Warning: "), program_name);
-  vfprintf (stderr, message, args);
-  va_end (args);
-}
-
 void
 free_debug_memory (void)
 {
-  enum dwarf_section_display_enum i;
+  unsigned int i;
 
   free_abbrevs ();
 
   for (i = 0; i < max; i++)
-    free_debug_section (i);
+    free_debug_section ((enum dwarf_section_display_enum) i);
 
-  if (debug_information)
+  if (debug_information != NULL)
     {
-      for (i = 0; i < num_debug_info_entries; i++)
+      if (num_debug_info_entries != DEBUG_INFO_UNAVAILABLE)
        {
-         if (!debug_information [i].max_loc_offsets)
+         for (i = 0; i < num_debug_info_entries; i++)
            {
-             free (debug_information [i].loc_offsets);
-             free (debug_information [i].have_frame_base);
+             if (!debug_information [i].max_loc_offsets)
+               {
+                 free (debug_information [i].loc_offsets);
+                 free (debug_information [i].have_frame_base);
+               }
+             if (!debug_information [i].max_range_lists)
+               free (debug_information [i].range_lists);
            }
-         if (!debug_information [i].max_range_lists)
-           free (debug_information [i].range_lists);
        }
+
       free (debug_information);
       debug_information = NULL;
       num_debug_info_entries = 0;
     }
+}
+
+void
+dwarf_select_sections_by_names (const char *names)
+{
+  typedef struct
+  {
+    const char * option;
+    int *        variable;
+    int          val;
+  }
+  debug_dump_long_opts;
+
+  static const debug_dump_long_opts opts_table [] =
+    {
+      /* Please keep this table alpha- sorted.  */
+      { "Ranges", & do_debug_ranges, 1 },
+      { "abbrev", & do_debug_abbrevs, 1 },
+      { "aranges", & do_debug_aranges, 1 },
+      { "frames", & do_debug_frames, 1 },
+      { "frames-interp", & do_debug_frames_interp, 1 },
+      { "info", & do_debug_info, 1 },
+      { "line", & do_debug_lines, FLAG_DEBUG_LINES_RAW }, /* For backwards compatibility.  */
+      { "rawline", & do_debug_lines, FLAG_DEBUG_LINES_RAW },
+      { "decodedline", & do_debug_lines, FLAG_DEBUG_LINES_DECODED },
+      { "loc",  & do_debug_loc, 1 },
+      { "macro", & do_debug_macinfo, 1 },
+      { "pubnames", & do_debug_pubnames, 1 },
+      { "pubtypes", & do_debug_pubtypes, 1 },
+      /* This entry is for compatability
+        with earlier versions of readelf.  */
+      { "ranges", & do_debug_aranges, 1 },
+      { "str", & do_debug_str, 1 },
+      /* The special .gdb_index section.  */
+      { "gdb_index", & do_gdb_index, 1 },
+      /* These trace_* sections are used by Itanium VMS.  */
+      { "trace_abbrev", & do_trace_abbrevs, 1 },
+      { "trace_aranges", & do_trace_aranges, 1 },
+      { "trace_info", & do_trace_info, 1 },
+      { NULL, NULL, 0 }
+    };
+
+  const char *p;
+  
+  p = names;
+  while (*p)
+    {
+      const debug_dump_long_opts * entry;
+      
+      for (entry = opts_table; entry->option; entry++)
+       {
+         size_t len = strlen (entry->option);
+         
+         if (strncmp (p, entry->option, len) == 0
+             && (p[len] == ',' || p[len] == '\0'))
+           {
+             * entry->variable |= entry->val;
+             
+             /* The --debug-dump=frames-interp option also
+                enables the --debug-dump=frames option.  */
+             if (do_debug_frames_interp)
+               do_debug_frames = 1;
 
+             p += len;
+             break;
+           }
+       }
+      
+      if (entry->option == NULL)
+       {
+         warn (_("Unrecognized debug option '%s'\n"), p);
+         p = strchr (p, ',');
+         if (p == NULL)
+           break;
+       }
+      
+      if (*p == ',')
+       p++;
+    }
+}
+
+void
+dwarf_select_sections_by_letters (const char *letters)
+{
+  unsigned int lindex = 0;
+
+  while (letters[lindex])
+    switch (letters[lindex++])
+      {
+      case 'i':
+       do_debug_info = 1;
+       break;
+       
+      case 'a':
+       do_debug_abbrevs = 1;
+       break;
+       
+      case 'l':
+       do_debug_lines |= FLAG_DEBUG_LINES_RAW;
+       break;
+       
+      case 'L':
+       do_debug_lines |= FLAG_DEBUG_LINES_DECODED;
+       break;
+       
+      case 'p':
+       do_debug_pubnames = 1;
+       break;
+       
+      case 't':
+       do_debug_pubtypes = 1;
+       break;
+       
+      case 'r':
+       do_debug_aranges = 1;
+       break;
+       
+      case 'R':
+       do_debug_ranges = 1;
+       break;
+       
+      case 'F':
+       do_debug_frames_interp = 1;
+      case 'f':
+       do_debug_frames = 1;
+       break;
+       
+      case 'm':
+       do_debug_macinfo = 1;
+       break;
+       
+      case 's':
+       do_debug_str = 1;
+       break;
+       
+      case 'o':
+       do_debug_loc = 1;
+       break;
+       
+      default:
+       warn (_("Unrecognized debug option '%s'\n"), optarg);
+       break;
+      }
+}
+
+void
+dwarf_select_sections_all (void)
+{
+  do_debug_info = 1;
+  do_debug_abbrevs = 1;
+  do_debug_lines = FLAG_DEBUG_LINES_RAW;
+  do_debug_pubnames = 1;
+  do_debug_pubtypes = 1;
+  do_debug_aranges = 1;
+  do_debug_ranges = 1;
+  do_debug_frames = 1;
+  do_debug_macinfo = 1;
+  do_debug_str = 1;
+  do_debug_loc = 1;
+  do_gdb_index = 1;
+  do_trace_info = 1;
+  do_trace_abbrevs = 1;
+  do_trace_aranges = 1;
 }
 
 struct dwarf_section_display debug_displays[] =
 {
-  { { ".debug_abbrev",         NULL,   0,      0 },
-    display_debug_abbrev,              0,      0 },
-  { { ".debug_aranges",                NULL,   0,      0 },
-    display_debug_aranges,             0,      0 },
-  { { ".debug_frame",          NULL,   0,      0 },
-    display_debug_frames,              1,      0 },
-  { { ".debug_info",           NULL,   0,      0 },
-    display_debug_info,                        1,      0 },
-  { { ".debug_line",           NULL,   0,      0 },
-    display_debug_lines,               0,      0 },
-  { { ".debug_pubnames",       NULL,   0,      0 },
-    display_debug_pubnames,            0,      0 },
-  { { ".eh_frame",             NULL,   0,      0 },
-    display_debug_frames,              1,      1 },
-  { { ".debug_macinfo",                NULL,   0,      0 },
-    display_debug_macinfo,             0,      0 },
-  { { ".debug_str",            NULL,   0,      0 },
-    display_debug_str,                 0,      0 },
-  { { ".debug_loc",            NULL,   0,      0 },
-    display_debug_loc,                 0,      0 },
-  { { ".debug_pubtypes",       NULL,   0,      0 },
-    display_debug_pubnames,            0,      0 },
-  { { ".debug_ranges",         NULL,   0,      0 },
-    display_debug_ranges,              0,      0 },
-  { { ".debug_static_func",    NULL,   0,      0 },
-    display_debug_not_supported,       0,      0 },
-  { { ".debug_static_vars",    NULL,   0,      0 },
-    display_debug_not_supported,       0,      0 },
-  { { ".debug_types",          NULL,   0,      0 },
-    display_debug_not_supported,       0,      0 },
-  { { ".debug_weaknames",      NULL,   0,      0 },
-    display_debug_not_supported,       0,      0 }
+  { { ".debug_abbrev",         ".zdebug_abbrev",       NULL, NULL, 0, 0 },
+    display_debug_abbrev,              &do_debug_abbrevs,      0 },
+  { { ".debug_aranges",                ".zdebug_aranges",      NULL, NULL, 0, 0 },
+    display_debug_aranges,             &do_debug_aranges,      1 },
+  { { ".debug_frame",          ".zdebug_frame",        NULL, NULL, 0, 0 },
+    display_debug_frames,              &do_debug_frames,       1 },
+  { { ".debug_info",           ".zdebug_info",         NULL, NULL, 0, 0 },
+    display_debug_info,                        &do_debug_info,         1 },
+  { { ".debug_line",           ".zdebug_line",         NULL, NULL, 0, 0 },
+    display_debug_lines,               &do_debug_lines,        1 },
+  { { ".debug_pubnames",       ".zdebug_pubnames",     NULL, NULL, 0, 0 },
+    display_debug_pubnames,            &do_debug_pubnames,     0 },
+  { { ".eh_frame",             "",                     NULL, NULL, 0, 0 },
+    display_debug_frames,              &do_debug_frames,       1 },
+  { { ".debug_macinfo",                ".zdebug_macinfo",      NULL, NULL, 0, 0 },
+    display_debug_macinfo,             &do_debug_macinfo,      0 },
+  { { ".debug_str",            ".zdebug_str",          NULL, NULL, 0, 0 },
+    display_debug_str,                 &do_debug_str,          0 },
+  { { ".debug_loc",            ".zdebug_loc",          NULL, NULL, 0, 0 },
+    display_debug_loc,                 &do_debug_loc,          1 },
+  { { ".debug_pubtypes",       ".zdebug_pubtypes",     NULL, NULL, 0, 0 },
+    display_debug_pubnames,            &do_debug_pubtypes,     0 },
+  { { ".debug_ranges",         ".zdebug_ranges",       NULL, NULL, 0, 0 },
+    display_debug_ranges,              &do_debug_ranges,       1 },
+  { { ".debug_static_func",    ".zdebug_static_func",  NULL, NULL, 0, 0 },
+    display_debug_not_supported,       NULL,                   0 },
+  { { ".debug_static_vars",    ".zdebug_static_vars",  NULL, NULL, 0, 0 },
+    display_debug_not_supported,       NULL,                   0 },
+  { { ".debug_types",          ".zdebug_types",        NULL, NULL, 0, 0 },
+    display_debug_types,               &do_debug_info,         1 },
+  { { ".debug_weaknames",      ".zdebug_weaknames",    NULL, NULL, 0, 0 },
+    display_debug_not_supported,       NULL,                   0 },
+  { { ".gdb_index",            "",                     NULL, NULL, 0, 0 },
+    display_gdb_index,                 &do_gdb_index,          0 },
+  { { ".trace_info",           "",                     NULL, NULL, 0, 0 },
+    display_trace_info,                        &do_trace_info,         1 },
+  { { ".trace_abbrev",         "",                     NULL, NULL, 0, 0 },
+    display_debug_abbrev,              &do_trace_abbrevs,      0 },
+  { { ".trace_aranges",                "",                     NULL, NULL, 0, 0 },
+    display_debug_aranges,             &do_trace_aranges,      0 }
 };
This page took 0.073488 seconds and 4 git commands to generate.