BZ 615
authorNick Clifton <nickc@redhat.com>
Tue, 4 Jan 2005 11:20:45 +0000 (11:20 +0000)
committerNick Clifton <nickc@redhat.com>
Tue, 4 Jan 2005 11:20:45 +0000 (11:20 +0000)
* readelf.c (process_debug_info): New.
(debug_info): Add num_loc_offsets, loc_offsets and
last_loc_offset_p.
(get_debug_info): Use process_debug_info.
(display_debug_loc): Properly handle location list. Warn if bad
location lists are encoutnered.
(read_and_process_attr_value): New.
(read_and_display_attr_value): Use "%lx" for DW_FORM_data4.
(display_debug_info): Use process_debug_info.
(process_object): Also free loc_offsets in debug_information.

binutils/ChangeLog
binutils/readelf.c

index e2bbebf95f8fc6941eedc3cf4042023bf81e0446..ad750ebfc2eb38977005a7efc2973b475ca08304 100644 (file)
@@ -1,3 +1,17 @@
+2005-01-04  H.J. Lu  <hongjiu.lu@intel.com>
+
+       BZ 615
+       * readelf.c (process_debug_info): New.
+       (debug_info): Add num_loc_offsets, loc_offsets and
+       last_loc_offset_p.
+       (get_debug_info): Use process_debug_info.
+       (display_debug_loc): Properly handle location list. Warn if bad
+       location lists are encoutnered.
+       (read_and_process_attr_value): New.
+       (read_and_display_attr_value): Use "%lx" for DW_FORM_data4.
+       (display_debug_info): Use process_debug_info.
+       (process_object): Also free loc_offsets in debug_information.
+
 2004-12-31  Alan Modra  <amodra@bigpond.net.au>
 
        * objdump.c (remove_useless_symbols): Discard section symbols.
@@ -6,6 +20,25 @@
 
        * readelf.c (read_leb128): Support 64bit host.
 
+2004-12-23  Nick Clifton  <nickc@redhat.com>
+
+       PR binutils/616
+       * readelf.c (debug_info): Add 'cu_offset' field.
+       (get+pointer_size_of_comp_unit): Rename to
+       'get_pointer_size_and_offset_of_comp_unit'.  Add code to return
+       the offset of the comp_unit if requested.
+       (get_debug_info): Record comp_unit offsets as well.
+       (display_debug_lines): Call get_pointer_size_of_comp_unit.
+       (decode_location_expression): Add an extra parameter - the offset
+       of the current comp-unit.  Use this when decoding the DW_OP_call2
+       and DW_OP_call4 operators.
+       (display_debug_loc): Call get_pointer_size_of_comp_unit, pass the
+       comp_unit offset on the decode_location_expression.
+       (read_and_display_attr_value): Pass the comp_unit offset on the
+       decode_location_expression.
+       (display_debug_frames): Pass 0 as the comp_unit offset to
+       decode_location_expression.
+       
 2004-12-22  Nick Clifton  <nickc@redhat.com>
 
        * readelf.c (last_pointer_size, warned_about_missing_comp_units):
index 6cecdc34804bfda5f5057f8c79bbfd00a2317080..d81907caebcc6ba8b160b44cb5a54334cb0c1a9f 100644 (file)
@@ -1,5 +1,5 @@
 /* readelf.c -- display contents of an ELF format file
-   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004
+   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
    Free Software Foundation, Inc.
 
    Originally developed by Eric Youngdale <eric@andante.jic.com>
@@ -7068,527 +7068,360 @@ find_section (const char * name)
   return NULL;
 }
 
-/* This could just be an array of unsigned integers, but I expect
-   that we will want to extend the structure to contain other
-   information.  */
-typedef struct
+static const char *debug_str_contents;
+static bfd_vma debug_str_size;
+
+static void
+load_debug_str (FILE *file)
 {
-  unsigned int pointer_size;
-}
-debug_info;
+  Elf_Internal_Shdr *sec;
 
-static debug_info *   debug_information = NULL;
-static unsigned int   num_debug_info_entries = 0;
-static unsigned int   last_pointer_size = 0;
-static int            warned_about_missing_comp_units = FALSE;
+  /* If it is already loaded, do nothing.  */
+  if (debug_str_contents != NULL)
+    return;
 
-static unsigned int
-get_pointer_size_of_comp_unit (unsigned int comp_unit,
-                              const char * section_name)
+  /* Locate the .debug_str section.  */
+  sec = find_section (".debug_str");
+  if (sec == NULL)
+    return;
+
+  debug_str_size = sec->sh_size;
+
+  debug_str_contents = get_data (NULL, file, sec->sh_offset, sec->sh_size,
+                                _("debug_str section data"));
+}
+
+static void
+free_debug_str (void)
 {
-  if (num_debug_info_entries == 0)
-    {
-      error (_("%s section needs a populated .debug_info section\n"),
-            section_name);
-      return 0;
-    }
+  if (debug_str_contents == NULL)
+    return;
 
-  if (comp_unit >= num_debug_info_entries)
-    {
-      if (!warned_about_missing_comp_units)
-       {
-         warn (_("%s section has more comp units than .debug_info section\n"),
-               section_name);
-         warn (_("assuming that the pointer size is %d, from the last comp unit in .debug_info\n\n"),
-               last_pointer_size);
-         warned_about_missing_comp_units = TRUE;
-       }
-    }
-  else
-    last_pointer_size = debug_information [comp_unit].pointer_size;
+  free ((char *) debug_str_contents);
+  debug_str_contents = NULL;
+  debug_str_size = 0;
+}
 
-  return last_pointer_size;
+static const char *
+fetch_indirect_string (unsigned long offset)
+{
+  if (debug_str_contents == NULL)
+    return _("<no .debug_str section>");
+
+  if (offset > debug_str_size)
+    return _("<offset is too big>");
 
+  return debug_str_contents + offset;
 }
 
-/* Locate and scan the .debug_info section in the file and record the pointer
-   sizes for the compilation units in it.  Usually an executable will have
-   just one pointer size, but this is not guaranteed, and so we try not to
-   make any assumptions.  Returns zero upon failure, or the number of
-   compilation units upon success.  */
+static const char *debug_loc_contents;
+static bfd_vma debug_loc_size;
 
-static unsigned int
-get_debug_info (FILE * file)
+static void
+load_debug_loc (FILE *file)
 {
-  Elf_Internal_Shdr * section;
-  unsigned char *     start;
-  unsigned char *     end;
-  unsigned char *     begin;
-  unsigned long       length;
-  unsigned int        num_units;
-  unsigned int        unit;
-
-  /* Reset the last pointer size so that we can issue correct
-     error messages if we are displaying the contents of more
-     than one file.  */
-  last_pointer_size = 0;
-  warned_about_missing_comp_units = FALSE;
+  Elf_Internal_Shdr *sec;
 
-  /* If we already have the information there is nothing else to do.  */
-  if (num_debug_info_entries > 0)
-    return num_debug_info_entries;
+  /* If it is already loaded, do nothing.  */
+  if (debug_loc_contents != NULL)
+    return;
 
-  section = find_section (".debug_info");
-  if (section == NULL)
-    return 0;
+  /* Locate the .debug_loc section.  */
+  sec = find_section (".debug_loc");
+  if (sec == NULL)
+    return;
 
-  length = section->sh_size;
-  start = get_data (NULL, file, section->sh_offset, section->sh_size,
-                   _("extracting information from .debug_info section"));
-  if (start == NULL)
-    return 0;
+  debug_loc_size = sec->sh_size;
 
-  end = start + section->sh_size;
-  /* First scan the section to get the number of comp units.  */
-  for (begin = start, num_units = 0; begin < end; num_units++)
-    {
-      /* Read the first 4 bytes.  For a 32-bit DWARF section, this will
-        be the length.  For a 64-bit DWARF section, it'll be the escape
-        code 0xffffffff followed by an 8 byte length.  */
-      length = byte_get (begin, 4);
+  debug_loc_contents = get_data (NULL, file, sec->sh_offset, sec->sh_size,
+                                _("debug_loc section data"));
+}
 
-      if (length == 0xffffffff)
-       {
-         length = byte_get (begin + 4, 8);
-         begin += length + 12;
-       }
-      else
-       begin += length + 4;
-    }
+static void
+free_debug_loc (void)
+{
+  if (debug_loc_contents == NULL)
+    return;
 
-  if (num_units == 0)
-    {
-      error (_("No comp units in .debug_info section ?"));
-      free (start);
-      return 0;
-    }
+  free ((char *) debug_loc_contents);
+  debug_loc_contents = NULL;
+  debug_loc_size = 0;
+}
 
-  /* Then allocate an array to hold the information.  */
-  debug_information = malloc (num_units * sizeof * debug_information);
-  if (debug_information == NULL)
-    {
-      error (_("Not enough memory for a debug info array of %u entries"),
-            num_units);
-      free (start);
-      return 0;
-    }
+static const char *   debug_range_contents;
+static unsigned long  debug_range_size;
 
-  /* Populate the array.  */
-  for (begin = start, unit = 0; begin < end; unit++)
-    {
-      length = byte_get (begin, 4);
-      if (length == 0xffffffff)
-       {
-         /* For 64-bit DWARF, the 1-byte address_size field is 22 bytes
-            from the start of the section.  This is computed as follows:
+static void
+load_debug_range (FILE *file)
+{
+  Elf_Internal_Shdr *sec;
 
-            unit_length:         12 bytes
-            version:              2 bytes
-            debug_abbrev_offset:  8 bytes
-            -----------------------------
-            Total:               22 bytes  */
+  /* If it is already loaded, do nothing.  */
+  if (debug_range_contents != NULL)
+    return;
 
-         debug_information [unit].pointer_size = byte_get (begin + 22, 1);
-         length = byte_get (begin + 4, 8);
-         begin += length + 12;
-       }
-      else
-       {
-         /* For 32-bit DWARF, the 1-byte address_size field is 10 bytes from
-            the start of the section:
+  /* Locate the .debug_str section.  */
+  sec = find_section (".debug_ranges");
+  if (sec == NULL)
+    return;
 
-            unit_length:          4 bytes
-            version:              2 bytes
-            debug_abbrev_offset:  4 bytes
-            -----------------------------
-            Total:               10 bytes  */
+  debug_range_size = sec->sh_size;
 
-         debug_information [unit].pointer_size = byte_get (begin + 10, 1);
-         begin += length + 4;
-       }
-    }
+  debug_range_contents = get_data (NULL, file, sec->sh_offset, sec->sh_size,
+                                  _("debug_range section data"));
+}
 
-  free (start);
+static void
+free_debug_range (void)
+{
+  if (debug_range_contents == NULL)
+    return;
 
-  return num_debug_info_entries = num_units;
+  free ((char *) debug_range_contents);
+  debug_range_contents = NULL;
+  debug_range_size = 0;
 }
 
+/* Apply addends of RELA relocations.  */
+
 static int
-display_debug_lines (Elf_Internal_Shdr *section,
-                    unsigned char *start, FILE *file)
+debug_apply_rela_addends (FILE *file,
+                         Elf_Internal_Shdr *section,
+                         int reloc_size,
+                         unsigned char *sec_data,
+                         unsigned char *start,
+                         unsigned char *end)
 {
-  unsigned char *data = start;
-  unsigned char *end = start + section->sh_size;
-  unsigned int comp_unit = 0;
-
-  printf (_("\nDump of debug contents of section %s:\n\n"),
-         SECTION_NAME (section));
+  Elf_Internal_Shdr *relsec;
 
-  get_debug_info (file);
+  if (end - start < reloc_size)
+    return 1;
 
-  while (data < end)
+  for (relsec = section_headers;
+       relsec < section_headers + elf_header.e_shnum;
+       ++relsec)
     {
-      DWARF2_Internal_LineInfo info;
-      unsigned char *standard_opcodes;
-      unsigned char *end_of_sequence;
-      unsigned char *hdrptr;
-      unsigned int pointer_size;
-      int initial_length_size;
-      int offset_size;
-      int i;
-
-      hdrptr = data;
+      unsigned long nrelas;
+      Elf_Internal_Rela *rela, *rp;
+      Elf_Internal_Shdr *symsec;
+      Elf_Internal_Sym *symtab;
+      Elf_Internal_Sym *sym;
 
-      /* Check the length of the block.  */
-      info.li_length = byte_get (hdrptr, 4);
-      hdrptr += 4;
+      if (relsec->sh_type != SHT_RELA
+         || SECTION_HEADER (relsec->sh_info) != section
+         || relsec->sh_size == 0)
+       continue;
 
-      if (info.li_length == 0xffffffff)
-       {
-         /* This section is 64-bit DWARF 3.  */
-         info.li_length = byte_get (hdrptr, 8);
-         hdrptr += 8;
-         offset_size = 8;
-         initial_length_size = 12;
-       }
-      else
-       {
-         offset_size = 4;
-         initial_length_size = 4;
-       }
+      if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size,
+                             &rela, &nrelas))
+       return 0;
 
-      if (info.li_length + initial_length_size > section->sh_size)
-       {
-         warn
-           (_("The line info appears to be corrupt - the section is too small\n"));
-         return 0;
-       }
+      symsec = SECTION_HEADER (relsec->sh_link);
+      symtab = GET_ELF_SYMBOLS (file, symsec);
 
-      /* Check its version number.  */
-      info.li_version = byte_get (hdrptr, 2);
-      hdrptr += 2;
-      if (info.li_version != 2 && info.li_version != 3)
+      for (rp = rela; rp < rela + nrelas; ++rp)
        {
-         warn (_("Only DWARF version 2 and 3 line info is currently supported.\n"));
-         return 0;
-       }
+         unsigned char *loc;
 
-      info.li_prologue_length = byte_get (hdrptr, offset_size);
-      hdrptr += offset_size;
-      info.li_min_insn_length = byte_get (hdrptr, 1);
-      hdrptr++;
-      info.li_default_is_stmt = byte_get (hdrptr, 1);
-      hdrptr++;
-      info.li_line_base = byte_get (hdrptr, 1);
-      hdrptr++;
-      info.li_line_range = byte_get (hdrptr, 1);
-      hdrptr++;
-      info.li_opcode_base = byte_get (hdrptr, 1);
-      hdrptr++;
+         if (rp->r_offset >= (bfd_vma) (start - sec_data)
+             && rp->r_offset < (bfd_vma) (end - sec_data) - reloc_size)
+           loc = sec_data + rp->r_offset;
+         else
+           continue;
 
-      /* Sign extend the line base field.  */
-      info.li_line_base <<= 24;
-      info.li_line_base >>= 24;
+         if (is_32bit_elf)
+           {
+             sym = symtab + ELF32_R_SYM (rp->r_info);
 
-      /* Get the pointer size from the comp unit associated
-        with this block of line number information.  */
-      pointer_size = get_pointer_size_of_comp_unit (comp_unit,
-                                                   ".debug_lines");
-      comp_unit ++;
+             if (ELF32_R_SYM (rp->r_info) != 0
+                 && ELF32_ST_TYPE (sym->st_info) != STT_SECTION
+                 /* Relocations against object symbols can happen,
+                    eg when referencing a global array.  For an
+                    example of this see the _clz.o binary in libgcc.a.  */
+                 && ELF32_ST_TYPE (sym->st_info) != STT_OBJECT)
+               {
+                 warn (_("%s: skipping unexpected symbol type %s in relocation in section .rela%s\n"),
+                       get_symbol_type (ELF32_ST_TYPE (sym->st_info)),
+                       SECTION_NAME (section));
+                 continue;
+               }
+           }
+         else
+           {
+             sym = symtab + ELF64_R_SYM (rp->r_info);
 
-      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 (_("  (Pointer size:               %u)\n"), pointer_size);
+             if (ELF64_R_SYM (rp->r_info) != 0
+                 && ELF64_ST_TYPE (sym->st_info) != STT_SECTION
+                 && ELF64_ST_TYPE (sym->st_info) != STT_OBJECT)
+               {
+                 warn (_("skipping unexpected symbol type %s in relocation in section .rela.%s\n"),
+                       get_symbol_type (ELF64_ST_TYPE (sym->st_info)),
+                       SECTION_NAME (section));
+                 continue;
+               }
+           }
 
-      end_of_sequence = data + info.li_length + initial_length_size;
+         byte_put (loc, rp->r_addend, reloc_size);
+       }
 
-      reset_state_machine (info.li_default_is_stmt);
+      free (symtab);
+      free (rela);
+      break;
+    }
+  return 1;
+}
 
-      /* Display the contents of the Opcodes table.  */
-      standard_opcodes = hdrptr;
+/* FIXME:  There are better and more efficient ways to handle
+   these structures.  For now though, I just want something that
+   is simple to implement.  */
+typedef struct abbrev_attr
+{
+  unsigned long attribute;
+  unsigned long form;
+  struct abbrev_attr *next;
+}
+abbrev_attr;
 
-      printf (_("\n Opcodes:\n"));
+typedef struct abbrev_entry
+{
+  unsigned long entry;
+  unsigned long tag;
+  int children;
+  struct abbrev_attr *first_attr;
+  struct abbrev_attr *last_attr;
+  struct abbrev_entry *next;
+}
+abbrev_entry;
 
-      for (i = 1; i < info.li_opcode_base; i++)
-       printf (_("  Opcode %d has %d args\n"), i, standard_opcodes[i - 1]);
+static abbrev_entry *first_abbrev = NULL;
+static abbrev_entry *last_abbrev = NULL;
 
-      /* Display the contents of the Directory table.  */
-      data = standard_opcodes + info.li_opcode_base - 1;
+static void
+free_abbrevs (void)
+{
+  abbrev_entry *abbrev;
 
-      if (*data == 0)
-       printf (_("\n The Directory Table is empty.\n"));
-      else
-       {
-         printf (_("\n The Directory Table:\n"));
+  for (abbrev = first_abbrev; abbrev;)
+    {
+      abbrev_entry *next = abbrev->next;
+      abbrev_attr *attr;
 
-         while (*data != 0)
-           {
-             printf (_("  %s\n"), data);
+      for (attr = abbrev->first_attr; attr;)
+       {
+         abbrev_attr *next = attr->next;
 
-             data += strlen ((char *) data) + 1;
-           }
+         free (attr);
+         attr = next;
        }
 
-      /* Skip the NUL at the end of the table.  */
-      data++;
+      free (abbrev);
+      abbrev = next;
+    }
 
-      /* Display the contents of the File Name table.  */
-      if (*data == 0)
-       printf (_("\n The File Name Table is empty.\n"));
-      else
-       {
-         printf (_("\n The File Name Table:\n"));
-         printf (_("  Entry\tDir\tTime\tSize\tName\n"));
+  last_abbrev = first_abbrev = NULL;
+}
 
-         while (*data != 0)
-           {
-             unsigned char *name;
-             int bytes_read;
+static void
+add_abbrev (unsigned long number, unsigned long tag, int children)
+{
+  abbrev_entry *entry;
 
-             printf (_("  %d\t"), ++state_machine_regs.last_file_entry);
-             name = data;
+  entry = malloc (sizeof (*entry));
 
-             data += strlen ((char *) data) + 1;
+  if (entry == NULL)
+    /* ugg */
+    return;
 
-             printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0));
-             data += bytes_read;
-             printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0));
-             data += bytes_read;
-             printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0));
-             data += bytes_read;
-             printf (_("%s\n"), name);
-           }
-       }
+  entry->entry      = number;
+  entry->tag        = tag;
+  entry->children   = children;
+  entry->first_attr = NULL;
+  entry->last_attr  = NULL;
+  entry->next       = NULL;
 
-      /* Skip the NUL at the end of the table.  */
-      data++;
+  if (first_abbrev == NULL)
+    first_abbrev = entry;
+  else
+    last_abbrev->next = entry;
 
-      /* Now display the statements.  */
-      printf (_("\n Line Number Statements:\n"));
+  last_abbrev = entry;
+}
 
-      while (data < end_of_sequence)
-       {
-         unsigned char op_code;
-         int adv;
-         int bytes_read;
+static void
+add_abbrev_attr (unsigned long attribute, unsigned long form)
+{
+  abbrev_attr *attr;
 
-         op_code = *data++;
+  attr = malloc (sizeof (*attr));
 
-         if (op_code >= info.li_opcode_base)
-           {
-             op_code -= info.li_opcode_base;
-             adv      = (op_code / info.li_line_range) * info.li_min_insn_length;
-             state_machine_regs.address += adv;
-             printf (_("  Special opcode %d: advance Address by %d to 0x%lx"),
-                     op_code, adv, state_machine_regs.address);
-             adv = (op_code % info.li_line_range) + info.li_line_base;
-             state_machine_regs.line += adv;
-             printf (_(" and Line by %d to %d\n"),
-                     adv, state_machine_regs.line);
-           }
-         else switch (op_code)
-           {
-           case DW_LNS_extended_op:
-             data += process_extended_line_op (data, info.li_default_is_stmt,
-                                               pointer_size);
-             break;
+  if (attr == NULL)
+    /* ugg */
+    return;
 
-           case DW_LNS_copy:
-             printf (_("  Copy\n"));
-             break;
+  attr->attribute = attribute;
+  attr->form      = form;
+  attr->next      = NULL;
 
-           case DW_LNS_advance_pc:
-             adv = info.li_min_insn_length * read_leb128 (data, & bytes_read, 0);
-             data += bytes_read;
-             state_machine_regs.address += adv;
-             printf (_("  Advance PC by %d to %lx\n"), adv,
-                     state_machine_regs.address);
-             break;
+  if (last_abbrev->first_attr == NULL)
+    last_abbrev->first_attr = attr;
+  else
+    last_abbrev->last_attr->next = attr;
 
-           case DW_LNS_advance_line:
-             adv = read_leb128 (data, & bytes_read, 1);
-             data += bytes_read;
-             state_machine_regs.line += adv;
-             printf (_("  Advance Line by %d to %d\n"), adv,
-                     state_machine_regs.line);
-             break;
+  last_abbrev->last_attr = attr;
+}
 
-           case DW_LNS_set_file:
-             adv = read_leb128 (data, & bytes_read, 0);
-             data += bytes_read;
-             printf (_("  Set File Name to entry %d in the File Name Table\n"),
-                     adv);
-             state_machine_regs.file = adv;
-             break;
+/* Processes the (partial) contents of a .debug_abbrev section.
+   Returns NULL if the end of the section was encountered.
+   Returns the address after the last byte read if the end of
+   an abbreviation set was found.  */
 
-           case DW_LNS_set_column:
-             adv = read_leb128 (data, & bytes_read, 0);
-             data += bytes_read;
-             printf (_("  Set column to %d\n"), adv);
-             state_machine_regs.column = adv;
-             break;
+static unsigned char *
+process_abbrev_section (unsigned char *start, unsigned char *end)
+{
+  if (first_abbrev != NULL)
+    return NULL;
 
-           case DW_LNS_negate_stmt:
-             adv = state_machine_regs.is_stmt;
-             adv = ! adv;
-             printf (_("  Set is_stmt to %d\n"), adv);
-             state_machine_regs.is_stmt = adv;
-             break;
+  while (start < end)
+    {
+      int bytes_read;
+      unsigned long entry;
+      unsigned long tag;
+      unsigned long attribute;
+      int children;
 
-           case DW_LNS_set_basic_block:
-             printf (_("  Set basic block\n"));
-             state_machine_regs.basic_block = 1;
-             break;
+      entry = read_leb128 (start, & bytes_read, 0);
+      start += bytes_read;
 
-           case DW_LNS_const_add_pc:
-             adv = (((255 - info.li_opcode_base) / info.li_line_range)
-                    * info.li_min_insn_length);
-             state_machine_regs.address += adv;
-             printf (_("  Advance PC by constant %d to 0x%lx\n"), adv,
-                     state_machine_regs.address);
-             break;
-
-           case DW_LNS_fixed_advance_pc:
-             adv = byte_get (data, 2);
-             data += 2;
-             state_machine_regs.address += adv;
-             printf (_("  Advance PC by fixed size amount %d to 0x%lx\n"),
-                     adv, state_machine_regs.address);
-             break;
-
-           case DW_LNS_set_prologue_end:
-             printf (_("  Set prologue_end to true\n"));
-             break;
-
-           case DW_LNS_set_epilogue_begin:
-             printf (_("  Set epilogue_begin to true\n"));
-             break;
-
-           case DW_LNS_set_isa:
-             adv = read_leb128 (data, & bytes_read, 0);
-             data += bytes_read;
-             printf (_("  Set ISA to %d\n"), adv);
-             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;
-           }
-       }
-      putchar ('\n');
-    }
-
-  return 1;
-}
-
-static int
-display_debug_pubnames (Elf_Internal_Shdr *section,
-                       unsigned char *start,
-                       FILE *file ATTRIBUTE_UNUSED)
-{
-  DWARF2_Internal_PubNames pubnames;
-  unsigned char *end;
-
-  end = start + section->sh_size;
-
-  printf (_("Contents of the %s section:\n\n"), SECTION_NAME (section));
-
-  while (start < end)
-    {
-      unsigned char *data;
-      unsigned long offset;
-      int offset_size, initial_length_size;
-
-      data = start;
+      /* A single zero is supposed to end the section according
+        to the standard.  If there's more, then signal that to
+        the caller.  */
+      if (entry == 0)
+       return start == end ? NULL : start;
 
-      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;
-       }
+      tag = read_leb128 (start, & bytes_read, 0);
+      start += bytes_read;
 
-      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;
+      children = *start++;
 
-      start += pubnames.pn_length + initial_length_size;
+      add_abbrev (entry, tag, children);
 
-      if (pubnames.pn_version != 2 && pubnames.pn_version != 3)
+      do
        {
-         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);
-      printf (_("  Version:                             %d\n"),
-             pubnames.pn_version);
-      printf (_("  Offset into .debug_info section:     %ld\n"),
-             pubnames.pn_offset);
-      printf (_("  Size of area in .debug_info section: %ld\n"),
-             pubnames.pn_size);
+         unsigned long form;
 
-      printf (_("\n    Offset\tName\n"));
+         attribute = read_leb128 (start, & bytes_read, 0);
+         start += bytes_read;
 
-      do
-       {
-         offset = byte_get (data, offset_size);
+         form = read_leb128 (start, & bytes_read, 0);
+         start += bytes_read;
 
-         if (offset != 0)
-           {
-             data += offset_size;
-             printf ("    %-6ld\t\t%s\n", offset, data);
-             data += strlen ((char *) data) + 1;
-           }
+         if (attribute != 0)
+           add_abbrev_attr (attribute, form);
        }
-      while (offset != 0);
+      while (attribute != 0);
     }
 
-  printf ("\n");
-  return 1;
+  return NULL;
 }
 
 static char *
@@ -7671,119 +7504,6 @@ get_TAG_name (unsigned long tag)
     }
 }
 
-static char *
-get_AT_name (unsigned long attribute)
-{
-  switch (attribute)
-    {
-    case DW_AT_sibling:                        return "DW_AT_sibling";
-    case DW_AT_location:               return "DW_AT_location";
-    case DW_AT_name:                   return "DW_AT_name";
-    case DW_AT_ordering:               return "DW_AT_ordering";
-    case DW_AT_subscr_data:            return "DW_AT_subscr_data";
-    case DW_AT_byte_size:              return "DW_AT_byte_size";
-    case DW_AT_bit_offset:             return "DW_AT_bit_offset";
-    case DW_AT_bit_size:               return "DW_AT_bit_size";
-    case DW_AT_element_list:           return "DW_AT_element_list";
-    case DW_AT_stmt_list:              return "DW_AT_stmt_list";
-    case DW_AT_low_pc:                 return "DW_AT_low_pc";
-    case DW_AT_high_pc:                        return "DW_AT_high_pc";
-    case DW_AT_language:               return "DW_AT_language";
-    case DW_AT_member:                 return "DW_AT_member";
-    case DW_AT_discr:                  return "DW_AT_discr";
-    case DW_AT_discr_value:            return "DW_AT_discr_value";
-    case DW_AT_visibility:             return "DW_AT_visibility";
-    case DW_AT_import:                 return "DW_AT_import";
-    case DW_AT_string_length:          return "DW_AT_string_length";
-    case DW_AT_common_reference:       return "DW_AT_common_reference";
-    case DW_AT_comp_dir:               return "DW_AT_comp_dir";
-    case DW_AT_const_value:            return "DW_AT_const_value";
-    case DW_AT_containing_type:                return "DW_AT_containing_type";
-    case DW_AT_default_value:          return "DW_AT_default_value";
-    case DW_AT_inline:                 return "DW_AT_inline";
-    case DW_AT_is_optional:            return "DW_AT_is_optional";
-    case DW_AT_lower_bound:            return "DW_AT_lower_bound";
-    case DW_AT_producer:               return "DW_AT_producer";
-    case DW_AT_prototyped:             return "DW_AT_prototyped";
-    case DW_AT_return_addr:            return "DW_AT_return_addr";
-    case DW_AT_start_scope:            return "DW_AT_start_scope";
-    case DW_AT_stride_size:            return "DW_AT_stride_size";
-    case DW_AT_upper_bound:            return "DW_AT_upper_bound";
-    case DW_AT_abstract_origin:                return "DW_AT_abstract_origin";
-    case DW_AT_accessibility:          return "DW_AT_accessibility";
-    case DW_AT_address_class:          return "DW_AT_address_class";
-    case DW_AT_artificial:             return "DW_AT_artificial";
-    case DW_AT_base_types:             return "DW_AT_base_types";
-    case DW_AT_calling_convention:     return "DW_AT_calling_convention";
-    case DW_AT_count:                  return "DW_AT_count";
-    case DW_AT_data_member_location:   return "DW_AT_data_member_location";
-    case DW_AT_decl_column:            return "DW_AT_decl_column";
-    case DW_AT_decl_file:              return "DW_AT_decl_file";
-    case DW_AT_decl_line:              return "DW_AT_decl_line";
-    case DW_AT_declaration:            return "DW_AT_declaration";
-    case DW_AT_discr_list:             return "DW_AT_discr_list";
-    case DW_AT_encoding:               return "DW_AT_encoding";
-    case DW_AT_external:               return "DW_AT_external";
-    case DW_AT_frame_base:             return "DW_AT_frame_base";
-    case DW_AT_friend:                 return "DW_AT_friend";
-    case DW_AT_identifier_case:                return "DW_AT_identifier_case";
-    case DW_AT_macro_info:             return "DW_AT_macro_info";
-    case DW_AT_namelist_items:         return "DW_AT_namelist_items";
-    case DW_AT_priority:               return "DW_AT_priority";
-    case DW_AT_segment:                        return "DW_AT_segment";
-    case DW_AT_specification:          return "DW_AT_specification";
-    case DW_AT_static_link:            return "DW_AT_static_link";
-    case DW_AT_type:                   return "DW_AT_type";
-    case DW_AT_use_location:           return "DW_AT_use_location";
-    case DW_AT_variable_parameter:     return "DW_AT_variable_parameter";
-    case DW_AT_virtuality:             return "DW_AT_virtuality";
-    case DW_AT_vtable_elem_location:   return "DW_AT_vtable_elem_location";
-      /* DWARF 2.1 values.  */
-    case DW_AT_allocated:              return "DW_AT_allocated";
-    case DW_AT_associated:             return "DW_AT_associated";
-    case DW_AT_data_location:          return "DW_AT_data_location";
-    case DW_AT_stride:                 return "DW_AT_stride";
-    case DW_AT_entry_pc:               return "DW_AT_entry_pc";
-    case DW_AT_use_UTF8:               return "DW_AT_use_UTF8";
-    case DW_AT_extension:              return "DW_AT_extension";
-    case DW_AT_ranges:                 return "DW_AT_ranges";
-    case DW_AT_trampoline:             return "DW_AT_trampoline";
-    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";
-      /* 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";
-      /* UPC extension.  */
-    case DW_AT_upc_threads_scaled:     return "DW_AT_upc_threads_scaled";
-    default:
-      {
-       static char buffer[100];
-
-       sprintf (buffer, _("Unknown AT value: %lx"), attribute);
-       return buffer;
-      }
-    }
-}
-
 static char *
 get_FORM_name (unsigned long form)
 {
@@ -7820,325 +7540,51 @@ get_FORM_name (unsigned long form)
     }
 }
 
-/* FIXME:  There are better and more efficient ways to handle
-   these structures.  For now though, I just want something that
-   is simple to implement.  */
-typedef struct abbrev_attr
+static unsigned char *
+display_block (unsigned char *data, unsigned long length)
 {
-  unsigned long attribute;
-  unsigned long form;
-  struct abbrev_attr *next;
-}
-abbrev_attr;
-
-typedef struct abbrev_entry
-{
-  unsigned long entry;
-  unsigned long tag;
-  int children;
-  struct abbrev_attr *first_attr;
-  struct abbrev_attr *last_attr;
-  struct abbrev_entry *next;
-}
-abbrev_entry;
-
-static abbrev_entry *first_abbrev = NULL;
-static abbrev_entry *last_abbrev = NULL;
-
-static void
-free_abbrevs (void)
-{
-  abbrev_entry *abbrev;
-
-  for (abbrev = first_abbrev; abbrev;)
-    {
-      abbrev_entry *next = abbrev->next;
-      abbrev_attr *attr;
-
-      for (attr = abbrev->first_attr; attr;)
-       {
-         abbrev_attr *next = attr->next;
-
-         free (attr);
-         attr = next;
-       }
-
-      free (abbrev);
-      abbrev = next;
-    }
-
-  last_abbrev = first_abbrev = NULL;
-}
-
-static void
-add_abbrev (unsigned long number, unsigned long tag, int children)
-{
-  abbrev_entry *entry;
-
-  entry = malloc (sizeof (*entry));
-
-  if (entry == NULL)
-    /* ugg */
-    return;
-
-  entry->entry      = number;
-  entry->tag        = tag;
-  entry->children   = children;
-  entry->first_attr = NULL;
-  entry->last_attr  = NULL;
-  entry->next       = NULL;
+  printf (_(" %lu byte block: "), length);
 
-  if (first_abbrev == NULL)
-    first_abbrev = entry;
-  else
-    last_abbrev->next = entry;
+  while (length --)
+    printf ("%lx ", (unsigned long) byte_get (data++, 1));
 
-  last_abbrev = entry;
+  return data;
 }
 
 static void
-add_abbrev_attr (unsigned long attribute, unsigned long form)
-{
-  abbrev_attr *attr;
-
-  attr = malloc (sizeof (*attr));
-
-  if (attr == NULL)
-    /* ugg */
-    return;
-
-  attr->attribute = attribute;
-  attr->form      = form;
-  attr->next      = NULL;
-
-  if (last_abbrev->first_attr == NULL)
-    last_abbrev->first_attr = attr;
-  else
-    last_abbrev->last_attr->next = attr;
-
-  last_abbrev->last_attr = attr;
-}
-
-/* Processes the (partial) contents of a .debug_abbrev section.
-   Returns NULL if the end of the section was encountered.
-   Returns the address after the last byte read if the end of
-   an abbreviation set was found.  */
-
-static unsigned char *
-process_abbrev_section (unsigned char *start, unsigned char *end)
-{
-  if (first_abbrev != NULL)
-    return NULL;
-
-  while (start < end)
-    {
-      int bytes_read;
-      unsigned long entry;
-      unsigned long tag;
-      unsigned long attribute;
-      int children;
-
-      entry = read_leb128 (start, & bytes_read, 0);
-      start += bytes_read;
-
-      /* A single zero is supposed to end the section according
-        to the standard.  If there's more, then signal that to
-        the caller.  */
-      if (entry == 0)
-       return start == end ? NULL : start;
-
-      tag = read_leb128 (start, & bytes_read, 0);
-      start += bytes_read;
-
-      children = *start++;
-
-      add_abbrev (entry, tag, children);
-
-      do
-       {
-         unsigned long form;
-
-         attribute = read_leb128 (start, & bytes_read, 0);
-         start += bytes_read;
-
-         form = read_leb128 (start, & bytes_read, 0);
-         start += bytes_read;
-
-         if (attribute != 0)
-           add_abbrev_attr (attribute, form);
-       }
-      while (attribute != 0);
-    }
-
-  return NULL;
-}
-
-
-static int
-display_debug_macinfo (Elf_Internal_Shdr *section,
-                      unsigned char *start,
-                      FILE *file ATTRIBUTE_UNUSED)
+decode_location_expression (unsigned char * data,
+                           unsigned int pointer_size,
+                           unsigned long length,
+                           unsigned long cu_offset)
 {
-  unsigned char *end = start + section->sh_size;
-  unsigned char *curr = start;
-  unsigned int bytes_read;
-  enum dwarf_macinfo_record_type op;
-
-  printf (_("Contents of the %s section:\n\n"), SECTION_NAME (section));
+  unsigned op;
+  int bytes_read;
+  unsigned long uvalue;
+  unsigned char *end = data + length;
 
-  while (curr < end)
+  while (data < end)
     {
-      unsigned int lineno;
-      const char *string;
-
-      op = *curr;
-      curr++;
+      op = *data++;
 
       switch (op)
        {
-       case DW_MACINFO_start_file:
-         {
-           unsigned int filenum;
-
-           lineno = read_leb128 (curr, & bytes_read, 0);
-           curr += bytes_read;
-           filenum = read_leb128 (curr, & bytes_read, 0);
-           curr += bytes_read;
-
-           printf (_(" DW_MACINFO_start_file - lineno: %d filenum: %d\n"),
-                   lineno, filenum);
-         }
+       case DW_OP_addr:
+         printf ("DW_OP_addr: %lx",
+                 (unsigned long) byte_get (data, pointer_size));
+         data += pointer_size;
          break;
-
-       case DW_MACINFO_end_file:
-         printf (_(" DW_MACINFO_end_file\n"));
+       case DW_OP_deref:
+         printf ("DW_OP_deref");
          break;
-
-       case DW_MACINFO_define:
-         lineno = read_leb128 (curr, & bytes_read, 0);
-         curr += bytes_read;
-         string = curr;
-         curr += strlen (string) + 1;
-         printf (_(" DW_MACINFO_define - lineno : %d macro : %s\n"),
-                 lineno, string);
+       case DW_OP_const1u:
+         printf ("DW_OP_const1u: %lu", (unsigned long) byte_get (data++, 1));
          break;
-
-       case DW_MACINFO_undef:
-         lineno = read_leb128 (curr, & bytes_read, 0);
-         curr += bytes_read;
-         string = curr;
-         curr += strlen (string) + 1;
-         printf (_(" DW_MACINFO_undef - lineno : %d macro : %s\n"),
-                 lineno, string);
+       case DW_OP_const1s:
+         printf ("DW_OP_const1s: %ld", (long) byte_get_signed (data++, 1));
          break;
-
-       case DW_MACINFO_vendor_ext:
-         {
-           unsigned int constant;
-
-           constant = read_leb128 (curr, & bytes_read, 0);
-           curr += bytes_read;
-           string = curr;
-           curr += strlen (string) + 1;
-           printf (_(" DW_MACINFO_vendor_ext - constant : %d string : %s\n"),
-                   constant, string);
-         }
-         break;
-       }
-    }
-
-  return 1;
-}
-
-
-static int
-display_debug_abbrev (Elf_Internal_Shdr *section,
-                     unsigned char *start,
-                     FILE *file ATTRIBUTE_UNUSED)
-{
-  abbrev_entry *entry;
-  unsigned char *end = start + section->sh_size;
-
-  printf (_("Contents of the %s section:\n\n"), SECTION_NAME (section));
-
-  do
-    {
-      start = process_abbrev_section (start, end);
-
-      if (first_abbrev == NULL)
-       continue;
-
-      printf (_("  Number TAG\n"));
-
-      for (entry = first_abbrev; entry; entry = entry->next)
-       {
-         abbrev_attr *attr;
-
-         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"),
-                   get_AT_name (attr->attribute),
-                   get_FORM_name (attr->form));
-       }
-
-      free_abbrevs ();
-    }
-  while (start);
-
-  printf ("\n");
-
-  return 1;
-}
-
-
-static unsigned char *
-display_block (unsigned char *data, unsigned long length)
-{
-  printf (_(" %lu byte block: "), length);
-
-  while (length --)
-    printf ("%lx ", (unsigned long) byte_get (data++, 1));
-
-  return data;
-}
-
-static void
-decode_location_expression (unsigned char * data,
-                           unsigned int pointer_size,
-                           unsigned long length)
-{
-  unsigned op;
-  int bytes_read;
-  unsigned long uvalue;
-  unsigned char *end = data + length;
-
-  while (data < end)
-    {
-      op = *data++;
-
-      switch (op)
-       {
-       case DW_OP_addr:
-         printf ("DW_OP_addr: %lx",
-                 (unsigned long) byte_get (data, pointer_size));
-         data += pointer_size;
-         break;
-       case DW_OP_deref:
-         printf ("DW_OP_deref");
-         break;
-       case DW_OP_const1u:
-         printf ("DW_OP_const1u: %lu", (unsigned long) byte_get (data++, 1));
-         break;
-       case DW_OP_const1s:
-         printf ("DW_OP_const1s: %ld", (long) byte_get_signed (data++, 1));
-         break;
-       case DW_OP_const2u:
-         printf ("DW_OP_const2u: %lu", (unsigned long) byte_get (data, 2));
-         data += 2;
+       case DW_OP_const2u:
+         printf ("DW_OP_const2u: %lu", (unsigned long) byte_get (data, 2));
+         data += 2;
          break;
        case DW_OP_const2s:
          printf ("DW_OP_const2s: %ld", (long) byte_get_signed (data, 2));
@@ -8265,1153 +7711,1894 @@ decode_location_expression (unsigned char * data,
          data += 2;
          break;
 
-       case DW_OP_lit0:
-       case DW_OP_lit1:
-       case DW_OP_lit2:
-       case DW_OP_lit3:
-       case DW_OP_lit4:
-       case DW_OP_lit5:
-       case DW_OP_lit6:
-       case DW_OP_lit7:
-       case DW_OP_lit8:
-       case DW_OP_lit9:
-       case DW_OP_lit10:
-       case DW_OP_lit11:
-       case DW_OP_lit12:
-       case DW_OP_lit13:
-       case DW_OP_lit14:
-       case DW_OP_lit15:
-       case DW_OP_lit16:
-       case DW_OP_lit17:
-       case DW_OP_lit18:
-       case DW_OP_lit19:
-       case DW_OP_lit20:
-       case DW_OP_lit21:
-       case DW_OP_lit22:
-       case DW_OP_lit23:
-       case DW_OP_lit24:
-       case DW_OP_lit25:
-       case DW_OP_lit26:
-       case DW_OP_lit27:
-       case DW_OP_lit28:
-       case DW_OP_lit29:
-       case DW_OP_lit30:
-       case DW_OP_lit31:
-         printf ("DW_OP_lit%d", op - DW_OP_lit0);
-         break;
+       case DW_OP_lit0:
+       case DW_OP_lit1:
+       case DW_OP_lit2:
+       case DW_OP_lit3:
+       case DW_OP_lit4:
+       case DW_OP_lit5:
+       case DW_OP_lit6:
+       case DW_OP_lit7:
+       case DW_OP_lit8:
+       case DW_OP_lit9:
+       case DW_OP_lit10:
+       case DW_OP_lit11:
+       case DW_OP_lit12:
+       case DW_OP_lit13:
+       case DW_OP_lit14:
+       case DW_OP_lit15:
+       case DW_OP_lit16:
+       case DW_OP_lit17:
+       case DW_OP_lit18:
+       case DW_OP_lit19:
+       case DW_OP_lit20:
+       case DW_OP_lit21:
+       case DW_OP_lit22:
+       case DW_OP_lit23:
+       case DW_OP_lit24:
+       case DW_OP_lit25:
+       case DW_OP_lit26:
+       case DW_OP_lit27:
+       case DW_OP_lit28:
+       case DW_OP_lit29:
+       case DW_OP_lit30:
+       case DW_OP_lit31:
+         printf ("DW_OP_lit%d", op - DW_OP_lit0);
+         break;
+
+       case DW_OP_reg0:
+       case DW_OP_reg1:
+       case DW_OP_reg2:
+       case DW_OP_reg3:
+       case DW_OP_reg4:
+       case DW_OP_reg5:
+       case DW_OP_reg6:
+       case DW_OP_reg7:
+       case DW_OP_reg8:
+       case DW_OP_reg9:
+       case DW_OP_reg10:
+       case DW_OP_reg11:
+       case DW_OP_reg12:
+       case DW_OP_reg13:
+       case DW_OP_reg14:
+       case DW_OP_reg15:
+       case DW_OP_reg16:
+       case DW_OP_reg17:
+       case DW_OP_reg18:
+       case DW_OP_reg19:
+       case DW_OP_reg20:
+       case DW_OP_reg21:
+       case DW_OP_reg22:
+       case DW_OP_reg23:
+       case DW_OP_reg24:
+       case DW_OP_reg25:
+       case DW_OP_reg26:
+       case DW_OP_reg27:
+       case DW_OP_reg28:
+       case DW_OP_reg29:
+       case DW_OP_reg30:
+       case DW_OP_reg31:
+         printf ("DW_OP_reg%d", op - DW_OP_reg0);
+         break;
+
+       case DW_OP_breg0:
+       case DW_OP_breg1:
+       case DW_OP_breg2:
+       case DW_OP_breg3:
+       case DW_OP_breg4:
+       case DW_OP_breg5:
+       case DW_OP_breg6:
+       case DW_OP_breg7:
+       case DW_OP_breg8:
+       case DW_OP_breg9:
+       case DW_OP_breg10:
+       case DW_OP_breg11:
+       case DW_OP_breg12:
+       case DW_OP_breg13:
+       case DW_OP_breg14:
+       case DW_OP_breg15:
+       case DW_OP_breg16:
+       case DW_OP_breg17:
+       case DW_OP_breg18:
+       case DW_OP_breg19:
+       case DW_OP_breg20:
+       case DW_OP_breg21:
+       case DW_OP_breg22:
+       case DW_OP_breg23:
+       case DW_OP_breg24:
+       case DW_OP_breg25:
+       case DW_OP_breg26:
+       case DW_OP_breg27:
+       case DW_OP_breg28:
+       case DW_OP_breg29:
+       case DW_OP_breg30:
+       case DW_OP_breg31:
+         printf ("DW_OP_breg%d: %ld", op - DW_OP_breg0,
+                 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));
+         data += bytes_read;
+         break;
+       case DW_OP_fbreg:
+         printf ("DW_OP_fbreg: %ld", read_leb128 (data, &bytes_read, 1));
+         data += bytes_read;
+         break;
+       case DW_OP_bregx:
+         uvalue = read_leb128 (data, &bytes_read, 0);
+         data += bytes_read;
+         printf ("DW_OP_bregx: %lu %ld", uvalue,
+                 read_leb128 (data, &bytes_read, 1));
+         data += bytes_read;
+         break;
+       case DW_OP_piece:
+         printf ("DW_OP_piece: %lu", read_leb128 (data, &bytes_read, 0));
+         data += bytes_read;
+         break;
+       case DW_OP_deref_size:
+         printf ("DW_OP_deref_size: %ld", (long) byte_get (data++, 1));
+         break;
+       case DW_OP_xderef_size:
+         printf ("DW_OP_xderef_size: %ld", (long) byte_get (data++, 1));
+         break;
+       case DW_OP_nop:
+         printf ("DW_OP_nop");
+         break;
+
+         /* DWARF 3 extensions.  */
+       case DW_OP_push_object_address:
+         printf ("DW_OP_push_object_address");
+         break;
+       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);
+         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);
+         data += 4;
+         break;
+       case DW_OP_call_ref:
+         printf ("DW_OP_call_ref");
+         break;
+
+         /* GNU extensions.  */
+       case DW_OP_GNU_push_tls_address:
+         printf ("DW_OP_GNU_push_tls_address");
+         break;
+
+       default:
+         if (op >= DW_OP_lo_user
+             && op <= DW_OP_hi_user)
+           printf (_("(User defined location op)"));
+         else
+           printf (_("(Unknown location op)"));
+         /* No way to tell where the next op is, so just bail.  */
+         return;
+       }
+
+      /* Separate the ops.  */
+      if (data < end)
+       printf ("; ");
+    }
+}
+
+/* Decode a DW_AT_ranges attribute for 64bit DWARF3 .  */
+
+static void
+decode_64bit_range (unsigned long offset, bfd_vma base_address)
+{
+  const char * start = debug_range_contents + offset;
+  const char * end   = debug_range_contents + debug_range_size;
+
+  do
+    {
+      bfd_vma a;
+      bfd_vma b;
+
+      a = byte_get ((unsigned char *) start, 8);
+      b = byte_get ((unsigned char *) start + 8, 8);
+
+      if (a == 0xffffffff)
+       {
+         base_address = b;
+       }
+      else if (a == 0 && b == 0)
+       break;
+      else if (a > b)
+       printf (_(" [corrupt: start > end]"));
+      else
+       {
+         printf (" ");
+         print_vma (base_address + a, PREFIX_HEX);
+         printf (" - ");
+         print_vma (base_address + b, PREFIX_HEX);
+         printf (", ");
+       }
+
+      start += 16;
+    }
+  while (start < end);
+}
+
+/* Decode a DW_AT_ranges attribute.  */
+
+static void
+decode_range (unsigned long offset, bfd_vma base_address)
+{
+  const char * start;
+  const char * end;
+
+  if (offset >= (debug_range_size - 8))
+    {
+      printf (_("[corrupt: offset is outside the .debug_ranges section]"));
+      return;
+    }
+
+  /* Since all entries in the .debug_ranges section are pairs of either
+     4-byte integers (32-bit DWARF3) or 8-byte integers (64-bit DWARF3)
+     the offset should always be a multiple of 8 bytes.  */
+  if (offset % 8)
+    {
+      printf (_("[corrupt: offset is not a multiple of 8]"));
+      return;
+    }  
+
+  start = debug_range_contents + offset;
+
+  if (offset > 0
+      /* Be paranoid - check to see if the previous
+        two words were and end-of-range marker.  */
+      && (byte_get ((unsigned char *) start - 4, 4) != 0
+         || byte_get ((unsigned char *) start - 8, 4) != 0))
+    {
+      printf (_("[corrupt: offset is not at the start of a range]"));
+      return;
+    }  
+
+  end = debug_range_contents + debug_range_size;
+
+  printf ("(");
+  do
+    {
+      unsigned long a;
+      unsigned long b;
+
+      a = byte_get ((unsigned char *) start, 4);
+      b = byte_get ((unsigned char *) start + 4, 4);
+
+      if (a == 0xffffffff)
+       {
+         if (b == 0xffffffff)
+           {
+             decode_64bit_range (offset, base_address);
+             return;
+           }
+
+         base_address = b;
+       }
+      else if (a == 0 && b == 0)
+       break;
+      else if (a > b)
+       printf (_("[corrupt: start > end]"));
+      else
+       {
+         if (start > debug_range_contents + offset)
+           printf (", ");
+
+         printf (_("0x%lx - 0x%lx"),
+                 (unsigned long) base_address + a,
+                 (unsigned long) base_address + b);
+       }
+
+      start += 8;
+    }
+  while (start < end);
+  printf (")");
+}
+
+/* This structure records the information that
+   we extract from the.debug_info section.  */
+typedef struct
+{
+  unsigned int   pointer_size;
+  unsigned long  cu_offset;
+  /* This is an array of offsets to the location list table.  */
+  unsigned long *loc_offsets;
+  unsigned int   num_loc_offsets;
+  unsigned int   max_loc_offsets;
+}
+debug_info;
+
+static debug_info *   debug_information = NULL;
+static unsigned int   num_debug_info_entries = 0;
+static unsigned int   last_pointer_size = 0;
+static int            warned_about_missing_comp_units = FALSE;
+
+static unsigned char *
+read_and_display_attr_value (unsigned long attribute,
+                            unsigned long form,
+                            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)
+{
+  static unsigned long saved_DW_AT_low_pc = 0;
+  unsigned long uvalue = 0;
+  unsigned char *block_start = NULL;
+  int bytes_read;
+
+  switch (form)
+    {
+    default:
+      break;
+
+    case DW_FORM_ref_addr:
+      if (dwarf_version == 2)
+       {
+         uvalue = byte_get (data, pointer_size);
+         data += pointer_size;
+       }
+      else if (dwarf_version == 3)
+       {
+         uvalue = byte_get (data, offset_size);
+         data += offset_size;
+       }
+      else
+       {
+         error (_("Internal error: DWARF version is not 2 or 3.\n"));
+       }
+      break;
+
+    case DW_FORM_addr:
+      uvalue = byte_get (data, pointer_size);
+      data += pointer_size;
+      break;
+
+    case DW_FORM_strp:
+      uvalue = byte_get (data, offset_size);
+      data += offset_size;
+      break;
+
+    case DW_FORM_ref1:
+    case DW_FORM_flag:
+    case DW_FORM_data1:
+      uvalue = byte_get (data++, 1);
+      break;
+
+    case DW_FORM_ref2:
+    case DW_FORM_data2:
+      uvalue = byte_get (data, 2);
+      data += 2;
+      break;
+
+    case DW_FORM_ref4:
+    case DW_FORM_data4:
+      uvalue = byte_get (data, 4);
+      data += 4;
+      break;
+
+    case DW_FORM_sdata:
+      uvalue = read_leb128 (data, & bytes_read, 1);
+      data += bytes_read;
+      break;
+
+    case DW_FORM_ref_udata:
+    case DW_FORM_udata:
+      uvalue = read_leb128 (data, & bytes_read, 0);
+      data += bytes_read;
+      break;
+
+    case DW_FORM_indirect:
+      form = read_leb128 (data, & bytes_read, 0);
+      data += bytes_read;
+      if (!do_loc)
+       printf (" %s", get_FORM_name (form));
+      return read_and_display_attr_value (attribute, form, data,
+                                         cu_offset, pointer_size,
+                                         offset_size, dwarf_version,
+                                         debug_info_p, do_loc);
+    }
+
+  switch (form)
+    {
+    case DW_FORM_ref_addr:
+      if (!do_loc)
+       printf (" <#%lx>", uvalue);
+      break;
+
+    case DW_FORM_ref1:
+    case DW_FORM_ref2:
+    case DW_FORM_ref4:
+    case DW_FORM_ref_udata:
+      if (!do_loc)
+       printf (" <%lx>", uvalue + cu_offset);
+      break;
+
+    case DW_FORM_data4:
+    case DW_FORM_addr:
+      if (!do_loc)
+       printf (" %#lx", uvalue);
+      break;
+
+    case DW_FORM_flag:
+    case DW_FORM_data1:
+    case DW_FORM_data2:
+    case DW_FORM_sdata:
+    case DW_FORM_udata:
+      if (!do_loc)
+       printf (" %ld", uvalue);
+      break;
+
+    case DW_FORM_ref8:
+    case DW_FORM_data8:
+      if (!do_loc)
+       {
+         uvalue = byte_get (data, 4);
+         printf (" %lx", uvalue);
+         printf (" %lx", (unsigned long) byte_get (data + 4, 4));
+       }
+      if ((do_loc || do_debug_loc)
+         && num_debug_info_entries == 0)
+       {
+         if (sizeof (uvalue) == 8)
+           uvalue = byte_get (data, 8);
+         else
+           error (_("DW_FORM_data8 is unsupported when sizeof (unsigned long) != 8\n"));
+       }
+      data += 8;
+      break;
+
+    case DW_FORM_string:
+      if (!do_loc)
+       printf (" %s", data);
+      data += strlen ((char *) data) + 1;
+      break;
+
+    case DW_FORM_block:
+      uvalue = read_leb128 (data, & bytes_read, 0);
+      block_start = data + bytes_read;
+      if (do_loc)
+       data = block_start + uvalue;
+      else
+       data = display_block (block_start, uvalue);
+      break;
+
+    case DW_FORM_block1:
+      uvalue = byte_get (data, 1);
+      block_start = data + 1;
+      if (do_loc)
+       data = block_start + uvalue;
+      else
+       data = display_block (block_start, uvalue);
+      break;
+
+    case DW_FORM_block2:
+      uvalue = byte_get (data, 2);
+      block_start = data + 2;
+      if (do_loc)
+       data = block_start + uvalue;
+      else
+       data = display_block (block_start, uvalue);
+      break;
+
+    case DW_FORM_block4:
+      uvalue = byte_get (data, 4);
+      block_start = data + 4;
+      if (do_loc)
+       data = block_start + uvalue;
+      else
+       data = display_block (block_start, uvalue);
+      break;
+
+    case DW_FORM_strp:
+      if (!do_loc)
+       printf (_(" (indirect string, offset: 0x%lx): %s"),
+               uvalue, fetch_indirect_string (uvalue));
+      break;
+
+    case DW_FORM_indirect:
+      /* Handled above.  */
+      break;
+
+    default:
+      warn (_("Unrecognized form: %d\n"), form);
+      break;
+    }
+
+  /* For some attributes we can display further information.  */
+  if ((do_loc || do_debug_loc)
+      && num_debug_info_entries == 0)
+    {
+      switch (attribute)
+       {
+       case DW_AT_frame_base:
+       case DW_AT_location:
+       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)
+           {
+             /* Process location list.  */
+             unsigned int max = debug_info_p->max_loc_offsets;
+             unsigned int num = debug_info_p->num_loc_offsets;
+
+             if (max == 0 || num >= max)
+               {
+                 max += 1024;
+                 debug_info_p->loc_offsets
+                   = xrealloc (debug_info_p->loc_offsets,
+                               max * sizeof (*debug_info_p->loc_offsets));
+                 debug_info_p->max_loc_offsets = max;
+               }
+             debug_info_p->loc_offsets [num] = uvalue;
+             debug_info_p->num_loc_offsets++;
+           }
+         break;
+
+       default:
+         break;
+       }
+    }
+
+  if (do_loc)
+    return data;
+
+  printf ("\t");
+
+  switch (attribute)
+    {
+    case DW_AT_inline:
+      switch (uvalue)
+       {
+       case DW_INL_not_inlined:
+         printf (_("(not inlined)"));
+         break;
+       case DW_INL_inlined:
+         printf (_("(inlined)"));
+         break;
+       case DW_INL_declared_not_inlined:
+         printf (_("(declared as inline but ignored)"));
+         break;
+       case DW_INL_declared_inlined:
+         printf (_("(declared as inline and inlined)"));
+         break;
+       default:
+         printf (_("  (Unknown inline attribute value: %lx)"), uvalue);
+         break;
+       }
+      break;
+
+    case DW_AT_language:
+      switch (uvalue)
+       {
+       case DW_LANG_C:                 printf ("(non-ANSI C)"); break;
+       case DW_LANG_C89:               printf ("(ANSI C)"); break;
+       case DW_LANG_C_plus_plus:       printf ("(C++)"); 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;
+         /* DWARF 2.1 values.  */
+       case DW_LANG_C99:               printf ("(ANSI C99)"); break;
+       case DW_LANG_Ada95:             printf ("(ADA 95)"); break;
+       case DW_LANG_Fortran95:         printf ("(Fortran 95)"); 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);
+         break;
+       }
+      break;
+
+    case DW_AT_encoding:
+      switch (uvalue)
+       {
+       case DW_ATE_void:               printf ("(void)"); break;
+       case DW_ATE_address:            printf ("(machine address)"); break;
+       case DW_ATE_boolean:            printf ("(boolean)"); break;
+       case DW_ATE_complex_float:      printf ("(complex float)"); break;
+       case DW_ATE_float:              printf ("(float)"); break;
+       case DW_ATE_signed:             printf ("(signed)"); break;
+       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.  */
+       case DW_ATE_imaginary_float:    printf ("(imaginary float)"); break;
+       default:
+         if (uvalue >= DW_ATE_lo_user
+             && uvalue <= DW_ATE_hi_user)
+           printf ("(user defined type)");
+         else
+           printf ("(unknown type)");
+         break;
+       }
+      break;
+
+    case DW_AT_accessibility:
+      switch (uvalue)
+       {
+       case DW_ACCESS_public:          printf ("(public)"); break;
+       case DW_ACCESS_protected:       printf ("(protected)"); break;
+       case DW_ACCESS_private:         printf ("(private)"); break;
+       default:
+         printf ("(unknown accessibility)");
+         break;
+       }
+      break;
+
+    case DW_AT_visibility:
+      switch (uvalue)
+       {
+       case DW_VIS_local:              printf ("(local)"); break;
+       case DW_VIS_exported:           printf ("(exported)"); break;
+       case DW_VIS_qualified:          printf ("(qualified)"); break;
+       default:                        printf ("(unknown visibility)"); break;
+       }
+      break;
+
+    case DW_AT_virtuality:
+      switch (uvalue)
+       {
+       case DW_VIRTUALITY_none:        printf ("(none)"); break;
+       case DW_VIRTUALITY_virtual:     printf ("(virtual)"); break;
+       case DW_VIRTUALITY_pure_virtual:printf ("(pure_virtual)"); break;
+       default:                        printf ("(unknown virtuality)"); break;
+       }
+      break;
+
+    case DW_AT_identifier_case:
+      switch (uvalue)
+       {
+       case DW_ID_case_sensitive:      printf ("(case_sensitive)"); break;
+       case DW_ID_up_case:             printf ("(up_case)"); break;
+       case DW_ID_down_case:           printf ("(down_case)"); break;
+       case DW_ID_case_insensitive:    printf ("(case_insensitive)"); break;
+       default:                        printf ("(unknown case)"); break;
+       }
+      break;
+
+    case DW_AT_calling_convention:
+      switch (uvalue)
+       {
+       case DW_CC_normal:      printf ("(normal)"); break;
+       case DW_CC_program:     printf ("(program)"); break;
+       case DW_CC_nocall:      printf ("(nocall)"); break;
+       default:
+         if (uvalue >= DW_CC_lo_user
+             && uvalue <= DW_CC_hi_user)
+           printf ("(user defined)");
+         else
+           printf ("(unknown convention)");
+       }
+      break;
+
+    case DW_AT_ordering:
+      switch (uvalue)
+       {
+       case -1: printf ("(undefined)"); break;
+       case 0:  printf ("(row major)"); break;
+       case 1:  printf ("(column major)"); break;
+       }
+      break;
+
+    case DW_AT_frame_base:
+    case DW_AT_location:
+    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 (block_start)
+       {
+         printf ("(");
+         decode_location_expression (block_start, pointer_size, uvalue, cu_offset);
+         printf (")");
+       }
+      else if (form == DW_FORM_data4 || form == DW_FORM_data8)
+       printf (_("(location list)"));
+
+      break;
+
+    case DW_AT_low_pc:
+      /* This is a hack.  We keep track of the DW_AT_low_pc attributes
+        and use them when decoding DW_AT_ranges attributes.  The
+        assumption here is that we are decoding the attributes in order
+        and so the correct base address for the range is the low_pc.  */
+      saved_DW_AT_low_pc = uvalue;
+      break;
+
+    case DW_AT_ranges:
+      decode_range (uvalue, saved_DW_AT_low_pc);
+      break;
+
+    default:
+      break;
+    }
+
+  return data;
+}
+
+static char *
+get_AT_name (unsigned long attribute)
+{
+  switch (attribute)
+    {
+    case DW_AT_sibling:                        return "DW_AT_sibling";
+    case DW_AT_location:               return "DW_AT_location";
+    case DW_AT_name:                   return "DW_AT_name";
+    case DW_AT_ordering:               return "DW_AT_ordering";
+    case DW_AT_subscr_data:            return "DW_AT_subscr_data";
+    case DW_AT_byte_size:              return "DW_AT_byte_size";
+    case DW_AT_bit_offset:             return "DW_AT_bit_offset";
+    case DW_AT_bit_size:               return "DW_AT_bit_size";
+    case DW_AT_element_list:           return "DW_AT_element_list";
+    case DW_AT_stmt_list:              return "DW_AT_stmt_list";
+    case DW_AT_low_pc:                 return "DW_AT_low_pc";
+    case DW_AT_high_pc:                        return "DW_AT_high_pc";
+    case DW_AT_language:               return "DW_AT_language";
+    case DW_AT_member:                 return "DW_AT_member";
+    case DW_AT_discr:                  return "DW_AT_discr";
+    case DW_AT_discr_value:            return "DW_AT_discr_value";
+    case DW_AT_visibility:             return "DW_AT_visibility";
+    case DW_AT_import:                 return "DW_AT_import";
+    case DW_AT_string_length:          return "DW_AT_string_length";
+    case DW_AT_common_reference:       return "DW_AT_common_reference";
+    case DW_AT_comp_dir:               return "DW_AT_comp_dir";
+    case DW_AT_const_value:            return "DW_AT_const_value";
+    case DW_AT_containing_type:                return "DW_AT_containing_type";
+    case DW_AT_default_value:          return "DW_AT_default_value";
+    case DW_AT_inline:                 return "DW_AT_inline";
+    case DW_AT_is_optional:            return "DW_AT_is_optional";
+    case DW_AT_lower_bound:            return "DW_AT_lower_bound";
+    case DW_AT_producer:               return "DW_AT_producer";
+    case DW_AT_prototyped:             return "DW_AT_prototyped";
+    case DW_AT_return_addr:            return "DW_AT_return_addr";
+    case DW_AT_start_scope:            return "DW_AT_start_scope";
+    case DW_AT_stride_size:            return "DW_AT_stride_size";
+    case DW_AT_upper_bound:            return "DW_AT_upper_bound";
+    case DW_AT_abstract_origin:                return "DW_AT_abstract_origin";
+    case DW_AT_accessibility:          return "DW_AT_accessibility";
+    case DW_AT_address_class:          return "DW_AT_address_class";
+    case DW_AT_artificial:             return "DW_AT_artificial";
+    case DW_AT_base_types:             return "DW_AT_base_types";
+    case DW_AT_calling_convention:     return "DW_AT_calling_convention";
+    case DW_AT_count:                  return "DW_AT_count";
+    case DW_AT_data_member_location:   return "DW_AT_data_member_location";
+    case DW_AT_decl_column:            return "DW_AT_decl_column";
+    case DW_AT_decl_file:              return "DW_AT_decl_file";
+    case DW_AT_decl_line:              return "DW_AT_decl_line";
+    case DW_AT_declaration:            return "DW_AT_declaration";
+    case DW_AT_discr_list:             return "DW_AT_discr_list";
+    case DW_AT_encoding:               return "DW_AT_encoding";
+    case DW_AT_external:               return "DW_AT_external";
+    case DW_AT_frame_base:             return "DW_AT_frame_base";
+    case DW_AT_friend:                 return "DW_AT_friend";
+    case DW_AT_identifier_case:                return "DW_AT_identifier_case";
+    case DW_AT_macro_info:             return "DW_AT_macro_info";
+    case DW_AT_namelist_items:         return "DW_AT_namelist_items";
+    case DW_AT_priority:               return "DW_AT_priority";
+    case DW_AT_segment:                        return "DW_AT_segment";
+    case DW_AT_specification:          return "DW_AT_specification";
+    case DW_AT_static_link:            return "DW_AT_static_link";
+    case DW_AT_type:                   return "DW_AT_type";
+    case DW_AT_use_location:           return "DW_AT_use_location";
+    case DW_AT_variable_parameter:     return "DW_AT_variable_parameter";
+    case DW_AT_virtuality:             return "DW_AT_virtuality";
+    case DW_AT_vtable_elem_location:   return "DW_AT_vtable_elem_location";
+      /* DWARF 2.1 values.  */
+    case DW_AT_allocated:              return "DW_AT_allocated";
+    case DW_AT_associated:             return "DW_AT_associated";
+    case DW_AT_data_location:          return "DW_AT_data_location";
+    case DW_AT_stride:                 return "DW_AT_stride";
+    case DW_AT_entry_pc:               return "DW_AT_entry_pc";
+    case DW_AT_use_UTF8:               return "DW_AT_use_UTF8";
+    case DW_AT_extension:              return "DW_AT_extension";
+    case DW_AT_ranges:                 return "DW_AT_ranges";
+    case DW_AT_trampoline:             return "DW_AT_trampoline";
+    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";
+      /* 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";
+      /* UPC extension.  */
+    case DW_AT_upc_threads_scaled:     return "DW_AT_upc_threads_scaled";
+    default:
+      {
+       static char buffer[100];
+
+       sprintf (buffer, _("Unknown AT value: %lx"), attribute);
+       return buffer;
+      }
+    }
+}
 
-       case DW_OP_reg0:
-       case DW_OP_reg1:
-       case DW_OP_reg2:
-       case DW_OP_reg3:
-       case DW_OP_reg4:
-       case DW_OP_reg5:
-       case DW_OP_reg6:
-       case DW_OP_reg7:
-       case DW_OP_reg8:
-       case DW_OP_reg9:
-       case DW_OP_reg10:
-       case DW_OP_reg11:
-       case DW_OP_reg12:
-       case DW_OP_reg13:
-       case DW_OP_reg14:
-       case DW_OP_reg15:
-       case DW_OP_reg16:
-       case DW_OP_reg17:
-       case DW_OP_reg18:
-       case DW_OP_reg19:
-       case DW_OP_reg20:
-       case DW_OP_reg21:
-       case DW_OP_reg22:
-       case DW_OP_reg23:
-       case DW_OP_reg24:
-       case DW_OP_reg25:
-       case DW_OP_reg26:
-       case DW_OP_reg27:
-       case DW_OP_reg28:
-       case DW_OP_reg29:
-       case DW_OP_reg30:
-       case DW_OP_reg31:
-         printf ("DW_OP_reg%d", op - DW_OP_reg0);
-         break;
+static unsigned char *
+read_and_display_attr (unsigned long attribute,
+                      unsigned long form,
+                      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)
+{
+  if (!do_loc)
+    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);
+  if (!do_loc)
+    printf ("\n");
+  return data;
+}
 
-       case DW_OP_breg0:
-       case DW_OP_breg1:
-       case DW_OP_breg2:
-       case DW_OP_breg3:
-       case DW_OP_breg4:
-       case DW_OP_breg5:
-       case DW_OP_breg6:
-       case DW_OP_breg7:
-       case DW_OP_breg8:
-       case DW_OP_breg9:
-       case DW_OP_breg10:
-       case DW_OP_breg11:
-       case DW_OP_breg12:
-       case DW_OP_breg13:
-       case DW_OP_breg14:
-       case DW_OP_breg15:
-       case DW_OP_breg16:
-       case DW_OP_breg17:
-       case DW_OP_breg18:
-       case DW_OP_breg19:
-       case DW_OP_breg20:
-       case DW_OP_breg21:
-       case DW_OP_breg22:
-       case DW_OP_breg23:
-       case DW_OP_breg24:
-       case DW_OP_breg25:
-       case DW_OP_breg26:
-       case DW_OP_breg27:
-       case DW_OP_breg28:
-       case DW_OP_breg29:
-       case DW_OP_breg30:
-       case DW_OP_breg31:
-         printf ("DW_OP_breg%d: %ld", op - DW_OP_breg0,
-                 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));
-         data += bytes_read;
-         break;
-       case DW_OP_fbreg:
-         printf ("DW_OP_fbreg: %ld", read_leb128 (data, &bytes_read, 1));
-         data += bytes_read;
-         break;
-       case DW_OP_bregx:
-         uvalue = read_leb128 (data, &bytes_read, 0);
-         data += bytes_read;
-         printf ("DW_OP_bregx: %lu %ld", uvalue,
-                 read_leb128 (data, &bytes_read, 1));
-         data += bytes_read;
-         break;
-       case DW_OP_piece:
-         printf ("DW_OP_piece: %lu", read_leb128 (data, &bytes_read, 0));
-         data += bytes_read;
-         break;
-       case DW_OP_deref_size:
-         printf ("DW_OP_deref_size: %ld", (long) byte_get (data++, 1));
-         break;
-       case DW_OP_xderef_size:
-         printf ("DW_OP_xderef_size: %ld", (long) byte_get (data++, 1));
-         break;
-       case DW_OP_nop:
-         printf ("DW_OP_nop");
-         break;
+/* 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.  */
 
-         /* DWARF 3 extensions.  */
-       case DW_OP_push_object_address:
-         printf ("DW_OP_push_object_address");
-         break;
-       case DW_OP_call2:
-         printf ("DW_OP_call2: <%lx>", (long) byte_get (data, 2));
-         data += 2;
-         break;
-       case DW_OP_call4:
-         printf ("DW_OP_call4: <%lx>", (long) byte_get (data, 4));
-         data += 4;
-         break;
-       case DW_OP_call_ref:
-         printf ("DW_OP_call_ref");
-         break;
+static int
+process_debug_info (Elf_Internal_Shdr *section, unsigned char *start,
+                   FILE *file, int do_loc)
+{
+  unsigned char *end = start + section->sh_size;
+  unsigned char *section_begin;
+  unsigned int unit;
+  unsigned int num_units = 0;
 
-         /* GNU extensions.  */
-       case DW_OP_GNU_push_tls_address:
-         printf ("DW_OP_GNU_push_tls_address");
-         break;
+  if ((do_loc || do_debug_loc)
+      && num_debug_info_entries == 0)
+    {
+      unsigned long length;
 
-       default:
-         if (op >= DW_OP_lo_user
-             && op <= DW_OP_hi_user)
-           printf (_("(User defined location op)"));
+      /* First scan the section to get the number of comp units.  */
+      for (section_begin = start, num_units = 0; section_begin < end;
+          num_units ++)
+       {
+         /* Read the first 4 bytes.  For a 32-bit DWARF section, this
+            will be the length.  For a 64-bit DWARF section, it'll be
+            the escape code 0xffffffff followed by an 8 byte length.  */
+         length = byte_get (section_begin, 4);
+
+         if (length == 0xffffffff)
+           {
+             length = byte_get (section_begin + 4, 8);
+             section_begin += length + 12;
+           }
          else
-           printf (_("(Unknown location op)"));
-         /* No way to tell where the next op is, so just bail.  */
-         return;
+           section_begin += length + 4;
        }
 
-      /* Separate the ops.  */
-      if (data < end)
-       printf ("; ");
+      if (num_units == 0)
+       {
+         error (_("No comp units in .debug_info section ?"));
+         return 0;
+       }
+
+      /* Then allocate an array to hold the information.  */
+      debug_information = malloc (num_units *
+                                 sizeof (* debug_information));
+      if (debug_information == NULL)
+       {
+         error (_("Not enough memory for a debug info array of %u entries"),
+                num_units);
+         return 0;
+       }
     }
-}
 
-static const char *debug_loc_contents;
-static bfd_vma debug_loc_size;
+  if (!do_loc)
+    {
+      printf (_("The section %s contains:\n\n"),
+             SECTION_NAME (section));
 
-static void
-load_debug_loc (FILE *file)
-{
-  Elf_Internal_Shdr *sec;
+      load_debug_str (file);
+      load_debug_loc (file);
+      load_debug_range (file);
+    }
 
-  /* If it is already loaded, do nothing.  */
-  if (debug_loc_contents != NULL)
-    return;
+  for (section_begin = start, unit = 0; start < end; unit++)
+    {
+      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;
 
-  /* Locate the .debug_loc section.  */
-  sec = find_section (".debug_loc");
-  if (sec == NULL)
-    return;
+      hdrptr = start;
 
-  debug_loc_size = sec->sh_size;
+      compunit.cu_length = byte_get (hdrptr, 4);
+      hdrptr += 4;
 
-  debug_loc_contents = get_data (NULL, file, sec->sh_offset, sec->sh_size,
-                                _("debug_loc section data"));
-}
+      if (compunit.cu_length == 0xffffffff)
+       {
+         compunit.cu_length = byte_get (hdrptr, 8);
+         hdrptr += 8;
+         offset_size = 8;
+         initial_length_size = 12;
+       }
+      else
+       {
+         offset_size = 4;
+         initial_length_size = 4;
+       }
 
-static void
-free_debug_loc (void)
-{
-  if (debug_loc_contents == NULL)
-    return;
+      compunit.cu_version = byte_get (hdrptr, 2);
+      hdrptr += 2;
+
+      cu_offset = start - section_begin;
+      start += compunit.cu_length + initial_length_size;
 
-  free ((char *) debug_loc_contents);
-  debug_loc_contents = NULL;
-  debug_loc_size = 0;
-}
+      if (elf_header.e_type == ET_REL
+         && !debug_apply_rela_addends (file, section, offset_size,
+                                       section_begin, hdrptr, start))
+       return 0;
 
+      cu_abbrev_offset_ptr = hdrptr;
+      compunit.cu_abbrev_offset = byte_get (hdrptr, offset_size);
+      hdrptr += offset_size;
 
-static int
-display_debug_loc (Elf_Internal_Shdr *section,
-                  unsigned char *start, FILE *file)
-{
-  unsigned char *section_end;
-  unsigned long bytes;
-  unsigned char *section_begin = start;
-  bfd_vma addr;
-  unsigned int comp_unit = 0;
+      compunit.cu_pointer_size = byte_get (hdrptr, 1);
+      hdrptr += 1;
+      if ((do_loc || do_debug_loc)
+         && num_debug_info_entries == 0)
+       {
+         debug_information [unit].cu_offset = cu_offset;
+         debug_information [unit].pointer_size
+           = compunit.cu_pointer_size;
+         debug_information [unit].loc_offsets = NULL;
+         debug_information [unit].max_loc_offsets = 0;
+         debug_information [unit].num_loc_offsets = 0;
+       }
 
-  addr = section->sh_addr;
-  bytes = section->sh_size;
-  section_end = start + bytes;
+      tags = hdrptr;
 
-  if (bytes == 0)
-    {
-      printf (_("\nThe .debug_loc section is empty.\n"));
-      return 0;
-    }
+      if (!do_loc)
+       {
+         printf (_("  Compilation Unit @ %lx:\n"), cu_offset);
+         printf (_("   Length:        %ld\n"), compunit.cu_length);
+         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);
+       }
 
-  get_debug_info (file);
+      if (compunit.cu_version != 2 && compunit.cu_version != 3)
+       {
+         warn (_("Only version 2 and 3 DWARF debug information is currently supported.\n"));
+         continue;
+       }
 
-  printf (_("Contents of the .debug_loc section:\n\n"));
-  printf (_("\n    Offset   Begin    End      Expression\n"));
+      free_abbrevs ();
 
-  while (start < section_end)
-    {
-      unsigned long begin;
-      unsigned long end;
-      unsigned short length;
-      unsigned long offset;
-      unsigned int pointer_size;
+      /* Read in the abbrevs used by this compilation unit.  */
+      {
+       Elf_Internal_Shdr *sec;
+       unsigned char *begin;
 
-      offset = start - section_begin;
+       /* Locate the .debug_abbrev section and process it.  */
+       sec = find_section (".debug_abbrev");
+       if (sec == NULL)
+         {
+           warn (_("Unable to locate .debug_abbrev section!\n"));
+           return 0;
+         }
 
-      /* Get the pointer size from the comp unit associated
-        with this block of location information.  */
-      pointer_size = get_pointer_size_of_comp_unit (comp_unit, ".debug_loc");
+       begin = get_data (NULL, file, sec->sh_offset, sec->sh_size,
+                         _("debug_abbrev section data"));
+       if (!begin)
+         return 0;
 
-      comp_unit ++;
+       process_abbrev_section (begin + compunit.cu_abbrev_offset,
+                               begin + sec->sh_size);
+
+       free (begin);
+      }
 
-      while (1)
+      level = 0;
+      while (tags < start)
        {
-         begin = byte_get (start, pointer_size);
-         start += pointer_size;
-         end = byte_get (start, pointer_size);
-         start += pointer_size;
+         int bytes_read;
+         unsigned long abbrev_number;
+         abbrev_entry *entry;
+         abbrev_attr *attr;
 
-         if (begin == 0 && end == 0)
-           break;
+         abbrev_number = read_leb128 (tags, & bytes_read, 0);
+         tags += bytes_read;
 
-         /* For now, skip any base address specifiers.  */
-         if (begin == 0xffffffff)
-           continue;
+         /* A null DIE marks the end of a list of children.  */
+         if (abbrev_number == 0)
+           {
+             --level;
+             continue;
+           }
 
-         begin += addr;
-         end += addr;
+         /* Scan through the abbreviation list until we reach the
+            correct entry.  */
+         for (entry = first_abbrev;
+              entry && entry->entry != abbrev_number;
+              entry = entry->next)
+           continue;
 
-         length = byte_get (start, 2);
-         start += 2;
+         if (entry == NULL)
+           {
+             warn (_("Unable to locate entry %lu in the abbreviation table\n"),
+                   abbrev_number);
+             return 0;
+           }
 
-         printf ("    %8.8lx %8.8lx %8.8lx (", offset, begin, end);
-         decode_location_expression (start, pointer_size, length);
-         printf (")\n");
+         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));
+         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 (entry->children)
+           ++level;
+       }
+    }
+  /* Set num_debug_info_entries here so that it can be used
+     to check if we need to proecess .debug_loc section.  */
+  if ((do_loc || do_debug_loc)
+      && num_debug_info_entries == 0)
+    num_debug_info_entries = num_units;
+      
+  if (!do_loc)
+    {
+      free_debug_range ();
+      free_debug_str ();
+      free_debug_loc (); 
 
-         start += length;
-       }
       printf ("\n");
     }
   return 1;
 }
 
-static const char *debug_str_contents;
-static bfd_vma debug_str_size;
+/* Retrieve the pointer size associated with the given compilation unit.
+   Optionally the offset of this unit into the .debug_info section is
+   also retutned.  If there is no .debug_info section then an error
+   message is issued and 0 is returned.  If the requested comp unit has
+   not been defined in the .debug_info section then a warning message
+   is issued and the last know pointer size is returned.  This message
+   is only issued once per section dumped per file dumped.  */
 
-static void
-load_debug_str (FILE *file)
+static unsigned int
+get_pointer_size_and_offset_of_comp_unit (unsigned int comp_unit,
+                                         const char * section_name,
+                                         unsigned long * offset_return)
 {
-  Elf_Internal_Shdr *sec;
+  unsigned long offset = 0;
 
-  /* If it is already loaded, do nothing.  */
-  if (debug_str_contents != NULL)
-    return;
+  if (num_debug_info_entries == 0)
+    error (_("%s section needs a populated .debug_info section\n"),
+          section_name);
 
-  /* Locate the .debug_str section.  */
-  sec = find_section (".debug_str");
-  if (sec == NULL)
-    return;
+  else if (comp_unit >= num_debug_info_entries)
+    {
+      if (!warned_about_missing_comp_units)
+       {
+         warn (_("%s section has more comp units than .debug_info section\n"),
+               section_name);
+         warn (_("assuming that the pointer size is %d, from the last comp unit in .debug_info\n\n"),
+               last_pointer_size);
+         warned_about_missing_comp_units = TRUE;
+       }
+    }
+  else
+    {
+      last_pointer_size = debug_information [comp_unit].pointer_size;
+      offset = debug_information [comp_unit].cu_offset;
+    }
 
-  debug_str_size = sec->sh_size;
+  if (offset_return != NULL)
+    * offset_return = offset;
 
-  debug_str_contents = get_data (NULL, file, sec->sh_offset, sec->sh_size,
-                                _("debug_str section data"));
+  return last_pointer_size;
 }
 
-static void
-free_debug_str (void)
+/* Locate and scan the .debug_info section in the file and record the pointer
+   sizes and offsets for the compilation units in it.  Usually an executable
+   will have just one pointer size, but this is not guaranteed, and so we try
+   not to make any assumptions.  Returns zero upon failure, or the number of
+   compilation units upon success.  */
+
+static unsigned int
+get_debug_info (FILE * file)
 {
-  if (debug_str_contents == NULL)
-    return;
+  Elf_Internal_Shdr * section;
+  unsigned char *     start;
+  int                ret;
 
-  free ((char *) debug_str_contents);
-  debug_str_contents = NULL;
-  debug_str_size = 0;
-}
+  /* Reset the last pointer size so that we can issue correct error
+     messages if we are displaying the contents of more than one section.  */
+  last_pointer_size = 0;
+  warned_about_missing_comp_units = FALSE;
 
-static const char *
-fetch_indirect_string (unsigned long offset)
-{
-  if (debug_str_contents == NULL)
-    return _("<no .debug_str section>");
+  /* If we already have the information there is nothing else to do.  */
+  if (num_debug_info_entries > 0)
+    return num_debug_info_entries;
 
-  if (offset > debug_str_size)
-    return _("<offset is too big>");
+  section = find_section (".debug_info");
+  if (section == NULL)
+    return 0;
 
-  return debug_str_contents + offset;
+  start = get_data (NULL, file, section->sh_offset, section->sh_size,
+                   _("extracting information from .debug_info section"));
+  if (start == NULL)
+    return 0;
+
+  ret = process_debug_info (section, start, file, 1);
+  free (start);
+
+  return ret ? num_debug_info_entries : 0;
 }
 
 static int
-display_debug_str (Elf_Internal_Shdr *section,
-                  unsigned char *start,
-                  FILE *file ATTRIBUTE_UNUSED)
+display_debug_lines (Elf_Internal_Shdr *section,
+                    unsigned char *start, FILE *file)
 {
-  unsigned long bytes;
-  bfd_vma addr;
+  unsigned char *data = start;
+  unsigned char *end = start + section->sh_size;
+  unsigned int comp_unit = 0;
 
-  addr  = section->sh_addr;
-  bytes = section->sh_size;
+  printf (_("\nDump of debug contents of section %s:\n\n"),
+         SECTION_NAME (section));
 
-  if (bytes == 0)
+  get_debug_info (file);
+
+  while (data < end)
     {
-      printf (_("\nThe .debug_str section is empty.\n"));
-      return 0;
-    }
+      DWARF2_Internal_LineInfo info;
+      unsigned char *standard_opcodes;
+      unsigned char *end_of_sequence;
+      unsigned char *hdrptr;
+      unsigned int pointer_size;
+      int initial_length_size;
+      int offset_size;
+      int i;
+
+      hdrptr = data;
+
+      /* Check the length of the block.  */
+      info.li_length = byte_get (hdrptr, 4);
+      hdrptr += 4;
+
+      if (info.li_length == 0xffffffff)
+       {
+         /* This section is 64-bit DWARF 3.  */
+         info.li_length = byte_get (hdrptr, 8);
+         hdrptr += 8;
+         offset_size = 8;
+         initial_length_size = 12;
+       }
+      else
+       {
+         offset_size = 4;
+         initial_length_size = 4;
+       }
+
+      if (info.li_length + initial_length_size > section->sh_size)
+       {
+         warn
+           (_("The line info appears to be corrupt - the section is too small\n"));
+         return 0;
+       }
+
+      /* Check its version number.  */
+      info.li_version = byte_get (hdrptr, 2);
+      hdrptr += 2;
+      if (info.li_version != 2 && info.li_version != 3)
+       {
+         warn (_("Only DWARF version 2 and 3 line info is currently supported.\n"));
+         return 0;
+       }
+
+      info.li_prologue_length = byte_get (hdrptr, offset_size);
+      hdrptr += offset_size;
+      info.li_min_insn_length = byte_get (hdrptr, 1);
+      hdrptr++;
+      info.li_default_is_stmt = byte_get (hdrptr, 1);
+      hdrptr++;
+      info.li_line_base = byte_get (hdrptr, 1);
+      hdrptr++;
+      info.li_line_range = byte_get (hdrptr, 1);
+      hdrptr++;
+      info.li_opcode_base = byte_get (hdrptr, 1);
+      hdrptr++;
 
-  printf (_("Contents of the .debug_str section:\n\n"));
+      /* Sign extend the line base field.  */
+      info.li_line_base <<= 24;
+      info.li_line_base >>= 24;
 
-  while (bytes)
-    {
-      int j;
-      int k;
-      int lbytes;
+      /* Get the pointer size from the comp unit associated
+        with this block of line number information.  */
+      pointer_size = get_pointer_size_and_offset_of_comp_unit
+       (comp_unit, ".debug_lines", NULL);
+      comp_unit ++;
 
-      lbytes = (bytes > 16 ? 16 : bytes);
+      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 (_("  (Pointer size:               %u)\n"), pointer_size);
 
-      printf ("  0x%8.8lx ", (unsigned long) addr);
+      end_of_sequence = data + info.li_length + initial_length_size;
 
-      for (j = 0; j < 16; j++)
-       {
-         if (j < lbytes)
-           printf ("%2.2x", start[j]);
-         else
-           printf ("  ");
+      reset_state_machine (info.li_default_is_stmt);
 
-         if ((j & 3) == 3)
-           printf (" ");
-       }
+      /* Display the contents of the Opcodes table.  */
+      standard_opcodes = hdrptr;
 
-      for (j = 0; j < lbytes; j++)
-       {
-         k = start[j];
-         if (k >= ' ' && k < 0x80)
-           printf ("%c", k);
-         else
-           printf (".");
-       }
+      printf (_("\n Opcodes:\n"));
 
-      putchar ('\n');
+      for (i = 1; i < info.li_opcode_base; i++)
+       printf (_("  Opcode %d has %d args\n"), i, standard_opcodes[i - 1]);
 
-      start += lbytes;
-      addr  += lbytes;
-      bytes -= lbytes;
-    }
+      /* Display the contents of the Directory table.  */
+      data = standard_opcodes + info.li_opcode_base - 1;
 
-  return 1;
-}
+      if (*data == 0)
+       printf (_("\n The Directory Table is empty.\n"));
+      else
+       {
+         printf (_("\n The Directory Table:\n"));
 
-static const char *   debug_range_contents;
-static unsigned long  debug_range_size;
+         while (*data != 0)
+           {
+             printf (_("  %s\n"), data);
 
-static void
-load_debug_range (FILE *file)
-{
-  Elf_Internal_Shdr *sec;
+             data += strlen ((char *) data) + 1;
+           }
+       }
 
-  /* If it is already loaded, do nothing.  */
-  if (debug_range_contents != NULL)
-    return;
+      /* Skip the NUL at the end of the table.  */
+      data++;
 
-  /* Locate the .debug_str section.  */
-  sec = find_section (".debug_ranges");
-  if (sec == NULL)
-    return;
+      /* Display the contents of the File Name table.  */
+      if (*data == 0)
+       printf (_("\n The File Name Table is empty.\n"));
+      else
+       {
+         printf (_("\n The File Name Table:\n"));
+         printf (_("  Entry\tDir\tTime\tSize\tName\n"));
 
-  debug_range_size = sec->sh_size;
+         while (*data != 0)
+           {
+             unsigned char *name;
+             int bytes_read;
 
-  debug_range_contents = get_data (NULL, file, sec->sh_offset, sec->sh_size,
-                                  _("debug_range section data"));
-}
+             printf (_("  %d\t"), ++state_machine_regs.last_file_entry);
+             name = data;
 
-static void
-free_debug_range (void)
-{
-  if (debug_range_contents == NULL)
-    return;
+             data += strlen ((char *) data) + 1;
 
-  free ((char *) debug_range_contents);
-  debug_range_contents = NULL;
-  debug_range_size = 0;
-}
+             printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0));
+             data += bytes_read;
+             printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0));
+             data += bytes_read;
+             printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0));
+             data += bytes_read;
+             printf (_("%s\n"), name);
+           }
+       }
 
+      /* Skip the NUL at the end of the table.  */
+      data++;
 
-/* Decode a DW_AT_ranges attribute for 64bit DWARF3 .  */
+      /* Now display the statements.  */
+      printf (_("\n Line Number Statements:\n"));
 
-static void
-decode_64bit_range (unsigned long offset, bfd_vma base_address)
-{
-  const char * start = debug_range_contents + offset;
-  const char * end   = debug_range_contents + debug_range_size;
+      while (data < end_of_sequence)
+       {
+         unsigned char op_code;
+         int adv;
+         int bytes_read;
 
-  do
-    {
-      bfd_vma a;
-      bfd_vma b;
+         op_code = *data++;
 
-      a = byte_get ((unsigned char *) start, 8);
-      b = byte_get ((unsigned char *) start + 8, 8);
+         if (op_code >= info.li_opcode_base)
+           {
+             op_code -= info.li_opcode_base;
+             adv      = (op_code / info.li_line_range) * info.li_min_insn_length;
+             state_machine_regs.address += adv;
+             printf (_("  Special opcode %d: advance Address by %d to 0x%lx"),
+                     op_code, adv, state_machine_regs.address);
+             adv = (op_code % info.li_line_range) + info.li_line_base;
+             state_machine_regs.line += adv;
+             printf (_(" and Line by %d to %d\n"),
+                     adv, state_machine_regs.line);
+           }
+         else switch (op_code)
+           {
+           case DW_LNS_extended_op:
+             data += process_extended_line_op (data, info.li_default_is_stmt,
+                                               pointer_size);
+             break;
 
-      if (a == 0xffffffff)
-       {
-         base_address = b;
-       }
-      else if (a == 0 && b == 0)
-       break;
-      else if (a > b)
-       printf (_(" [corrupt: start > end]"));
-      else
-       {
-         printf (" ");
-         print_vma (base_address + a, PREFIX_HEX);
-         printf (" - ");
-         print_vma (base_address + b, PREFIX_HEX);
-         printf (", ");
-       }
+           case DW_LNS_copy:
+             printf (_("  Copy\n"));
+             break;
 
-      start += 16;
-    }
-  while (start < end);
-}
+           case DW_LNS_advance_pc:
+             adv = info.li_min_insn_length * read_leb128 (data, & bytes_read, 0);
+             data += bytes_read;
+             state_machine_regs.address += adv;
+             printf (_("  Advance PC by %d to %lx\n"), adv,
+                     state_machine_regs.address);
+             break;
 
-/* Decode a DW_AT_ranges attribute.  */
+           case DW_LNS_advance_line:
+             adv = read_leb128 (data, & bytes_read, 1);
+             data += bytes_read;
+             state_machine_regs.line += adv;
+             printf (_("  Advance Line by %d to %d\n"), adv,
+                     state_machine_regs.line);
+             break;
 
-static void
-decode_range (unsigned long offset, bfd_vma base_address)
-{
-  const char * start;
-  const char * end;
+           case DW_LNS_set_file:
+             adv = read_leb128 (data, & bytes_read, 0);
+             data += bytes_read;
+             printf (_("  Set File Name to entry %d in the File Name Table\n"),
+                     adv);
+             state_machine_regs.file = adv;
+             break;
 
-  if (offset >= (debug_range_size - 8))
-    {
-      printf (_("[corrupt: offset is outside the .debug_ranges section]"));
-      return;
-    }
+           case DW_LNS_set_column:
+             adv = read_leb128 (data, & bytes_read, 0);
+             data += bytes_read;
+             printf (_("  Set column to %d\n"), adv);
+             state_machine_regs.column = adv;
+             break;
 
-  /* Since all entries in the .debug_ranges section are pairs of either
-     4-byte integers (32-bit DWARF3) or 8-byte integers (64-bit DWARF3)
-     the offset should always be a multiple of 8 bytes.  */
-  if (offset % 8)
-    {
-      printf (_("[corrupt: offset is not a multiple of 8]"));
-      return;
-    }  
+           case DW_LNS_negate_stmt:
+             adv = state_machine_regs.is_stmt;
+             adv = ! adv;
+             printf (_("  Set is_stmt to %d\n"), adv);
+             state_machine_regs.is_stmt = adv;
+             break;
 
-  start = debug_range_contents + offset;
+           case DW_LNS_set_basic_block:
+             printf (_("  Set basic block\n"));
+             state_machine_regs.basic_block = 1;
+             break;
 
-  if (offset > 0
-      /* Be paranoid - check to see if the previous
-        two words were and end-of-range marker.  */
-      && (byte_get ((unsigned char *) start - 4, 4) != 0
-         || byte_get ((unsigned char *) start - 8, 4) != 0))
-    {
-      printf (_("[corrupt: offset is not at the start of a range]"));
-      return;
-    }  
+           case DW_LNS_const_add_pc:
+             adv = (((255 - info.li_opcode_base) / info.li_line_range)
+                    * info.li_min_insn_length);
+             state_machine_regs.address += adv;
+             printf (_("  Advance PC by constant %d to 0x%lx\n"), adv,
+                     state_machine_regs.address);
+             break;
 
-  end = debug_range_contents + debug_range_size;
+           case DW_LNS_fixed_advance_pc:
+             adv = byte_get (data, 2);
+             data += 2;
+             state_machine_regs.address += adv;
+             printf (_("  Advance PC by fixed size amount %d to 0x%lx\n"),
+                     adv, state_machine_regs.address);
+             break;
 
-  printf ("(");
-  do
-    {
-      unsigned long a;
-      unsigned long b;
+           case DW_LNS_set_prologue_end:
+             printf (_("  Set prologue_end to true\n"));
+             break;
 
-      a = byte_get ((unsigned char *) start, 4);
-      b = byte_get ((unsigned char *) start + 4, 4);
+           case DW_LNS_set_epilogue_begin:
+             printf (_("  Set epilogue_begin to true\n"));
+             break;
 
-      if (a == 0xffffffff)
-       {
-         if (b == 0xffffffff)
-           {
-             decode_64bit_range (offset, base_address);
-             return;
-           }
+           case DW_LNS_set_isa:
+             adv = read_leb128 (data, & bytes_read, 0);
+             data += bytes_read;
+             printf (_("  Set ISA to %d\n"), adv);
+             break;
 
-         base_address = b;
-       }
-      else if (a == 0 && b == 0)
-       break;
-      else if (a > b)
-       printf (_("[corrupt: start > end]"));
-      else
-       {
-         if (start > debug_range_contents + offset)
-           printf (", ");
+           default:
+             printf (_("  Unknown opcode %d with operands: "), op_code);
 
-         printf (_("0x%lx - 0x%lx"),
-                 (unsigned long) base_address + a,
-                 (unsigned long) base_address + b);
+             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;
+           }
        }
-
-      start += 8;
+      putchar ('\n');
     }
-  while (start < end);
-  printf (")");
-}
 
+  return 1;
+}
 
-static unsigned char *
-read_and_display_attr_value (unsigned long attribute,
-                            unsigned long form,
-                            unsigned char *data,
-                            unsigned long cu_offset,
-                            unsigned long pointer_size,
-                            unsigned long offset_size,
-                            int dwarf_version)
+static int
+display_debug_pubnames (Elf_Internal_Shdr *section,
+                       unsigned char *start,
+                       FILE *file ATTRIBUTE_UNUSED)
 {
-  static unsigned long saved_DW_AT_low_pc = 0;
-  unsigned long uvalue = 0;
-  unsigned char *block_start = NULL;
-  int bytes_read;
+  DWARF2_Internal_PubNames pubnames;
+  unsigned char *end;
 
-  switch (form)
+  end = start + section->sh_size;
+
+  printf (_("Contents of the %s section:\n\n"), SECTION_NAME (section));
+
+  while (start < end)
     {
-    default:
-      break;
+      unsigned char *data;
+      unsigned long offset;
+      int offset_size, initial_length_size;
 
-    case DW_FORM_ref_addr:
-      if (dwarf_version == 2)
-       {
-         uvalue = byte_get (data, pointer_size);
-         data += pointer_size;
-       }
-      else if (dwarf_version == 3)
+      data = start;
+
+      pubnames.pn_length = byte_get (data, 4);
+      data += 4;
+      if (pubnames.pn_length == 0xffffffff)
        {
-         uvalue = byte_get (data, offset_size);
-         data += offset_size;
+         pubnames.pn_length = byte_get (data, 8);
+         data += 8;
+         offset_size = 8;
+         initial_length_size = 12;
        }
       else
        {
-         error (_("Internal error: DWARF version is not 2 or 3.\n"));
+         offset_size = 4;
+         initial_length_size = 4;
        }
-      break;
-
-    case DW_FORM_addr:
-      uvalue = byte_get (data, pointer_size);
-      data += pointer_size;
-      break;
-
-    case DW_FORM_strp:
-      uvalue = byte_get (data, offset_size);
-      data += offset_size;
-      break;
-
-    case DW_FORM_ref1:
-    case DW_FORM_flag:
-    case DW_FORM_data1:
-      uvalue = byte_get (data++, 1);
-      break;
 
-    case DW_FORM_ref2:
-    case DW_FORM_data2:
-      uvalue = byte_get (data, 2);
+      pubnames.pn_version = byte_get (data, 2);
       data += 2;
-      break;
-
-    case DW_FORM_ref4:
-    case DW_FORM_data4:
-      uvalue = byte_get (data, 4);
-      data += 4;
-      break;
-
-    case DW_FORM_sdata:
-      uvalue = read_leb128 (data, & bytes_read, 1);
-      data += bytes_read;
-      break;
-
-    case DW_FORM_ref_udata:
-    case DW_FORM_udata:
-      uvalue = read_leb128 (data, & bytes_read, 0);
-      data += bytes_read;
-      break;
-
-    case DW_FORM_indirect:
-      form = read_leb128 (data, & bytes_read, 0);
-      data += bytes_read;
-      printf (" %s", get_FORM_name (form));
-      return read_and_display_attr_value (attribute, form, data, cu_offset,
-                                         pointer_size, offset_size,
-                                         dwarf_version);
-    }
-
-  switch (form)
-    {
-    case DW_FORM_ref_addr:
-      printf (" <#%lx>", uvalue);
-      break;
-
-    case DW_FORM_ref1:
-    case DW_FORM_ref2:
-    case DW_FORM_ref4:
-    case DW_FORM_ref_udata:
-      printf (" <%lx>", uvalue + cu_offset);
-      break;
-
-    case DW_FORM_addr:
-      printf (" %#lx", uvalue);
-      break;
-
-    case DW_FORM_flag:
-    case DW_FORM_data1:
-    case DW_FORM_data2:
-    case DW_FORM_data4:
-    case DW_FORM_sdata:
-    case DW_FORM_udata:
-      printf (" %ld", uvalue);
-      break;
-
-    case DW_FORM_ref8:
-    case DW_FORM_data8:
-      uvalue = byte_get (data, 4);
-      printf (" %lx", uvalue);
-      printf (" %lx", (unsigned long) byte_get (data + 4, 4));
-      data += 8;
-      break;
+      pubnames.pn_offset = byte_get (data, offset_size);
+      data += offset_size;
+      pubnames.pn_size = byte_get (data, offset_size);
+      data += offset_size;
 
-    case DW_FORM_string:
-      printf (" %s", data);
-      data += strlen ((char *) data) + 1;
-      break;
+      start += pubnames.pn_length + initial_length_size;
 
-    case DW_FORM_block:
-      uvalue = read_leb128 (data, & bytes_read, 0);
-      block_start = data + bytes_read;
-      data = display_block (block_start, uvalue);
-      break;
+      if (pubnames.pn_version != 2 && pubnames.pn_version != 3)
+       {
+         static int warned = 0;
 
-    case DW_FORM_block1:
-      uvalue = byte_get (data, 1);
-      block_start = data + 1;
-      data = display_block (block_start, uvalue);
-      break;
+         if (! warned)
+           {
+             warn (_("Only DWARF 2 and 3 pubnames are currently supported\n"));
+             warned = 1;
+           }
 
-    case DW_FORM_block2:
-      uvalue = byte_get (data, 2);
-      block_start = data + 2;
-      data = display_block (block_start, uvalue);
-      break;
+         continue;
+       }
 
-    case DW_FORM_block4:
-      uvalue = byte_get (data, 4);
-      block_start = data + 4;
-      data = display_block (block_start, uvalue);
-      break;
+      printf (_("  Length:                              %ld\n"),
+             pubnames.pn_length);
+      printf (_("  Version:                             %d\n"),
+             pubnames.pn_version);
+      printf (_("  Offset into .debug_info section:     %ld\n"),
+             pubnames.pn_offset);
+      printf (_("  Size of area in .debug_info section: %ld\n"),
+             pubnames.pn_size);
 
-    case DW_FORM_strp:
-      printf (_(" (indirect string, offset: 0x%lx): %s"),
-             uvalue, fetch_indirect_string (uvalue));
-      break;
+      printf (_("\n    Offset\tName\n"));
 
-    case DW_FORM_indirect:
-      /* Handled above.  */
-      break;
+      do
+       {
+         offset = byte_get (data, offset_size);
 
-    default:
-      warn (_("Unrecognized form: %d\n"), form);
-      break;
+         if (offset != 0)
+           {
+             data += offset_size;
+             printf ("    %-6ld\t\t%s\n", offset, data);
+             data += strlen ((char *) data) + 1;
+           }
+       }
+      while (offset != 0);
     }
 
-  /* For some attributes we can display further information.  */
+  printf ("\n");
+  return 1;
+}
+
+static int
+display_debug_macinfo (Elf_Internal_Shdr *section,
+                      unsigned char *start,
+                      FILE *file ATTRIBUTE_UNUSED)
+{
+  unsigned char *end = start + section->sh_size;
+  unsigned char *curr = start;
+  unsigned int bytes_read;
+  enum dwarf_macinfo_record_type op;
 
-  printf ("\t");
+  printf (_("Contents of the %s section:\n\n"), SECTION_NAME (section));
 
-  switch (attribute)
+  while (curr < end)
     {
-    case DW_AT_inline:
-      switch (uvalue)
+      unsigned int lineno;
+      const char *string;
+
+      op = *curr;
+      curr++;
+
+      switch (op)
        {
-       case DW_INL_not_inlined:
-         printf (_("(not inlined)"));
-         break;
-       case DW_INL_inlined:
-         printf (_("(inlined)"));
-         break;
-       case DW_INL_declared_not_inlined:
-         printf (_("(declared as inline but ignored)"));
-         break;
-       case DW_INL_declared_inlined:
-         printf (_("(declared as inline and inlined)"));
+       case DW_MACINFO_start_file:
+         {
+           unsigned int filenum;
+
+           lineno = read_leb128 (curr, & bytes_read, 0);
+           curr += bytes_read;
+           filenum = read_leb128 (curr, & bytes_read, 0);
+           curr += bytes_read;
+
+           printf (_(" DW_MACINFO_start_file - lineno: %d filenum: %d\n"),
+                   lineno, filenum);
+         }
          break;
-       default:
-         printf (_("  (Unknown inline attribute value: %lx)"), uvalue);
+
+       case DW_MACINFO_end_file:
+         printf (_(" DW_MACINFO_end_file\n"));
          break;
-       }
-      break;
 
-    case DW_AT_language:
-      switch (uvalue)
-       {
-       case DW_LANG_C:                 printf ("(non-ANSI C)"); break;
-       case DW_LANG_C89:               printf ("(ANSI C)"); break;
-       case DW_LANG_C_plus_plus:       printf ("(C++)"); 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;
-         /* DWARF 2.1 values.  */
-       case DW_LANG_C99:               printf ("(ANSI C99)"); break;
-       case DW_LANG_Ada95:             printf ("(ADA 95)"); break;
-       case DW_LANG_Fortran95:         printf ("(Fortran 95)"); 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);
+       case DW_MACINFO_define:
+         lineno = read_leb128 (curr, & bytes_read, 0);
+         curr += bytes_read;
+         string = curr;
+         curr += strlen (string) + 1;
+         printf (_(" DW_MACINFO_define - lineno : %d macro : %s\n"),
+                 lineno, string);
          break;
-       }
-      break;
 
-    case DW_AT_encoding:
-      switch (uvalue)
-       {
-       case DW_ATE_void:               printf ("(void)"); break;
-       case DW_ATE_address:            printf ("(machine address)"); break;
-       case DW_ATE_boolean:            printf ("(boolean)"); break;
-       case DW_ATE_complex_float:      printf ("(complex float)"); break;
-       case DW_ATE_float:              printf ("(float)"); break;
-       case DW_ATE_signed:             printf ("(signed)"); break;
-       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.  */
-       case DW_ATE_imaginary_float:    printf ("(imaginary float)"); break;
-       default:
-         if (uvalue >= DW_ATE_lo_user
-             && uvalue <= DW_ATE_hi_user)
-           printf ("(user defined type)");
-         else
-           printf ("(unknown type)");
+       case DW_MACINFO_undef:
+         lineno = read_leb128 (curr, & bytes_read, 0);
+         curr += bytes_read;
+         string = curr;
+         curr += strlen (string) + 1;
+         printf (_(" DW_MACINFO_undef - lineno : %d macro : %s\n"),
+                 lineno, string);
          break;
-       }
-      break;
 
-    case DW_AT_accessibility:
-      switch (uvalue)
-       {
-       case DW_ACCESS_public:          printf ("(public)"); break;
-       case DW_ACCESS_protected:       printf ("(protected)"); break;
-       case DW_ACCESS_private:         printf ("(private)"); break;
-       default:
-         printf ("(unknown accessibility)");
+       case DW_MACINFO_vendor_ext:
+         {
+           unsigned int constant;
+
+           constant = read_leb128 (curr, & bytes_read, 0);
+           curr += bytes_read;
+           string = curr;
+           curr += strlen (string) + 1;
+           printf (_(" DW_MACINFO_vendor_ext - constant : %d string : %s\n"),
+                   constant, string);
+         }
          break;
        }
-      break;
+    }
 
-    case DW_AT_visibility:
-      switch (uvalue)
-       {
-       case DW_VIS_local:              printf ("(local)"); break;
-       case DW_VIS_exported:           printf ("(exported)"); break;
-       case DW_VIS_qualified:          printf ("(qualified)"); break;
-       default:                        printf ("(unknown visibility)"); break;
-       }
-      break;
+  return 1;
+}
 
-    case DW_AT_virtuality:
-      switch (uvalue)
-       {
-       case DW_VIRTUALITY_none:        printf ("(none)"); break;
-       case DW_VIRTUALITY_virtual:     printf ("(virtual)"); break;
-       case DW_VIRTUALITY_pure_virtual:printf ("(pure_virtual)"); break;
-       default:                        printf ("(unknown virtuality)"); break;
-       }
-      break;
 
-    case DW_AT_identifier_case:
-      switch (uvalue)
-       {
-       case DW_ID_case_sensitive:      printf ("(case_sensitive)"); break;
-       case DW_ID_up_case:             printf ("(up_case)"); break;
-       case DW_ID_down_case:           printf ("(down_case)"); break;
-       case DW_ID_case_insensitive:    printf ("(case_insensitive)"); break;
-       default:                        printf ("(unknown case)"); break;
-       }
-      break;
+static int
+display_debug_abbrev (Elf_Internal_Shdr *section,
+                     unsigned char *start,
+                     FILE *file ATTRIBUTE_UNUSED)
+{
+  abbrev_entry *entry;
+  unsigned char *end = start + section->sh_size;
 
-    case DW_AT_calling_convention:
-      switch (uvalue)
-       {
-       case DW_CC_normal:      printf ("(normal)"); break;
-       case DW_CC_program:     printf ("(program)"); break;
-       case DW_CC_nocall:      printf ("(nocall)"); break;
-       default:
-         if (uvalue >= DW_CC_lo_user
-             && uvalue <= DW_CC_hi_user)
-           printf ("(user defined)");
-         else
-           printf ("(unknown convention)");
-       }
-      break;
+  printf (_("Contents of the %s section:\n\n"), SECTION_NAME (section));
 
-    case DW_AT_ordering:
-      switch (uvalue)
-       {
-       case -1: printf ("(undefined)"); break;
-       case 0:  printf ("(row major)"); break;
-       case 1:  printf ("(column major)"); break;
-       }
-      break;
+  do
+    {
+      start = process_abbrev_section (start, end);
 
-    case DW_AT_frame_base:
-    case DW_AT_location:
-    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 (block_start)
-       {
-         printf ("(");
-         decode_location_expression (block_start, pointer_size, uvalue);
-         printf (")");
-       }
-      else if (form == DW_FORM_data4 || form == DW_FORM_data8)
-       printf (_("(location list)"));
+      if (first_abbrev == NULL)
+       continue;
 
-      break;
+      printf (_("  Number TAG\n"));
 
-    case DW_AT_low_pc:
-      /* This is a hack.  We keep track of the DW_AT_low_pc attributes
-        and use them when decoding DW_AT_ranges attributes.  The
-        assumption here is that we are decoding the attributes in order
-        and so the correct base address for the range is the low_pc.  */
-      saved_DW_AT_low_pc = uvalue;
-      break;
+      for (entry = first_abbrev; entry; entry = entry->next)
+       {
+         abbrev_attr *attr;
 
-    case DW_AT_ranges:
-      decode_range (uvalue, saved_DW_AT_low_pc);
-      break;
+         printf (_("   %ld      %s    [%s]\n"),
+                 entry->entry,
+                 get_TAG_name (entry->tag),
+                 entry->children ? _("has children") : _("no children"));
 
-    default:
-      break;
-    }
+         for (attr = entry->first_attr; attr; attr = attr->next)
+           printf (_("    %-18s %s\n"),
+                   get_AT_name (attr->attribute),
+                   get_FORM_name (attr->form));
+       }
 
-  return data;
-}
+      free_abbrevs ();
+    }
+  while (start);
 
-static unsigned char *
-read_and_display_attr (unsigned long attribute,
-                      unsigned long form,
-                      unsigned char *data,
-                      unsigned long cu_offset,
-                      unsigned long pointer_size,
-                      unsigned long offset_size,
-                      int dwarf_version)
-{
-  printf ("     %-18s:", get_AT_name (attribute));
-  data = read_and_display_attr_value (attribute, form, data, cu_offset,
-                                     pointer_size, offset_size, dwarf_version);
   printf ("\n");
-  return data;
-}
 
-/* Apply addends of RELA relocations.  */
+  return 1;
+}
 
 static int
-debug_apply_rela_addends (FILE *file,
-                         Elf_Internal_Shdr *section,
-                         int reloc_size,
-                         unsigned char *sec_data,
-                         unsigned char *start,
-                         unsigned char *end)
+display_debug_loc (Elf_Internal_Shdr *section,
+                  unsigned char *start, FILE *file)
 {
-  Elf_Internal_Shdr *relsec;
+  unsigned char *section_end;
+  unsigned long bytes;
+  unsigned char *section_begin = start;
+  bfd_vma addr;
+  unsigned int num_loc_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;
 
-  if (end - start < reloc_size)
-    return 1;
+  addr = section->sh_addr;
+  bytes = section->sh_size;
+  section_end = start + bytes;
 
-  for (relsec = section_headers;
-       relsec < section_headers + elf_header.e_shnum;
-       ++relsec)
+  if (bytes == 0)
     {
-      unsigned long nrelas;
-      Elf_Internal_Rela *rela, *rp;
-      Elf_Internal_Shdr *symsec;
-      Elf_Internal_Sym *symtab;
-      Elf_Internal_Sym *sym;
+      printf (_("\nThe .debug_loc section is empty.\n"));
+      return 0;
+    }
 
-      if (relsec->sh_type != SHT_RELA
-         || SECTION_HEADER (relsec->sh_info) != section
-         || relsec->sh_size == 0)
-       continue;
+  get_debug_info (file);
 
-      if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size,
-                             &rela, &nrelas))
-       return 0;
+  /* Check the order of location list in .debug_info section. If
+     offsets of location lists are in the ascending order, we can
+     use `debug_information' directly.  */
+  for (i = 0; i < num_debug_info_entries; i++)
+    {
+      unsigned int num;
 
-      symsec = SECTION_HEADER (relsec->sh_link);
-      symtab = GET_ELF_SYMBOLS (file, symsec);
+      num = debug_information [i].num_loc_offsets;
+      num_loc_list += num;
 
-      for (rp = rela; rp < rela + nrelas; ++rp)
+      /* Check if we can use `debug_information' directly.  */
+      if (use_debug_info && num != 0)
        {
-         unsigned char *loc;
-
-         if (rp->r_offset >= (bfd_vma) (start - sec_data)
-             && rp->r_offset < (bfd_vma) (end - sec_data) - reloc_size)
-           loc = sec_data + rp->r_offset;
-         else
-           continue;
-
-         if (is_32bit_elf)
+         if (!seen_first_offset)
            {
-             sym = symtab + ELF32_R_SYM (rp->r_info);
-
-             if (ELF32_R_SYM (rp->r_info) != 0
-                 && ELF32_ST_TYPE (sym->st_info) != STT_SECTION
-                 /* Relocations against object symbols can happen,
-                    eg when referencing a global array.  For an
-                    example of this see the _clz.o binary in libgcc.a.  */
-                 && ELF32_ST_TYPE (sym->st_info) != STT_OBJECT)
-               {
-                 warn (_("%s: skipping unexpected symbol type %s in relocation in section .rela%s\n"),
-                       get_symbol_type (ELF32_ST_TYPE (sym->st_info)),
-                       SECTION_NAME (section));
-                 continue;
-               }
+             /* This is the first location list.  */
+             last_offset = debug_information [i].loc_offsets [0];
+             first = i;
+             seen_first_offset = 1;
+             j = 1;
            }
          else
-           {
-             sym = symtab + ELF64_R_SYM (rp->r_info);
+           j = 0;
 
-             if (ELF64_R_SYM (rp->r_info) != 0
-                 && ELF64_ST_TYPE (sym->st_info) != STT_SECTION
-                 && ELF64_ST_TYPE (sym->st_info) != STT_OBJECT)
+         for (; j < num; j++)
+           {
+             if (last_offset >
+                 debug_information [i].loc_offsets [j])
                {
-                 warn (_("skipping unexpected symbol type %s in relocation in section .rela.%s\n"),
-                       get_symbol_type (ELF64_ST_TYPE (sym->st_info)),
-                       SECTION_NAME (section));
-                 continue;
+                 use_debug_info = 0;
+                 break;
                }
+             last_offset = debug_information [i].loc_offsets [j];
            }
-
-         byte_put (loc, rp->r_addend, reloc_size);
        }
-
-      free (symtab);
-      free (rela);
-      break;
     }
-  return 1;
-}
 
-static int
-display_debug_info (Elf_Internal_Shdr *section,
-                   unsigned char *start,
-                   FILE *file)
-{
-  unsigned char *end = start + section->sh_size;
-  unsigned char *section_begin = start;
+  if (!use_debug_info)
+    /* FIXME: Should we handle this case?  */
+    error (_("Location lists in .debug_info section aren't in ascending order!\n"));
 
-  printf (_("The section %s contains:\n\n"), SECTION_NAME (section));
+  if (!seen_first_offset)
+    error (_("No location lists in .debug_info section!\n"));
 
-  load_debug_str (file);
-  load_debug_loc (file);
-  load_debug_range (file);
+  if (debug_information [first].loc_offsets [0] != 0)
+    warn (_("Location lists in .debug_loc section start at 0x%lx\n"),
+         debug_information [first].loc_offsets [0]);
 
-  while (start < end)
+  printf (_("Contents of the .debug_loc section:\n\n"));
+  printf (_("    Offset   Begin    End      Expression\n"));
+
+  seen_first_offset = 0;
+  for (i = first; i < num_debug_info_entries; i++)
     {
-      DWARF2_Internal_CompUnit compunit;
-      unsigned char *hdrptr;
-      unsigned char *cu_abbrev_offset_ptr;
-      unsigned char *tags;
-      int level;
+      unsigned long begin;
+      unsigned long end;
+      unsigned short length;
+      unsigned long offset;
+      unsigned int pointer_size;
       unsigned long cu_offset;
-      int offset_size;
-      int initial_length_size;
-
-      hdrptr = start;
 
-      compunit.cu_length = byte_get (hdrptr, 4);
-      hdrptr += 4;
+      pointer_size = debug_information [i].pointer_size;
+      cu_offset = debug_information [i].cu_offset;
 
-      if (compunit.cu_length == 0xffffffff)
+      for (j = 0; j < debug_information [i].num_loc_offsets; j++)
        {
-         compunit.cu_length = byte_get (hdrptr, 8);
-         hdrptr += 8;
-         offset_size = 8;
-         initial_length_size = 12;
-       }
-      else
-       {
-         offset_size = 4;
-         initial_length_size = 4;
-       }
+         offset = debug_information [i].loc_offsets [j];
+         next = section_begin + offset;
 
-      compunit.cu_version = byte_get (hdrptr, 2);
-      hdrptr += 2;
+         if (!seen_first_offset)
+           seen_first_offset = 1;
+         else
+           {
+             if (start < next)
+               warn (_("There is a hole [0x%lx - 0x%lx] in .debug_loc section.\n"),
+                     start, next);
+             else if (start > next)
+               warn (_("There is an overlap [0x%lx - 0x%lx] in .debug_loc section.\n"),
+                     start, next);
+           }
+         start = next;
 
-      cu_offset = start - section_begin;
-      start += compunit.cu_length + initial_length_size;
+         while (1)
+           {
+             begin = byte_get (start, pointer_size);
+             start += pointer_size;
+             end = byte_get (start, pointer_size);
+             start += pointer_size;
 
-      if (elf_header.e_type == ET_REL
-         && !debug_apply_rela_addends (file, section, offset_size,
-                                       section_begin, hdrptr, start))
-       return 0;
+             if (begin == 0 && end == 0)
+               break;
 
-      cu_abbrev_offset_ptr = hdrptr;
-      compunit.cu_abbrev_offset = byte_get (hdrptr, offset_size);
-      hdrptr += offset_size;
+             /* For now, skip any base address specifiers.  */
+             if (begin == 0xffffffff)
+               continue;
 
-      compunit.cu_pointer_size = byte_get (hdrptr, 1);
-      hdrptr += 1;
+             begin += addr;
+             end += addr;
 
-      tags = hdrptr;
+             length = byte_get (start, 2);
+             start += 2;
 
-      printf (_("  Compilation Unit @ %lx:\n"), cu_offset);
-      printf (_("   Length:        %ld\n"), compunit.cu_length);
-      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);
+             printf ("    %8.8lx %8.8lx %8.8lx (",
+                     offset, begin, end);
+             decode_location_expression (start, pointer_size, length,
+                                         cu_offset);
+             printf (")\n");
 
-      if (compunit.cu_version != 2 && compunit.cu_version != 3)
-       {
-         warn (_("Only version 2 and 3 DWARF debug information is currently supported.\n"));
-         continue;
-       }
+             if (begin >= end)
+               warn ("Bad location list at %8.8lx from %8.8lx to %8.8lx\n",
+                     offset, begin, end);
 
-      free_abbrevs ();
+             start += length;
+           }
 
-      /* Read in the abbrevs used by this compilation unit.  */
-      {
-       Elf_Internal_Shdr *sec;
-       unsigned char *begin;
+         if (j < debug_information [i].num_loc_offsets -1)
+           printf (_("  <End of list>"));
+         printf ("\n");
+       }
+    }
+  return 1;
+}
 
-       /* Locate the .debug_abbrev section and process it.  */
-       sec = find_section (".debug_abbrev");
-       if (sec == NULL)
-         {
-           warn (_("Unable to locate .debug_abbrev section!\n"));
-           return 0;
-         }
+static int
+display_debug_str (Elf_Internal_Shdr *section,
+                  unsigned char *start,
+                  FILE *file ATTRIBUTE_UNUSED)
+{
+  unsigned long bytes;
+  bfd_vma addr;
 
-       begin = get_data (NULL, file, sec->sh_offset, sec->sh_size,
-                         _("debug_abbrev section data"));
-       if (!begin)
-         return 0;
+  addr  = section->sh_addr;
+  bytes = section->sh_size;
 
-       process_abbrev_section (begin + compunit.cu_abbrev_offset,
-                               begin + sec->sh_size);
+  if (bytes == 0)
+    {
+      printf (_("\nThe .debug_str section is empty.\n"));
+      return 0;
+    }
 
-       free (begin);
-      }
+  printf (_("Contents of the .debug_str section:\n\n"));
 
-      level = 0;
-      while (tags < start)
-       {
-         int bytes_read;
-         unsigned long abbrev_number;
-         abbrev_entry *entry;
-         abbrev_attr *attr;
+  while (bytes)
+    {
+      int j;
+      int k;
+      int lbytes;
 
-         abbrev_number = read_leb128 (tags, & bytes_read, 0);
-         tags += bytes_read;
+      lbytes = (bytes > 16 ? 16 : bytes);
 
-         /* A null DIE marks the end of a list of children.  */
-         if (abbrev_number == 0)
-           {
-             --level;
-             continue;
-           }
+      printf ("  0x%8.8lx ", (unsigned long) addr);
 
-         /* Scan through the abbreviation list until we reach the
-            correct entry.  */
-         for (entry = first_abbrev;
-              entry && entry->entry != abbrev_number;
-              entry = entry->next)
-           continue;
+      for (j = 0; j < 16; j++)
+       {
+         if (j < lbytes)
+           printf ("%2.2x", start[j]);
+         else
+           printf ("  ");
 
-         if (entry == NULL)
-           {
-             warn (_("Unable to locate entry %lu in the abbreviation table\n"),
-                   abbrev_number);
-             return 0;
-           }
+         if ((j & 3) == 3)
+           printf (" ");
+       }
 
-         printf (_(" <%d><%lx>: Abbrev Number: %lu (%s)\n"),
-                 level,
-                 (unsigned long) (tags - section_begin - bytes_read),
-                 abbrev_number,
-                 get_TAG_name (entry->tag));
+      for (j = 0; j < lbytes; j++)
+       {
+         k = start[j];
+         if (k >= ' ' && k < 0x80)
+           printf ("%c", k);
+         else
+           printf (".");
+       }
 
-         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);
+      putchar ('\n');
 
-         if (entry->children)
-           ++level;
-       }
+      start += lbytes;
+      addr  += lbytes;
+      bytes -= lbytes;
     }
 
-  free_debug_range ();
-  free_debug_str ();
-  free_debug_loc ();
+  return 1;
+}
 
-  printf ("\n");
 
-  return 1;
+static int
+display_debug_info (Elf_Internal_Shdr * section,
+                   unsigned char * start, FILE * file)
+{
+  return process_debug_info (section, start, file, 0);
 }
 
+
 static int
 display_debug_aranges (Elf_Internal_Shdr *section,
                       unsigned char *start,
@@ -9984,6 +10171,7 @@ display_debug_frames (Elf_Internal_Shdr *section,
          if (! do_debug_frames_interp && augmentation_data_len)
            {
              unsigned long i;
+
              printf ("  Augmentation data:    ");
              for (i = 0; i < augmentation_data_len; ++i)
                printf (" %02x", augmentation_data[i]);
@@ -10314,7 +10502,7 @@ display_debug_frames (Elf_Internal_Shdr *section,
              if (! do_debug_frames_interp)
                {
                  printf ("  DW_CFA_def_cfa_expression (");
-                 decode_location_expression (start, addr_size, ul);
+                 decode_location_expression (start, addr_size, ul, 0);
                  printf (")\n");
                }
              fc->cfa_exp = 1;
@@ -10327,7 +10515,7 @@ display_debug_frames (Elf_Internal_Shdr *section,
              if (! do_debug_frames_interp)
                {
                  printf ("  DW_CFA_expression: r%ld (", reg);
-                 decode_location_expression (start, addr_size, ul);
+                 decode_location_expression (start, addr_size, ul, 0);
                  printf (")\n");
                }
              fc->col_type[reg] = DW_CFA_expression;
@@ -11559,6 +11747,9 @@ process_object (char *file_name, FILE *file)
 
   if (debug_information)
     {
+      for (i = 0; i < num_debug_info_entries; i++)
+       if (debug_information [i].loc_offsets != NULL)
+         free (debug_information [i].loc_offsets);
       free (debug_information);
       debug_information = NULL;
       num_debug_info_entries = 0;