PATCHES: Dumping DWARF info with objdump (Darwin/i386)

H. J. Lu hjl@lucon.org
Thu Sep 15 21:14:00 GMT 2005


On Thu, Sep 15, 2005 at 06:39:07AM -0700, H. J. Lu wrote:
> On Wed, Sep 14, 2005 at 10:50:24PM -0700, Eric Christopher wrote:
> > >
> > >I have patches to add "-W/--dwarf" to objdump. Since objdump uses bfd
> > >to get relocated section contents, it works better on RELA .o files.
> > >Otherthan that, there are no differences between "readelf -w" and
> > >"objdump -W/--dwarf". I also have a patch to support "-W/--dwarf"
> > >on Darwin/i386. Let me know if they should be in the GNU binutils.
> > >Otherwise, I will keep them in the Linux binutils.
> > 
> > I'd like to see it, of course :) Though doesn't some of this require  
> > at least
> > minimal bfd support for mach-o?
> 
> The current mach-o support in bfd is enough for dumping DWARF info.
> 
> 

Here are patches to dump DWARF info with objdump as well as mach-o
support. They have to be applied in the order of

binutils-darwin-1.patch
readelf-reloc-1.patch
readelf-gen-8.patch
readelf-dwarf-12.patch
objdump-dump-6.patch
objdump-mach-o-3.patch


H.J.
-------------- next part --------------
2005-09-15  H.J. Lu  <hongjiu.lu@intel.com>

	* configure.in (*-*-darwin*): Build bfd, binutils and opcodes.
	* configure: Regenerated.

--- binutils/configure.darwin	2005-09-02 11:15:13.000000000 -0700
+++ binutils/configure	2005-09-14 06:45:02.000000000 -0700
@@ -1156,7 +1156,7 @@ case "${target}" in
     noconfigdirs="$noconfigdirs sim target-rda"
     ;;
   *-*-darwin*)
-    noconfigdirs="$noconfigdirs bfd binutils ld gas opcodes gdb gprof"
+    noconfigdirs="$noconfigdirs ld gas gdb gprof"
     noconfigdirs="$noconfigdirs sim target-rda"
     noconfigdirs="$noconfigdirs ${libgcj}"
     ;;
--- binutils/configure.in.darwin	2005-09-02 11:15:13.000000000 -0700
+++ binutils/configure.in	2005-09-14 06:44:52.000000000 -0700
@@ -364,7 +364,7 @@ case "${target}" in
     noconfigdirs="$noconfigdirs sim target-rda"
     ;;
   *-*-darwin*)
-    noconfigdirs="$noconfigdirs bfd binutils ld gas opcodes gdb gprof"
+    noconfigdirs="$noconfigdirs ld gas gdb gprof"
     noconfigdirs="$noconfigdirs sim target-rda"
     noconfigdirs="$noconfigdirs ${libgcj}"
     ;;
-------------- next part --------------
2005-09-02  H.J. Lu  <hongjiu.lu@intel.com>

	* readelf.c (debug_apply_rela_addends): Relocate the whole
	section.
	(process_debug_info): Don't call debug_apply_rela_addends.
	(display_debug_frames): Likewise.
	(get_debug_info): Call debug_apply_rela_addends.
	(debug_displays): Add the "relocate" field.
	(display_debug_section): Call debug_apply_rela_addends if
	needed.

--- binutils/readelf.c.reloc	2005-09-02 08:27:45.000000000 -0700
+++ binutils/readelf.c	2005-09-02 11:38:33.000000000 -0700
@@ -7747,14 +7747,17 @@ free_debug_abbrev (void)
 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)
+			  unsigned char *start)
 {
   Elf_Internal_Shdr *relsec;
+  unsigned char *end = start + section->sh_size;
+  /* FIXME: The relocation field size is relocation type dependent.  */
+  unsigned int reloc_size = 4;
+
+  if (elf_header.e_type != ET_REL)
+    return 1;
 
-  if (end - start < reloc_size)
+  if (section->sh_size < reloc_size)
     return 1;
 
   for (relsec = section_headers;
@@ -7785,11 +7788,14 @@ debug_apply_rela_addends (FILE *file,
 	{
 	  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;
+	  loc = start + rp->r_offset;
+	  if ((loc + reloc_size) > end)
+	    {
+	      warn (_("skipping invalid relocation offset 0x%lx in section %s\n"),
+		    (unsigned long) rp->r_offset,
+		    SECTION_NAME (section));
+	      continue;
+	    }
 
 	  if (is_32bit_elf)
 	    {
@@ -9177,11 +9183,6 @@ process_debug_info (Elf_Internal_Shdr *s
       cu_offset = start - section_begin;
       start += compunit.cu_length + initial_length_size;
 
-      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;
@@ -9393,7 +9394,9 @@ get_debug_info (FILE * file)
   if (start == NULL)
     return 0;
 
-  ret = process_debug_info (section, start, file, 1);
+  ret = (debug_apply_rela_addends (file, section, start)
+	 && process_debug_info (section, start, file, 1));
+
   free (start);
 
   return ret ? num_debug_info_entries : 0;
@@ -10594,11 +10597,6 @@ display_debug_frames (Elf_Internal_Shdr 
       block_end = saved_start + length + initial_length_size;
       cie_id = byte_get (start, offset_size); start += offset_size;
 
-      if (elf_header.e_type == ET_REL
-	  && !debug_apply_rela_addends (file, section, offset_size,
-					section_start, start, block_end))
-	return 0;
-
       if (is_eh ? (cie_id == 0) : (cie_id == DW_CIE_ID))
 	{
 	  int version;
@@ -11236,25 +11234,26 @@ static struct
 {
   const char *const name;
   int (*display) (Elf_Internal_Shdr *, unsigned char *, FILE *);
+  unsigned int relocate : 1;
 }
 debug_displays[] =
 {
-  { ".debug_abbrev",		display_debug_abbrev },
-  { ".debug_aranges",		display_debug_aranges },
-  { ".debug_frame",		display_debug_frames },
-  { ".debug_info",		display_debug_info },
-  { ".debug_line",		display_debug_lines },
-  { ".debug_pubnames",		display_debug_pubnames },
-  { ".eh_frame",		display_debug_frames },
-  { ".debug_macinfo",		display_debug_macinfo },
-  { ".debug_str",		display_debug_str },
-  { ".debug_loc",		display_debug_loc },
-  { ".debug_pubtypes",		display_debug_pubnames },
-  { ".debug_ranges",		display_debug_ranges },
-  { ".debug_static_func",	display_debug_not_supported },
-  { ".debug_static_vars",	display_debug_not_supported },
-  { ".debug_types",		display_debug_not_supported },
-  { ".debug_weaknames",		display_debug_not_supported }
+  { ".debug_abbrev",		display_debug_abbrev,		0 },
+  { ".debug_aranges",		display_debug_aranges,		0 },
+  { ".debug_frame",		display_debug_frames,		1 },
+  { ".debug_info",		display_debug_info,		1 },
+  { ".debug_line",		display_debug_lines,		0 },
+  { ".debug_pubnames",		display_debug_pubnames,		0 },
+  { ".eh_frame",		display_debug_frames,		1 },
+  { ".debug_macinfo",		display_debug_macinfo,		0 },
+  { ".debug_str",		display_debug_str,		0 },
+  { ".debug_loc",		display_debug_loc,		0 },
+  { ".debug_pubtypes",		display_debug_pubnames,		0 },
+  { ".debug_ranges",		display_debug_ranges,		0 },
+  { ".debug_static_func",	display_debug_not_supported,	0 },
+  { ".debug_static_vars",	display_debug_not_supported,	0 },
+  { ".debug_types",		display_debug_not_supported,	0 },
+  { ".debug_weaknames",		display_debug_not_supported,	0 }
 };
 
 static int
@@ -11289,7 +11288,10 @@ display_debug_section (Elf_Internal_Shdr
 	    break;
 	  }
 
-	result &= debug_displays[i].display (section, start, file);
+	if (!debug_displays[i].relocate
+	    || debug_apply_rela_addends (file, section, start))
+	  result &= debug_displays[i].display (section, start, file);
+
 	free (start);
 
 	/* If we loaded in the abbrev section
-------------- next part --------------
2005-09-15  H.J. Lu  <hongjiu.lu@intel.com>

	* readelf.c: Reordered.
	(is_relocatable): New.
	(dwarf_section): New structure for DWARF section.
	(load_debug_section): New.
	(free_debug_section): Likewise.
	(debug_str_section): Likewise.
	(debug_abbrev_section): Likewise.
	(debug_str_contents): Removed.
	(debug_str_size): Likewise.
	(debug_loc_contents): Likewise.
	(debug_loc_size): Likewise.
	(debug_range_contents): Likewise.
	(debug_range_size): Likewise.
	(load_debug_str): Likewise.
	(free_debug_str): Likewise.
	(load_debug_loc): Likewise.
	(free_debug_loc): Likewise.
	(load_debug_arange): Likewise.
	(free_debug_arange): Likewise.
	(load_debug_abbrev): Likewise.
	(free_debug_abbrev): Likewise.
	(fetch_indirect_string): Updated.
	(debug_apply_rela_addends): Likewise.
	(process_debug_info): Likewise.
	(get_debug_info): Likewise.
	(display_debug_lines): Likewise.
	(display_debug_pubnames): Likewise.
	(display_debug_macinfo): Likewise.
	(display_debug_abbrev): Likewise.
	(display_debug_loc): Likewise.
	(display_debug_str): Likewise.
	(display_debug_info): Likewise.
	(display_debug_aranges): Likewise.
	(display_debug_ranges): Likewise.
	(display_debug_frames): Likewise.
	(display_debug_not_supported): Likewise.
	(debug_displays): Likewise.
	(display_debug_section): Likewise.
	(get_file_header): Set is_relocatable.

--- binutils/readelf.c.gen	2005-09-15 07:00:09.000000000 -0700
+++ binutils/readelf.c	2005-09-15 07:12:57.000000000 -0700
@@ -171,6 +171,7 @@ static int do_debug_loc;
 static int do_arch;
 static int do_notes;
 static int is_32bit_elf;
+static int is_relocatable;
 static int have_frame_base;
 static int need_base_address;
 static bfd_vma eh_addr_size;
@@ -363,68 +364,6 @@ get_data (void *var, FILE *file, long of
   return mvar;
 }
 
-static bfd_vma
-byte_get_little_endian (unsigned char *field, int size)
-{
-  switch (size)
-    {
-    case 1:
-      return *field;
-
-    case 2:
-      return  ((unsigned int) (field[0]))
-	|    (((unsigned int) (field[1])) << 8);
-
-#ifndef BFD64
-    case 8:
-      /* We want to extract data from an 8 byte wide field and
-	 place it into a 4 byte wide field.  Since this is a little
-	 endian source we can just use the 4 byte extraction code.  */
-      /* Fall through.  */
-#endif
-    case 4:
-      return  ((unsigned long) (field[0]))
-	|    (((unsigned long) (field[1])) << 8)
-	|    (((unsigned long) (field[2])) << 16)
-	|    (((unsigned long) (field[3])) << 24);
-
-#ifdef BFD64
-    case 8:
-      return  ((bfd_vma) (field[0]))
-	|    (((bfd_vma) (field[1])) << 8)
-	|    (((bfd_vma) (field[2])) << 16)
-	|    (((bfd_vma) (field[3])) << 24)
-	|    (((bfd_vma) (field[4])) << 32)
-	|    (((bfd_vma) (field[5])) << 40)
-	|    (((bfd_vma) (field[6])) << 48)
-	|    (((bfd_vma) (field[7])) << 56);
-#endif
-    default:
-      error (_("Unhandled data length: %d\n"), size);
-      abort ();
-    }
-}
-
-static bfd_vma
-byte_get_signed (unsigned char *field, int size)
-{
-  bfd_vma x = byte_get (field, size);
-
-  switch (size)
-    {
-    case 1:
-      return (x ^ 0x80) - 0x80;
-    case 2:
-      return (x ^ 0x8000) - 0x8000;
-    case 4:
-      return (x ^ 0x80000000) - 0x80000000;
-    case 8:
-      return x;
-    default:
-      abort ();
-    }
-}
-
 static void
 byte_put_little_endian (unsigned char *field, bfd_vma value, int size)
 {
@@ -614,48 +553,6 @@ print_symbol (int width, const char *sym
     printf ("%-.*s", width, symbol);
 }
 
-static bfd_vma
-byte_get_big_endian (unsigned char *field, int size)
-{
-  switch (size)
-    {
-    case 1:
-      return *field;
-
-    case 2:
-      return ((unsigned int) (field[1])) | (((int) (field[0])) << 8);
-
-#ifndef BFD64
-    case 8:
-      /* Although we are extracing data from an 8 byte wide field,
-	 we are returning only 4 bytes of data.  */
-      field += 4;
-      /* Fall thru */
-#endif
-    case 4:
-      return ((unsigned long) (field[3]))
-	|   (((unsigned long) (field[2])) << 8)
-	|   (((unsigned long) (field[1])) << 16)
-	|   (((unsigned long) (field[0])) << 24);
-
-#ifdef BFD64
-    case 8:
-      return ((bfd_vma) (field[7]))
-	|   (((bfd_vma) (field[6])) << 8)
-	|   (((bfd_vma) (field[5])) << 16)
-	|   (((bfd_vma) (field[4])) << 24)
-	|   (((bfd_vma) (field[3])) << 32)
-	|   (((bfd_vma) (field[2])) << 40)
-	|   (((bfd_vma) (field[1])) << 48)
-	|   (((bfd_vma) (field[0])) << 56);
-#endif
-
-    default:
-      error (_("Unhandled data length: %d\n"), size);
-      abort ();
-    }
-}
-
 static void
 byte_put_big_endian (unsigned char *field, bfd_vma value, int size)
 {
@@ -7474,295 +7371,66 @@ dump_section (Elf_Internal_Shdr *section
 }
 
 
-static unsigned long int
-read_leb128 (unsigned char *data, unsigned int *length_return, int sign)
-{
-  unsigned long int result = 0;
-  unsigned int num_read = 0;
-  unsigned int shift = 0;
-  unsigned char byte;
-
-  do
-    {
-      byte = *data++;
-      num_read++;
-
-      result |= ((unsigned long int) (byte & 0x7f)) << shift;
-
-      shift += 7;
-
-    }
-  while (byte & 0x80);
-
-  if (length_return != NULL)
-    *length_return = num_read;
-
-  if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40))
-    result |= -1L << shift;
-
-  return result;
-}
-
-typedef struct State_Machine_Registers
-{
-  unsigned long address;
-  unsigned int file;
-  unsigned int line;
-  unsigned int column;
-  int is_stmt;
-  int basic_block;
-  int end_sequence;
-/* This variable hold the number of the last entry seen
-   in the File Table.  */
-  unsigned int last_file_entry;
-} SMR;
-
-static SMR state_machine_regs;
-
-static void
-reset_state_machine (int is_stmt)
-{
-  state_machine_regs.address = 0;
-  state_machine_regs.file = 1;
-  state_machine_regs.line = 1;
-  state_machine_regs.column = 0;
-  state_machine_regs.is_stmt = is_stmt;
-  state_machine_regs.basic_block = 0;
-  state_machine_regs.end_sequence = 0;
-  state_machine_regs.last_file_entry = 0;
-}
-
-/* Handled an extend line op.
-   Returns the number of bytes read.  */
-
-static int
-process_extended_line_op (unsigned char *data, int is_stmt, int pointer_size)
+struct dwarf_section
 {
-  unsigned char op_code;
-  unsigned int bytes_read;
-  unsigned int len;
-  unsigned char *name;
-  unsigned long adr;
-
-  len = read_leb128 (data, & bytes_read, 0);
-  data += bytes_read;
-
-  if (len == 0)
-    {
-      warn (_("badly formed extended line op encountered!\n"));
-      return bytes_read;
-    }
-
-  len += bytes_read;
-  op_code = *data++;
-
-  printf (_("  Extended opcode %d: "), op_code);
-
-  switch (op_code)
-    {
-    case DW_LNE_end_sequence:
-      printf (_("End of Sequence\n\n"));
-      reset_state_machine (is_stmt);
-      break;
-
-    case DW_LNE_set_address:
-      adr = byte_get (data, pointer_size);
-      printf (_("set Address to 0x%lx\n"), adr);
-      state_machine_regs.address = adr;
-      break;
-
-    case DW_LNE_define_file:
-      printf (_("  define new File Table entry\n"));
-      printf (_("  Entry\tDir\tTime\tSize\tName\n"));
-
-      printf (_("   %d\t"), ++state_machine_regs.last_file_entry);
-      name = data;
-      data += strlen ((char *) data) + 1;
-      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));
-      printf (_("%s\n\n"), name);
-      break;
-
-    default:
-      printf (_("UNKNOWN: length %d\n"), len - bytes_read);
-      break;
-    }
-
-  return len;
-}
+  const char *name;
+  unsigned char *start;
+  bfd_vma address;
+  bfd_size_type size;
+};
 
-static const char *debug_str_contents;
-static bfd_vma debug_str_size;
+static int process_debug_info (struct dwarf_section *, void *, int);
 
 static void
-load_debug_str (FILE *file)
+load_debug_section (struct dwarf_section *section, void *file)
 {
   Elf_Internal_Shdr *sec;
+  char buf [64];
 
   /* If it is already loaded, do nothing.  */
-  if (debug_str_contents != NULL)
+  if (section->start != NULL)
     return;
 
-  /* Locate the .debug_str section.  */
-  sec = find_section (".debug_str");
+  /* Locate the debug section.  */
+  sec = find_section (section->name);
   if (sec == NULL)
     return;
 
-  debug_str_size = sec->sh_size;
-
-  debug_str_contents = get_data (NULL, file, sec->sh_offset, 1, sec->sh_size,
-				 _("debug_str section data"));
+  snprintf (buf, sizeof (buf), _("%s section data"), section->name);
+  section->address = sec->sh_addr;
+  section->size = sec->sh_size;
+  section->start = get_data (NULL, file, sec->sh_offset, 1,
+			     sec->sh_size, buf);
 }
 
 static void
-free_debug_str (void)
+free_debug_section (struct dwarf_section *section)
 {
-  if (debug_str_contents == NULL)
+  if (section->start == NULL)
     return;
 
-  free ((char *) debug_str_contents);
-  debug_str_contents = NULL;
-  debug_str_size = 0;
-}
-
-static const char *
-fetch_indirect_string (unsigned long offset)
-{
-  if (debug_str_contents == NULL)
-    return _("<no .debug_str section>");
-
-  if (offset > debug_str_size)
-    {
-      warn (_("DW_FORM_strp offset too big: %lx\n"), offset);
-      return _("<offset is too big>");
-    }
-
-  return debug_str_contents + offset;
+  free ((char *) section->start);
+  section->start = NULL;
+  section->size = 0;
 }
 
-static const char *debug_loc_contents;
-static bfd_vma debug_loc_size;
+/* Apply addends of RELA relocations.  */
 
-static void
-load_debug_loc (FILE *file)
+static int
+debug_apply_rela_addends (void *file,
+			  Elf_Internal_Shdr *section,
+			  unsigned char *start)
 {
-  Elf_Internal_Shdr *sec;
-
-  /* If it is already loaded, do nothing.  */
-  if (debug_loc_contents != NULL)
-    return;
+  Elf_Internal_Shdr *relsec;
+  unsigned char *end = start + section->sh_size;
+  /* FIXME: The relocation field size is relocation type dependent.  */
+  unsigned int reloc_size = 4;
 
-  /* Locate the .debug_loc section.  */
-  sec = find_section (".debug_loc");
-  if (sec == NULL)
-    return;
+  if (!is_relocatable)
+    return 1;
 
-  debug_loc_size = sec->sh_size;
-
-  debug_loc_contents = get_data (NULL, file, sec->sh_offset, 1, sec->sh_size,
-				 _("debug_loc section data"));
-}
-
-static void
-free_debug_loc (void)
-{
-  if (debug_loc_contents == NULL)
-    return;
-
-  free ((char *) debug_loc_contents);
-  debug_loc_contents = NULL;
-  debug_loc_size = 0;
-}
-
-static const char *   debug_range_contents;
-static unsigned long  debug_range_size;
-
-static void
-load_debug_range (FILE *file)
-{
-  Elf_Internal_Shdr *sec;
-
-  /* If it is already loaded, do nothing.  */
-  if (debug_range_contents != NULL)
-    return;
-
-  /* Locate the .debug_ranges section.  */
-  sec = find_section (".debug_ranges");
-  if (sec == NULL)
-    return;
-
-  debug_range_size = sec->sh_size;
-
-  debug_range_contents = get_data (NULL, file, sec->sh_offset, 1, sec->sh_size,
-				   _("debug_range section data"));
-}
-
-static void
-free_debug_range (void)
-{
-  if (debug_range_contents == NULL)
-    return;
-
-  free ((char *) debug_range_contents);
-  debug_range_contents = NULL;
-  debug_range_size = 0;
-}
-
-static unsigned char *debug_abbrev_contents;
-static unsigned long debug_abbrev_size;
-
-static void
-load_debug_abbrev (FILE *file)
-{
-  Elf_Internal_Shdr *sec;
-
-  /* If it is already loaded, do nothing.  */
-  if (debug_abbrev_contents != NULL)
-    return;
-
-  /* Locate the .debug_ranges section.  */
-  sec = find_section (".debug_abbrev");
-  if (sec == NULL)
-    return;
-
-  debug_abbrev_size = sec->sh_size;
-
-  debug_abbrev_contents = get_data (NULL, file, sec->sh_offset, 1,
-				    sec->sh_size,
-				    _("debug_abbrev section data"));
-}
-
-static void
-free_debug_abbrev (void)
-{
-  if (debug_abbrev_contents == NULL)
-    return;
-
-  free ((char *) debug_abbrev_contents);
-  debug_abbrev_contents = NULL;
-  debug_abbrev_size = 0;
-}
-
-/* Apply addends of RELA relocations.  */
-
-static int
-debug_apply_rela_addends (FILE *file,
-			  Elf_Internal_Shdr *section,
-			  unsigned char *start)
-{
-  Elf_Internal_Shdr *relsec;
-  unsigned char *end = start + section->sh_size;
-  /* FIXME: The relocation field size is relocation type dependent.  */
-  unsigned int reloc_size = 4;
-
-  if (elf_header.e_type != ET_REL)
-    return 1;
-
-  if (section->sh_size < reloc_size)
-    return 1;
+  if (section->sh_size < reloc_size)
+    return 1;
 
   for (relsec = section_headers;
        relsec < section_headers + elf_header.e_shnum;
@@ -7855,6 +7523,259 @@ debug_apply_rela_addends (FILE *file,
   return 1;
 }
 
+static bfd_vma
+byte_get_little_endian (unsigned char *field, int size)
+{
+  switch (size)
+    {
+    case 1:
+      return *field;
+
+    case 2:
+      return  ((unsigned int) (field[0]))
+	|    (((unsigned int) (field[1])) << 8);
+
+#ifndef BFD64
+    case 8:
+      /* We want to extract data from an 8 byte wide field and
+	 place it into a 4 byte wide field.  Since this is a little
+	 endian source we can just use the 4 byte extraction code.  */
+      /* Fall through.  */
+#endif
+    case 4:
+      return  ((unsigned long) (field[0]))
+	|    (((unsigned long) (field[1])) << 8)
+	|    (((unsigned long) (field[2])) << 16)
+	|    (((unsigned long) (field[3])) << 24);
+
+#ifdef BFD64
+    case 8:
+      return  ((bfd_vma) (field[0]))
+	|    (((bfd_vma) (field[1])) << 8)
+	|    (((bfd_vma) (field[2])) << 16)
+	|    (((bfd_vma) (field[3])) << 24)
+	|    (((bfd_vma) (field[4])) << 32)
+	|    (((bfd_vma) (field[5])) << 40)
+	|    (((bfd_vma) (field[6])) << 48)
+	|    (((bfd_vma) (field[7])) << 56);
+#endif
+    default:
+      error (_("Unhandled data length: %d\n"), size);
+      abort ();
+    }
+}
+
+static bfd_vma
+byte_get_signed (unsigned char *field, int size)
+{
+  bfd_vma x = byte_get (field, size);
+
+  switch (size)
+    {
+    case 1:
+      return (x ^ 0x80) - 0x80;
+    case 2:
+      return (x ^ 0x8000) - 0x8000;
+    case 4:
+      return (x ^ 0x80000000) - 0x80000000;
+    case 8:
+      return x;
+    default:
+      abort ();
+    }
+}
+
+static bfd_vma
+byte_get_big_endian (unsigned char *field, int size)
+{
+  switch (size)
+    {
+    case 1:
+      return *field;
+
+    case 2:
+      return ((unsigned int) (field[1])) | (((int) (field[0])) << 8);
+
+#ifndef BFD64
+    case 8:
+      /* Although we are extracing data from an 8 byte wide field,
+	 we are returning only 4 bytes of data.  */
+      field += 4;
+      /* Fall thru */
+#endif
+    case 4:
+      return ((unsigned long) (field[3]))
+	|   (((unsigned long) (field[2])) << 8)
+	|   (((unsigned long) (field[1])) << 16)
+	|   (((unsigned long) (field[0])) << 24);
+
+#ifdef BFD64
+    case 8:
+      return ((bfd_vma) (field[7]))
+	|   (((bfd_vma) (field[6])) << 8)
+	|   (((bfd_vma) (field[5])) << 16)
+	|   (((bfd_vma) (field[4])) << 24)
+	|   (((bfd_vma) (field[3])) << 32)
+	|   (((bfd_vma) (field[2])) << 40)
+	|   (((bfd_vma) (field[1])) << 48)
+	|   (((bfd_vma) (field[0])) << 56);
+#endif
+
+    default:
+      error (_("Unhandled data length: %d\n"), size);
+      abort ();
+    }
+}
+
+static unsigned long int
+read_leb128 (unsigned char *data, unsigned int *length_return, int sign)
+{
+  unsigned long int result = 0;
+  unsigned int num_read = 0;
+  unsigned int shift = 0;
+  unsigned char byte;
+
+  do
+    {
+      byte = *data++;
+      num_read++;
+
+      result |= ((unsigned long int) (byte & 0x7f)) << shift;
+
+      shift += 7;
+
+    }
+  while (byte & 0x80);
+
+  if (length_return != NULL)
+    *length_return = num_read;
+
+  if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40))
+    result |= -1L << shift;
+
+  return result;
+}
+
+typedef struct State_Machine_Registers
+{
+  unsigned long address;
+  unsigned int file;
+  unsigned int line;
+  unsigned int column;
+  int is_stmt;
+  int basic_block;
+  int end_sequence;
+/* This variable hold the number of the last entry seen
+   in the File Table.  */
+  unsigned int last_file_entry;
+} SMR;
+
+static SMR state_machine_regs;
+
+static void
+reset_state_machine (int is_stmt)
+{
+  state_machine_regs.address = 0;
+  state_machine_regs.file = 1;
+  state_machine_regs.line = 1;
+  state_machine_regs.column = 0;
+  state_machine_regs.is_stmt = is_stmt;
+  state_machine_regs.basic_block = 0;
+  state_machine_regs.end_sequence = 0;
+  state_machine_regs.last_file_entry = 0;
+}
+
+/* Handled an extend line op.
+   Returns the number of bytes read.  */
+
+static int
+process_extended_line_op (unsigned char *data, int is_stmt, int pointer_size)
+{
+  unsigned char op_code;
+  unsigned int bytes_read;
+  unsigned int len;
+  unsigned char *name;
+  unsigned long adr;
+
+  len = read_leb128 (data, & bytes_read, 0);
+  data += bytes_read;
+
+  if (len == 0)
+    {
+      warn (_("badly formed extended line op encountered!\n"));
+      return bytes_read;
+    }
+
+  len += bytes_read;
+  op_code = *data++;
+
+  printf (_("  Extended opcode %d: "), op_code);
+
+  switch (op_code)
+    {
+    case DW_LNE_end_sequence:
+      printf (_("End of Sequence\n\n"));
+      reset_state_machine (is_stmt);
+      break;
+
+    case DW_LNE_set_address:
+      adr = byte_get (data, pointer_size);
+      printf (_("set Address to 0x%lx\n"), adr);
+      state_machine_regs.address = adr;
+      break;
+
+    case DW_LNE_define_file:
+      printf (_("  define new File Table entry\n"));
+      printf (_("  Entry\tDir\tTime\tSize\tName\n"));
+
+      printf (_("   %d\t"), ++state_machine_regs.last_file_entry);
+      name = data;
+      data += strlen ((char *) data) + 1;
+      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));
+      printf (_("%s\n\n"), name);
+      break;
+
+    default:
+      printf (_("UNKNOWN: length %d\n"), len - bytes_read);
+      break;
+    }
+
+  return len;
+}
+
+static struct dwarf_section debug_str_section = {
+  ".debug_str",
+  NULL,
+  0,
+  0
+};
+
+static const char *
+fetch_indirect_string (unsigned long offset)
+{
+  if (debug_str_section.start == NULL)
+    return _("<no .debug_str section>");
+
+  if (offset > debug_str_section.size)
+    {
+      warn (_("DW_FORM_strp offset too big: %lx\n"), offset);
+      return _("<offset is too big>");
+    }
+
+  return debug_str_section.start + offset;
+}
+
+static struct dwarf_section debug_abbrev_section = {
+  ".debug_abbrev",
+  NULL,
+  0,
+  0
+};
+
 /* FIXME:  There are better and more efficient ways to handle
    these structures.  For now though, I just want something that
    is simple to implement.  */
@@ -9087,10 +9008,11 @@ read_and_display_attr (unsigned long att
    anything to the user.  */
 
 static int
-process_debug_info (Elf_Internal_Shdr *section, unsigned char *start,
-		    FILE *file, int do_loc)
+process_debug_info (struct dwarf_section *section, void *file,
+		    int do_loc)
 {
-  unsigned char *end = start + section->sh_size;
+  unsigned char *start = section->start;
+  unsigned char *end = start + section->size;
   unsigned char *section_begin;
   unsigned int unit;
   unsigned int num_units = 0;
@@ -9120,7 +9042,7 @@ process_debug_info (Elf_Internal_Shdr *s
 
       if (num_units == 0)
 	{
-	  error (_("No comp units in .debug_info section ?"));
+	  error (_("No comp units in %s section ?"), section->name);
 	  return 0;
 	}
 
@@ -9137,18 +9059,16 @@ process_debug_info (Elf_Internal_Shdr *s
 
   if (!do_loc)
     {
-      printf (_("The section %s contains:\n\n"),
-	      SECTION_NAME (section));
+      printf (_("The section %s contains:\n\n"), section->name);
 
-      load_debug_str (file);
-      load_debug_loc (file);
-      load_debug_range (file);
+      load_debug_section (&debug_str_section, file);
     }
 
-  load_debug_abbrev (file);
-  if (debug_abbrev_contents == NULL)
+  load_debug_section (&debug_abbrev_section, file);
+  if (debug_abbrev_section.start == NULL)
     {
-      warn (_("Unable to locate .debug_abbrev section!\n"));
+      warn (_("Unable to locate %s section!\n"),
+	    debug_abbrev_section.name);
       return 0;
     }
 
@@ -9230,8 +9150,10 @@ process_debug_info (Elf_Internal_Shdr *s
 
       /* Process the abbrevs used by this compilation unit.  */
       process_abbrev_section
-	(debug_abbrev_contents + compunit.cu_abbrev_offset,
-	 debug_abbrev_contents + debug_abbrev_size);
+	((unsigned char *) debug_abbrev_section.start
+	 + compunit.cu_abbrev_offset,
+	 (unsigned char *) debug_abbrev_section.start
+	 + debug_abbrev_section.size);
 
       level = 0;
       while (tags < start)
@@ -9305,7 +9227,7 @@ process_debug_info (Elf_Internal_Shdr *s
  	}
     }
  
-  free_debug_abbrev ();
+  free_debug_section (&debug_abbrev_section);
 
   /* Set num_debug_info_entries here so that it can be used to check if
      we need to process .debug_loc and .debug_ranges sections.  */
@@ -9315,9 +9237,7 @@ process_debug_info (Elf_Internal_Shdr *s
       
   if (!do_loc)
     {
-      free_debug_range ();
-      free_debug_str ();
-      free_debug_loc (); 
+      free_debug_section (&debug_str_section);
 
       printf ("\n");
     }
@@ -9374,11 +9294,11 @@ get_pointer_size_and_offset_of_comp_unit
    compilation units upon success.  */
 
 static unsigned int
-get_debug_info (FILE * file)
+get_debug_info (void * file)
 {
   Elf_Internal_Shdr * section;
-  unsigned char *     start;
-  int		      ret;
+  struct dwarf_section sec;
+  int ret;
 
   /* Reset the last pointer size so that we can issue correct error
      messages if we are displaying the contents of more than one section.  */
@@ -9389,33 +9309,37 @@ get_debug_info (FILE * file)
   if (num_debug_info_entries > 0)
     return num_debug_info_entries;
 
-  section = find_section (".debug_info");
+  sec.name = ".debug_info";
+  section = find_section (sec.name);
   if (section == NULL)
     return 0;
 
-  start = get_data (NULL, file, section->sh_offset, 1, section->sh_size,
-		    _("extracting information from .debug_info section"));
-  if (start == NULL)
+  sec.start = get_data (NULL, file, section->sh_offset, 1,
+			section->sh_size,
+			_("extracting information from .debug_info section"));
+  if (sec.start == NULL)
     return 0;
 
-  ret = (debug_apply_rela_addends (file, section, start)
-	 && process_debug_info (section, start, file, 1));
+  sec.address = section->sh_addr;
+  sec.size = section->sh_size;
+  ret = (debug_apply_rela_addends (file, section, sec.start)
+	 && process_debug_info (&sec, file, 1));
 
-  free (start);
+  free (sec.start);
 
   return ret ? num_debug_info_entries : 0;
 }
 
 static int
-display_debug_lines (Elf_Internal_Shdr *section,
-		     unsigned char *start, FILE *file)
+display_debug_lines (struct dwarf_section *section, void *file)
 {
+  unsigned char *start = section->start;
   unsigned char *data = start;
-  unsigned char *end = start + section->sh_size;
+  unsigned char *end = start + section->size;
   unsigned int comp_unit = 0;
 
   printf (_("\nDump of debug contents of section %s:\n\n"),
-	  SECTION_NAME (section));
+	  section->name);
 
   get_debug_info (file);
 
@@ -9450,7 +9374,7 @@ display_debug_lines (Elf_Internal_Shdr *
 	  initial_length_size = 4;
 	}
 
-      if (info.li_length + initial_length_size > section->sh_size)
+      if (info.li_length + initial_length_size > section->size)
 	{
 	  warn
 	    (_("The line info appears to be corrupt - the section is too small\n"));
@@ -9697,16 +9621,14 @@ display_debug_lines (Elf_Internal_Shdr *
 }
 
 static int
-display_debug_pubnames (Elf_Internal_Shdr *section,
-			unsigned char *start,
-			FILE *file ATTRIBUTE_UNUSED)
+display_debug_pubnames (struct dwarf_section *section,
+			void *file ATTRIBUTE_UNUSED)
 {
   DWARF2_Internal_PubNames pubnames;
-  unsigned char *end;
-
-  end = start + section->sh_size;
+  unsigned char *start = section->start;
+  unsigned char *end = start + section->size;
 
-  printf (_("Contents of the %s section:\n\n"), SECTION_NAME (section));
+  printf (_("Contents of the %s section:\n\n"), section->name);
 
   while (start < end)
     {
@@ -9783,16 +9705,16 @@ display_debug_pubnames (Elf_Internal_Shd
 }
 
 static int
-display_debug_macinfo (Elf_Internal_Shdr *section,
-		       unsigned char *start,
-		       FILE *file ATTRIBUTE_UNUSED)
+display_debug_macinfo (struct dwarf_section *section,
+		       void *file ATTRIBUTE_UNUSED)
 {
-  unsigned char *end = start + section->sh_size;
+  unsigned char *start = section->start;
+  unsigned char *end = start + section->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));
+  printf (_("Contents of the %s section:\n\n"), section->name);
 
   while (curr < end)
     {
@@ -9860,14 +9782,14 @@ display_debug_macinfo (Elf_Internal_Shdr
 
 
 static int
-display_debug_abbrev (Elf_Internal_Shdr *section,
-		      unsigned char *start,
-		      FILE *file ATTRIBUTE_UNUSED)
+display_debug_abbrev (struct dwarf_section *section,
+		      void *file ATTRIBUTE_UNUSED)
 {
   abbrev_entry *entry;
-  unsigned char *end = start + section->sh_size;
+  unsigned char *start = section->start;
+  unsigned char *end = start + section->size;
 
-  printf (_("Contents of the %s section:\n\n"), SECTION_NAME (section));
+  printf (_("Contents of the %s section:\n\n"), section->name);
 
   do
     {
@@ -9903,9 +9825,9 @@ display_debug_abbrev (Elf_Internal_Shdr 
 }
 
 static int
-display_debug_loc (Elf_Internal_Shdr *section,
-		   unsigned char *start, FILE *file)
+display_debug_loc (struct dwarf_section *section, void *file)
 {
+  unsigned char *start = section->start;
   unsigned char *section_end;
   unsigned long bytes;
   unsigned char *section_begin = start;
@@ -9918,12 +9840,12 @@ display_debug_loc (Elf_Internal_Shdr *se
   int use_debug_info = 1;
   unsigned char *next;
 
-  bytes = section->sh_size;
+  bytes = section->size;
   section_end = start + bytes;
 
   if (bytes == 0)
     {
-      printf (_("\nThe .debug_loc section is empty.\n"));
+      printf (_("\nThe %s section is empty.\n"), section->name);
       return 0;
     }
 
@@ -9974,10 +9896,10 @@ display_debug_loc (Elf_Internal_Shdr *se
     error (_("No location lists in .debug_info section!\n"));
 
   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]);
+    warn (_("Location lists in %s section start at 0x%lx\n"),
+	  section->name, debug_information [first].loc_offsets [0]);
 
-  printf (_("Contents of the .debug_loc section:\n\n"));
+  printf (_("Contents of the %s section:\n\n"), section->name);
   printf (_("    Offset   Begin    End      Expression\n"));
 
   seen_first_offset = 0;
@@ -10095,23 +10017,20 @@ display_debug_loc (Elf_Internal_Shdr *se
 }
 
 static int
-display_debug_str (Elf_Internal_Shdr *section,
-		   unsigned char *start,
-		   FILE *file ATTRIBUTE_UNUSED)
+display_debug_str (struct dwarf_section *section,
+		   void *file ATTRIBUTE_UNUSED)
 {
-  unsigned long bytes;
-  bfd_vma addr;
-
-  addr  = section->sh_addr;
-  bytes = section->sh_size;
+  unsigned char *start = section->start;
+  unsigned long bytes = section->size;
+  bfd_vma addr = section->address;
 
   if (bytes == 0)
     {
-      printf (_("\nThe .debug_str section is empty.\n"));
+      printf (_("\nThe %s section is empty.\n"), section->name);
       return 0;
     }
 
-  printf (_("Contents of the .debug_str section:\n\n"));
+  printf (_("Contents of the %s section:\n\n"), section->name);
 
   while (bytes)
     {
@@ -10157,21 +10076,20 @@ display_debug_str (Elf_Internal_Shdr *se
 
 
 static int
-display_debug_info (Elf_Internal_Shdr * section,
-		    unsigned char * start, FILE * file)
+display_debug_info (struct dwarf_section *section, void *file)
 {
-  return process_debug_info (section, start, file, 0);
+  return process_debug_info (section, file, 0);
 }
 
 
 static int
-display_debug_aranges (Elf_Internal_Shdr *section,
-		       unsigned char *start,
-		       FILE *file ATTRIBUTE_UNUSED)
+display_debug_aranges (struct dwarf_section *section,
+		       void *file ATTRIBUTE_UNUSED)
 {
-  unsigned char *end = start + section->sh_size;
+  unsigned char *start = section->start;
+  unsigned char *end = start + section->size;
 
-  printf (_("The section %s contains:\n\n"), SECTION_NAME (section));
+  printf (_("The section %s contains:\n\n"), section->name);
 
   while (start < end)
     {
@@ -10261,10 +10179,10 @@ display_debug_aranges (Elf_Internal_Shdr
 }
 
 static int
-display_debug_ranges (Elf_Internal_Shdr *section,
-		      unsigned char *start,
-		      FILE *file ATTRIBUTE_UNUSED)
+display_debug_ranges (struct dwarf_section *section,
+		      void *file ATTRIBUTE_UNUSED)
 {
+  unsigned char *start = section->start;
   unsigned char *section_end;
   unsigned long bytes;
   unsigned char *section_begin = start;
@@ -10277,12 +10195,12 @@ display_debug_ranges (Elf_Internal_Shdr 
   int use_debug_info = 1;
   unsigned char *next;
 
-  bytes = section->sh_size;
+  bytes = section->size;
   section_end = start + bytes;
 
   if (bytes == 0)
     {
-      printf (_("\nThe .debug_ranges section is empty.\n"));
+      printf (_("\nThe %s section is empty.\n"), section->name);
       return 0;
     }
 
@@ -10333,10 +10251,10 @@ display_debug_ranges (Elf_Internal_Shdr 
     error (_("No range lists in .debug_info section!\n"));
 
   if (debug_information [first].range_lists [0] != 0)
-    warn (_("Range lists in .debug_ranges section start at 0x%lx\n"),
-	  debug_information [first].range_lists [0]);
+    warn (_("Range lists in %s section start at 0x%lx\n"),
+	  section->name, debug_information [first].range_lists [0]);
 
-  printf (_("Contents of the .debug_ranges section:\n\n"));
+  printf (_("Contents of the %s section:\n\n"), section->name);
   printf (_("    Offset   Begin    End\n"));
 
   seen_first_offset = 0;
@@ -10361,11 +10279,13 @@ display_debug_ranges (Elf_Internal_Shdr 
 	  else
 	    {
 	      if (start < next)
-		warn (_("There is a hole [0x%lx - 0x%lx] in .debug_ranges section.\n"),
-		      (long)(start - section_begin), (long)(next - section_begin));
+		warn (_("There is a hole [0x%lx - 0x%lx] in %s section.\n"),
+		      (long)(start - section_begin),
+		      (long)(next - section_begin), section->name);
 	      else if (start > next)
-		warn (_("There is an overlap [0x%lx - 0x%lx] in .debug_ranges section.\n"),
-		      (long)(start - section_begin), (long)(next - section_begin));
+		warn (_("There is an overlap [0x%lx - 0x%lx] in %s section.\n"),
+		      (long)(start - section_begin),
+		      (long)(next - section_begin), section->name);
 	    }
 	  start = next;
 
@@ -10545,20 +10465,20 @@ get_encoded_value (unsigned char *data, 
 #define SLEB()	read_leb128 (start, & length_return, 1); start += length_return
 
 static int
-display_debug_frames (Elf_Internal_Shdr *section,
-		      unsigned char *start,
-		      FILE *file ATTRIBUTE_UNUSED)
+display_debug_frames (struct dwarf_section *section,
+		      void *file ATTRIBUTE_UNUSED)
 {
-  unsigned char *end = start + section->sh_size;
+  unsigned char *start = section->start;
+  unsigned char *end = start + section->size;
   unsigned char *section_start = start;
   Frame_Chunk *chunks = 0;
   Frame_Chunk *remembered_state = 0;
   Frame_Chunk *rs;
-  int is_eh = streq (SECTION_NAME (section), ".eh_frame");
+  int is_eh = streq (section->name, ".eh_frame");
   unsigned int length_return;
   int max_regs = 0;
 
-  printf (_("The section %s contains:\n"), SECTION_NAME (section));
+  printf (_("The section %s contains:\n"), section->name);
 
   while (start < end)
     {
@@ -10766,10 +10686,11 @@ display_debug_frames (Elf_Internal_Shdr 
 
 	  fc->pc_begin = get_encoded_value (start, fc->fde_encoding);
 	  if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel
-	      /* Don't adjust for ET_REL since there's invariably a pcrel
-		 reloc here, which we haven't applied.  */
-	      && elf_header.e_type != ET_REL)
-	    fc->pc_begin += section->sh_addr + (start - section_start);
+	      /* Don't adjust for relocatable file since there's
+		 invariably a pcrel reloc here, which we haven't
+		 applied.  */
+	      && !is_relocatable)
+	    fc->pc_begin += section->address + (start - section_start);
 	  start += encoded_ptr_size;
 	  fc->pc_range = byte_get (start, encoded_ptr_size);
 	  start += encoded_ptr_size;
@@ -10969,8 +10890,8 @@ display_debug_frames (Elf_Internal_Shdr 
 	    case DW_CFA_set_loc:
 	      vma = get_encoded_value (start, fc->fde_encoding);
 	      if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel
-		  && elf_header.e_type != ET_REL)
-		vma += section->sh_addr + (start - section_start);
+		  && !is_relocatable)
+		vma += section->address + (start - section_start);
 	      start += encoded_ptr_size;
 	      if (do_debug_frames_interp)
 		frame_display_row (fc, &need_col_headers, &max_regs);
@@ -11222,12 +11143,11 @@ display_debug_frames (Elf_Internal_Shdr 
 #undef SLEB
 
 static int
-display_debug_not_supported (Elf_Internal_Shdr *section,
-			     unsigned char *start ATTRIBUTE_UNUSED,
-			     FILE *file ATTRIBUTE_UNUSED)
+display_debug_not_supported (struct dwarf_section *section,
+			     void *file ATTRIBUTE_UNUSED)
 {
   printf (_("Displaying the debug contents of section %s is not yet supported.\n"),
-	    SECTION_NAME (section));
+	    section->name);
 
   return 1;
 }
@@ -11237,7 +11157,7 @@ display_debug_not_supported (Elf_Interna
 static struct
 {
   const char *const name;
-  int (*display) (Elf_Internal_Shdr *, unsigned char *, FILE *);
+  int (*display) (struct dwarf_section *, void *);
   unsigned int relocate : 1;
 }
 debug_displays[] =
@@ -11282,21 +11202,24 @@ display_debug_section (Elf_Internal_Shdr
   for (i = NUM_ELEM (debug_displays); i--;)
     if (streq (debug_displays[i].name, name))
       {
-	unsigned char *start;
+	struct dwarf_section sec;
 
-	start = get_data (NULL, file, section->sh_offset, 1, length,
-			  _("debug section data"));
-	if (start == NULL)
+	sec.name = name;
+	sec.address = section->sh_addr;
+	sec.size = section->sh_size;
+	sec.start = get_data (NULL, file, section->sh_offset, 1,
+			      length, _("debug section data"));
+	if (sec.start == NULL)
 	  {
 	    result = 0;
 	    break;
 	  }
 
 	if (!debug_displays[i].relocate
-	    || debug_apply_rela_addends (file, section, start))
-	  result &= debug_displays[i].display (section, start, file);
+	    || debug_apply_rela_addends (file, section, sec.start))
+	  result &= debug_displays[i].display (&sec, file);
 
-	free (start);
+	free (sec.start);
 
 	/* If we loaded in the abbrev section
 	   at some point, we must release it here.  */
@@ -12235,6 +12158,8 @@ get_file_header (FILE *file)
 	get_64bit_section_headers (file, 1);
     }
 
+  is_relocatable = elf_header.e_type == ET_REL;
+
   return 1;
 }
 
-------------- next part --------------
2005-09-15  H.J. Lu  <hongjiu.lu@intel.com>

	* Makefile.am (CFILES): Add dwarf.c.
	(readelf_SOURCES): Likewise.
	* Makefile.in: Regenerated.

	* dwarf.c: New file.
	* dwarf.h. Likewise.

	* readelf.c: Include "dwarf.h" instead of "bfd.h".
	(do_debug_info): Remove the static definition.
	(do_debug_abbrevs): Likewise.
	(do_debug_lines): Likewise.
	(do_debug_pubnames): Likewise.
	(do_debug_aranges): Likewise.
	(do_debug_ranges): Likewise.
	(do_debug_frames): Likewise.
	(do_debug_frames_interp): Likewise.
	(do_debug_macinfo): Likewise.
	(do_debug_str): Likewise.
	(do_debug_loc): Likewise.
	(is_relocatable): Likewise.
	(have_frame_base): Likewise.
	(need_base_address): Likewise.
	(eh_addr_size): Likewise.
	(error): Likewise.
	(warn): Likewise.
	(cmalloc): Likewise.
	(xcmalloc): Likewise.
	(xcrealloc): Likewise.
	(dwarf_section): Removed.
	(byte_get_little_endian): Likewise.
	(byte_get_signed): Likewise.
	(byte_get_big_endian): Likewise.
	(read_leb128): Likewise.
	(State_Machine_Registers): Likewise.
	(state_machine_regs): Likewise.
	(reset_state_machine): Likewise.
	(process_extended_line_op): Likewise.
	(debug_str_section): Likewise.
	(fetch_indirect_string): Likewise.
	(debug_abbrev_section): Likewise.
	(abbrev_attr): Likewise.
	(first_abbrev): Likewise.
	(last_abbrev): Likewise.
	(free_abbrevs): Likewise.
	(add_abbrev_attr): Likewise.
	(process_abbrev_section): Likewise.
	(get_TAG_name): Likewise.
	(get_FORM_name): Likewise.
	(display_block): Likewise.
	(decode_location_expression): Likewise.
	(debug_info): Likewise.
	(debug_information): Likewise.
	(num_debug_info_entries): Likewise.
	(last_pointer_size): Likewise.
	(warned_about_missing_comp_units): Likewise.
	(read_and_display_attr_value): Likewise.
	(get_AT_name): Likewise.
	(read_and_display_attr): Likewise.
	(process_debug_info): Likewise.
	(get_pointer_size_and_offset_of_comp_unit): Likewise.
	(get_debug_info): Likewise.
	(display_debug_lines): Likewise.
	(display_debug_pubnames): Likewise.
	(display_debug_macinfo): Likewise.
	(display_debug_abbrev): Likewise.
	(display_debug_loc): Likewise.
	(display_debug_str): Likewise.
	(display_debug_aranges): Likewise.
	(display_debug_ranges): Likewise.
	(Frame_Chunk): Likewise.
	(DW_CFA_unreferenced): Likewise.
	(frame_need_space): Likewise.
	(frame_display_row): Likewise.
	(size_of_encoded_value): Likewise.
	(get_encoded_value): Likewise.
	(GET): Likewise.
	(LEB): Likewise.
	(SLEB): Likewise.
	(display_debug_frames): Likewise.
	(display_debug_not_supported): Likewise.
	(debug_displays): Likewise.
	(load_debug_section): Updated.
	(free_debug_section): Likewise.
	(display_debug_section): Likewise.
	(process_object): Call free_debug_memory to free debug memory.

--- binutils/Makefile.am.dwarf	2005-07-16 10:06:23.000000000 -0700
+++ binutils/Makefile.am	2005-09-15 07:16:00.000000000 -0700
@@ -88,7 +88,8 @@ GENERATED_HFILES = arparse.h sysroff.h s
 
 CFILES = \
 	addr2line.c ar.c arsup.c binemul.c bucomm.c budemang.c \
-	coffdump.c coffgrok.c cxxfilt.c debug.c dlltool.c dllwrap.c \
+	coffdump.c coffgrok.c cxxfilt.c \
+	dwarf.c debug.c dlltool.c dllwrap.c \
 	emul_aix.c emul_vanilla.c filemode.c \
 	ieee.c is-ranlib.c is-strip.c maybe-ranlib.c maybe-strip.c \
 	nlmconv.c nm.c not-ranlib.c not-strip.c \
@@ -160,7 +161,7 @@ objcopy_SOURCES = objcopy.c not-strip.c 
 
 strings_SOURCES = strings.c $(BULIBS)
 
-readelf_SOURCES = readelf.c version.c unwind-ia64.c
+readelf_SOURCES = readelf.c version.c unwind-ia64.c dwarf.c
 readelf_LDADD   = $(INTLLIBS) $(LIBIBERTY)
 
 strip_new_SOURCES = objcopy.c is-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS)
--- binutils/Makefile.in.dwarf	2005-07-15 08:08:24.000000000 -0700
+++ binutils/Makefile.in	2005-09-15 07:16:00.000000000 -0700
@@ -156,7 +156,7 @@ ranlib_OBJECTS = $(am_ranlib_OBJECTS)
 ranlib_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \
 	$(am__DEPENDENCIES_3)
 am_readelf_OBJECTS = readelf.$(OBJEXT) version.$(OBJEXT) \
-	unwind-ia64.$(OBJEXT)
+	unwind-ia64.$(OBJEXT) dwarf.$(OBJEXT)
 readelf_OBJECTS = $(am_readelf_OBJECTS)
 readelf_DEPENDENCIES = $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_2)
 am_size_OBJECTS = size.$(OBJEXT) $(am__objects_1)
@@ -413,7 +413,8 @@ HFILES = \
 GENERATED_HFILES = arparse.h sysroff.h sysinfo.h defparse.h rcparse.h
 CFILES = \
 	addr2line.c ar.c arsup.c binemul.c bucomm.c budemang.c \
-	coffdump.c coffgrok.c cxxfilt.c debug.c dlltool.c dllwrap.c \
+	coffdump.c coffgrok.c cxxfilt.c \
+	dwarf.c debug.c dlltool.c dllwrap.c \
 	emul_aix.c emul_vanilla.c filemode.c \
 	ieee.c is-ranlib.c is-strip.c maybe-ranlib.c maybe-strip.c \
 	nlmconv.c nm.c not-ranlib.c not-strip.c \
@@ -457,7 +458,7 @@ LDADD = $(BFDLIB) $(LIBIBERTY) $(INTLLIB
 size_SOURCES = size.c $(BULIBS)
 objcopy_SOURCES = objcopy.c not-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS)
 strings_SOURCES = strings.c $(BULIBS)
-readelf_SOURCES = readelf.c version.c unwind-ia64.c
+readelf_SOURCES = readelf.c version.c unwind-ia64.c dwarf.c
 readelf_LDADD = $(INTLLIBS) $(LIBIBERTY)
 strip_new_SOURCES = objcopy.c is-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS)
 nm_new_SOURCES = nm.c budemang.c $(BULIBS)
--- binutils/dwarf.c.dwarf	2005-09-15 07:16:00.000000000 -0700
+++ binutils/dwarf.c	2005-09-15 07:21:13.000000000 -0700
@@ -0,0 +1,3741 @@
+/* dwarf.c -- display DWARF contents of a BFD binary file
+   Copyright 2005
+   Free Software Foundation, Inc.
+
+   This file is part of GNU Binutils.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+#include <stdio.h>
+
+#include "dwarf.h"
+
+#include "bucomm.h"
+#include "libiberty.h"
+
+static int have_frame_base;
+static int need_base_address;
+
+static unsigned int last_pointer_size = 0;
+static int warned_about_missing_comp_units = FALSE;
+
+static unsigned int num_debug_info_entries = 0;
+static debug_info *debug_information = NULL;
+
+bfd_vma eh_addr_size;
+int is_relocatable;
+
+int do_debug_info;
+int do_debug_abbrevs;
+int do_debug_lines;
+int do_debug_pubnames;
+int do_debug_aranges;
+int do_debug_ranges;
+int do_debug_frames;
+int do_debug_frames_interp;
+int do_debug_macinfo;
+int do_debug_str;
+int do_debug_loc;
+
+bfd_vma (*byte_get) (unsigned char *, int);
+
+bfd_vma
+byte_get_little_endian (unsigned char *field, int size)
+{
+  switch (size)
+    {
+    case 1:
+      return *field;
+
+    case 2:
+      return  ((unsigned int) (field[0]))
+	|    (((unsigned int) (field[1])) << 8);
+
+#ifndef BFD64
+    case 8:
+      /* We want to extract data from an 8 byte wide field and
+	 place it into a 4 byte wide field.  Since this is a little
+	 endian source we can just use the 4 byte extraction code.  */
+      /* Fall through.  */
+#endif
+    case 4:
+      return  ((unsigned long) (field[0]))
+	|    (((unsigned long) (field[1])) << 8)
+	|    (((unsigned long) (field[2])) << 16)
+	|    (((unsigned long) (field[3])) << 24);
+
+#ifdef BFD64
+    case 8:
+      return  ((bfd_vma) (field[0]))
+	|    (((bfd_vma) (field[1])) << 8)
+	|    (((bfd_vma) (field[2])) << 16)
+	|    (((bfd_vma) (field[3])) << 24)
+	|    (((bfd_vma) (field[4])) << 32)
+	|    (((bfd_vma) (field[5])) << 40)
+	|    (((bfd_vma) (field[6])) << 48)
+	|    (((bfd_vma) (field[7])) << 56);
+#endif
+    default:
+      error (_("Unhandled data length: %d\n"), size);
+      abort ();
+    }
+}
+
+bfd_vma
+byte_get_big_endian (unsigned char *field, int size)
+{
+  switch (size)
+    {
+    case 1:
+      return *field;
+
+    case 2:
+      return ((unsigned int) (field[1])) | (((int) (field[0])) << 8);
+
+#ifndef BFD64
+    case 8:
+      /* Although we are extracing data from an 8 byte wide field,
+	 we are returning only 4 bytes of data.  */
+      field += 4;
+      /* Fall thru */
+#endif
+    case 4:
+      return ((unsigned long) (field[3]))
+	|   (((unsigned long) (field[2])) << 8)
+	|   (((unsigned long) (field[1])) << 16)
+	|   (((unsigned long) (field[0])) << 24);
+
+#ifdef BFD64
+    case 8:
+      return ((bfd_vma) (field[7]))
+	|   (((bfd_vma) (field[6])) << 8)
+	|   (((bfd_vma) (field[5])) << 16)
+	|   (((bfd_vma) (field[4])) << 24)
+	|   (((bfd_vma) (field[3])) << 32)
+	|   (((bfd_vma) (field[2])) << 40)
+	|   (((bfd_vma) (field[1])) << 48)
+	|   (((bfd_vma) (field[0])) << 56);
+#endif
+
+    default:
+      error (_("Unhandled data length: %d\n"), size);
+      abort ();
+    }
+}
+
+static bfd_vma
+byte_get_signed (unsigned char *field, int size)
+{
+  bfd_vma x = byte_get (field, size);
+
+  switch (size)
+    {
+    case 1:
+      return (x ^ 0x80) - 0x80;
+    case 2:
+      return (x ^ 0x8000) - 0x8000;
+    case 4:
+      return (x ^ 0x80000000) - 0x80000000;
+    case 8:
+      return x;
+    default:
+      abort ();
+    }
+}
+
+static unsigned long int
+read_leb128 (unsigned char *data, unsigned int *length_return, int sign)
+{
+  unsigned long int result = 0;
+  unsigned int num_read = 0;
+  unsigned int shift = 0;
+  unsigned char byte;
+
+  do
+    {
+      byte = *data++;
+      num_read++;
+
+      result |= ((unsigned long int) (byte & 0x7f)) << shift;
+
+      shift += 7;
+
+    }
+  while (byte & 0x80);
+
+  if (length_return != NULL)
+    *length_return = num_read;
+
+  if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40))
+    result |= -1L << shift;
+
+  return result;
+}
+
+typedef struct State_Machine_Registers
+{
+  unsigned long address;
+  unsigned int file;
+  unsigned int line;
+  unsigned int column;
+  int is_stmt;
+  int basic_block;
+  int end_sequence;
+/* This variable hold the number of the last entry seen
+   in the File Table.  */
+  unsigned int last_file_entry;
+} SMR;
+
+static SMR state_machine_regs;
+
+static void
+reset_state_machine (int is_stmt)
+{
+  state_machine_regs.address = 0;
+  state_machine_regs.file = 1;
+  state_machine_regs.line = 1;
+  state_machine_regs.column = 0;
+  state_machine_regs.is_stmt = is_stmt;
+  state_machine_regs.basic_block = 0;
+  state_machine_regs.end_sequence = 0;
+  state_machine_regs.last_file_entry = 0;
+}
+
+/* Handled an extend line op.
+   Returns the number of bytes read.  */
+
+static int
+process_extended_line_op (unsigned char *data, int is_stmt, int pointer_size)
+{
+  unsigned char op_code;
+  unsigned int bytes_read;
+  unsigned int len;
+  unsigned char *name;
+  unsigned long adr;
+
+  len = read_leb128 (data, & bytes_read, 0);
+  data += bytes_read;
+
+  if (len == 0)
+    {
+      warn (_("badly formed extended line op encountered!\n"));
+      return bytes_read;
+    }
+
+  len += bytes_read;
+  op_code = *data++;
+
+  printf (_("  Extended opcode %d: "), op_code);
+
+  switch (op_code)
+    {
+    case DW_LNE_end_sequence:
+      printf (_("End of Sequence\n\n"));
+      reset_state_machine (is_stmt);
+      break;
+
+    case DW_LNE_set_address:
+      adr = byte_get (data, pointer_size);
+      printf (_("set Address to 0x%lx\n"), adr);
+      state_machine_regs.address = adr;
+      break;
+
+    case DW_LNE_define_file:
+      printf (_("  define new File Table entry\n"));
+      printf (_("  Entry\tDir\tTime\tSize\tName\n"));
+
+      printf (_("   %d\t"), ++state_machine_regs.last_file_entry);
+      name = data;
+      data += strlen ((char *) data) + 1;
+      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));
+      printf (_("%s\n\n"), name);
+      break;
+
+    default:
+      printf (_("UNKNOWN: length %d\n"), len - bytes_read);
+      break;
+    }
+
+  return len;
+}
+
+static const char *
+fetch_indirect_string (unsigned long offset)
+{
+  struct dwarf_section *section = &debug_displays [str].section;
+
+  if (section->start == NULL)
+    return _("<no .debug_str section>");
+
+  if (offset > section->size)
+    {
+      warn (_("DW_FORM_strp offset too big: %lx\n"), offset);
+      return _("<offset is too big>");
+    }
+
+  return (const char *) section->start + offset;
+}
+
+/* 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;
+
+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;
+
+  if (first_abbrev == NULL)
+    first_abbrev = entry;
+  else
+    last_abbrev->next = entry;
+
+  last_abbrev = entry;
+}
+
+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)
+    {
+      unsigned 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 char *
+get_TAG_name (unsigned long tag)
+{
+  switch (tag)
+    {
+    case DW_TAG_padding:		return "DW_TAG_padding";
+    case DW_TAG_array_type:		return "DW_TAG_array_type";
+    case DW_TAG_class_type:		return "DW_TAG_class_type";
+    case DW_TAG_entry_point:		return "DW_TAG_entry_point";
+    case DW_TAG_enumeration_type:	return "DW_TAG_enumeration_type";
+    case DW_TAG_formal_parameter:	return "DW_TAG_formal_parameter";
+    case DW_TAG_imported_declaration:	return "DW_TAG_imported_declaration";
+    case DW_TAG_label:			return "DW_TAG_label";
+    case DW_TAG_lexical_block:		return "DW_TAG_lexical_block";
+    case DW_TAG_member:			return "DW_TAG_member";
+    case DW_TAG_pointer_type:		return "DW_TAG_pointer_type";
+    case DW_TAG_reference_type:		return "DW_TAG_reference_type";
+    case DW_TAG_compile_unit:		return "DW_TAG_compile_unit";
+    case DW_TAG_string_type:		return "DW_TAG_string_type";
+    case DW_TAG_structure_type:		return "DW_TAG_structure_type";
+    case DW_TAG_subroutine_type:	return "DW_TAG_subroutine_type";
+    case DW_TAG_typedef:		return "DW_TAG_typedef";
+    case DW_TAG_union_type:		return "DW_TAG_union_type";
+    case DW_TAG_unspecified_parameters: return "DW_TAG_unspecified_parameters";
+    case DW_TAG_variant:		return "DW_TAG_variant";
+    case DW_TAG_common_block:		return "DW_TAG_common_block";
+    case DW_TAG_common_inclusion:	return "DW_TAG_common_inclusion";
+    case DW_TAG_inheritance:		return "DW_TAG_inheritance";
+    case DW_TAG_inlined_subroutine:	return "DW_TAG_inlined_subroutine";
+    case DW_TAG_module:			return "DW_TAG_module";
+    case DW_TAG_ptr_to_member_type:	return "DW_TAG_ptr_to_member_type";
+    case DW_TAG_set_type:		return "DW_TAG_set_type";
+    case DW_TAG_subrange_type:		return "DW_TAG_subrange_type";
+    case DW_TAG_with_stmt:		return "DW_TAG_with_stmt";
+    case DW_TAG_access_declaration:	return "DW_TAG_access_declaration";
+    case DW_TAG_base_type:		return "DW_TAG_base_type";
+    case DW_TAG_catch_block:		return "DW_TAG_catch_block";
+    case DW_TAG_const_type:		return "DW_TAG_const_type";
+    case DW_TAG_constant:		return "DW_TAG_constant";
+    case DW_TAG_enumerator:		return "DW_TAG_enumerator";
+    case DW_TAG_file_type:		return "DW_TAG_file_type";
+    case DW_TAG_friend:			return "DW_TAG_friend";
+    case DW_TAG_namelist:		return "DW_TAG_namelist";
+    case DW_TAG_namelist_item:		return "DW_TAG_namelist_item";
+    case DW_TAG_packed_type:		return "DW_TAG_packed_type";
+    case DW_TAG_subprogram:		return "DW_TAG_subprogram";
+    case DW_TAG_template_type_param:	return "DW_TAG_template_type_param";
+    case DW_TAG_template_value_param:	return "DW_TAG_template_value_param";
+    case DW_TAG_thrown_type:		return "DW_TAG_thrown_type";
+    case DW_TAG_try_block:		return "DW_TAG_try_block";
+    case DW_TAG_variant_part:		return "DW_TAG_variant_part";
+    case DW_TAG_variable:		return "DW_TAG_variable";
+    case DW_TAG_volatile_type:		return "DW_TAG_volatile_type";
+    case DW_TAG_MIPS_loop:		return "DW_TAG_MIPS_loop";
+    case DW_TAG_format_label:		return "DW_TAG_format_label";
+    case DW_TAG_function_template:	return "DW_TAG_function_template";
+    case DW_TAG_class_template:		return "DW_TAG_class_template";
+      /* DWARF 2.1 values.  */
+    case DW_TAG_dwarf_procedure:	return "DW_TAG_dwarf_procedure";
+    case DW_TAG_restrict_type:		return "DW_TAG_restrict_type";
+    case DW_TAG_interface_type:		return "DW_TAG_interface_type";
+    case DW_TAG_namespace:		return "DW_TAG_namespace";
+    case DW_TAG_imported_module:	return "DW_TAG_imported_module";
+    case DW_TAG_unspecified_type:	return "DW_TAG_unspecified_type";
+    case DW_TAG_partial_unit:		return "DW_TAG_partial_unit";
+    case DW_TAG_imported_unit:		return "DW_TAG_imported_unit";
+      /* UPC values.  */
+    case DW_TAG_upc_shared_type:	return "DW_TAG_upc_shared_type";
+    case DW_TAG_upc_strict_type:	return "DW_TAG_upc_strict_type";
+    case DW_TAG_upc_relaxed_type:	return "DW_TAG_upc_relaxed_type";
+    default:
+      {
+	static char buffer[100];
+
+	snprintf (buffer, sizeof (buffer), _("Unknown TAG value: %lx"), tag);
+	return buffer;
+      }
+    }
+}
+
+static char *
+get_FORM_name (unsigned long form)
+{
+  switch (form)
+    {
+    case DW_FORM_addr:		return "DW_FORM_addr";
+    case DW_FORM_block2:	return "DW_FORM_block2";
+    case DW_FORM_block4:	return "DW_FORM_block4";
+    case DW_FORM_data2:		return "DW_FORM_data2";
+    case DW_FORM_data4:		return "DW_FORM_data4";
+    case DW_FORM_data8:		return "DW_FORM_data8";
+    case DW_FORM_string:	return "DW_FORM_string";
+    case DW_FORM_block:		return "DW_FORM_block";
+    case DW_FORM_block1:	return "DW_FORM_block1";
+    case DW_FORM_data1:		return "DW_FORM_data1";
+    case DW_FORM_flag:		return "DW_FORM_flag";
+    case DW_FORM_sdata:		return "DW_FORM_sdata";
+    case DW_FORM_strp:		return "DW_FORM_strp";
+    case DW_FORM_udata:		return "DW_FORM_udata";
+    case DW_FORM_ref_addr:	return "DW_FORM_ref_addr";
+    case DW_FORM_ref1:		return "DW_FORM_ref1";
+    case DW_FORM_ref2:		return "DW_FORM_ref2";
+    case DW_FORM_ref4:		return "DW_FORM_ref4";
+    case DW_FORM_ref8:		return "DW_FORM_ref8";
+    case DW_FORM_ref_udata:	return "DW_FORM_ref_udata";
+    case DW_FORM_indirect:	return "DW_FORM_indirect";
+    default:
+      {
+	static char buffer[100];
+
+	snprintf (buffer, sizeof (buffer), _("Unknown FORM value: %lx"), form);
+	return buffer;
+      }
+    }
+}
+
+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 int
+decode_location_expression (unsigned char * data,
+			    unsigned int pointer_size,
+			    unsigned long length,
+			    unsigned long cu_offset)
+{
+  unsigned op;
+  unsigned int bytes_read;
+  unsigned long uvalue;
+  unsigned char *end = data + length;
+  int need_frame_base = 0;
+
+  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;
+	  break;
+	case DW_OP_const2s:
+	  printf ("DW_OP_const2s: %ld", (long) byte_get_signed (data, 2));
+	  data += 2;
+	  break;
+	case DW_OP_const4u:
+	  printf ("DW_OP_const4u: %lu", (unsigned long) byte_get (data, 4));
+	  data += 4;
+	  break;
+	case DW_OP_const4s:
+	  printf ("DW_OP_const4s: %ld", (long) byte_get_signed (data, 4));
+	  data += 4;
+	  break;
+	case DW_OP_const8u:
+	  printf ("DW_OP_const8u: %lu %lu", (unsigned long) byte_get (data, 4),
+		  (unsigned long) byte_get (data + 4, 4));
+	  data += 8;
+	  break;
+	case DW_OP_const8s:
+	  printf ("DW_OP_const8s: %ld %ld", (long) byte_get (data, 4),
+		  (long) byte_get (data + 4, 4));
+	  data += 8;
+	  break;
+	case DW_OP_constu:
+	  printf ("DW_OP_constu: %lu", read_leb128 (data, &bytes_read, 0));
+	  data += bytes_read;
+	  break;
+	case DW_OP_consts:
+	  printf ("DW_OP_consts: %ld", read_leb128 (data, &bytes_read, 1));
+	  data += bytes_read;
+	  break;
+	case DW_OP_dup:
+	  printf ("DW_OP_dup");
+	  break;
+	case DW_OP_drop:
+	  printf ("DW_OP_drop");
+	  break;
+	case DW_OP_over:
+	  printf ("DW_OP_over");
+	  break;
+	case DW_OP_pick:
+	  printf ("DW_OP_pick: %ld", (unsigned long) byte_get (data++, 1));
+	  break;
+	case DW_OP_swap:
+	  printf ("DW_OP_swap");
+	  break;
+	case DW_OP_rot:
+	  printf ("DW_OP_rot");
+	  break;
+	case DW_OP_xderef:
+	  printf ("DW_OP_xderef");
+	  break;
+	case DW_OP_abs:
+	  printf ("DW_OP_abs");
+	  break;
+	case DW_OP_and:
+	  printf ("DW_OP_and");
+	  break;
+	case DW_OP_div:
+	  printf ("DW_OP_div");
+	  break;
+	case DW_OP_minus:
+	  printf ("DW_OP_minus");
+	  break;
+	case DW_OP_mod:
+	  printf ("DW_OP_mod");
+	  break;
+	case DW_OP_mul:
+	  printf ("DW_OP_mul");
+	  break;
+	case DW_OP_neg:
+	  printf ("DW_OP_neg");
+	  break;
+	case DW_OP_not:
+	  printf ("DW_OP_not");
+	  break;
+	case DW_OP_or:
+	  printf ("DW_OP_or");
+	  break;
+	case DW_OP_plus:
+	  printf ("DW_OP_plus");
+	  break;
+	case DW_OP_plus_uconst:
+	  printf ("DW_OP_plus_uconst: %lu",
+		  read_leb128 (data, &bytes_read, 0));
+	  data += bytes_read;
+	  break;
+	case DW_OP_shl:
+	  printf ("DW_OP_shl");
+	  break;
+	case DW_OP_shr:
+	  printf ("DW_OP_shr");
+	  break;
+	case DW_OP_shra:
+	  printf ("DW_OP_shra");
+	  break;
+	case DW_OP_xor:
+	  printf ("DW_OP_xor");
+	  break;
+	case DW_OP_bra:
+	  printf ("DW_OP_bra: %ld", (long) byte_get_signed (data, 2));
+	  data += 2;
+	  break;
+	case DW_OP_eq:
+	  printf ("DW_OP_eq");
+	  break;
+	case DW_OP_ge:
+	  printf ("DW_OP_ge");
+	  break;
+	case DW_OP_gt:
+	  printf ("DW_OP_gt");
+	  break;
+	case DW_OP_le:
+	  printf ("DW_OP_le");
+	  break;
+	case DW_OP_lt:
+	  printf ("DW_OP_lt");
+	  break;
+	case DW_OP_ne:
+	  printf ("DW_OP_ne");
+	  break;
+	case DW_OP_skip:
+	  printf ("DW_OP_skip: %ld", (long) byte_get_signed (data, 2));
+	  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_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:
+	  need_frame_base = 1;
+	  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 need_frame_base;
+	}
+
+      /* Separate the ops.  */
+      if (data < end)
+	printf ("; ");
+    }
+
+  return need_frame_base;
+}
+
+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)
+{
+  unsigned long uvalue = 0;
+  unsigned char *block_start = NULL;
+  unsigned 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 || do_debug_ranges)
+	  && 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: %lu\n"), form);
+      break;
+    }
+
+  /* For some attributes we can display further information.  */
+  if ((do_loc || do_debug_loc || do_debug_ranges)
+      && num_debug_info_entries == 0)
+    {
+      switch (attribute)
+	{
+	case DW_AT_frame_base:
+	  have_frame_base = 1;
+	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
+		    = xcrealloc (debug_info_p->loc_offsets,
+				 max, sizeof (*debug_info_p->loc_offsets));
+		  debug_info_p->have_frame_base
+		    = xcrealloc (debug_info_p->have_frame_base,
+				 max, sizeof (*debug_info_p->have_frame_base));
+		  debug_info_p->max_loc_offsets = max;
+		}
+	      debug_info_p->loc_offsets [num] = uvalue;
+	      debug_info_p->have_frame_base [num] = have_frame_base;
+	      debug_info_p->num_loc_offsets++;
+	    }
+	  break;
+	
+	case DW_AT_low_pc:
+	  if (need_base_address)
+	    debug_info_p->base_address = uvalue;
+	  break;
+
+	case DW_AT_ranges:
+	  if (form == DW_FORM_data4 || form == DW_FORM_data8)
+	    {
+	      /* Process range list.  */
+	      unsigned int max = debug_info_p->max_range_lists;
+	      unsigned int num = debug_info_p->num_range_lists;
+
+	      if (max == 0 || num >= max)
+		{
+		  max += 1024;
+		  debug_info_p->range_lists
+		    = xcrealloc (debug_info_p->range_lists,
+				 max, sizeof (*debug_info_p->range_lists));
+		  debug_info_p->max_range_lists = max;
+		}
+	      debug_info_p->range_lists [num] = uvalue;
+	      debug_info_p->num_range_lists++;
+	    }
+	  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;
+	case DW_ATE_decimal_float:	printf ("(decimal 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:
+      have_frame_base = 1;
+    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)
+	{
+	  int need_frame_base;
+
+	  printf ("(");
+	  need_frame_base = decode_location_expression (block_start,
+							pointer_size,
+							uvalue,
+							cu_offset);
+	  printf (")");
+	  if (need_frame_base && !have_frame_base)
+	    printf (_(" [without DW_AT_frame_base]"));
+	}
+      else if (form == DW_FORM_data4 || form == DW_FORM_data8)
+	printf (_("(location list)"));
+
+      break;
+
+    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];
+
+	snprintf (buffer, sizeof (buffer), _("Unknown AT value: %lx"),
+		  attribute);
+	return buffer;
+      }
+    }
+}
+
+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;
+}
+
+
+/* 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.  */
+
+static int
+process_debug_info (struct dwarf_section *section, void *file,
+		    int do_loc)
+{
+  unsigned char *start = section->start;
+  unsigned char *end = start + section->size;
+  unsigned char *section_begin;
+  unsigned int unit;
+  unsigned int num_units = 0;
+
+  if ((do_loc || do_debug_loc || do_debug_ranges)
+      && num_debug_info_entries == 0)
+    {
+      unsigned long length;
+
+      /* 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
+	    section_begin += length + 4;
+	}
+
+      if (num_units == 0)
+	{
+	  error (_("No comp units in %s section ?"), section->name);
+	  return 0;
+	}
+
+      /* Then allocate an array to hold the information.  */
+      debug_information = cmalloc (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;
+	}
+    }
+
+  if (!do_loc)
+    {
+      printf (_("The section %s contains:\n\n"), section->name);
+
+      load_debug_section (str, file);
+    }
+
+  load_debug_section (abbrev, file);
+  if (debug_displays [abbrev].section.start == NULL)
+    {
+      warn (_("Unable to locate %s section!\n"),
+	    debug_displays [abbrev].section.name);
+      return 0;
+    }
+
+  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;
+
+      hdrptr = start;
+
+      compunit.cu_length = byte_get (hdrptr, 4);
+      hdrptr += 4;
+
+      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;
+	}
+
+      compunit.cu_version = byte_get (hdrptr, 2);
+      hdrptr += 2;
+
+      cu_offset = start - section_begin;
+      start += compunit.cu_length + initial_length_size;
+
+      cu_abbrev_offset_ptr = hdrptr;
+      compunit.cu_abbrev_offset = byte_get (hdrptr, offset_size);
+      hdrptr += offset_size;
+
+      compunit.cu_pointer_size = byte_get (hdrptr, 1);
+      hdrptr += 1;
+      if ((do_loc || do_debug_loc || do_debug_ranges)
+	  && num_debug_info_entries == 0)
+	{
+	  debug_information [unit].cu_offset = cu_offset;
+	  debug_information [unit].pointer_size
+	    = compunit.cu_pointer_size;
+	  debug_information [unit].base_address = 0;
+	  debug_information [unit].loc_offsets = NULL;
+	  debug_information [unit].have_frame_base = NULL;
+	  debug_information [unit].max_loc_offsets = 0;
+	  debug_information [unit].num_loc_offsets = 0;
+	  debug_information [unit].range_lists = NULL;
+	  debug_information [unit].max_range_lists= 0;
+	  debug_information [unit].num_range_lists = 0;
+	}
+
+      tags = hdrptr;
+
+      if (!do_loc)
+	{
+	  printf (_("  Compilation Unit @ offset 0x%lx:\n"), cu_offset);
+	  printf (_("   Length:        %ld\n"), compunit.cu_length);
+	  printf (_("   Version:       %d\n"), compunit.cu_version);
+	  printf (_("   Abbrev Offset: %ld\n"), compunit.cu_abbrev_offset);
+	  printf (_("   Pointer Size:  %d\n"), compunit.cu_pointer_size);
+	}
+
+      if (compunit.cu_version != 2 && compunit.cu_version != 3)
+	{
+	  warn (_("Only version 2 and 3 DWARF debug information is currently supported.\n"));
+	  continue;
+	}
+
+      free_abbrevs ();
+
+      /* Process the abbrevs used by this compilation unit.  */
+      process_abbrev_section
+	((unsigned char *) debug_displays [abbrev].section.start
+	 + compunit.cu_abbrev_offset,
+	 (unsigned char *) debug_displays [abbrev].section.start
+	 + debug_displays [abbrev].section.size);
+
+      level = 0;
+      while (tags < start)
+	{
+	  unsigned int bytes_read;
+	  unsigned long abbrev_number;
+	  abbrev_entry *entry;
+	  abbrev_attr *attr;
+
+	  abbrev_number = read_leb128 (tags, & bytes_read, 0);
+	  tags += bytes_read;
+
+	  /* A null DIE marks the end of a list of children.  */
+	  if (abbrev_number == 0)
+	    {
+	      --level;
+	      continue;
+	    }
+
+	  /* Scan through the abbreviation list until we reach the
+	     correct entry.  */
+	  for (entry = first_abbrev;
+	       entry && entry->entry != abbrev_number;
+	       entry = entry->next)
+	    continue;
+
+	  if (entry == NULL)
+	    {
+	      warn (_("Unable to locate entry %lu in the abbreviation table\n"),
+		    abbrev_number);
+	      return 0;
+	    }
+
+	  if (!do_loc)
+	    printf (_(" <%d><%lx>: Abbrev Number: %lu (%s)\n"),
+		    level,
+		    (unsigned long) (tags - section_begin
+				     - bytes_read),
+		    abbrev_number,
+		    get_TAG_name (entry->tag));
+ 
+	  switch (entry->tag)
+	    {
+	    default:
+	      need_base_address = 0;
+	      break;
+	    case DW_TAG_compile_unit:
+	      need_base_address = 1;
+	      break;
+	    case DW_TAG_entry_point:
+	    case DW_TAG_inlined_subroutine:
+	    case DW_TAG_subprogram:
+	      need_base_address = 0;
+	      /* Assuming that there is no DW_AT_frame_base.  */
+	      have_frame_base = 0;
+	      break;
+	    }
+
+	  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 process .debug_loc and .debug_ranges sections.  */
+  if ((do_loc || do_debug_loc || do_debug_ranges)
+      && num_debug_info_entries == 0)
+    num_debug_info_entries = num_units;
+      
+  if (!do_loc)
+    {
+      printf ("\n");
+    }
+ 
+  return 1;
+}
+
+/* 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
+load_debug_info (void * file)
+{
+  /* 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;
+
+  /* If we already have the information there is nothing else to do.  */
+  if (num_debug_info_entries > 0)
+    return num_debug_info_entries;
+
+  if (load_debug_section (info, file)
+      && process_debug_info (&debug_displays [info].section, file, 1))
+    return num_debug_info_entries;
+  else
+    return 0;
+}
+
+/* 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 unsigned int
+get_pointer_size_and_offset_of_comp_unit (unsigned int comp_unit,
+					  const char * section_name,
+					  unsigned long * offset_return)
+{
+  unsigned long offset = 0;
+
+  if (num_debug_info_entries == 0)
+    error (_("%s section needs a populated .debug_info section\n"),
+	   section_name);
+
+  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;
+    }
+
+  if (offset_return != NULL)
+    * offset_return = offset;
+
+  return last_pointer_size;
+}
+
+static int
+display_debug_lines (struct dwarf_section *section, void *file)
+{
+  unsigned char *start = section->start;
+  unsigned char *data = start;
+  unsigned char *end = start + section->size;
+  unsigned int comp_unit = 0;
+
+  printf (_("\nDump of debug contents of section %s:\n\n"),
+	  section->name);
+
+  load_debug_info (file);
+
+  while (data < end)
+    {
+      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->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++;
+
+      /* Sign extend the line base field.  */
+      info.li_line_base <<= 24;
+      info.li_line_base >>= 24;
+
+      /* 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_line", NULL);
+      comp_unit ++;
+
+      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)%s\n"),
+	      pointer_size,
+	      warned_about_missing_comp_units ? " [assumed]" : "" );
+
+      end_of_sequence = data + info.li_length + initial_length_size;
+
+      reset_state_machine (info.li_default_is_stmt);
+
+      /* Display the contents of the Opcodes table.  */
+      standard_opcodes = hdrptr;
+
+      printf (_("\n Opcodes:\n"));
+
+      for (i = 1; i < info.li_opcode_base; i++)
+	printf (_("  Opcode %d has %d args\n"), i, standard_opcodes[i - 1]);
+
+      /* Display the contents of the Directory table.  */
+      data = standard_opcodes + info.li_opcode_base - 1;
+
+      if (*data == 0)
+	printf (_("\n The Directory Table is empty.\n"));
+      else
+	{
+	  printf (_("\n The Directory Table:\n"));
+
+	  while (*data != 0)
+	    {
+	      printf (_("  %s\n"), data);
+
+	      data += strlen ((char *) data) + 1;
+	    }
+	}
+
+      /* Skip the NUL at the end of the table.  */
+      data++;
+
+      /* 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"));
+
+	  while (*data != 0)
+	    {
+	      unsigned char *name;
+	      unsigned int bytes_read;
+
+	      printf (_("  %d\t"), ++state_machine_regs.last_file_entry);
+	      name = data;
+
+	      data += strlen ((char *) data) + 1;
+
+	      printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0));
+	      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++;
+
+      /* Now display the statements.  */
+      printf (_("\n Line Number Statements:\n"));
+
+      while (data < end_of_sequence)
+	{
+	  unsigned char op_code;
+	  int adv;
+	  unsigned int bytes_read;
+
+	  op_code = *data++;
+
+	  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:
+	      if (pointer_size == 0)
+		{
+		  warn (_("Extend line ops need a valid pointer size, guessing at 4\n"));
+		  pointer_size = 4;
+		}
+
+	      data += process_extended_line_op (data, info.li_default_is_stmt,
+						pointer_size);
+	      break;
+
+	    case DW_LNS_copy:
+	      printf (_("  Copy\n"));
+	      break;
+
+	    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;
+
+	    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;
+
+	    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;
+
+	    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;
+
+	    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;
+
+	    case DW_LNS_set_basic_block:
+	      printf (_("  Set basic block\n"));
+	      state_machine_regs.basic_block = 1;
+	      break;
+
+	    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 (struct dwarf_section *section,
+			void *file ATTRIBUTE_UNUSED)
+{
+  DWARF2_Internal_PubNames pubnames;
+  unsigned char *start = section->start;
+  unsigned char *end = start + section->size;
+
+  printf (_("Contents of the %s section:\n\n"), section->name);
+
+  while (start < end)
+    {
+      unsigned char *data;
+      unsigned long offset;
+      int offset_size, initial_length_size;
+
+      data = start;
+
+      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;
+	}
+
+      pubnames.pn_version = byte_get (data, 2);
+      data += 2;
+      pubnames.pn_offset = byte_get (data, offset_size);
+      data += offset_size;
+      pubnames.pn_size = byte_get (data, offset_size);
+      data += offset_size;
+
+      start += pubnames.pn_length + initial_length_size;
+
+      if (pubnames.pn_version != 2 && pubnames.pn_version != 3)
+	{
+	  static int warned = 0;
+
+	  if (! warned)
+	    {
+	      warn (_("Only DWARF 2 and 3 pubnames are currently supported\n"));
+	      warned = 1;
+	    }
+
+	  continue;
+	}
+
+      printf (_("  Length:                              %ld\n"),
+	      pubnames.pn_length);
+      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);
+
+      printf (_("\n    Offset\tName\n"));
+
+      do
+	{
+	  offset = byte_get (data, offset_size);
+
+	  if (offset != 0)
+	    {
+	      data += offset_size;
+	      printf ("    %-6ld\t\t%s\n", offset, data);
+	      data += strlen ((char *) data) + 1;
+	    }
+	}
+      while (offset != 0);
+    }
+
+  printf ("\n");
+  return 1;
+}
+
+static int
+display_debug_macinfo (struct dwarf_section *section,
+		       void *file ATTRIBUTE_UNUSED)
+{
+  unsigned char *start = section->start;
+  unsigned char *end = start + section->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);
+
+  while (curr < end)
+    {
+      unsigned int lineno;
+      const char *string;
+
+      op = *curr;
+      curr++;
+
+      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);
+	  }
+	  break;
+
+	case DW_MACINFO_end_file:
+	  printf (_(" DW_MACINFO_end_file\n"));
+	  break;
+
+	case DW_MACINFO_define:
+	  lineno = read_leb128 (curr, & bytes_read, 0);
+	  curr += bytes_read;
+	  string = (char *) curr;
+	  curr += strlen (string) + 1;
+	  printf (_(" DW_MACINFO_define - lineno : %d macro : %s\n"),
+		  lineno, string);
+	  break;
+
+	case DW_MACINFO_undef:
+	  lineno = read_leb128 (curr, & bytes_read, 0);
+	  curr += bytes_read;
+	  string = (char *) curr;
+	  curr += strlen (string) + 1;
+	  printf (_(" DW_MACINFO_undef - lineno : %d macro : %s\n"),
+		  lineno, string);
+	  break;
+
+	case DW_MACINFO_vendor_ext:
+	  {
+	    unsigned int constant;
+
+	    constant = read_leb128 (curr, & bytes_read, 0);
+	    curr += bytes_read;
+	    string = (char *) 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 (struct dwarf_section *section,
+		      void *file ATTRIBUTE_UNUSED)
+{
+  abbrev_entry *entry;
+  unsigned char *start = section->start;
+  unsigned char *end = start + section->size;
+
+  printf (_("Contents of the %s section:\n\n"), section->name);
+
+  do
+    {
+      free_abbrevs ();
+
+      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));
+	}
+    }
+  while (start);
+
+  printf ("\n");
+
+  return 1;
+}
+
+static int
+display_debug_loc (struct dwarf_section *section, void *file)
+{
+  unsigned char *start = section->start;
+  unsigned char *section_end;
+  unsigned long bytes;
+  unsigned char *section_begin = start;
+  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;
+
+  bytes = section->size;
+  section_end = start + bytes;
+
+  if (bytes == 0)
+    {
+      printf (_("\nThe %s section is empty.\n"), section->name);
+      return 0;
+    }
+
+  load_debug_info (file);
+
+  /* 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;
+
+      num = debug_information [i].num_loc_offsets;
+      num_loc_list += num;
+
+      /* Check if we can use `debug_information' directly.  */
+      if (use_debug_info && num != 0)
+	{
+	  if (!seen_first_offset)
+	    {
+	      /* This is the first location list.  */
+	      last_offset = debug_information [i].loc_offsets [0];
+	      first = i;
+	      seen_first_offset = 1;
+	      j = 1;
+	    }
+	  else
+	    j = 0;
+
+	  for (; j < num; j++)
+	    {
+	      if (last_offset >
+		  debug_information [i].loc_offsets [j])
+		{
+		  use_debug_info = 0;
+		  break;
+		}
+	      last_offset = debug_information [i].loc_offsets [j];
+	    }
+	}
+    }
+
+  if (!use_debug_info)
+    /* FIXME: Should we handle this case?  */
+    error (_("Location lists in .debug_info section aren't in ascending order!\n"));
+
+  if (!seen_first_offset)
+    error (_("No location lists in .debug_info section!\n"));
+
+  if (debug_information [first].loc_offsets [0] != 0)
+    warn (_("Location lists in %s section start at 0x%lx\n"),
+	  section->name, debug_information [first].loc_offsets [0]);
+
+  printf (_("Contents of the %s section:\n\n"), section->name);
+  printf (_("    Offset   Begin    End      Expression\n"));
+
+  seen_first_offset = 0;
+  for (i = first; i < num_debug_info_entries; i++)
+    {
+      unsigned long begin;
+      unsigned long end;
+      unsigned short length;
+      unsigned long offset;
+      unsigned int pointer_size;
+      unsigned long cu_offset;
+      unsigned long base_address;
+      int need_frame_base;
+      int has_frame_base;
+
+      pointer_size = debug_information [i].pointer_size;
+      cu_offset = debug_information [i].cu_offset;
+
+      for (j = 0; j < debug_information [i].num_loc_offsets; j++)
+	{
+	  has_frame_base = debug_information [i].have_frame_base [j];
+	  offset = debug_information [i].loc_offsets [j];
+	  next = section_begin + offset;
+	  base_address = debug_information [i].base_address;
+
+	  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"),
+		      (long)(start - section_begin), (long)(next - section_begin));
+	      else if (start > next)
+		warn (_("There is an overlap [0x%lx - 0x%lx] in .debug_loc section.\n"),
+		      (long)(start - section_begin), (long)(next - section_begin));
+	    }
+	  start = next;
+
+	  if (offset >= bytes)
+	    {
+	      warn (_("Offset 0x%lx is bigger than .debug_loc section size.\n"),
+		    offset);
+	      continue;
+	    }
+
+	  while (1)
+	    {
+	      if (start + 2 * pointer_size > section_end)
+		{
+		  warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
+			offset);
+		  break;
+		}
+
+	      begin = byte_get (start, pointer_size);
+	      start += pointer_size;
+	      end = byte_get (start, pointer_size);
+	      start += pointer_size;
+
+	      if (begin == 0 && end == 0)
+		{
+		  printf (_("    %8.8lx <End of list>\n"), offset);
+		  break;
+		}
+
+	      /* Check base address specifiers.  */
+	      if (begin == -1UL && end != -1UL)
+		{
+		  base_address = end;
+		  printf (_("    %8.8lx %8.8lx %8.8lx (base address)\n"),
+			  offset, begin, end);
+		  continue;
+		}
+
+	      if (start + 2 > section_end)
+		{
+		  warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
+			offset);
+		  break;
+		}
+
+	      length = byte_get (start, 2);
+	      start += 2;
+
+	      if (start + length > section_end)
+		{
+		  warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
+			offset);
+		  break;
+		}
+
+	      printf ("    %8.8lx %8.8lx %8.8lx (",
+		      offset, begin + base_address, end + base_address);
+	      need_frame_base = decode_location_expression (start,
+							    pointer_size,
+							    length,
+							    cu_offset);
+	      putchar (')');
+
+	      if (need_frame_base && !has_frame_base)
+		printf (_(" [without DW_AT_frame_base]"));
+
+	      if (begin == end)
+		fputs (_(" (start == end)"), stdout);
+	      else if (begin > end)
+		fputs (_(" (start > end)"), stdout);
+
+	      putchar ('\n');
+
+	      start += length;
+	    }
+	}
+    }
+  return 1;
+}
+
+static int
+display_debug_str (struct dwarf_section *section,
+		   void *file ATTRIBUTE_UNUSED)
+{
+  unsigned char *start = section->start;
+  unsigned long bytes = section->size;
+  bfd_vma addr = section->address;
+
+  if (bytes == 0)
+    {
+      printf (_("\nThe %s section is empty.\n"), section->name);
+      return 0;
+    }
+
+  printf (_("Contents of the %s section:\n\n"), section->name);
+
+  while (bytes)
+    {
+      int j;
+      int k;
+      int lbytes;
+
+      lbytes = (bytes > 16 ? 16 : bytes);
+
+      printf ("  0x%8.8lx ", (unsigned long) addr);
+
+      for (j = 0; j < 16; j++)
+	{
+	  if (j < lbytes)
+	    printf ("%2.2x", start[j]);
+	  else
+	    printf ("  ");
+
+	  if ((j & 3) == 3)
+	    printf (" ");
+	}
+
+      for (j = 0; j < lbytes; j++)
+	{
+	  k = start[j];
+	  if (k >= ' ' && k < 0x80)
+	    printf ("%c", k);
+	  else
+	    printf (".");
+	}
+
+      putchar ('\n');
+
+      start += lbytes;
+      addr  += lbytes;
+      bytes -= lbytes;
+    }
+
+  putchar ('\n');
+
+  return 1;
+}
+
+
+static int
+display_debug_info (struct dwarf_section *section, void *file)
+{
+  return process_debug_info (section, file, 0);
+}
+
+
+static int
+display_debug_aranges (struct dwarf_section *section,
+		       void *file ATTRIBUTE_UNUSED)
+{
+  unsigned char *start = section->start;
+  unsigned char *end = start + section->size;
+
+  printf (_("The section %s contains:\n\n"), section->name);
+
+  while (start < end)
+    {
+      unsigned char *hdrptr;
+      DWARF2_Internal_ARange arange;
+      unsigned char *ranges;
+      unsigned long length;
+      unsigned long address;
+      int excess;
+      int offset_size;
+      int initial_length_size;
+
+      hdrptr = start;
+
+      arange.ar_length = byte_get (hdrptr, 4);
+      hdrptr += 4;
+
+      if (arange.ar_length == 0xffffffff)
+	{
+	  arange.ar_length = byte_get (hdrptr, 8);
+	  hdrptr += 8;
+	  offset_size = 8;
+	  initial_length_size = 12;
+	}
+      else
+	{
+	  offset_size = 4;
+	  initial_length_size = 4;
+	}
+
+      arange.ar_version = byte_get (hdrptr, 2);
+      hdrptr += 2;
+
+      arange.ar_info_offset = byte_get (hdrptr, offset_size);
+      hdrptr += offset_size;
+
+      arange.ar_pointer_size = byte_get (hdrptr, 1);
+      hdrptr += 1;
+
+      arange.ar_segment_size = byte_get (hdrptr, 1);
+      hdrptr += 1;
+
+      if (arange.ar_version != 2 && arange.ar_version != 3)
+	{
+	  warn (_("Only DWARF 2 and 3 aranges are currently supported.\n"));
+	  break;
+	}
+
+      printf (_("  Length:                   %ld\n"), arange.ar_length);
+      printf (_("  Version:                  %d\n"), arange.ar_version);
+      printf (_("  Offset into .debug_info:  %lx\n"), arange.ar_info_offset);
+      printf (_("  Pointer Size:             %d\n"), arange.ar_pointer_size);
+      printf (_("  Segment Size:             %d\n"), arange.ar_segment_size);
+
+      printf (_("\n    Address  Length\n"));
+
+      ranges = hdrptr;
+
+      /* Must pad to an alignment boundary that is twice the pointer size.  */
+      excess = (hdrptr - start) % (2 * arange.ar_pointer_size);
+      if (excess)
+	ranges += (2 * arange.ar_pointer_size) - excess;
+
+      for (;;)
+	{
+	  address = byte_get (ranges, arange.ar_pointer_size);
+
+	  ranges += arange.ar_pointer_size;
+
+	  length  = byte_get (ranges, arange.ar_pointer_size);
+
+	  ranges += arange.ar_pointer_size;
+
+	  /* A pair of zeros marks the end of the list.  */
+	  if (address == 0 && length == 0)
+	    break;
+
+	  printf ("    %8.8lx %lu\n", address, length);
+	}
+
+      start += arange.ar_length + initial_length_size;
+    }
+
+  printf ("\n");
+
+  return 1;
+}
+
+static int
+display_debug_ranges (struct dwarf_section *section,
+		      void *file ATTRIBUTE_UNUSED)
+{
+  unsigned char *start = section->start;
+  unsigned char *section_end;
+  unsigned long bytes;
+  unsigned char *section_begin = start;
+  unsigned int num_range_list = 0;
+  unsigned long last_offset = 0;
+  unsigned int first = 0;
+  unsigned int i;
+  unsigned int j;
+  int seen_first_offset = 0;
+  int use_debug_info = 1;
+  unsigned char *next;
+
+  bytes = section->size;
+  section_end = start + bytes;
+
+  if (bytes == 0)
+    {
+      printf (_("\nThe %s section is empty.\n"), section->name);
+      return 0;
+    }
+
+  load_debug_info (file);
+
+  /* Check the order of range list in .debug_info section. If
+     offsets of range lists are in the ascending order, we can
+     use `debug_information' directly.  */
+  for (i = 0; i < num_debug_info_entries; i++)
+    {
+      unsigned int num;
+
+      num = debug_information [i].num_range_lists;
+      num_range_list += num;
+
+      /* Check if we can use `debug_information' directly.  */
+      if (use_debug_info && num != 0)
+	{
+	  if (!seen_first_offset)
+	    {
+	      /* This is the first range list.  */
+	      last_offset = debug_information [i].range_lists [0];
+	      first = i;
+	      seen_first_offset = 1;
+	      j = 1;
+	    }
+	  else
+	    j = 0;
+
+	  for (; j < num; j++)
+	    {
+	      if (last_offset >
+		  debug_information [i].range_lists [j])
+		{
+		  use_debug_info = 0;
+		  break;
+		}
+	      last_offset = debug_information [i].range_lists [j];
+	    }
+	}
+    }
+
+  if (!use_debug_info)
+    /* FIXME: Should we handle this case?  */
+    error (_("Range lists in .debug_info section aren't in ascending order!\n"));
+
+  if (!seen_first_offset)
+    error (_("No range lists in .debug_info section!\n"));
+
+  if (debug_information [first].range_lists [0] != 0)
+    warn (_("Range lists in %s section start at 0x%lx\n"),
+	  section->name, debug_information [first].range_lists [0]);
+
+  printf (_("Contents of the %s section:\n\n"), section->name);
+  printf (_("    Offset   Begin    End\n"));
+
+  seen_first_offset = 0;
+  for (i = first; i < num_debug_info_entries; i++)
+    {
+      unsigned long begin;
+      unsigned long end;
+      unsigned long offset;
+      unsigned int pointer_size;
+      unsigned long base_address;
+
+      pointer_size = debug_information [i].pointer_size;
+
+      for (j = 0; j < debug_information [i].num_range_lists; j++)
+	{
+	  offset = debug_information [i].range_lists [j];
+	  next = section_begin + offset;
+	  base_address = debug_information [i].base_address;
+
+	  if (!seen_first_offset)
+	    seen_first_offset = 1;
+	  else
+	    {
+	      if (start < next)
+		warn (_("There is a hole [0x%lx - 0x%lx] in %s section.\n"),
+		      (long)(start - section_begin),
+		      (long)(next - section_begin), section->name);
+	      else if (start > next)
+		warn (_("There is an overlap [0x%lx - 0x%lx] in %s section.\n"),
+		      (long)(start - section_begin),
+		      (long)(next - section_begin), section->name);
+	    }
+	  start = next;
+
+	  while (1)
+	    {
+	      begin = byte_get (start, pointer_size);
+	      start += pointer_size;
+	      end = byte_get (start, pointer_size);
+	      start += pointer_size;
+
+	      if (begin == 0 && end == 0)
+		{
+		  printf (_("    %8.8lx <End of list>\n"), offset);
+		  break;
+		}
+
+	      /* Check base address specifiers.  */
+	      if (begin == -1UL && end != -1UL)
+		{
+		  base_address = end;
+		  printf ("    %8.8lx %8.8lx %8.8lx (base address)\n",
+			  offset, begin, end);
+		  continue;
+		}
+
+	      printf ("    %8.8lx %8.8lx %8.8lx",
+		      offset, begin + base_address, end + base_address);
+
+	      if (begin == end)
+		fputs (_(" (start == end)"), stdout);
+	      else if (begin > end)
+		fputs (_(" (start > end)"), stdout);
+
+	      putchar ('\n');
+	    }
+	}
+    }
+  putchar ('\n');
+  return 1;
+}
+
+typedef struct Frame_Chunk
+{
+  struct Frame_Chunk *next;
+  unsigned char *chunk_start;
+  int ncols;
+  /* DW_CFA_{undefined,same_value,offset,register,unreferenced}  */
+  short int *col_type;
+  int *col_offset;
+  char *augmentation;
+  unsigned int code_factor;
+  int data_factor;
+  unsigned long pc_begin;
+  unsigned long pc_range;
+  int cfa_reg;
+  int cfa_offset;
+  int ra;
+  unsigned char fde_encoding;
+  unsigned char cfa_exp;
+}
+Frame_Chunk;
+
+/* A marker for a col_type that means this column was never referenced
+   in the frame info.  */
+#define DW_CFA_unreferenced (-1)
+
+static void
+frame_need_space (Frame_Chunk *fc, int reg)
+{
+  int prev = fc->ncols;
+
+  if (reg < fc->ncols)
+    return;
+
+  fc->ncols = reg + 1;
+  fc->col_type = xcrealloc (fc->col_type, fc->ncols, sizeof (short int));
+  fc->col_offset = xcrealloc (fc->col_offset, fc->ncols, sizeof (int));
+
+  while (prev < fc->ncols)
+    {
+      fc->col_type[prev] = DW_CFA_unreferenced;
+      fc->col_offset[prev] = 0;
+      prev++;
+    }
+}
+
+static void
+frame_display_row (Frame_Chunk *fc, int *need_col_headers, int *max_regs)
+{
+  int r;
+  char tmp[100];
+
+  if (*max_regs < fc->ncols)
+    *max_regs = fc->ncols;
+
+  if (*need_col_headers)
+    {
+      *need_col_headers = 0;
+
+      printf ("   LOC   CFA      ");
+
+      for (r = 0; r < *max_regs; r++)
+	if (fc->col_type[r] != DW_CFA_unreferenced)
+	  {
+	    if (r == fc->ra)
+	      printf ("ra   ");
+	    else
+	      printf ("r%-4d", r);
+	  }
+
+      printf ("\n");
+    }
+
+  printf ("%08lx ", fc->pc_begin);
+  if (fc->cfa_exp)
+    strcpy (tmp, "exp");
+  else
+    sprintf (tmp, "r%d%+d", fc->cfa_reg, fc->cfa_offset);
+  printf ("%-8s ", tmp);
+
+  for (r = 0; r < fc->ncols; r++)
+    {
+      if (fc->col_type[r] != DW_CFA_unreferenced)
+	{
+	  switch (fc->col_type[r])
+	    {
+	    case DW_CFA_undefined:
+	      strcpy (tmp, "u");
+	      break;
+	    case DW_CFA_same_value:
+	      strcpy (tmp, "s");
+	      break;
+	    case DW_CFA_offset:
+	      sprintf (tmp, "c%+d", fc->col_offset[r]);
+	      break;
+	    case DW_CFA_register:
+	      sprintf (tmp, "r%d", fc->col_offset[r]);
+	      break;
+	    case DW_CFA_expression:
+	      strcpy (tmp, "exp");
+	      break;
+	    default:
+	      strcpy (tmp, "n/a");
+	      break;
+	    }
+	  printf ("%-5s", tmp);
+	}
+    }
+  printf ("\n");
+}
+
+static int
+size_of_encoded_value (int encoding)
+{
+  switch (encoding & 0x7)
+    {
+    default:	/* ??? */
+    case 0:	return eh_addr_size;
+    case 2:	return 2;
+    case 3:	return 4;
+    case 4:	return 8;
+    }
+}
+
+static bfd_vma
+get_encoded_value (unsigned char *data, int encoding)
+{
+  int size = size_of_encoded_value (encoding);
+  if (encoding & DW_EH_PE_signed)
+    return byte_get_signed (data, size);
+  else
+    return byte_get (data, size);
+}
+
+#define GET(N)	byte_get (start, N); start += N
+#define LEB()	read_leb128 (start, & length_return, 0); start += length_return
+#define SLEB()	read_leb128 (start, & length_return, 1); start += length_return
+
+static int
+display_debug_frames (struct dwarf_section *section,
+		      void *file ATTRIBUTE_UNUSED)
+{
+  unsigned char *start = section->start;
+  unsigned char *end = start + section->size;
+  unsigned char *section_start = start;
+  Frame_Chunk *chunks = 0;
+  Frame_Chunk *remembered_state = 0;
+  Frame_Chunk *rs;
+  int is_eh = strcmp (section->name, ".eh_frame") == 0;
+  unsigned int length_return;
+  int max_regs = 0;
+
+  printf (_("The section %s contains:\n"), section->name);
+
+  while (start < end)
+    {
+      unsigned char *saved_start;
+      unsigned char *block_end;
+      unsigned long length;
+      unsigned long cie_id;
+      Frame_Chunk *fc;
+      Frame_Chunk *cie;
+      int need_col_headers = 1;
+      unsigned char *augmentation_data = NULL;
+      unsigned long augmentation_data_len = 0;
+      int encoded_ptr_size = eh_addr_size;
+      int offset_size;
+      int initial_length_size;
+
+      saved_start = start;
+      length = byte_get (start, 4); start += 4;
+
+      if (length == 0)
+	{
+	  printf ("\n%08lx ZERO terminator\n\n",
+		    (unsigned long)(saved_start - section_start));
+	  return 1;
+	}
+
+      if (length == 0xffffffff)
+	{
+	  length = byte_get (start, 8);
+	  start += 8;
+	  offset_size = 8;
+	  initial_length_size = 12;
+	}
+      else
+	{
+	  offset_size = 4;
+	  initial_length_size = 4;
+	}
+
+      block_end = saved_start + length + initial_length_size;
+      cie_id = byte_get (start, offset_size); start += offset_size;
+
+      if (is_eh ? (cie_id == 0) : (cie_id == DW_CIE_ID))
+	{
+	  int version;
+
+	  fc = xmalloc (sizeof (Frame_Chunk));
+	  memset (fc, 0, sizeof (Frame_Chunk));
+
+	  fc->next = chunks;
+	  chunks = fc;
+	  fc->chunk_start = saved_start;
+	  fc->ncols = 0;
+	  fc->col_type = xmalloc (sizeof (short int));
+	  fc->col_offset = xmalloc (sizeof (int));
+	  frame_need_space (fc, max_regs-1);
+
+	  version = *start++;
+
+	  fc->augmentation = (char *) start;
+	  start = (unsigned char *) strchr ((char *) start, '\0') + 1;
+
+	  if (fc->augmentation[0] == 'z')
+	    {
+	      fc->code_factor = LEB ();
+	      fc->data_factor = SLEB ();
+	      if (version == 1)
+		{
+		  fc->ra = GET (1);
+		}
+	      else
+		{
+		  fc->ra = LEB ();
+		}
+	      augmentation_data_len = LEB ();
+	      augmentation_data = start;
+	      start += augmentation_data_len;
+	    }
+	  else if (strcmp (fc->augmentation, "eh") == 0)
+	    {
+	      start += eh_addr_size;
+	      fc->code_factor = LEB ();
+	      fc->data_factor = SLEB ();
+	      if (version == 1)
+		{
+		  fc->ra = GET (1);
+		}
+	      else
+		{
+		  fc->ra = LEB ();
+		}
+	    }
+	  else
+	    {
+	      fc->code_factor = LEB ();
+	      fc->data_factor = SLEB ();
+	      if (version == 1)
+		{
+		  fc->ra = GET (1);
+		}
+	      else
+		{
+		  fc->ra = LEB ();
+		}
+	    }
+	  cie = fc;
+
+	  if (do_debug_frames_interp)
+	    printf ("\n%08lx %08lx %08lx CIE \"%s\" cf=%d df=%d ra=%d\n",
+		    (unsigned long)(saved_start - section_start), length, cie_id,
+		    fc->augmentation, fc->code_factor, fc->data_factor,
+		    fc->ra);
+	  else
+	    {
+	      printf ("\n%08lx %08lx %08lx CIE\n",
+		      (unsigned long)(saved_start - section_start), length, cie_id);
+	      printf ("  Version:               %d\n", version);
+	      printf ("  Augmentation:          \"%s\"\n", fc->augmentation);
+	      printf ("  Code alignment factor: %u\n", fc->code_factor);
+	      printf ("  Data alignment factor: %d\n", fc->data_factor);
+	      printf ("  Return address column: %d\n", fc->ra);
+
+	      if (augmentation_data_len)
+		{
+		  unsigned long i;
+		  printf ("  Augmentation data:    ");
+		  for (i = 0; i < augmentation_data_len; ++i)
+		    printf (" %02x", augmentation_data[i]);
+		  putchar ('\n');
+		}
+	      putchar ('\n');
+	    }
+
+	  if (augmentation_data_len)
+	    {
+	      unsigned char *p, *q;
+	      p = (unsigned char *) fc->augmentation + 1;
+	      q = augmentation_data;
+
+	      while (1)
+		{
+		  if (*p == 'L')
+		    q++;
+		  else if (*p == 'P')
+		    q += 1 + size_of_encoded_value (*q);
+		  else if (*p == 'R')
+		    fc->fde_encoding = *q++;
+		  else
+		    break;
+		  p++;
+		}
+
+	      if (fc->fde_encoding)
+		encoded_ptr_size = size_of_encoded_value (fc->fde_encoding);
+	    }
+
+	  frame_need_space (fc, fc->ra);
+	}
+      else
+	{
+	  unsigned char *look_for;
+	  static Frame_Chunk fde_fc;
+
+	  fc = & fde_fc;
+	  memset (fc, 0, sizeof (Frame_Chunk));
+
+	  look_for = is_eh ? start - 4 - cie_id : section_start + cie_id;
+
+	  for (cie = chunks; cie ; cie = cie->next)
+	    if (cie->chunk_start == look_for)
+	      break;
+
+	  if (!cie)
+	    {
+	      warn ("Invalid CIE pointer %08lx in FDE at %p\n",
+		    cie_id, saved_start);
+	      start = block_end;
+	      fc->ncols = 0;
+	      fc->col_type = xmalloc (sizeof (short int));
+	      fc->col_offset = xmalloc (sizeof (int));
+	      frame_need_space (fc, max_regs - 1);
+	      cie = fc;
+	      fc->augmentation = "";
+	      fc->fde_encoding = 0;
+	    }
+	  else
+	    {
+	      fc->ncols = cie->ncols;
+	      fc->col_type = xcmalloc (fc->ncols, sizeof (short int));
+	      fc->col_offset = xcmalloc (fc->ncols, sizeof (int));
+	      memcpy (fc->col_type, cie->col_type, fc->ncols * sizeof (short int));
+	      memcpy (fc->col_offset, cie->col_offset, fc->ncols * sizeof (int));
+	      fc->augmentation = cie->augmentation;
+	      fc->code_factor = cie->code_factor;
+	      fc->data_factor = cie->data_factor;
+	      fc->cfa_reg = cie->cfa_reg;
+	      fc->cfa_offset = cie->cfa_offset;
+	      fc->ra = cie->ra;
+	      frame_need_space (fc, max_regs-1);
+	      fc->fde_encoding = cie->fde_encoding;
+	    }
+
+	  if (fc->fde_encoding)
+	    encoded_ptr_size = size_of_encoded_value (fc->fde_encoding);
+
+	  fc->pc_begin = get_encoded_value (start, fc->fde_encoding);
+	  if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel
+	      /* Don't adjust for relocatable file since there's
+		 invariably a pcrel reloc here, which we haven't
+		 applied.  */
+	      && !is_relocatable)
+	    fc->pc_begin += section->address + (start - section_start);
+	  start += encoded_ptr_size;
+	  fc->pc_range = byte_get (start, encoded_ptr_size);
+	  start += encoded_ptr_size;
+
+	  if (cie->augmentation[0] == 'z')
+	    {
+	      augmentation_data_len = LEB ();
+	      augmentation_data = start;
+	      start += augmentation_data_len;
+	    }
+
+	  printf ("\n%08lx %08lx %08lx FDE cie=%08lx pc=%08lx..%08lx\n",
+		  (unsigned long)(saved_start - section_start), length, cie_id,
+		  (unsigned long)(cie->chunk_start - section_start),
+		  fc->pc_begin, fc->pc_begin + fc->pc_range);
+	  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]);
+	      putchar ('\n');
+	      putchar ('\n');
+	    }
+	}
+
+      /* At this point, fc is the current chunk, cie (if any) is set, and
+	 we're about to interpret instructions for the chunk.  */
+      /* ??? At present we need to do this always, since this sizes the
+	 fc->col_type and fc->col_offset arrays, which we write into always.
+	 We should probably split the interpreted and non-interpreted bits
+	 into two different routines, since there's so much that doesn't
+	 really overlap between them.  */
+      if (1 || do_debug_frames_interp)
+	{
+	  /* Start by making a pass over the chunk, allocating storage
+	     and taking note of what registers are used.  */
+	  unsigned char *tmp = start;
+
+	  while (start < block_end)
+	    {
+	      unsigned op, opa;
+	      unsigned long reg, tmp;
+
+	      op = *start++;
+	      opa = op & 0x3f;
+	      if (op & 0xc0)
+		op &= 0xc0;
+
+	      /* Warning: if you add any more cases to this switch, be
+		 sure to add them to the corresponding switch below.  */
+	      switch (op)
+		{
+		case DW_CFA_advance_loc:
+		  break;
+		case DW_CFA_offset:
+		  LEB ();
+		  frame_need_space (fc, opa);
+		  fc->col_type[opa] = DW_CFA_undefined;
+		  break;
+		case DW_CFA_restore:
+		  frame_need_space (fc, opa);
+		  fc->col_type[opa] = DW_CFA_undefined;
+		  break;
+		case DW_CFA_set_loc:
+		  start += encoded_ptr_size;
+		  break;
+		case DW_CFA_advance_loc1:
+		  start += 1;
+		  break;
+		case DW_CFA_advance_loc2:
+		  start += 2;
+		  break;
+		case DW_CFA_advance_loc4:
+		  start += 4;
+		  break;
+		case DW_CFA_offset_extended:
+		  reg = LEB (); LEB ();
+		  frame_need_space (fc, reg);
+		  fc->col_type[reg] = DW_CFA_undefined;
+		  break;
+		case DW_CFA_restore_extended:
+		  reg = LEB ();
+		  frame_need_space (fc, reg);
+		  fc->col_type[reg] = DW_CFA_undefined;
+		  break;
+		case DW_CFA_undefined:
+		  reg = LEB ();
+		  frame_need_space (fc, reg);
+		  fc->col_type[reg] = DW_CFA_undefined;
+		  break;
+		case DW_CFA_same_value:
+		  reg = LEB ();
+		  frame_need_space (fc, reg);
+		  fc->col_type[reg] = DW_CFA_undefined;
+		  break;
+		case DW_CFA_register:
+		  reg = LEB (); LEB ();
+		  frame_need_space (fc, reg);
+		  fc->col_type[reg] = DW_CFA_undefined;
+		  break;
+		case DW_CFA_def_cfa:
+		  LEB (); LEB ();
+		  break;
+		case DW_CFA_def_cfa_register:
+		  LEB ();
+		  break;
+		case DW_CFA_def_cfa_offset:
+		  LEB ();
+		  break;
+		case DW_CFA_def_cfa_expression:
+		  tmp = LEB ();
+		  start += tmp;
+		  break;
+		case DW_CFA_expression:
+		  reg = LEB ();
+		  tmp = LEB ();
+		  start += tmp;
+		  frame_need_space (fc, reg);
+		  fc->col_type[reg] = DW_CFA_undefined;
+		  break;
+		case DW_CFA_offset_extended_sf:
+		  reg = LEB (); SLEB ();
+		  frame_need_space (fc, reg);
+		  fc->col_type[reg] = DW_CFA_undefined;
+		  break;
+		case DW_CFA_def_cfa_sf:
+		  LEB (); SLEB ();
+		  break;
+		case DW_CFA_def_cfa_offset_sf:
+		  SLEB ();
+		  break;
+		case DW_CFA_MIPS_advance_loc8:
+		  start += 8;
+		  break;
+		case DW_CFA_GNU_args_size:
+		  LEB ();
+		  break;
+		case DW_CFA_GNU_negative_offset_extended:
+		  reg = LEB (); LEB ();
+		  frame_need_space (fc, reg);
+		  fc->col_type[reg] = DW_CFA_undefined;
+
+		default:
+		  break;
+		}
+	    }
+	  start = tmp;
+	}
+
+      /* Now we know what registers are used, make a second pass over
+	 the chunk, this time actually printing out the info.  */
+
+      while (start < block_end)
+	{
+	  unsigned op, opa;
+	  unsigned long ul, reg, roffs;
+	  long l, ofs;
+	  bfd_vma vma;
+
+	  op = *start++;
+	  opa = op & 0x3f;
+	  if (op & 0xc0)
+	    op &= 0xc0;
+
+	  /* Warning: if you add any more cases to this switch, be
+	     sure to add them to the corresponding switch above.  */
+	  switch (op)
+	    {
+	    case DW_CFA_advance_loc:
+	      if (do_debug_frames_interp)
+		frame_display_row (fc, &need_col_headers, &max_regs);
+	      else
+		printf ("  DW_CFA_advance_loc: %d to %08lx\n",
+			opa * fc->code_factor,
+			fc->pc_begin + opa * fc->code_factor);
+	      fc->pc_begin += opa * fc->code_factor;
+	      break;
+
+	    case DW_CFA_offset:
+	      roffs = LEB ();
+	      if (! do_debug_frames_interp)
+		printf ("  DW_CFA_offset: r%d at cfa%+ld\n",
+			opa, roffs * fc->data_factor);
+	      fc->col_type[opa] = DW_CFA_offset;
+	      fc->col_offset[opa] = roffs * fc->data_factor;
+	      break;
+
+	    case DW_CFA_restore:
+	      if (! do_debug_frames_interp)
+		printf ("  DW_CFA_restore: r%d\n", opa);
+	      fc->col_type[opa] = cie->col_type[opa];
+	      fc->col_offset[opa] = cie->col_offset[opa];
+	      break;
+
+	    case DW_CFA_set_loc:
+	      vma = get_encoded_value (start, fc->fde_encoding);
+	      if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel
+		  && !is_relocatable)
+		vma += section->address + (start - section_start);
+	      start += encoded_ptr_size;
+	      if (do_debug_frames_interp)
+		frame_display_row (fc, &need_col_headers, &max_regs);
+	      else
+		printf ("  DW_CFA_set_loc: %08lx\n", (unsigned long)vma);
+	      fc->pc_begin = vma;
+	      break;
+
+	    case DW_CFA_advance_loc1:
+	      ofs = byte_get (start, 1); start += 1;
+	      if (do_debug_frames_interp)
+		frame_display_row (fc, &need_col_headers, &max_regs);
+	      else
+		printf ("  DW_CFA_advance_loc1: %ld to %08lx\n",
+			ofs * fc->code_factor,
+			fc->pc_begin + ofs * fc->code_factor);
+	      fc->pc_begin += ofs * fc->code_factor;
+	      break;
+
+	    case DW_CFA_advance_loc2:
+	      ofs = byte_get (start, 2); start += 2;
+	      if (do_debug_frames_interp)
+		frame_display_row (fc, &need_col_headers, &max_regs);
+	      else
+		printf ("  DW_CFA_advance_loc2: %ld to %08lx\n",
+			ofs * fc->code_factor,
+			fc->pc_begin + ofs * fc->code_factor);
+	      fc->pc_begin += ofs * fc->code_factor;
+	      break;
+
+	    case DW_CFA_advance_loc4:
+	      ofs = byte_get (start, 4); start += 4;
+	      if (do_debug_frames_interp)
+		frame_display_row (fc, &need_col_headers, &max_regs);
+	      else
+		printf ("  DW_CFA_advance_loc4: %ld to %08lx\n",
+			ofs * fc->code_factor,
+			fc->pc_begin + ofs * fc->code_factor);
+	      fc->pc_begin += ofs * fc->code_factor;
+	      break;
+
+	    case DW_CFA_offset_extended:
+	      reg = LEB ();
+	      roffs = LEB ();
+	      if (! do_debug_frames_interp)
+		printf ("  DW_CFA_offset_extended: r%ld at cfa%+ld\n",
+			reg, roffs * fc->data_factor);
+	      fc->col_type[reg] = DW_CFA_offset;
+	      fc->col_offset[reg] = roffs * fc->data_factor;
+	      break;
+
+	    case DW_CFA_restore_extended:
+	      reg = LEB ();
+	      if (! do_debug_frames_interp)
+		printf ("  DW_CFA_restore_extended: r%ld\n", reg);
+	      fc->col_type[reg] = cie->col_type[reg];
+	      fc->col_offset[reg] = cie->col_offset[reg];
+	      break;
+
+	    case DW_CFA_undefined:
+	      reg = LEB ();
+	      if (! do_debug_frames_interp)
+		printf ("  DW_CFA_undefined: r%ld\n", reg);
+	      fc->col_type[reg] = DW_CFA_undefined;
+	      fc->col_offset[reg] = 0;
+	      break;
+
+	    case DW_CFA_same_value:
+	      reg = LEB ();
+	      if (! do_debug_frames_interp)
+		printf ("  DW_CFA_same_value: r%ld\n", reg);
+	      fc->col_type[reg] = DW_CFA_same_value;
+	      fc->col_offset[reg] = 0;
+	      break;
+
+	    case DW_CFA_register:
+	      reg = LEB ();
+	      roffs = LEB ();
+	      if (! do_debug_frames_interp)
+		printf ("  DW_CFA_register: r%ld in r%ld\n", reg, roffs);
+	      fc->col_type[reg] = DW_CFA_register;
+	      fc->col_offset[reg] = roffs;
+	      break;
+
+	    case DW_CFA_remember_state:
+	      if (! do_debug_frames_interp)
+		printf ("  DW_CFA_remember_state\n");
+	      rs = xmalloc (sizeof (Frame_Chunk));
+	      rs->ncols = fc->ncols;
+	      rs->col_type = xcmalloc (rs->ncols, sizeof (short int));
+	      rs->col_offset = xcmalloc (rs->ncols, sizeof (int));
+	      memcpy (rs->col_type, fc->col_type, rs->ncols);
+	      memcpy (rs->col_offset, fc->col_offset, rs->ncols * sizeof (int));
+	      rs->next = remembered_state;
+	      remembered_state = rs;
+	      break;
+
+	    case DW_CFA_restore_state:
+	      if (! do_debug_frames_interp)
+		printf ("  DW_CFA_restore_state\n");
+	      rs = remembered_state;
+	      if (rs)
+		{
+		  remembered_state = rs->next;
+		  frame_need_space (fc, rs->ncols-1);
+		  memcpy (fc->col_type, rs->col_type, rs->ncols);
+		  memcpy (fc->col_offset, rs->col_offset,
+			  rs->ncols * sizeof (int));
+		  free (rs->col_type);
+		  free (rs->col_offset);
+		  free (rs);
+		}
+	      else if (do_debug_frames_interp)
+		printf ("Mismatched DW_CFA_restore_state\n");
+	      break;
+
+	    case DW_CFA_def_cfa:
+	      fc->cfa_reg = LEB ();
+	      fc->cfa_offset = LEB ();
+	      fc->cfa_exp = 0;
+	      if (! do_debug_frames_interp)
+		printf ("  DW_CFA_def_cfa: r%d ofs %d\n",
+			fc->cfa_reg, fc->cfa_offset);
+	      break;
+
+	    case DW_CFA_def_cfa_register:
+	      fc->cfa_reg = LEB ();
+	      fc->cfa_exp = 0;
+	      if (! do_debug_frames_interp)
+		printf ("  DW_CFA_def_cfa_reg: r%d\n", fc->cfa_reg);
+	      break;
+
+	    case DW_CFA_def_cfa_offset:
+	      fc->cfa_offset = LEB ();
+	      if (! do_debug_frames_interp)
+		printf ("  DW_CFA_def_cfa_offset: %d\n", fc->cfa_offset);
+	      break;
+
+	    case DW_CFA_nop:
+	      if (! do_debug_frames_interp)
+		printf ("  DW_CFA_nop\n");
+	      break;
+
+	    case DW_CFA_def_cfa_expression:
+	      ul = LEB ();
+	      if (! do_debug_frames_interp)
+		{
+		  printf ("  DW_CFA_def_cfa_expression (");
+		  decode_location_expression (start, eh_addr_size, ul, 0);
+		  printf (")\n");
+		}
+	      fc->cfa_exp = 1;
+	      start += ul;
+	      break;
+
+	    case DW_CFA_expression:
+	      reg = LEB ();
+	      ul = LEB ();
+	      if (! do_debug_frames_interp)
+		{
+		  printf ("  DW_CFA_expression: r%ld (", reg);
+		  decode_location_expression (start, eh_addr_size, ul, 0);
+		  printf (")\n");
+		}
+	      fc->col_type[reg] = DW_CFA_expression;
+	      start += ul;
+	      break;
+
+	    case DW_CFA_offset_extended_sf:
+	      reg = LEB ();
+	      l = SLEB ();
+	      frame_need_space (fc, reg);
+	      if (! do_debug_frames_interp)
+		printf ("  DW_CFA_offset_extended_sf: r%ld at cfa%+ld\n",
+			reg, l * fc->data_factor);
+	      fc->col_type[reg] = DW_CFA_offset;
+	      fc->col_offset[reg] = l * fc->data_factor;
+	      break;
+
+	    case DW_CFA_def_cfa_sf:
+	      fc->cfa_reg = LEB ();
+	      fc->cfa_offset = SLEB ();
+	      fc->cfa_offset = fc->cfa_offset * fc->data_factor;
+	      fc->cfa_exp = 0;
+	      if (! do_debug_frames_interp)
+		printf ("  DW_CFA_def_cfa_sf: r%d ofs %d\n",
+			fc->cfa_reg, fc->cfa_offset);
+	      break;
+
+	    case DW_CFA_def_cfa_offset_sf:
+	      fc->cfa_offset = SLEB ();
+	      fc->cfa_offset = fc->cfa_offset * fc->data_factor;
+	      if (! do_debug_frames_interp)
+		printf ("  DW_CFA_def_cfa_offset_sf: %d\n", fc->cfa_offset);
+	      break;
+
+	    case DW_CFA_MIPS_advance_loc8:
+	      ofs = byte_get (start, 8); start += 8;
+	      if (do_debug_frames_interp)
+		frame_display_row (fc, &need_col_headers, &max_regs);
+	      else
+		printf ("  DW_CFA_MIPS_advance_loc8: %ld to %08lx\n",
+			ofs * fc->code_factor,
+			fc->pc_begin + ofs * fc->code_factor);
+	      fc->pc_begin += ofs * fc->code_factor;
+	      break;
+
+	    case DW_CFA_GNU_window_save:
+	      if (! do_debug_frames_interp)
+		printf ("  DW_CFA_GNU_window_save\n");
+	      break;
+
+	    case DW_CFA_GNU_args_size:
+	      ul = LEB ();
+	      if (! do_debug_frames_interp)
+		printf ("  DW_CFA_GNU_args_size: %ld\n", ul);
+	      break;
+
+	    case DW_CFA_GNU_negative_offset_extended:
+	      reg = LEB ();
+	      l = - LEB ();
+	      frame_need_space (fc, reg);
+	      if (! do_debug_frames_interp)
+		printf ("  DW_CFA_GNU_negative_offset_extended: r%ld at cfa%+ld\n",
+			reg, l * fc->data_factor);
+	      fc->col_type[reg] = DW_CFA_offset;
+	      fc->col_offset[reg] = l * fc->data_factor;
+	      break;
+
+	    default:
+	      warn (_("unsupported or unknown DW_CFA_%d\n"), op);
+	      start = block_end;
+	    }
+	}
+
+      if (do_debug_frames_interp)
+	frame_display_row (fc, &need_col_headers, &max_regs);
+
+      start = block_end;
+    }
+
+  printf ("\n");
+
+  return 1;
+}
+
+#undef GET
+#undef LEB
+#undef SLEB
+
+static int
+display_debug_not_supported (struct dwarf_section *section,
+			     void *file ATTRIBUTE_UNUSED)
+{
+  printf (_("Displaying the debug contents of section %s is not yet supported.\n"),
+	    section->name);
+
+  return 1;
+}
+
+void *
+cmalloc (size_t nmemb, size_t size)
+{
+  /* Check for overflow.  */
+  if (nmemb >= ~(size_t) 0 / size)
+    return NULL;
+  else
+    return malloc (nmemb * size);
+}
+
+void *
+xcmalloc (size_t nmemb, size_t size)
+{
+  /* Check for overflow.  */
+  if (nmemb >= ~(size_t) 0 / size)
+    return NULL;
+  else
+    return xmalloc (nmemb * size);
+}
+
+void *
+xcrealloc (void *ptr, size_t nmemb, size_t size)
+{
+  /* Check for overflow.  */
+  if (nmemb >= ~(size_t) 0 / size)
+    return NULL;
+  else
+    return xrealloc (ptr, nmemb * size);
+}
+
+void
+error (const char *message, ...)
+{
+  va_list args;
+
+  va_start (args, message);
+  fprintf (stderr, _("%s: Error: "), program_name);
+  vfprintf (stderr, message, args);
+  va_end (args);
+}
+
+void
+warn (const char *message, ...)
+{
+  va_list args;
+
+  va_start (args, message);
+  fprintf (stderr, _("%s: Warning: "), program_name);
+  vfprintf (stderr, message, args);
+  va_end (args);
+}
+
+void
+free_debug_memory (void)
+{
+  enum dwarf_section_display_enum i;
+
+  free_abbrevs ();
+
+  for (i = 0; i < max; i++)
+    free_debug_section (i);
+
+  if (debug_information)
+    {
+      for (i = 0; i < num_debug_info_entries; i++)
+	{
+	  if (!debug_information [i].max_loc_offsets)
+	    {
+	      free (debug_information [i].loc_offsets);
+	      free (debug_information [i].have_frame_base);
+	    }
+	  if (!debug_information [i].max_range_lists)
+	    free (debug_information [i].range_lists);
+	}
+      free (debug_information);
+      debug_information = NULL;
+      num_debug_info_entries = 0;
+    }
+
+}
+
+struct dwarf_section_display debug_displays[] =
+{
+  { { ".debug_abbrev",		NULL,	0,	0 },
+    display_debug_abbrev,		0,	0 },
+  { { ".debug_aranges",		NULL,	0,	0 },
+    display_debug_aranges,		0,	0 },
+  { { ".debug_frame",		NULL,	0,	0 },
+    display_debug_frames,		1,	0 },
+  { { ".debug_info",		NULL,	0,	0 },
+    display_debug_info,			1,	0 },
+  { { ".debug_line",		NULL,	0,	0 },
+    display_debug_lines,		0,	0 },
+  { { ".debug_pubnames",	NULL,	0,	0 },
+    display_debug_pubnames,		0,	0 },
+  { { ".eh_frame",		NULL,	0,	0 },
+    display_debug_frames,		1,	1 },
+  { { ".debug_macinfo",		NULL,	0,	0 },
+    display_debug_macinfo,		0,	0 },
+  { { ".debug_str",		NULL,	0,	0 },
+    display_debug_str,			0,	0 },
+  { { ".debug_loc",		NULL,	0,	0 },
+    display_debug_loc,			0,	0 },
+  { { ".debug_pubtypes",	NULL,	0,	0 },
+    display_debug_pubnames,		0,	0 },
+  { { ".debug_ranges",		NULL,	0,	0 },
+    display_debug_ranges,		0,	0 },
+  { { ".debug_static_func",	NULL,	0,	0 },
+    display_debug_not_supported,	0,	0 },
+  { { ".debug_static_vars",	NULL,	0,	0 },
+    display_debug_not_supported,	0,	0 },
+  { { ".debug_types",		NULL,	0,	0 },
+    display_debug_not_supported,	0,	0 },
+  { { ".debug_weaknames",	NULL,	0,	0 },
+    display_debug_not_supported,	0,	0 }
+};
--- binutils/dwarf.h.dwarf	2005-09-15 07:16:00.000000000 -0700
+++ binutils/dwarf.h	2005-09-15 07:21:18.000000000 -0700
@@ -0,0 +1,112 @@
+/* dwwrf.h - DWARF support header file
+   Copyright 2005
+   Free Software Foundation, Inc.
+
+This file is part of GNU Binutils.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#include "bfd.h"
+#include "elf/dwarf2.h"
+
+struct dwarf_section
+{
+  const char *name;
+  unsigned char *start;
+  bfd_vma address;
+  bfd_size_type size;
+};
+
+/* A structure containing the name of a debug section
+   and a pointer to a function that can decode it.  */
+struct dwarf_section_display
+{
+  struct dwarf_section section;
+  int (*display) (struct dwarf_section *, void *);
+  unsigned int relocate : 1;
+  unsigned int eh_frame : 1;
+};
+
+enum dwarf_section_display_enum {
+  abbrev = 0,
+  aranges,
+  frame,
+  info,
+  line,
+  pubnames,
+  eh_frame,
+  macinfo,
+  str,
+  loc,
+  pubtypes,
+  ranges,
+  static_func,
+  static_vars,
+  types,
+  weaknames,
+  max
+};
+
+extern struct dwarf_section_display debug_displays [];
+
+/* This structure records the information that
+   we extract from the.debug_info section.  */
+typedef struct
+{
+  unsigned int   pointer_size;
+  unsigned long  cu_offset;
+  unsigned long	 base_address;
+  /* This is an array of offsets to the location list table.  */
+  unsigned long *loc_offsets;
+  int		*have_frame_base;
+  unsigned int   num_loc_offsets;
+  unsigned int   max_loc_offsets;
+  unsigned long *range_lists;
+  unsigned int   num_range_lists;
+  unsigned int   max_range_lists;
+}
+debug_info;
+
+extern bfd_vma (*byte_get) (unsigned char *, int);
+extern bfd_vma byte_get_little_endian (unsigned char *, int);
+extern bfd_vma byte_get_big_endian (unsigned char *, int);
+
+extern bfd_vma eh_addr_size;
+extern int is_relocatable;
+
+extern int do_debug_info;
+extern int do_debug_abbrevs;
+extern int do_debug_lines;
+extern int do_debug_pubnames;
+extern int do_debug_aranges;
+extern int do_debug_ranges;
+extern int do_debug_frames;
+extern int do_debug_frames_interp;
+extern int do_debug_macinfo;
+extern int do_debug_str;
+extern int do_debug_loc;
+
+extern int load_debug_section (enum dwarf_section_display_enum,
+			       void *);
+extern void free_debug_section (enum dwarf_section_display_enum);
+
+extern void free_debug_memory (void);
+
+void *cmalloc (size_t, size_t);
+void *xcmalloc (size_t, size_t);
+void *xcrealloc (void *, size_t, size_t);
+
+void error (const char *, ...) ATTRIBUTE_PRINTF_1;
+void warn (const char *, ...) ATTRIBUTE_PRINTF_1;
--- binutils/readelf.c.dwarf	2005-09-15 07:16:00.000000000 -0700
+++ binutils/readelf.c	2005-09-15 07:21:25.000000000 -0700
@@ -55,12 +55,11 @@
 #define BFD64
 #endif
 
-#include "bfd.h"
+#include "dwarf.h"
 
 #include "elf/common.h"
 #include "elf/external.h"
 #include "elf/internal.h"
-#include "elf/dwarf2.h"
 
 /* The following headers use the elf/reloc-macros.h file to
    automatically generate relocation recognition functions
@@ -157,24 +156,9 @@ static int do_version;
 static int do_wide;
 static int do_histogram;
 static int do_debugging;
-static int do_debug_info;
-static int do_debug_abbrevs;
-static int do_debug_lines;
-static int do_debug_pubnames;
-static int do_debug_aranges;
-static int do_debug_ranges;
-static int do_debug_frames;
-static int do_debug_frames_interp;
-static int do_debug_macinfo;
-static int do_debug_str;
-static int do_debug_loc;
 static int do_arch;
 static int do_notes;
 static int is_32bit_elf;
-static int is_relocatable;
-static int have_frame_base;
-static int need_base_address;
-static bfd_vma eh_addr_size;
 
 struct group_list
 {
@@ -222,7 +206,6 @@ typedef enum print_mode
 }
 print_mode;
 
-static bfd_vma (*byte_get) (unsigned char *, int);
 static void (*byte_put) (unsigned char *, bfd_vma, int);
 
 #define UNKNOWN -1
@@ -266,58 +249,6 @@ static void (*byte_put) (unsigned char *
 #define streq(a,b)	(strcmp ((a), (b)) == 0)
 #define strneq(a,b,n)	(strncmp ((a), (b), (n)) == 0)
 
-static void ATTRIBUTE_PRINTF_1
-error (const char *message, ...)
-{
-  va_list args;
-
-  va_start (args, message);
-  fprintf (stderr, _("%s: Error: "), program_name);
-  vfprintf (stderr, message, args);
-  va_end (args);
-}
-
-static void ATTRIBUTE_PRINTF_1
-warn (const char *message, ...)
-{
-  va_list args;
-
-  va_start (args, message);
-  fprintf (stderr, _("%s: Warning: "), program_name);
-  vfprintf (stderr, message, args);
-  va_end (args);
-}
-
-static void *
-cmalloc (size_t nmemb, size_t size)
-{
-  /* Check for overflow.  */
-  if (nmemb >= ~(size_t) 0 / size)
-    return NULL;
-  else
-    return malloc (nmemb * size);
-}
-
-static void *
-xcmalloc (size_t nmemb, size_t size)
-{
-  /* Check for overflow.  */
-  if (nmemb >= ~(size_t) 0 / size)
-    return NULL;
-  else
-    return xmalloc (nmemb * size);
-}
-
-static void *
-xcrealloc (void *ptr, size_t nmemb, size_t size)
-{
-  /* Check for overflow.  */
-  if (nmemb >= ~(size_t) 0 / size)
-    return NULL;
-  else
-    return xrealloc (ptr, nmemb * size);
-}
-
 static void *
 get_data (void *var, FILE *file, long offset, size_t size, size_t nmemb,
 	  const char *reason)
@@ -7370,50 +7301,6 @@ dump_section (Elf_Internal_Shdr *section
   return 1;
 }
 
-
-struct dwarf_section
-{
-  const char *name;
-  unsigned char *start;
-  bfd_vma address;
-  bfd_size_type size;
-};
-
-static int process_debug_info (struct dwarf_section *, void *, int);
-
-static void
-load_debug_section (struct dwarf_section *section, void *file)
-{
-  Elf_Internal_Shdr *sec;
-  char buf [64];
-
-  /* If it is already loaded, do nothing.  */
-  if (section->start != NULL)
-    return;
-
-  /* Locate the debug section.  */
-  sec = find_section (section->name);
-  if (sec == NULL)
-    return;
-
-  snprintf (buf, sizeof (buf), _("%s section data"), section->name);
-  section->address = sec->sh_addr;
-  section->size = sec->sh_size;
-  section->start = get_data (NULL, file, sec->sh_offset, 1,
-			     sec->sh_size, buf);
-}
-
-static void
-free_debug_section (struct dwarf_section *section)
-{
-  if (section->start == NULL)
-    return;
-
-  free ((char *) section->start);
-  section->start = NULL;
-  section->size = 0;
-}
-
 /* Apply addends of RELA relocations.  */
 
 static int
@@ -7523,3786 +7410,157 @@ debug_apply_rela_addends (void *file,
   return 1;
 }
 
-static bfd_vma
-byte_get_little_endian (unsigned char *field, int size)
-{
-  switch (size)
-    {
-    case 1:
-      return *field;
-
-    case 2:
-      return  ((unsigned int) (field[0]))
-	|    (((unsigned int) (field[1])) << 8);
-
-#ifndef BFD64
-    case 8:
-      /* We want to extract data from an 8 byte wide field and
-	 place it into a 4 byte wide field.  Since this is a little
-	 endian source we can just use the 4 byte extraction code.  */
-      /* Fall through.  */
-#endif
-    case 4:
-      return  ((unsigned long) (field[0]))
-	|    (((unsigned long) (field[1])) << 8)
-	|    (((unsigned long) (field[2])) << 16)
-	|    (((unsigned long) (field[3])) << 24);
-
-#ifdef BFD64
-    case 8:
-      return  ((bfd_vma) (field[0]))
-	|    (((bfd_vma) (field[1])) << 8)
-	|    (((bfd_vma) (field[2])) << 16)
-	|    (((bfd_vma) (field[3])) << 24)
-	|    (((bfd_vma) (field[4])) << 32)
-	|    (((bfd_vma) (field[5])) << 40)
-	|    (((bfd_vma) (field[6])) << 48)
-	|    (((bfd_vma) (field[7])) << 56);
-#endif
-    default:
-      error (_("Unhandled data length: %d\n"), size);
-      abort ();
-    }
-}
-
-static bfd_vma
-byte_get_signed (unsigned char *field, int size)
-{
-  bfd_vma x = byte_get (field, size);
-
-  switch (size)
-    {
-    case 1:
-      return (x ^ 0x80) - 0x80;
-    case 2:
-      return (x ^ 0x8000) - 0x8000;
-    case 4:
-      return (x ^ 0x80000000) - 0x80000000;
-    case 8:
-      return x;
-    default:
-      abort ();
-    }
-}
-
-static bfd_vma
-byte_get_big_endian (unsigned char *field, int size)
-{
-  switch (size)
-    {
-    case 1:
-      return *field;
-
-    case 2:
-      return ((unsigned int) (field[1])) | (((int) (field[0])) << 8);
-
-#ifndef BFD64
-    case 8:
-      /* Although we are extracing data from an 8 byte wide field,
-	 we are returning only 4 bytes of data.  */
-      field += 4;
-      /* Fall thru */
-#endif
-    case 4:
-      return ((unsigned long) (field[3]))
-	|   (((unsigned long) (field[2])) << 8)
-	|   (((unsigned long) (field[1])) << 16)
-	|   (((unsigned long) (field[0])) << 24);
-
-#ifdef BFD64
-    case 8:
-      return ((bfd_vma) (field[7]))
-	|   (((bfd_vma) (field[6])) << 8)
-	|   (((bfd_vma) (field[5])) << 16)
-	|   (((bfd_vma) (field[4])) << 24)
-	|   (((bfd_vma) (field[3])) << 32)
-	|   (((bfd_vma) (field[2])) << 40)
-	|   (((bfd_vma) (field[1])) << 48)
-	|   (((bfd_vma) (field[0])) << 56);
-#endif
-
-    default:
-      error (_("Unhandled data length: %d\n"), size);
-      abort ();
-    }
-}
-
-static unsigned long int
-read_leb128 (unsigned char *data, unsigned int *length_return, int sign)
+int
+load_debug_section (enum dwarf_section_display_enum debug, void *file)
 {
-  unsigned long int result = 0;
-  unsigned int num_read = 0;
-  unsigned int shift = 0;
-  unsigned char byte;
-
-  do
-    {
-      byte = *data++;
-      num_read++;
-
-      result |= ((unsigned long int) (byte & 0x7f)) << shift;
+  struct dwarf_section *section = &debug_displays [debug].section;
+  Elf_Internal_Shdr *sec;
+  char buf [64];
 
-      shift += 7;
+  /* If it is already loaded, do nothing.  */
+  if (section->start != NULL)
+    return 1;
 
-    }
-  while (byte & 0x80);
+  /* Locate the debug section.  */
+  sec = find_section (section->name);
+  if (sec == NULL)
+    return 0;
 
-  if (length_return != NULL)
-    *length_return = num_read;
+  snprintf (buf, sizeof (buf), _("%s section data"), section->name);
+  section->address = sec->sh_addr;
+  section->size = sec->sh_size;
+  section->start = get_data (NULL, file, sec->sh_offset, 1,
+			     sec->sh_size, buf);
 
-  if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40))
-    result |= -1L << shift;
+  if (debug_displays [debug].relocate)
+    debug_apply_rela_addends (file, sec, section->start);
 
-  return result;
+  return section->start != NULL;
 }
 
-typedef struct State_Machine_Registers
+void
+free_debug_section (enum dwarf_section_display_enum debug)
 {
-  unsigned long address;
-  unsigned int file;
-  unsigned int line;
-  unsigned int column;
-  int is_stmt;
-  int basic_block;
-  int end_sequence;
-/* This variable hold the number of the last entry seen
-   in the File Table.  */
-  unsigned int last_file_entry;
-} SMR;
+  struct dwarf_section *section = &debug_displays [debug].section;
 
-static SMR state_machine_regs;
+  if (section->start == NULL)
+    return;
 
-static void
-reset_state_machine (int is_stmt)
-{
-  state_machine_regs.address = 0;
-  state_machine_regs.file = 1;
-  state_machine_regs.line = 1;
-  state_machine_regs.column = 0;
-  state_machine_regs.is_stmt = is_stmt;
-  state_machine_regs.basic_block = 0;
-  state_machine_regs.end_sequence = 0;
-  state_machine_regs.last_file_entry = 0;
+  free ((char *) section->start);
+  section->start = NULL;
+  section->size = 0;
 }
 
-/* Handled an extend line op.
-   Returns the number of bytes read.  */
-
 static int
-process_extended_line_op (unsigned char *data, int is_stmt, int pointer_size)
+display_debug_section (Elf_Internal_Shdr *section, FILE *file)
 {
-  unsigned char op_code;
-  unsigned int bytes_read;
-  unsigned int len;
-  unsigned char *name;
-  unsigned long adr;
-
-  len = read_leb128 (data, & bytes_read, 0);
-  data += bytes_read;
+  char *name = SECTION_NAME (section);
+  bfd_size_type length;
+  int result = 1;
+  enum dwarf_section_display_enum i;
 
-  if (len == 0)
+  length = section->sh_size;
+  if (length == 0)
     {
-      warn (_("badly formed extended line op encountered!\n"));
-      return bytes_read;
+      printf (_("\nSection '%s' has no debugging data.\n"), name);
+      return 0;
     }
 
-  len += bytes_read;
-  op_code = *data++;
-
-  printf (_("  Extended opcode %d: "), op_code);
-
-  switch (op_code)
-    {
-    case DW_LNE_end_sequence:
-      printf (_("End of Sequence\n\n"));
-      reset_state_machine (is_stmt);
-      break;
-
-    case DW_LNE_set_address:
-      adr = byte_get (data, pointer_size);
-      printf (_("set Address to 0x%lx\n"), adr);
-      state_machine_regs.address = adr;
-      break;
-
-    case DW_LNE_define_file:
-      printf (_("  define new File Table entry\n"));
-      printf (_("  Entry\tDir\tTime\tSize\tName\n"));
-
-      printf (_("   %d\t"), ++state_machine_regs.last_file_entry);
-      name = data;
-      data += strlen ((char *) data) + 1;
-      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));
-      printf (_("%s\n\n"), name);
-      break;
+  if (strneq (name, ".gnu.linkonce.wi.", 17))
+    name = ".debug_info";
 
-    default:
-      printf (_("UNKNOWN: length %d\n"), len - bytes_read);
-      break;
-    }
+  /* See if we know how to display the contents of this section.  */
+  for (i = 0; i < max; i++)
+    if (streq (debug_displays[i].section.name, name))
+      {
+	struct dwarf_section *sec = &debug_displays [i].section;
 
-  return len;
-}
+	if (load_debug_section (i, file))
+	  {
+	    result &= debug_displays[i].display (sec, file);
 
-static struct dwarf_section debug_str_section = {
-  ".debug_str",
-  NULL,
-  0,
-  0
-};
+	    if (i != info && i != abbrev)
+	      free_debug_section (i);
+	  }
 
-static const char *
-fetch_indirect_string (unsigned long offset)
-{
-  if (debug_str_section.start == NULL)
-    return _("<no .debug_str section>");
+	break;
+      }
 
-  if (offset > debug_str_section.size)
+  if (i == max)
     {
-      warn (_("DW_FORM_strp offset too big: %lx\n"), offset);
-      return _("<offset is too big>");
+      printf (_("Unrecognized debug section: %s\n"), name);
+      result = 0;
     }
 
-  return debug_str_section.start + offset;
-}
-
-static struct dwarf_section debug_abbrev_section = {
-  ".debug_abbrev",
-  NULL,
-  0,
-  0
-};
-
-/* 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;
-
-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;
+  return result;
 }
-abbrev_entry;
-
-static abbrev_entry *first_abbrev = NULL;
-static abbrev_entry *last_abbrev = NULL;
 
 static void
-free_abbrevs (void)
+process_section_contents (FILE *file)
 {
-  abbrev_entry *abbrev;
-
-  for (abbrev = first_abbrev; abbrev;)
-    {
-      abbrev_entry *next = abbrev->next;
-      abbrev_attr *attr;
+  Elf_Internal_Shdr *section;
+  unsigned int i;
 
-      for (attr = abbrev->first_attr; attr;)
-	{
-	  abbrev_attr *next = attr->next;
+  if (! do_dump)
+    return;
 
-	  free (attr);
-	  attr = next;
-	}
+  for (i = 0, section = section_headers;
+       i < elf_header.e_shnum && i < num_dump_sects;
+       i++, section++)
+    {
+#ifdef SUPPORT_DISASSEMBLY
+      if (dump_sects[i] & DISASS_DUMP)
+	disassemble_section (section, file);
+#endif
+      if (dump_sects[i] & HEX_DUMP)
+	dump_section (section, file);
 
-      free (abbrev);
-      abbrev = next;
+      if (dump_sects[i] & DEBUG_DUMP)
+	display_debug_section (section, file);
     }
 
-  last_abbrev = first_abbrev = NULL;
+  /* Check to see if the user requested a
+     dump of a section that does not exist.  */
+  while (i++ < num_dump_sects)
+    if (dump_sects[i])
+      warn (_("Section %d was not dumped because it does not exist!\n"), i);
 }
 
 static void
-add_abbrev (unsigned long number, unsigned long tag, int children)
+process_mips_fpe_exception (int mask)
 {
-  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;
-
-  if (first_abbrev == NULL)
-    first_abbrev = entry;
+  if (mask)
+    {
+      int first = 1;
+      if (mask & OEX_FPU_INEX)
+	fputs ("INEX", stdout), first = 0;
+      if (mask & OEX_FPU_UFLO)
+	printf ("%sUFLO", first ? "" : "|"), first = 0;
+      if (mask & OEX_FPU_OFLO)
+	printf ("%sOFLO", first ? "" : "|"), first = 0;
+      if (mask & OEX_FPU_DIV0)
+	printf ("%sDIV0", first ? "" : "|"), first = 0;
+      if (mask & OEX_FPU_INVAL)
+	printf ("%sINVAL", first ? "" : "|");
+    }
   else
-    last_abbrev->next = entry;
-
-  last_abbrev = entry;
+    fputs ("0", stdout);
 }
 
-static void
-add_abbrev_attr (unsigned long attribute, unsigned long form)
+static int
+process_mips_specific (FILE *file)
 {
-  abbrev_attr *attr;
-
-  attr = malloc (sizeof (*attr));
-
-  if (attr == NULL)
-    /* ugg */
-    return;
-
-  attr->attribute = attribute;
-  attr->form      = form;
-  attr->next      = NULL;
+  Elf_Internal_Dyn *entry;
+  size_t liblist_offset = 0;
+  size_t liblistno = 0;
+  size_t conflictsno = 0;
+  size_t options_offset = 0;
+  size_t conflicts_offset = 0;
 
-  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)
-    {
-      unsigned 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 char *
-get_TAG_name (unsigned long tag)
-{
-  switch (tag)
-    {
-    case DW_TAG_padding:		return "DW_TAG_padding";
-    case DW_TAG_array_type:		return "DW_TAG_array_type";
-    case DW_TAG_class_type:		return "DW_TAG_class_type";
-    case DW_TAG_entry_point:		return "DW_TAG_entry_point";
-    case DW_TAG_enumeration_type:	return "DW_TAG_enumeration_type";
-    case DW_TAG_formal_parameter:	return "DW_TAG_formal_parameter";
-    case DW_TAG_imported_declaration:	return "DW_TAG_imported_declaration";
-    case DW_TAG_label:			return "DW_TAG_label";
-    case DW_TAG_lexical_block:		return "DW_TAG_lexical_block";
-    case DW_TAG_member:			return "DW_TAG_member";
-    case DW_TAG_pointer_type:		return "DW_TAG_pointer_type";
-    case DW_TAG_reference_type:		return "DW_TAG_reference_type";
-    case DW_TAG_compile_unit:		return "DW_TAG_compile_unit";
-    case DW_TAG_string_type:		return "DW_TAG_string_type";
-    case DW_TAG_structure_type:		return "DW_TAG_structure_type";
-    case DW_TAG_subroutine_type:	return "DW_TAG_subroutine_type";
-    case DW_TAG_typedef:		return "DW_TAG_typedef";
-    case DW_TAG_union_type:		return "DW_TAG_union_type";
-    case DW_TAG_unspecified_parameters: return "DW_TAG_unspecified_parameters";
-    case DW_TAG_variant:		return "DW_TAG_variant";
-    case DW_TAG_common_block:		return "DW_TAG_common_block";
-    case DW_TAG_common_inclusion:	return "DW_TAG_common_inclusion";
-    case DW_TAG_inheritance:		return "DW_TAG_inheritance";
-    case DW_TAG_inlined_subroutine:	return "DW_TAG_inlined_subroutine";
-    case DW_TAG_module:			return "DW_TAG_module";
-    case DW_TAG_ptr_to_member_type:	return "DW_TAG_ptr_to_member_type";
-    case DW_TAG_set_type:		return "DW_TAG_set_type";
-    case DW_TAG_subrange_type:		return "DW_TAG_subrange_type";
-    case DW_TAG_with_stmt:		return "DW_TAG_with_stmt";
-    case DW_TAG_access_declaration:	return "DW_TAG_access_declaration";
-    case DW_TAG_base_type:		return "DW_TAG_base_type";
-    case DW_TAG_catch_block:		return "DW_TAG_catch_block";
-    case DW_TAG_const_type:		return "DW_TAG_const_type";
-    case DW_TAG_constant:		return "DW_TAG_constant";
-    case DW_TAG_enumerator:		return "DW_TAG_enumerator";
-    case DW_TAG_file_type:		return "DW_TAG_file_type";
-    case DW_TAG_friend:			return "DW_TAG_friend";
-    case DW_TAG_namelist:		return "DW_TAG_namelist";
-    case DW_TAG_namelist_item:		return "DW_TAG_namelist_item";
-    case DW_TAG_packed_type:		return "DW_TAG_packed_type";
-    case DW_TAG_subprogram:		return "DW_TAG_subprogram";
-    case DW_TAG_template_type_param:	return "DW_TAG_template_type_param";
-    case DW_TAG_template_value_param:	return "DW_TAG_template_value_param";
-    case DW_TAG_thrown_type:		return "DW_TAG_thrown_type";
-    case DW_TAG_try_block:		return "DW_TAG_try_block";
-    case DW_TAG_variant_part:		return "DW_TAG_variant_part";
-    case DW_TAG_variable:		return "DW_TAG_variable";
-    case DW_TAG_volatile_type:		return "DW_TAG_volatile_type";
-    case DW_TAG_MIPS_loop:		return "DW_TAG_MIPS_loop";
-    case DW_TAG_format_label:		return "DW_TAG_format_label";
-    case DW_TAG_function_template:	return "DW_TAG_function_template";
-    case DW_TAG_class_template:		return "DW_TAG_class_template";
-      /* DWARF 2.1 values.  */
-    case DW_TAG_dwarf_procedure:	return "DW_TAG_dwarf_procedure";
-    case DW_TAG_restrict_type:		return "DW_TAG_restrict_type";
-    case DW_TAG_interface_type:		return "DW_TAG_interface_type";
-    case DW_TAG_namespace:		return "DW_TAG_namespace";
-    case DW_TAG_imported_module:	return "DW_TAG_imported_module";
-    case DW_TAG_unspecified_type:	return "DW_TAG_unspecified_type";
-    case DW_TAG_partial_unit:		return "DW_TAG_partial_unit";
-    case DW_TAG_imported_unit:		return "DW_TAG_imported_unit";
-      /* UPC values.  */
-    case DW_TAG_upc_shared_type:	return "DW_TAG_upc_shared_type";
-    case DW_TAG_upc_strict_type:	return "DW_TAG_upc_strict_type";
-    case DW_TAG_upc_relaxed_type:	return "DW_TAG_upc_relaxed_type";
-    default:
-      {
-	static char buffer[100];
-
-	snprintf (buffer, sizeof (buffer), _("Unknown TAG value: %lx"), tag);
-	return buffer;
-      }
-    }
-}
-
-static char *
-get_FORM_name (unsigned long form)
-{
-  switch (form)
-    {
-    case DW_FORM_addr:		return "DW_FORM_addr";
-    case DW_FORM_block2:	return "DW_FORM_block2";
-    case DW_FORM_block4:	return "DW_FORM_block4";
-    case DW_FORM_data2:		return "DW_FORM_data2";
-    case DW_FORM_data4:		return "DW_FORM_data4";
-    case DW_FORM_data8:		return "DW_FORM_data8";
-    case DW_FORM_string:	return "DW_FORM_string";
-    case DW_FORM_block:		return "DW_FORM_block";
-    case DW_FORM_block1:	return "DW_FORM_block1";
-    case DW_FORM_data1:		return "DW_FORM_data1";
-    case DW_FORM_flag:		return "DW_FORM_flag";
-    case DW_FORM_sdata:		return "DW_FORM_sdata";
-    case DW_FORM_strp:		return "DW_FORM_strp";
-    case DW_FORM_udata:		return "DW_FORM_udata";
-    case DW_FORM_ref_addr:	return "DW_FORM_ref_addr";
-    case DW_FORM_ref1:		return "DW_FORM_ref1";
-    case DW_FORM_ref2:		return "DW_FORM_ref2";
-    case DW_FORM_ref4:		return "DW_FORM_ref4";
-    case DW_FORM_ref8:		return "DW_FORM_ref8";
-    case DW_FORM_ref_udata:	return "DW_FORM_ref_udata";
-    case DW_FORM_indirect:	return "DW_FORM_indirect";
-    default:
-      {
-	static char buffer[100];
-
-	snprintf (buffer, sizeof (buffer), _("Unknown FORM value: %lx"), form);
-	return buffer;
-      }
-    }
-}
-
-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 int
-decode_location_expression (unsigned char * data,
-			    unsigned int pointer_size,
-			    unsigned long length,
-			    unsigned long cu_offset)
-{
-  unsigned op;
-  unsigned int bytes_read;
-  unsigned long uvalue;
-  unsigned char *end = data + length;
-  int need_frame_base = 0;
-
-  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;
-	  break;
-	case DW_OP_const2s:
-	  printf ("DW_OP_const2s: %ld", (long) byte_get_signed (data, 2));
-	  data += 2;
-	  break;
-	case DW_OP_const4u:
-	  printf ("DW_OP_const4u: %lu", (unsigned long) byte_get (data, 4));
-	  data += 4;
-	  break;
-	case DW_OP_const4s:
-	  printf ("DW_OP_const4s: %ld", (long) byte_get_signed (data, 4));
-	  data += 4;
-	  break;
-	case DW_OP_const8u:
-	  printf ("DW_OP_const8u: %lu %lu", (unsigned long) byte_get (data, 4),
-		  (unsigned long) byte_get (data + 4, 4));
-	  data += 8;
-	  break;
-	case DW_OP_const8s:
-	  printf ("DW_OP_const8s: %ld %ld", (long) byte_get (data, 4),
-		  (long) byte_get (data + 4, 4));
-	  data += 8;
-	  break;
-	case DW_OP_constu:
-	  printf ("DW_OP_constu: %lu", read_leb128 (data, &bytes_read, 0));
-	  data += bytes_read;
-	  break;
-	case DW_OP_consts:
-	  printf ("DW_OP_consts: %ld", read_leb128 (data, &bytes_read, 1));
-	  data += bytes_read;
-	  break;
-	case DW_OP_dup:
-	  printf ("DW_OP_dup");
-	  break;
-	case DW_OP_drop:
-	  printf ("DW_OP_drop");
-	  break;
-	case DW_OP_over:
-	  printf ("DW_OP_over");
-	  break;
-	case DW_OP_pick:
-	  printf ("DW_OP_pick: %ld", (unsigned long) byte_get (data++, 1));
-	  break;
-	case DW_OP_swap:
-	  printf ("DW_OP_swap");
-	  break;
-	case DW_OP_rot:
-	  printf ("DW_OP_rot");
-	  break;
-	case DW_OP_xderef:
-	  printf ("DW_OP_xderef");
-	  break;
-	case DW_OP_abs:
-	  printf ("DW_OP_abs");
-	  break;
-	case DW_OP_and:
-	  printf ("DW_OP_and");
-	  break;
-	case DW_OP_div:
-	  printf ("DW_OP_div");
-	  break;
-	case DW_OP_minus:
-	  printf ("DW_OP_minus");
-	  break;
-	case DW_OP_mod:
-	  printf ("DW_OP_mod");
-	  break;
-	case DW_OP_mul:
-	  printf ("DW_OP_mul");
-	  break;
-	case DW_OP_neg:
-	  printf ("DW_OP_neg");
-	  break;
-	case DW_OP_not:
-	  printf ("DW_OP_not");
-	  break;
-	case DW_OP_or:
-	  printf ("DW_OP_or");
-	  break;
-	case DW_OP_plus:
-	  printf ("DW_OP_plus");
-	  break;
-	case DW_OP_plus_uconst:
-	  printf ("DW_OP_plus_uconst: %lu",
-		  read_leb128 (data, &bytes_read, 0));
-	  data += bytes_read;
-	  break;
-	case DW_OP_shl:
-	  printf ("DW_OP_shl");
-	  break;
-	case DW_OP_shr:
-	  printf ("DW_OP_shr");
-	  break;
-	case DW_OP_shra:
-	  printf ("DW_OP_shra");
-	  break;
-	case DW_OP_xor:
-	  printf ("DW_OP_xor");
-	  break;
-	case DW_OP_bra:
-	  printf ("DW_OP_bra: %ld", (long) byte_get_signed (data, 2));
-	  data += 2;
-	  break;
-	case DW_OP_eq:
-	  printf ("DW_OP_eq");
-	  break;
-	case DW_OP_ge:
-	  printf ("DW_OP_ge");
-	  break;
-	case DW_OP_gt:
-	  printf ("DW_OP_gt");
-	  break;
-	case DW_OP_le:
-	  printf ("DW_OP_le");
-	  break;
-	case DW_OP_lt:
-	  printf ("DW_OP_lt");
-	  break;
-	case DW_OP_ne:
-	  printf ("DW_OP_ne");
-	  break;
-	case DW_OP_skip:
-	  printf ("DW_OP_skip: %ld", (long) byte_get_signed (data, 2));
-	  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_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:
-	  need_frame_base = 1;
-	  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 need_frame_base;
-	}
-
-      /* Separate the ops.  */
-      if (data < end)
-	printf ("; ");
-    }
-
-  return need_frame_base;
-}
-
-/* This structure records the information that
-   we extract from the.debug_info section.  */
-typedef struct
-{
-  unsigned int   pointer_size;
-  unsigned long  cu_offset;
-  unsigned long	 base_address;
-  /* This is an array of offsets to the location list table.  */
-  unsigned long *loc_offsets;
-  int		*have_frame_base;
-  unsigned int   num_loc_offsets;
-  unsigned int   max_loc_offsets;
-  unsigned long *range_lists;
-  unsigned int   num_range_lists;
-  unsigned int   max_range_lists;
-}
-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)
-{
-  unsigned long uvalue = 0;
-  unsigned char *block_start = NULL;
-  unsigned 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 || do_debug_ranges)
-	  && 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: %lu\n"), form);
-      break;
-    }
-
-  /* For some attributes we can display further information.  */
-  if ((do_loc || do_debug_loc || do_debug_ranges)
-      && num_debug_info_entries == 0)
-    {
-      switch (attribute)
-	{
-	case DW_AT_frame_base:
-	  have_frame_base = 1;
-	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
-		    = xcrealloc (debug_info_p->loc_offsets,
-				 max, sizeof (*debug_info_p->loc_offsets));
-		  debug_info_p->have_frame_base
-		    = xcrealloc (debug_info_p->have_frame_base,
-				 max, sizeof (*debug_info_p->have_frame_base));
-		  debug_info_p->max_loc_offsets = max;
-		}
-	      debug_info_p->loc_offsets [num] = uvalue;
-	      debug_info_p->have_frame_base [num] = have_frame_base;
-	      debug_info_p->num_loc_offsets++;
-	    }
-	  break;
-	
-	case DW_AT_low_pc:
-	  if (need_base_address)
-	    debug_info_p->base_address = uvalue;
-	  break;
-
-	case DW_AT_ranges:
-	  if (form == DW_FORM_data4 || form == DW_FORM_data8)
-	    {
-	      /* Process range list.  */
-	      unsigned int max = debug_info_p->max_range_lists;
-	      unsigned int num = debug_info_p->num_range_lists;
-
-	      if (max == 0 || num >= max)
-		{
-		  max += 1024;
-		  debug_info_p->range_lists
-		    = xcrealloc (debug_info_p->range_lists,
-				 max, sizeof (*debug_info_p->range_lists));
-		  debug_info_p->max_range_lists = max;
-		}
-	      debug_info_p->range_lists [num] = uvalue;
-	      debug_info_p->num_range_lists++;
-	    }
-	  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;
-	case DW_ATE_decimal_float:	printf ("(decimal 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:
-      have_frame_base = 1;
-    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)
-	{
-	  int need_frame_base;
-
-	  printf ("(");
-	  need_frame_base = decode_location_expression (block_start,
-							pointer_size,
-							uvalue,
-							cu_offset);
-	  printf (")");
-	  if (need_frame_base && !have_frame_base)
-	    printf (_(" [without DW_AT_frame_base]"));
-	}
-      else if (form == DW_FORM_data4 || form == DW_FORM_data8)
-	printf (_("(location list)"));
-
-      break;
-
-    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];
-
-	snprintf (buffer, sizeof (buffer), _("Unknown AT value: %lx"),
-		  attribute);
-	return buffer;
-      }
-    }
-}
-
-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;
-}
-
-
-/* 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.  */
-
-static int
-process_debug_info (struct dwarf_section *section, void *file,
-		    int do_loc)
-{
-  unsigned char *start = section->start;
-  unsigned char *end = start + section->size;
-  unsigned char *section_begin;
-  unsigned int unit;
-  unsigned int num_units = 0;
-
-  if ((do_loc || do_debug_loc || do_debug_ranges)
-      && num_debug_info_entries == 0)
-    {
-      unsigned long length;
-
-      /* 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
-	    section_begin += length + 4;
-	}
-
-      if (num_units == 0)
-	{
-	  error (_("No comp units in %s section ?"), section->name);
-	  return 0;
-	}
-
-      /* Then allocate an array to hold the information.  */
-      debug_information = cmalloc (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;
-	}
-    }
-
-  if (!do_loc)
-    {
-      printf (_("The section %s contains:\n\n"), section->name);
-
-      load_debug_section (&debug_str_section, file);
-    }
-
-  load_debug_section (&debug_abbrev_section, file);
-  if (debug_abbrev_section.start == NULL)
-    {
-      warn (_("Unable to locate %s section!\n"),
-	    debug_abbrev_section.name);
-      return 0;
-    }
-
-  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;
-
-      hdrptr = start;
-
-      compunit.cu_length = byte_get (hdrptr, 4);
-      hdrptr += 4;
-
-      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;
-	}
-
-      compunit.cu_version = byte_get (hdrptr, 2);
-      hdrptr += 2;
-
-      cu_offset = start - section_begin;
-      start += compunit.cu_length + initial_length_size;
-
-      cu_abbrev_offset_ptr = hdrptr;
-      compunit.cu_abbrev_offset = byte_get (hdrptr, offset_size);
-      hdrptr += offset_size;
-
-      compunit.cu_pointer_size = byte_get (hdrptr, 1);
-      hdrptr += 1;
-      if ((do_loc || do_debug_loc || do_debug_ranges)
-	  && num_debug_info_entries == 0)
-	{
-	  debug_information [unit].cu_offset = cu_offset;
-	  debug_information [unit].pointer_size
-	    = compunit.cu_pointer_size;
-	  debug_information [unit].base_address = 0;
-	  debug_information [unit].loc_offsets = NULL;
-	  debug_information [unit].have_frame_base = NULL;
-	  debug_information [unit].max_loc_offsets = 0;
-	  debug_information [unit].num_loc_offsets = 0;
-	  debug_information [unit].range_lists = NULL;
-	  debug_information [unit].max_range_lists= 0;
-	  debug_information [unit].num_range_lists = 0;
-	}
-
-      tags = hdrptr;
-
-      if (!do_loc)
-	{
-	  printf (_("  Compilation Unit @ offset 0x%lx:\n"), cu_offset);
-	  printf (_("   Length:        %ld\n"), compunit.cu_length);
-	  printf (_("   Version:       %d\n"), compunit.cu_version);
-	  printf (_("   Abbrev Offset: %ld\n"), compunit.cu_abbrev_offset);
-	  printf (_("   Pointer Size:  %d\n"), compunit.cu_pointer_size);
-	}
-
-      if (compunit.cu_version != 2 && compunit.cu_version != 3)
-	{
-	  warn (_("Only version 2 and 3 DWARF debug information is currently supported.\n"));
-	  continue;
-	}
-
-      free_abbrevs ();
-
-      /* Process the abbrevs used by this compilation unit.  */
-      process_abbrev_section
-	((unsigned char *) debug_abbrev_section.start
-	 + compunit.cu_abbrev_offset,
-	 (unsigned char *) debug_abbrev_section.start
-	 + debug_abbrev_section.size);
-
-      level = 0;
-      while (tags < start)
-	{
-	  unsigned int bytes_read;
-	  unsigned long abbrev_number;
-	  abbrev_entry *entry;
-	  abbrev_attr *attr;
-
-	  abbrev_number = read_leb128 (tags, & bytes_read, 0);
-	  tags += bytes_read;
-
-	  /* A null DIE marks the end of a list of children.  */
-	  if (abbrev_number == 0)
-	    {
-	      --level;
-	      continue;
-	    }
-
-	  /* Scan through the abbreviation list until we reach the
-	     correct entry.  */
-	  for (entry = first_abbrev;
-	       entry && entry->entry != abbrev_number;
-	       entry = entry->next)
-	    continue;
-
-	  if (entry == NULL)
-	    {
-	      warn (_("Unable to locate entry %lu in the abbreviation table\n"),
-		    abbrev_number);
-	      return 0;
-	    }
-
-	  if (!do_loc)
-	    printf (_(" <%d><%lx>: Abbrev Number: %lu (%s)\n"),
-		    level,
-		    (unsigned long) (tags - section_begin
-				     - bytes_read),
-		    abbrev_number,
-		    get_TAG_name (entry->tag));
- 
-	  switch (entry->tag)
-	    {
-	    default:
-	      need_base_address = 0;
-	      break;
-	    case DW_TAG_compile_unit:
-	      need_base_address = 1;
-	      break;
-	    case DW_TAG_entry_point:
-	    case DW_TAG_inlined_subroutine:
-	    case DW_TAG_subprogram:
-	      need_base_address = 0;
-	      /* Assuming that there is no DW_AT_frame_base.  */
-	      have_frame_base = 0;
-	      break;
-	    }
-
-	  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;
- 	}
-    }
- 
-  free_debug_section (&debug_abbrev_section);
-
-  /* Set num_debug_info_entries here so that it can be used to check if
-     we need to process .debug_loc and .debug_ranges sections.  */
-  if ((do_loc || do_debug_loc || do_debug_ranges)
-      && num_debug_info_entries == 0)
-    num_debug_info_entries = num_units;
-      
-  if (!do_loc)
-    {
-      free_debug_section (&debug_str_section);
-
-      printf ("\n");
-    }
- 
-  return 1;
-}
-
-/* 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 unsigned int
-get_pointer_size_and_offset_of_comp_unit (unsigned int comp_unit,
-					  const char * section_name,
-					  unsigned long * offset_return)
-{
-  unsigned long offset = 0;
-
-  if (num_debug_info_entries == 0)
-    error (_("%s section needs a populated .debug_info section\n"),
-	   section_name);
-
-  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;
-    }
-
-  if (offset_return != NULL)
-    * offset_return = offset;
-
-  return last_pointer_size;
-}
-
-/* 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 (void * file)
-{
-  Elf_Internal_Shdr * section;
-  struct dwarf_section sec;
-  int ret;
-
-  /* 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;
-
-  /* If we already have the information there is nothing else to do.  */
-  if (num_debug_info_entries > 0)
-    return num_debug_info_entries;
-
-  sec.name = ".debug_info";
-  section = find_section (sec.name);
-  if (section == NULL)
-    return 0;
-
-  sec.start = get_data (NULL, file, section->sh_offset, 1,
-			section->sh_size,
-			_("extracting information from .debug_info section"));
-  if (sec.start == NULL)
-    return 0;
-
-  sec.address = section->sh_addr;
-  sec.size = section->sh_size;
-  ret = (debug_apply_rela_addends (file, section, sec.start)
-	 && process_debug_info (&sec, file, 1));
-
-  free (sec.start);
-
-  return ret ? num_debug_info_entries : 0;
-}
-
-static int
-display_debug_lines (struct dwarf_section *section, void *file)
-{
-  unsigned char *start = section->start;
-  unsigned char *data = start;
-  unsigned char *end = start + section->size;
-  unsigned int comp_unit = 0;
-
-  printf (_("\nDump of debug contents of section %s:\n\n"),
-	  section->name);
-
-  get_debug_info (file);
-
-  while (data < end)
-    {
-      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->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++;
-
-      /* Sign extend the line base field.  */
-      info.li_line_base <<= 24;
-      info.li_line_base >>= 24;
-
-      /* 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_line", NULL);
-      comp_unit ++;
-
-      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)%s\n"),
-	      pointer_size,
-	      warned_about_missing_comp_units ? " [assumed]" : "" );
-
-      end_of_sequence = data + info.li_length + initial_length_size;
-
-      reset_state_machine (info.li_default_is_stmt);
-
-      /* Display the contents of the Opcodes table.  */
-      standard_opcodes = hdrptr;
-
-      printf (_("\n Opcodes:\n"));
-
-      for (i = 1; i < info.li_opcode_base; i++)
-	printf (_("  Opcode %d has %d args\n"), i, standard_opcodes[i - 1]);
-
-      /* Display the contents of the Directory table.  */
-      data = standard_opcodes + info.li_opcode_base - 1;
-
-      if (*data == 0)
-	printf (_("\n The Directory Table is empty.\n"));
-      else
-	{
-	  printf (_("\n The Directory Table:\n"));
-
-	  while (*data != 0)
-	    {
-	      printf (_("  %s\n"), data);
-
-	      data += strlen ((char *) data) + 1;
-	    }
-	}
-
-      /* Skip the NUL at the end of the table.  */
-      data++;
-
-      /* 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"));
-
-	  while (*data != 0)
-	    {
-	      unsigned char *name;
-	      unsigned int bytes_read;
-
-	      printf (_("  %d\t"), ++state_machine_regs.last_file_entry);
-	      name = data;
-
-	      data += strlen ((char *) data) + 1;
-
-	      printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0));
-	      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++;
-
-      /* Now display the statements.  */
-      printf (_("\n Line Number Statements:\n"));
-
-      while (data < end_of_sequence)
-	{
-	  unsigned char op_code;
-	  int adv;
-	  unsigned int bytes_read;
-
-	  op_code = *data++;
-
-	  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:
-	      if (pointer_size == 0)
-		{
-		  warn (_("Extend line ops need a valid pointer size, guessing at 4\n"));
-		  pointer_size = 4;
-		}
-
-	      data += process_extended_line_op (data, info.li_default_is_stmt,
-						pointer_size);
-	      break;
-
-	    case DW_LNS_copy:
-	      printf (_("  Copy\n"));
-	      break;
-
-	    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;
-
-	    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;
-
-	    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;
-
-	    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;
-
-	    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;
-
-	    case DW_LNS_set_basic_block:
-	      printf (_("  Set basic block\n"));
-	      state_machine_regs.basic_block = 1;
-	      break;
-
-	    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 (struct dwarf_section *section,
-			void *file ATTRIBUTE_UNUSED)
-{
-  DWARF2_Internal_PubNames pubnames;
-  unsigned char *start = section->start;
-  unsigned char *end = start + section->size;
-
-  printf (_("Contents of the %s section:\n\n"), section->name);
-
-  while (start < end)
-    {
-      unsigned char *data;
-      unsigned long offset;
-      int offset_size, initial_length_size;
-
-      data = start;
-
-      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;
-	}
-
-      pubnames.pn_version = byte_get (data, 2);
-      data += 2;
-      pubnames.pn_offset = byte_get (data, offset_size);
-      data += offset_size;
-      pubnames.pn_size = byte_get (data, offset_size);
-      data += offset_size;
-
-      start += pubnames.pn_length + initial_length_size;
-
-      if (pubnames.pn_version != 2 && pubnames.pn_version != 3)
-	{
-	  static int warned = 0;
-
-	  if (! warned)
-	    {
-	      warn (_("Only DWARF 2 and 3 pubnames are currently supported\n"));
-	      warned = 1;
-	    }
-
-	  continue;
-	}
-
-      printf (_("  Length:                              %ld\n"),
-	      pubnames.pn_length);
-      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);
-
-      printf (_("\n    Offset\tName\n"));
-
-      do
-	{
-	  offset = byte_get (data, offset_size);
-
-	  if (offset != 0)
-	    {
-	      data += offset_size;
-	      printf ("    %-6ld\t\t%s\n", offset, data);
-	      data += strlen ((char *) data) + 1;
-	    }
-	}
-      while (offset != 0);
-    }
-
-  printf ("\n");
-  return 1;
-}
-
-static int
-display_debug_macinfo (struct dwarf_section *section,
-		       void *file ATTRIBUTE_UNUSED)
-{
-  unsigned char *start = section->start;
-  unsigned char *end = start + section->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);
-
-  while (curr < end)
-    {
-      unsigned int lineno;
-      const char *string;
-
-      op = *curr;
-      curr++;
-
-      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);
-	  }
-	  break;
-
-	case DW_MACINFO_end_file:
-	  printf (_(" DW_MACINFO_end_file\n"));
-	  break;
-
-	case DW_MACINFO_define:
-	  lineno = read_leb128 (curr, & bytes_read, 0);
-	  curr += bytes_read;
-	  string = (char *) curr;
-	  curr += strlen (string) + 1;
-	  printf (_(" DW_MACINFO_define - lineno : %d macro : %s\n"),
-		  lineno, string);
-	  break;
-
-	case DW_MACINFO_undef:
-	  lineno = read_leb128 (curr, & bytes_read, 0);
-	  curr += bytes_read;
-	  string = (char *) curr;
-	  curr += strlen (string) + 1;
-	  printf (_(" DW_MACINFO_undef - lineno : %d macro : %s\n"),
-		  lineno, string);
-	  break;
-
-	case DW_MACINFO_vendor_ext:
-	  {
-	    unsigned int constant;
-
-	    constant = read_leb128 (curr, & bytes_read, 0);
-	    curr += bytes_read;
-	    string = (char *) 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 (struct dwarf_section *section,
-		      void *file ATTRIBUTE_UNUSED)
-{
-  abbrev_entry *entry;
-  unsigned char *start = section->start;
-  unsigned char *end = start + section->size;
-
-  printf (_("Contents of the %s section:\n\n"), section->name);
-
-  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 int
-display_debug_loc (struct dwarf_section *section, void *file)
-{
-  unsigned char *start = section->start;
-  unsigned char *section_end;
-  unsigned long bytes;
-  unsigned char *section_begin = start;
-  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;
-
-  bytes = section->size;
-  section_end = start + bytes;
-
-  if (bytes == 0)
-    {
-      printf (_("\nThe %s section is empty.\n"), section->name);
-      return 0;
-    }
-
-  get_debug_info (file);
-
-  /* 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;
-
-      num = debug_information [i].num_loc_offsets;
-      num_loc_list += num;
-
-      /* Check if we can use `debug_information' directly.  */
-      if (use_debug_info && num != 0)
-	{
-	  if (!seen_first_offset)
-	    {
-	      /* This is the first location list.  */
-	      last_offset = debug_information [i].loc_offsets [0];
-	      first = i;
-	      seen_first_offset = 1;
-	      j = 1;
-	    }
-	  else
-	    j = 0;
-
-	  for (; j < num; j++)
-	    {
-	      if (last_offset >
-		  debug_information [i].loc_offsets [j])
-		{
-		  use_debug_info = 0;
-		  break;
-		}
-	      last_offset = debug_information [i].loc_offsets [j];
-	    }
-	}
-    }
-
-  if (!use_debug_info)
-    /* FIXME: Should we handle this case?  */
-    error (_("Location lists in .debug_info section aren't in ascending order!\n"));
-
-  if (!seen_first_offset)
-    error (_("No location lists in .debug_info section!\n"));
-
-  if (debug_information [first].loc_offsets [0] != 0)
-    warn (_("Location lists in %s section start at 0x%lx\n"),
-	  section->name, debug_information [first].loc_offsets [0]);
-
-  printf (_("Contents of the %s section:\n\n"), section->name);
-  printf (_("    Offset   Begin    End      Expression\n"));
-
-  seen_first_offset = 0;
-  for (i = first; i < num_debug_info_entries; i++)
-    {
-      unsigned long begin;
-      unsigned long end;
-      unsigned short length;
-      unsigned long offset;
-      unsigned int pointer_size;
-      unsigned long cu_offset;
-      unsigned long base_address;
-      int need_frame_base;
-      int has_frame_base;
-
-      pointer_size = debug_information [i].pointer_size;
-      cu_offset = debug_information [i].cu_offset;
-
-      for (j = 0; j < debug_information [i].num_loc_offsets; j++)
-	{
-	  has_frame_base = debug_information [i].have_frame_base [j];
-	  offset = debug_information [i].loc_offsets [j];
-	  next = section_begin + offset;
-	  base_address = debug_information [i].base_address;
-
-	  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"),
-		      (long)(start - section_begin), (long)(next - section_begin));
-	      else if (start > next)
-		warn (_("There is an overlap [0x%lx - 0x%lx] in .debug_loc section.\n"),
-		      (long)(start - section_begin), (long)(next - section_begin));
-	    }
-	  start = next;
-
-	  if (offset >= bytes)
-	    {
-	      warn (_("Offset 0x%lx is bigger than .debug_loc section size.\n"),
-		    offset);
-	      continue;
-	    }
-
-	  while (1)
-	    {
-	      if (start + 2 * pointer_size > section_end)
-		{
-		  warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
-			offset);
-		  break;
-		}
-
-	      begin = byte_get (start, pointer_size);
-	      start += pointer_size;
-	      end = byte_get (start, pointer_size);
-	      start += pointer_size;
-
-	      if (begin == 0 && end == 0)
-		{
-		  printf (_("    %8.8lx <End of list>\n"), offset);
-		  break;
-		}
-
-	      /* Check base address specifiers.  */
-	      if (begin == -1UL && end != -1UL)
-		{
-		  base_address = end;
-		  printf (_("    %8.8lx %8.8lx %8.8lx (base address)\n"),
-			  offset, begin, end);
-		  continue;
-		}
-
-	      if (start + 2 > section_end)
-		{
-		  warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
-			offset);
-		  break;
-		}
-
-	      length = byte_get (start, 2);
-	      start += 2;
-
-	      if (start + length > section_end)
-		{
-		  warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
-			offset);
-		  break;
-		}
-
-	      printf ("    %8.8lx %8.8lx %8.8lx (",
-		      offset, begin + base_address, end + base_address);
-	      need_frame_base = decode_location_expression (start,
-							    pointer_size,
-							    length,
-							    cu_offset);
-	      putchar (')');
-
-	      if (need_frame_base && !has_frame_base)
-		printf (_(" [without DW_AT_frame_base]"));
-
-	      if (begin == end)
-		fputs (_(" (start == end)"), stdout);
-	      else if (begin > end)
-		fputs (_(" (start > end)"), stdout);
-
-	      putchar ('\n');
-
-	      start += length;
-	    }
-	}
-    }
-  return 1;
-}
-
-static int
-display_debug_str (struct dwarf_section *section,
-		   void *file ATTRIBUTE_UNUSED)
-{
-  unsigned char *start = section->start;
-  unsigned long bytes = section->size;
-  bfd_vma addr = section->address;
-
-  if (bytes == 0)
-    {
-      printf (_("\nThe %s section is empty.\n"), section->name);
-      return 0;
-    }
-
-  printf (_("Contents of the %s section:\n\n"), section->name);
-
-  while (bytes)
-    {
-      int j;
-      int k;
-      int lbytes;
-
-      lbytes = (bytes > 16 ? 16 : bytes);
-
-      printf ("  0x%8.8lx ", (unsigned long) addr);
-
-      for (j = 0; j < 16; j++)
-	{
-	  if (j < lbytes)
-	    printf ("%2.2x", start[j]);
-	  else
-	    printf ("  ");
-
-	  if ((j & 3) == 3)
-	    printf (" ");
-	}
-
-      for (j = 0; j < lbytes; j++)
-	{
-	  k = start[j];
-	  if (k >= ' ' && k < 0x80)
-	    printf ("%c", k);
-	  else
-	    printf (".");
-	}
-
-      putchar ('\n');
-
-      start += lbytes;
-      addr  += lbytes;
-      bytes -= lbytes;
-    }
-
-  putchar ('\n');
-
-  return 1;
-}
-
-
-static int
-display_debug_info (struct dwarf_section *section, void *file)
-{
-  return process_debug_info (section, file, 0);
-}
-
-
-static int
-display_debug_aranges (struct dwarf_section *section,
-		       void *file ATTRIBUTE_UNUSED)
-{
-  unsigned char *start = section->start;
-  unsigned char *end = start + section->size;
-
-  printf (_("The section %s contains:\n\n"), section->name);
-
-  while (start < end)
-    {
-      unsigned char *hdrptr;
-      DWARF2_Internal_ARange arange;
-      unsigned char *ranges;
-      unsigned long length;
-      unsigned long address;
-      int excess;
-      int offset_size;
-      int initial_length_size;
-
-      hdrptr = start;
-
-      arange.ar_length = byte_get (hdrptr, 4);
-      hdrptr += 4;
-
-      if (arange.ar_length == 0xffffffff)
-	{
-	  arange.ar_length = byte_get (hdrptr, 8);
-	  hdrptr += 8;
-	  offset_size = 8;
-	  initial_length_size = 12;
-	}
-      else
-	{
-	  offset_size = 4;
-	  initial_length_size = 4;
-	}
-
-      arange.ar_version = byte_get (hdrptr, 2);
-      hdrptr += 2;
-
-      arange.ar_info_offset = byte_get (hdrptr, offset_size);
-      hdrptr += offset_size;
-
-      arange.ar_pointer_size = byte_get (hdrptr, 1);
-      hdrptr += 1;
-
-      arange.ar_segment_size = byte_get (hdrptr, 1);
-      hdrptr += 1;
-
-      if (arange.ar_version != 2 && arange.ar_version != 3)
-	{
-	  warn (_("Only DWARF 2 and 3 aranges are currently supported.\n"));
-	  break;
-	}
-
-      printf (_("  Length:                   %ld\n"), arange.ar_length);
-      printf (_("  Version:                  %d\n"), arange.ar_version);
-      printf (_("  Offset into .debug_info:  %lx\n"), arange.ar_info_offset);
-      printf (_("  Pointer Size:             %d\n"), arange.ar_pointer_size);
-      printf (_("  Segment Size:             %d\n"), arange.ar_segment_size);
-
-      printf (_("\n    Address  Length\n"));
-
-      ranges = hdrptr;
-
-      /* Must pad to an alignment boundary that is twice the pointer size.  */
-      excess = (hdrptr - start) % (2 * arange.ar_pointer_size);
-      if (excess)
-	ranges += (2 * arange.ar_pointer_size) - excess;
-
-      for (;;)
-	{
-	  address = byte_get (ranges, arange.ar_pointer_size);
-
-	  ranges += arange.ar_pointer_size;
-
-	  length  = byte_get (ranges, arange.ar_pointer_size);
-
-	  ranges += arange.ar_pointer_size;
-
-	  /* A pair of zeros marks the end of the list.  */
-	  if (address == 0 && length == 0)
-	    break;
-
-	  printf ("    %8.8lx %lu\n", address, length);
-	}
-
-      start += arange.ar_length + initial_length_size;
-    }
-
-  printf ("\n");
-
-  return 1;
-}
-
-static int
-display_debug_ranges (struct dwarf_section *section,
-		      void *file ATTRIBUTE_UNUSED)
-{
-  unsigned char *start = section->start;
-  unsigned char *section_end;
-  unsigned long bytes;
-  unsigned char *section_begin = start;
-  unsigned int num_range_list = 0;
-  unsigned long last_offset = 0;
-  unsigned int first = 0;
-  unsigned int i;
-  unsigned int j;
-  int seen_first_offset = 0;
-  int use_debug_info = 1;
-  unsigned char *next;
-
-  bytes = section->size;
-  section_end = start + bytes;
-
-  if (bytes == 0)
-    {
-      printf (_("\nThe %s section is empty.\n"), section->name);
-      return 0;
-    }
-
-  get_debug_info (file);
-
-  /* Check the order of range list in .debug_info section. If
-     offsets of range lists are in the ascending order, we can
-     use `debug_information' directly.  */
-  for (i = 0; i < num_debug_info_entries; i++)
-    {
-      unsigned int num;
-
-      num = debug_information [i].num_range_lists;
-      num_range_list += num;
-
-      /* Check if we can use `debug_information' directly.  */
-      if (use_debug_info && num != 0)
-	{
-	  if (!seen_first_offset)
-	    {
-	      /* This is the first range list.  */
-	      last_offset = debug_information [i].range_lists [0];
-	      first = i;
-	      seen_first_offset = 1;
-	      j = 1;
-	    }
-	  else
-	    j = 0;
-
-	  for (; j < num; j++)
-	    {
-	      if (last_offset >
-		  debug_information [i].range_lists [j])
-		{
-		  use_debug_info = 0;
-		  break;
-		}
-	      last_offset = debug_information [i].range_lists [j];
-	    }
-	}
-    }
-
-  if (!use_debug_info)
-    /* FIXME: Should we handle this case?  */
-    error (_("Range lists in .debug_info section aren't in ascending order!\n"));
-
-  if (!seen_first_offset)
-    error (_("No range lists in .debug_info section!\n"));
-
-  if (debug_information [first].range_lists [0] != 0)
-    warn (_("Range lists in %s section start at 0x%lx\n"),
-	  section->name, debug_information [first].range_lists [0]);
-
-  printf (_("Contents of the %s section:\n\n"), section->name);
-  printf (_("    Offset   Begin    End\n"));
-
-  seen_first_offset = 0;
-  for (i = first; i < num_debug_info_entries; i++)
-    {
-      unsigned long begin;
-      unsigned long end;
-      unsigned long offset;
-      unsigned int pointer_size;
-      unsigned long base_address;
-
-      pointer_size = debug_information [i].pointer_size;
-
-      for (j = 0; j < debug_information [i].num_range_lists; j++)
-	{
-	  offset = debug_information [i].range_lists [j];
-	  next = section_begin + offset;
-	  base_address = debug_information [i].base_address;
-
-	  if (!seen_first_offset)
-	    seen_first_offset = 1;
-	  else
-	    {
-	      if (start < next)
-		warn (_("There is a hole [0x%lx - 0x%lx] in %s section.\n"),
-		      (long)(start - section_begin),
-		      (long)(next - section_begin), section->name);
-	      else if (start > next)
-		warn (_("There is an overlap [0x%lx - 0x%lx] in %s section.\n"),
-		      (long)(start - section_begin),
-		      (long)(next - section_begin), section->name);
-	    }
-	  start = next;
-
-	  while (1)
-	    {
-	      begin = byte_get (start, pointer_size);
-	      start += pointer_size;
-	      end = byte_get (start, pointer_size);
-	      start += pointer_size;
-
-	      if (begin == 0 && end == 0)
-		{
-		  printf (_("    %8.8lx <End of list>\n"), offset);
-		  break;
-		}
-
-	      /* Check base address specifiers.  */
-	      if (begin == -1UL && end != -1UL)
-		{
-		  base_address = end;
-		  printf ("    %8.8lx %8.8lx %8.8lx (base address)\n",
-			  offset, begin, end);
-		  continue;
-		}
-
-	      printf ("    %8.8lx %8.8lx %8.8lx",
-		      offset, begin + base_address, end + base_address);
-
-	      if (begin == end)
-		fputs (_(" (start == end)"), stdout);
-	      else if (begin > end)
-		fputs (_(" (start > end)"), stdout);
-
-	      putchar ('\n');
-	    }
-	}
-    }
-  putchar ('\n');
-  return 1;
-}
-
-typedef struct Frame_Chunk
-{
-  struct Frame_Chunk *next;
-  unsigned char *chunk_start;
-  int ncols;
-  /* DW_CFA_{undefined,same_value,offset,register,unreferenced}  */
-  short int *col_type;
-  int *col_offset;
-  char *augmentation;
-  unsigned int code_factor;
-  int data_factor;
-  unsigned long pc_begin;
-  unsigned long pc_range;
-  int cfa_reg;
-  int cfa_offset;
-  int ra;
-  unsigned char fde_encoding;
-  unsigned char cfa_exp;
-}
-Frame_Chunk;
-
-/* A marker for a col_type that means this column was never referenced
-   in the frame info.  */
-#define DW_CFA_unreferenced (-1)
-
-static void
-frame_need_space (Frame_Chunk *fc, int reg)
-{
-  int prev = fc->ncols;
-
-  if (reg < fc->ncols)
-    return;
-
-  fc->ncols = reg + 1;
-  fc->col_type = xcrealloc (fc->col_type, fc->ncols, sizeof (short int));
-  fc->col_offset = xcrealloc (fc->col_offset, fc->ncols, sizeof (int));
-
-  while (prev < fc->ncols)
-    {
-      fc->col_type[prev] = DW_CFA_unreferenced;
-      fc->col_offset[prev] = 0;
-      prev++;
-    }
-}
-
-static void
-frame_display_row (Frame_Chunk *fc, int *need_col_headers, int *max_regs)
-{
-  int r;
-  char tmp[100];
-
-  if (*max_regs < fc->ncols)
-    *max_regs = fc->ncols;
-
-  if (*need_col_headers)
-    {
-      *need_col_headers = 0;
-
-      printf ("   LOC   CFA      ");
-
-      for (r = 0; r < *max_regs; r++)
-	if (fc->col_type[r] != DW_CFA_unreferenced)
-	  {
-	    if (r == fc->ra)
-	      printf ("ra   ");
-	    else
-	      printf ("r%-4d", r);
-	  }
-
-      printf ("\n");
-    }
-
-  printf ("%08lx ", fc->pc_begin);
-  if (fc->cfa_exp)
-    strcpy (tmp, "exp");
-  else
-    sprintf (tmp, "r%d%+d", fc->cfa_reg, fc->cfa_offset);
-  printf ("%-8s ", tmp);
-
-  for (r = 0; r < fc->ncols; r++)
-    {
-      if (fc->col_type[r] != DW_CFA_unreferenced)
-	{
-	  switch (fc->col_type[r])
-	    {
-	    case DW_CFA_undefined:
-	      strcpy (tmp, "u");
-	      break;
-	    case DW_CFA_same_value:
-	      strcpy (tmp, "s");
-	      break;
-	    case DW_CFA_offset:
-	      sprintf (tmp, "c%+d", fc->col_offset[r]);
-	      break;
-	    case DW_CFA_register:
-	      sprintf (tmp, "r%d", fc->col_offset[r]);
-	      break;
-	    case DW_CFA_expression:
-	      strcpy (tmp, "exp");
-	      break;
-	    default:
-	      strcpy (tmp, "n/a");
-	      break;
-	    }
-	  printf ("%-5s", tmp);
-	}
-    }
-  printf ("\n");
-}
-
-static int
-size_of_encoded_value (int encoding)
-{
-  switch (encoding & 0x7)
-    {
-    default:	/* ??? */
-    case 0:	return eh_addr_size;
-    case 2:	return 2;
-    case 3:	return 4;
-    case 4:	return 8;
-    }
-}
-
-static bfd_vma
-get_encoded_value (unsigned char *data, int encoding)
-{
-  int size = size_of_encoded_value (encoding);
-  if (encoding & DW_EH_PE_signed)
-    return byte_get_signed (data, size);
-  else
-    return byte_get (data, size);
-}
-
-#define GET(N)	byte_get (start, N); start += N
-#define LEB()	read_leb128 (start, & length_return, 0); start += length_return
-#define SLEB()	read_leb128 (start, & length_return, 1); start += length_return
-
-static int
-display_debug_frames (struct dwarf_section *section,
-		      void *file ATTRIBUTE_UNUSED)
-{
-  unsigned char *start = section->start;
-  unsigned char *end = start + section->size;
-  unsigned char *section_start = start;
-  Frame_Chunk *chunks = 0;
-  Frame_Chunk *remembered_state = 0;
-  Frame_Chunk *rs;
-  int is_eh = streq (section->name, ".eh_frame");
-  unsigned int length_return;
-  int max_regs = 0;
-
-  printf (_("The section %s contains:\n"), section->name);
-
-  while (start < end)
-    {
-      unsigned char *saved_start;
-      unsigned char *block_end;
-      unsigned long length;
-      unsigned long cie_id;
-      Frame_Chunk *fc;
-      Frame_Chunk *cie;
-      int need_col_headers = 1;
-      unsigned char *augmentation_data = NULL;
-      unsigned long augmentation_data_len = 0;
-      int encoded_ptr_size = eh_addr_size;
-      int offset_size;
-      int initial_length_size;
-
-      saved_start = start;
-      length = byte_get (start, 4); start += 4;
-
-      if (length == 0)
-	{
-	  printf ("\n%08lx ZERO terminator\n\n",
-		    (unsigned long)(saved_start - section_start));
-	  return 1;
-	}
-
-      if (length == 0xffffffff)
-	{
-	  length = byte_get (start, 8);
-	  start += 8;
-	  offset_size = 8;
-	  initial_length_size = 12;
-	}
-      else
-	{
-	  offset_size = 4;
-	  initial_length_size = 4;
-	}
-
-      block_end = saved_start + length + initial_length_size;
-      cie_id = byte_get (start, offset_size); start += offset_size;
-
-      if (is_eh ? (cie_id == 0) : (cie_id == DW_CIE_ID))
-	{
-	  int version;
-
-	  fc = xmalloc (sizeof (Frame_Chunk));
-	  memset (fc, 0, sizeof (Frame_Chunk));
-
-	  fc->next = chunks;
-	  chunks = fc;
-	  fc->chunk_start = saved_start;
-	  fc->ncols = 0;
-	  fc->col_type = xmalloc (sizeof (short int));
-	  fc->col_offset = xmalloc (sizeof (int));
-	  frame_need_space (fc, max_regs-1);
-
-	  version = *start++;
-
-	  fc->augmentation = (char *) start;
-	  start = (unsigned char *) strchr ((char *) start, '\0') + 1;
-
-	  if (fc->augmentation[0] == 'z')
-	    {
-	      fc->code_factor = LEB ();
-	      fc->data_factor = SLEB ();
-	      if (version == 1)
-		{
-		  fc->ra = GET (1);
-		}
-	      else
-		{
-		  fc->ra = LEB ();
-		}
-	      augmentation_data_len = LEB ();
-	      augmentation_data = start;
-	      start += augmentation_data_len;
-	    }
-	  else if (streq (fc->augmentation, "eh"))
-	    {
-	      start += eh_addr_size;
-	      fc->code_factor = LEB ();
-	      fc->data_factor = SLEB ();
-	      if (version == 1)
-		{
-		  fc->ra = GET (1);
-		}
-	      else
-		{
-		  fc->ra = LEB ();
-		}
-	    }
-	  else
-	    {
-	      fc->code_factor = LEB ();
-	      fc->data_factor = SLEB ();
-	      if (version == 1)
-		{
-		  fc->ra = GET (1);
-		}
-	      else
-		{
-		  fc->ra = LEB ();
-		}
-	    }
-	  cie = fc;
-
-	  if (do_debug_frames_interp)
-	    printf ("\n%08lx %08lx %08lx CIE \"%s\" cf=%d df=%d ra=%d\n",
-		    (unsigned long)(saved_start - section_start), length, cie_id,
-		    fc->augmentation, fc->code_factor, fc->data_factor,
-		    fc->ra);
-	  else
-	    {
-	      printf ("\n%08lx %08lx %08lx CIE\n",
-		      (unsigned long)(saved_start - section_start), length, cie_id);
-	      printf ("  Version:               %d\n", version);
-	      printf ("  Augmentation:          \"%s\"\n", fc->augmentation);
-	      printf ("  Code alignment factor: %u\n", fc->code_factor);
-	      printf ("  Data alignment factor: %d\n", fc->data_factor);
-	      printf ("  Return address column: %d\n", fc->ra);
-
-	      if (augmentation_data_len)
-		{
-		  unsigned long i;
-		  printf ("  Augmentation data:    ");
-		  for (i = 0; i < augmentation_data_len; ++i)
-		    printf (" %02x", augmentation_data[i]);
-		  putchar ('\n');
-		}
-	      putchar ('\n');
-	    }
-
-	  if (augmentation_data_len)
-	    {
-	      unsigned char *p, *q;
-	      p = (unsigned char *) fc->augmentation + 1;
-	      q = augmentation_data;
-
-	      while (1)
-		{
-		  if (*p == 'L')
-		    q++;
-		  else if (*p == 'P')
-		    q += 1 + size_of_encoded_value (*q);
-		  else if (*p == 'R')
-		    fc->fde_encoding = *q++;
-		  else
-		    break;
-		  p++;
-		}
-
-	      if (fc->fde_encoding)
-		encoded_ptr_size = size_of_encoded_value (fc->fde_encoding);
-	    }
-
-	  frame_need_space (fc, fc->ra);
-	}
-      else
-	{
-	  unsigned char *look_for;
-	  static Frame_Chunk fde_fc;
-
-	  fc = & fde_fc;
-	  memset (fc, 0, sizeof (Frame_Chunk));
-
-	  look_for = is_eh ? start - 4 - cie_id : section_start + cie_id;
-
-	  for (cie = chunks; cie ; cie = cie->next)
-	    if (cie->chunk_start == look_for)
-	      break;
-
-	  if (!cie)
-	    {
-	      warn ("Invalid CIE pointer %08lx in FDE at %p\n",
-		    cie_id, saved_start);
-	      start = block_end;
-	      fc->ncols = 0;
-	      fc->col_type = xmalloc (sizeof (short int));
-	      fc->col_offset = xmalloc (sizeof (int));
-	      frame_need_space (fc, max_regs - 1);
-	      cie = fc;
-	      fc->augmentation = "";
-	      fc->fde_encoding = 0;
-	    }
-	  else
-	    {
-	      fc->ncols = cie->ncols;
-	      fc->col_type = xcmalloc (fc->ncols, sizeof (short int));
-	      fc->col_offset = xcmalloc (fc->ncols, sizeof (int));
-	      memcpy (fc->col_type, cie->col_type, fc->ncols * sizeof (short int));
-	      memcpy (fc->col_offset, cie->col_offset, fc->ncols * sizeof (int));
-	      fc->augmentation = cie->augmentation;
-	      fc->code_factor = cie->code_factor;
-	      fc->data_factor = cie->data_factor;
-	      fc->cfa_reg = cie->cfa_reg;
-	      fc->cfa_offset = cie->cfa_offset;
-	      fc->ra = cie->ra;
-	      frame_need_space (fc, max_regs-1);
-	      fc->fde_encoding = cie->fde_encoding;
-	    }
-
-	  if (fc->fde_encoding)
-	    encoded_ptr_size = size_of_encoded_value (fc->fde_encoding);
-
-	  fc->pc_begin = get_encoded_value (start, fc->fde_encoding);
-	  if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel
-	      /* Don't adjust for relocatable file since there's
-		 invariably a pcrel reloc here, which we haven't
-		 applied.  */
-	      && !is_relocatable)
-	    fc->pc_begin += section->address + (start - section_start);
-	  start += encoded_ptr_size;
-	  fc->pc_range = byte_get (start, encoded_ptr_size);
-	  start += encoded_ptr_size;
-
-	  if (cie->augmentation[0] == 'z')
-	    {
-	      augmentation_data_len = LEB ();
-	      augmentation_data = start;
-	      start += augmentation_data_len;
-	    }
-
-	  printf ("\n%08lx %08lx %08lx FDE cie=%08lx pc=%08lx..%08lx\n",
-		  (unsigned long)(saved_start - section_start), length, cie_id,
-		  (unsigned long)(cie->chunk_start - section_start),
-		  fc->pc_begin, fc->pc_begin + fc->pc_range);
-	  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]);
-	      putchar ('\n');
-	      putchar ('\n');
-	    }
-	}
-
-      /* At this point, fc is the current chunk, cie (if any) is set, and
-	 we're about to interpret instructions for the chunk.  */
-      /* ??? At present we need to do this always, since this sizes the
-	 fc->col_type and fc->col_offset arrays, which we write into always.
-	 We should probably split the interpreted and non-interpreted bits
-	 into two different routines, since there's so much that doesn't
-	 really overlap between them.  */
-      if (1 || do_debug_frames_interp)
-	{
-	  /* Start by making a pass over the chunk, allocating storage
-	     and taking note of what registers are used.  */
-	  unsigned char *tmp = start;
-
-	  while (start < block_end)
-	    {
-	      unsigned op, opa;
-	      unsigned long reg, tmp;
-
-	      op = *start++;
-	      opa = op & 0x3f;
-	      if (op & 0xc0)
-		op &= 0xc0;
-
-	      /* Warning: if you add any more cases to this switch, be
-		 sure to add them to the corresponding switch below.  */
-	      switch (op)
-		{
-		case DW_CFA_advance_loc:
-		  break;
-		case DW_CFA_offset:
-		  LEB ();
-		  frame_need_space (fc, opa);
-		  fc->col_type[opa] = DW_CFA_undefined;
-		  break;
-		case DW_CFA_restore:
-		  frame_need_space (fc, opa);
-		  fc->col_type[opa] = DW_CFA_undefined;
-		  break;
-		case DW_CFA_set_loc:
-		  start += encoded_ptr_size;
-		  break;
-		case DW_CFA_advance_loc1:
-		  start += 1;
-		  break;
-		case DW_CFA_advance_loc2:
-		  start += 2;
-		  break;
-		case DW_CFA_advance_loc4:
-		  start += 4;
-		  break;
-		case DW_CFA_offset_extended:
-		  reg = LEB (); LEB ();
-		  frame_need_space (fc, reg);
-		  fc->col_type[reg] = DW_CFA_undefined;
-		  break;
-		case DW_CFA_restore_extended:
-		  reg = LEB ();
-		  frame_need_space (fc, reg);
-		  fc->col_type[reg] = DW_CFA_undefined;
-		  break;
-		case DW_CFA_undefined:
-		  reg = LEB ();
-		  frame_need_space (fc, reg);
-		  fc->col_type[reg] = DW_CFA_undefined;
-		  break;
-		case DW_CFA_same_value:
-		  reg = LEB ();
-		  frame_need_space (fc, reg);
-		  fc->col_type[reg] = DW_CFA_undefined;
-		  break;
-		case DW_CFA_register:
-		  reg = LEB (); LEB ();
-		  frame_need_space (fc, reg);
-		  fc->col_type[reg] = DW_CFA_undefined;
-		  break;
-		case DW_CFA_def_cfa:
-		  LEB (); LEB ();
-		  break;
-		case DW_CFA_def_cfa_register:
-		  LEB ();
-		  break;
-		case DW_CFA_def_cfa_offset:
-		  LEB ();
-		  break;
-		case DW_CFA_def_cfa_expression:
-		  tmp = LEB ();
-		  start += tmp;
-		  break;
-		case DW_CFA_expression:
-		  reg = LEB ();
-		  tmp = LEB ();
-		  start += tmp;
-		  frame_need_space (fc, reg);
-		  fc->col_type[reg] = DW_CFA_undefined;
-		  break;
-		case DW_CFA_offset_extended_sf:
-		  reg = LEB (); SLEB ();
-		  frame_need_space (fc, reg);
-		  fc->col_type[reg] = DW_CFA_undefined;
-		  break;
-		case DW_CFA_def_cfa_sf:
-		  LEB (); SLEB ();
-		  break;
-		case DW_CFA_def_cfa_offset_sf:
-		  SLEB ();
-		  break;
-		case DW_CFA_MIPS_advance_loc8:
-		  start += 8;
-		  break;
-		case DW_CFA_GNU_args_size:
-		  LEB ();
-		  break;
-		case DW_CFA_GNU_negative_offset_extended:
-		  reg = LEB (); LEB ();
-		  frame_need_space (fc, reg);
-		  fc->col_type[reg] = DW_CFA_undefined;
-
-		default:
-		  break;
-		}
-	    }
-	  start = tmp;
-	}
-
-      /* Now we know what registers are used, make a second pass over
-	 the chunk, this time actually printing out the info.  */
-
-      while (start < block_end)
-	{
-	  unsigned op, opa;
-	  unsigned long ul, reg, roffs;
-	  long l, ofs;
-	  bfd_vma vma;
-
-	  op = *start++;
-	  opa = op & 0x3f;
-	  if (op & 0xc0)
-	    op &= 0xc0;
-
-	  /* Warning: if you add any more cases to this switch, be
-	     sure to add them to the corresponding switch above.  */
-	  switch (op)
-	    {
-	    case DW_CFA_advance_loc:
-	      if (do_debug_frames_interp)
-		frame_display_row (fc, &need_col_headers, &max_regs);
-	      else
-		printf ("  DW_CFA_advance_loc: %d to %08lx\n",
-			opa * fc->code_factor,
-			fc->pc_begin + opa * fc->code_factor);
-	      fc->pc_begin += opa * fc->code_factor;
-	      break;
-
-	    case DW_CFA_offset:
-	      roffs = LEB ();
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_offset: r%d at cfa%+ld\n",
-			opa, roffs * fc->data_factor);
-	      fc->col_type[opa] = DW_CFA_offset;
-	      fc->col_offset[opa] = roffs * fc->data_factor;
-	      break;
-
-	    case DW_CFA_restore:
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_restore: r%d\n", opa);
-	      fc->col_type[opa] = cie->col_type[opa];
-	      fc->col_offset[opa] = cie->col_offset[opa];
-	      break;
-
-	    case DW_CFA_set_loc:
-	      vma = get_encoded_value (start, fc->fde_encoding);
-	      if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel
-		  && !is_relocatable)
-		vma += section->address + (start - section_start);
-	      start += encoded_ptr_size;
-	      if (do_debug_frames_interp)
-		frame_display_row (fc, &need_col_headers, &max_regs);
-	      else
-		printf ("  DW_CFA_set_loc: %08lx\n", (unsigned long)vma);
-	      fc->pc_begin = vma;
-	      break;
-
-	    case DW_CFA_advance_loc1:
-	      ofs = byte_get (start, 1); start += 1;
-	      if (do_debug_frames_interp)
-		frame_display_row (fc, &need_col_headers, &max_regs);
-	      else
-		printf ("  DW_CFA_advance_loc1: %ld to %08lx\n",
-			ofs * fc->code_factor,
-			fc->pc_begin + ofs * fc->code_factor);
-	      fc->pc_begin += ofs * fc->code_factor;
-	      break;
-
-	    case DW_CFA_advance_loc2:
-	      ofs = byte_get (start, 2); start += 2;
-	      if (do_debug_frames_interp)
-		frame_display_row (fc, &need_col_headers, &max_regs);
-	      else
-		printf ("  DW_CFA_advance_loc2: %ld to %08lx\n",
-			ofs * fc->code_factor,
-			fc->pc_begin + ofs * fc->code_factor);
-	      fc->pc_begin += ofs * fc->code_factor;
-	      break;
-
-	    case DW_CFA_advance_loc4:
-	      ofs = byte_get (start, 4); start += 4;
-	      if (do_debug_frames_interp)
-		frame_display_row (fc, &need_col_headers, &max_regs);
-	      else
-		printf ("  DW_CFA_advance_loc4: %ld to %08lx\n",
-			ofs * fc->code_factor,
-			fc->pc_begin + ofs * fc->code_factor);
-	      fc->pc_begin += ofs * fc->code_factor;
-	      break;
-
-	    case DW_CFA_offset_extended:
-	      reg = LEB ();
-	      roffs = LEB ();
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_offset_extended: r%ld at cfa%+ld\n",
-			reg, roffs * fc->data_factor);
-	      fc->col_type[reg] = DW_CFA_offset;
-	      fc->col_offset[reg] = roffs * fc->data_factor;
-	      break;
-
-	    case DW_CFA_restore_extended:
-	      reg = LEB ();
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_restore_extended: r%ld\n", reg);
-	      fc->col_type[reg] = cie->col_type[reg];
-	      fc->col_offset[reg] = cie->col_offset[reg];
-	      break;
-
-	    case DW_CFA_undefined:
-	      reg = LEB ();
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_undefined: r%ld\n", reg);
-	      fc->col_type[reg] = DW_CFA_undefined;
-	      fc->col_offset[reg] = 0;
-	      break;
-
-	    case DW_CFA_same_value:
-	      reg = LEB ();
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_same_value: r%ld\n", reg);
-	      fc->col_type[reg] = DW_CFA_same_value;
-	      fc->col_offset[reg] = 0;
-	      break;
-
-	    case DW_CFA_register:
-	      reg = LEB ();
-	      roffs = LEB ();
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_register: r%ld in r%ld\n", reg, roffs);
-	      fc->col_type[reg] = DW_CFA_register;
-	      fc->col_offset[reg] = roffs;
-	      break;
-
-	    case DW_CFA_remember_state:
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_remember_state\n");
-	      rs = xmalloc (sizeof (Frame_Chunk));
-	      rs->ncols = fc->ncols;
-	      rs->col_type = xcmalloc (rs->ncols, sizeof (short int));
-	      rs->col_offset = xcmalloc (rs->ncols, sizeof (int));
-	      memcpy (rs->col_type, fc->col_type, rs->ncols);
-	      memcpy (rs->col_offset, fc->col_offset, rs->ncols * sizeof (int));
-	      rs->next = remembered_state;
-	      remembered_state = rs;
-	      break;
-
-	    case DW_CFA_restore_state:
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_restore_state\n");
-	      rs = remembered_state;
-	      if (rs)
-		{
-		  remembered_state = rs->next;
-		  frame_need_space (fc, rs->ncols-1);
-		  memcpy (fc->col_type, rs->col_type, rs->ncols);
-		  memcpy (fc->col_offset, rs->col_offset,
-			  rs->ncols * sizeof (int));
-		  free (rs->col_type);
-		  free (rs->col_offset);
-		  free (rs);
-		}
-	      else if (do_debug_frames_interp)
-		printf ("Mismatched DW_CFA_restore_state\n");
-	      break;
-
-	    case DW_CFA_def_cfa:
-	      fc->cfa_reg = LEB ();
-	      fc->cfa_offset = LEB ();
-	      fc->cfa_exp = 0;
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_def_cfa: r%d ofs %d\n",
-			fc->cfa_reg, fc->cfa_offset);
-	      break;
-
-	    case DW_CFA_def_cfa_register:
-	      fc->cfa_reg = LEB ();
-	      fc->cfa_exp = 0;
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_def_cfa_reg: r%d\n", fc->cfa_reg);
-	      break;
-
-	    case DW_CFA_def_cfa_offset:
-	      fc->cfa_offset = LEB ();
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_def_cfa_offset: %d\n", fc->cfa_offset);
-	      break;
-
-	    case DW_CFA_nop:
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_nop\n");
-	      break;
-
-	    case DW_CFA_def_cfa_expression:
-	      ul = LEB ();
-	      if (! do_debug_frames_interp)
-		{
-		  printf ("  DW_CFA_def_cfa_expression (");
-		  decode_location_expression (start, eh_addr_size, ul, 0);
-		  printf (")\n");
-		}
-	      fc->cfa_exp = 1;
-	      start += ul;
-	      break;
-
-	    case DW_CFA_expression:
-	      reg = LEB ();
-	      ul = LEB ();
-	      if (! do_debug_frames_interp)
-		{
-		  printf ("  DW_CFA_expression: r%ld (", reg);
-		  decode_location_expression (start, eh_addr_size, ul, 0);
-		  printf (")\n");
-		}
-	      fc->col_type[reg] = DW_CFA_expression;
-	      start += ul;
-	      break;
-
-	    case DW_CFA_offset_extended_sf:
-	      reg = LEB ();
-	      l = SLEB ();
-	      frame_need_space (fc, reg);
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_offset_extended_sf: r%ld at cfa%+ld\n",
-			reg, l * fc->data_factor);
-	      fc->col_type[reg] = DW_CFA_offset;
-	      fc->col_offset[reg] = l * fc->data_factor;
-	      break;
-
-	    case DW_CFA_def_cfa_sf:
-	      fc->cfa_reg = LEB ();
-	      fc->cfa_offset = SLEB ();
-	      fc->cfa_offset = fc->cfa_offset * fc->data_factor;
-	      fc->cfa_exp = 0;
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_def_cfa_sf: r%d ofs %d\n",
-			fc->cfa_reg, fc->cfa_offset);
-	      break;
-
-	    case DW_CFA_def_cfa_offset_sf:
-	      fc->cfa_offset = SLEB ();
-	      fc->cfa_offset = fc->cfa_offset * fc->data_factor;
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_def_cfa_offset_sf: %d\n", fc->cfa_offset);
-	      break;
-
-	    case DW_CFA_MIPS_advance_loc8:
-	      ofs = byte_get (start, 8); start += 8;
-	      if (do_debug_frames_interp)
-		frame_display_row (fc, &need_col_headers, &max_regs);
-	      else
-		printf ("  DW_CFA_MIPS_advance_loc8: %ld to %08lx\n",
-			ofs * fc->code_factor,
-			fc->pc_begin + ofs * fc->code_factor);
-	      fc->pc_begin += ofs * fc->code_factor;
-	      break;
-
-	    case DW_CFA_GNU_window_save:
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_GNU_window_save\n");
-	      break;
-
-	    case DW_CFA_GNU_args_size:
-	      ul = LEB ();
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_GNU_args_size: %ld\n", ul);
-	      break;
-
-	    case DW_CFA_GNU_negative_offset_extended:
-	      reg = LEB ();
-	      l = - LEB ();
-	      frame_need_space (fc, reg);
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_GNU_negative_offset_extended: r%ld at cfa%+ld\n",
-			reg, l * fc->data_factor);
-	      fc->col_type[reg] = DW_CFA_offset;
-	      fc->col_offset[reg] = l * fc->data_factor;
-	      break;
-
-	    default:
-	      warn (_("unsupported or unknown DW_CFA_%d\n"), op);
-	      start = block_end;
-	    }
-	}
-
-      if (do_debug_frames_interp)
-	frame_display_row (fc, &need_col_headers, &max_regs);
-
-      start = block_end;
-    }
-
-  printf ("\n");
-
-  return 1;
-}
-
-#undef GET
-#undef LEB
-#undef SLEB
-
-static int
-display_debug_not_supported (struct dwarf_section *section,
-			     void *file ATTRIBUTE_UNUSED)
-{
-  printf (_("Displaying the debug contents of section %s is not yet supported.\n"),
-	    section->name);
-
-  return 1;
-}
-
-/* A structure containing the name of a debug section
-   and a pointer to a function that can decode it.  */
-static struct
-{
-  const char *const name;
-  int (*display) (struct dwarf_section *, void *);
-  unsigned int relocate : 1;
-}
-debug_displays[] =
-{
-  { ".debug_abbrev",		display_debug_abbrev,		0 },
-  { ".debug_aranges",		display_debug_aranges,		0 },
-  { ".debug_frame",		display_debug_frames,		1 },
-  { ".debug_info",		display_debug_info,		1 },
-  { ".debug_line",		display_debug_lines,		0 },
-  { ".debug_pubnames",		display_debug_pubnames,		0 },
-  { ".eh_frame",		display_debug_frames,		1 },
-  { ".debug_macinfo",		display_debug_macinfo,		0 },
-  { ".debug_str",		display_debug_str,		0 },
-  { ".debug_loc",		display_debug_loc,		0 },
-  { ".debug_pubtypes",		display_debug_pubnames,		0 },
-  { ".debug_ranges",		display_debug_ranges,		0 },
-  { ".debug_static_func",	display_debug_not_supported,	0 },
-  { ".debug_static_vars",	display_debug_not_supported,	0 },
-  { ".debug_types",		display_debug_not_supported,	0 },
-  { ".debug_weaknames",		display_debug_not_supported,	0 }
-};
-
-static int
-display_debug_section (Elf_Internal_Shdr *section, FILE *file)
-{
-  char *name = SECTION_NAME (section);
-  bfd_size_type length;
-  int result = 1;
-  int i;
-
-  length = section->sh_size;
-  if (length == 0)
-    {
-      printf (_("\nSection '%s' has no debugging data.\n"), name);
-      return 0;
-    }
-
-  if (strneq (name, ".gnu.linkonce.wi.", 17))
-    name = ".debug_info";
-
-  /* See if we know how to display the contents of this section.  */
-  for (i = NUM_ELEM (debug_displays); i--;)
-    if (streq (debug_displays[i].name, name))
-      {
-	struct dwarf_section sec;
-
-	sec.name = name;
-	sec.address = section->sh_addr;
-	sec.size = section->sh_size;
-	sec.start = get_data (NULL, file, section->sh_offset, 1,
-			      length, _("debug section data"));
-	if (sec.start == NULL)
-	  {
-	    result = 0;
-	    break;
-	  }
-
-	if (!debug_displays[i].relocate
-	    || debug_apply_rela_addends (file, section, sec.start))
-	  result &= debug_displays[i].display (&sec, file);
-
-	free (sec.start);
-
-	/* If we loaded in the abbrev section
-	   at some point, we must release it here.  */
-	free_abbrevs ();
-
-	break;
-      }
-
-  if (i == -1)
-    {
-      printf (_("Unrecognized debug section: %s\n"), name);
-      result = 0;
-    }
-
-  return result;
-}
-
-static void
-process_section_contents (FILE *file)
-{
-  Elf_Internal_Shdr *section;
-  unsigned int i;
-
-  if (! do_dump)
-    return;
-
-  for (i = 0, section = section_headers;
-       i < elf_header.e_shnum && i < num_dump_sects;
-       i++, section++)
-    {
-#ifdef SUPPORT_DISASSEMBLY
-      if (dump_sects[i] & DISASS_DUMP)
-	disassemble_section (section, file);
-#endif
-      if (dump_sects[i] & HEX_DUMP)
-	dump_section (section, file);
-
-      if (dump_sects[i] & DEBUG_DUMP)
-	display_debug_section (section, file);
-    }
-
-  /* Check to see if the user requested a
-     dump of a section that does not exist.  */
-  while (i++ < num_dump_sects)
-    if (dump_sects[i])
-      warn (_("Section %d was not dumped because it does not exist!\n"), i);
-}
-
-static void
-process_mips_fpe_exception (int mask)
-{
-  if (mask)
-    {
-      int first = 1;
-      if (mask & OEX_FPU_INEX)
-	fputs ("INEX", stdout), first = 0;
-      if (mask & OEX_FPU_UFLO)
-	printf ("%sUFLO", first ? "" : "|"), first = 0;
-      if (mask & OEX_FPU_OFLO)
-	printf ("%sOFLO", first ? "" : "|"), first = 0;
-      if (mask & OEX_FPU_DIV0)
-	printf ("%sDIV0", first ? "" : "|"), first = 0;
-      if (mask & OEX_FPU_INVAL)
-	printf ("%sINVAL", first ? "" : "|");
-    }
-  else
-    fputs ("0", stdout);
-}
-
-static int
-process_mips_specific (FILE *file)
-{
-  Elf_Internal_Dyn *entry;
-  size_t liblist_offset = 0;
-  size_t liblistno = 0;
-  size_t conflictsno = 0;
-  size_t options_offset = 0;
-  size_t conflicts_offset = 0;
-
-  /* We have a lot of special sections.  Thanks SGI!  */
-  if (dynamic_section == NULL)
-    /* No information available.  */
-    return 0;
+  /* We have a lot of special sections.  Thanks SGI!  */
+  if (dynamic_section == NULL)
+    /* No information available.  */
+    return 0;
 
   for (entry = dynamic_section; entry->d_tag != DT_NULL; ++entry)
     switch (entry->d_tag)
@@ -12308,22 +8566,7 @@ process_object (char *file_name, FILE *f
       section_groups = NULL;
     }
 
-  if (debug_information)
-    {
-      for (i = 0; i < num_debug_info_entries; i++)
-	{
-	  if (!debug_information [i].max_loc_offsets)
-	    {
-	      free (debug_information [i].loc_offsets);
-	      free (debug_information [i].have_frame_base);
-	    }
-	  if (!debug_information [i].max_range_lists)
-	    free (debug_information [i].range_lists);
-	}
-      free (debug_information);
-      debug_information = NULL;
-      num_debug_info_entries = 0;
-    }
+  free_debug_memory ();
 
   return 0;
 }
-------------- next part --------------
2005-09-15  H.J. Lu  <hongjiu.lu@intel.com>

	* Makefile.am (objdump_SOURCES): Add dwarf.c.
	* Makefile.in: Regenerated.

	* objdump.c: Include "dwarf.h".
	(usage): Add -W/--dwarf.
	(long_options): Likewise.
	(dump_dwarf_section_info): New.
	(load_debug_section): Likewise.
	(free_debug_section): Likewise.
	(dump_dwarf_section): Likewise.
	(dump_dwarf): Likewise.
	(dump_bfd): Load symbol table and call dump_dwarf if
	dump_dwarf_section_info isn't zero.
	(main): Handle -W/--dwarf.

--- binutils/Makefile.am.dump	2005-09-14 09:22:18.000000000 -0700
+++ binutils/Makefile.am	2005-09-14 11:40:26.000000000 -0700
@@ -168,7 +168,7 @@ strip_new_SOURCES = objcopy.c is-strip.c
 
 nm_new_SOURCES = nm.c budemang.c $(BULIBS)
 
-objdump_SOURCES = objdump.c budemang.c prdbg.c $(DEBUG_SRCS) $(BULIBS)
+objdump_SOURCES = objdump.c dwarf.c budemang.c prdbg.c $(DEBUG_SRCS) $(BULIBS)
 objdump_LDADD = $(OPCODES) $(BFDLIB) $(LIBIBERTY) $(INTLLIBS)
 
 objdump.o:objdump.c
--- binutils/Makefile.in.dump	2005-09-14 09:22:18.000000000 -0700
+++ binutils/Makefile.in	2005-09-14 11:40:26.000000000 -0700
@@ -143,8 +143,9 @@ objcopy_OBJECTS = $(am_objcopy_OBJECTS)
 objcopy_LDADD = $(LDADD)
 objcopy_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \
 	$(am__DEPENDENCIES_3)
-am_objdump_OBJECTS = objdump.$(OBJEXT) budemang.$(OBJEXT) \
-	prdbg.$(OBJEXT) $(am__objects_2) $(am__objects_1)
+am_objdump_OBJECTS = objdump.$(OBJEXT) dwarf.$(OBJEXT) \
+	budemang.$(OBJEXT) prdbg.$(OBJEXT) $(am__objects_2) \
+	$(am__objects_1)
 objdump_OBJECTS = $(am_objdump_OBJECTS)
 am__DEPENDENCIES_4 = ../opcodes/libopcodes.la
 objdump_DEPENDENCIES = $(am__DEPENDENCIES_4) $(am__DEPENDENCIES_1) \
@@ -462,7 +463,7 @@ readelf_SOURCES = readelf.c version.c un
 readelf_LDADD = $(INTLLIBS) $(LIBIBERTY)
 strip_new_SOURCES = objcopy.c is-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS)
 nm_new_SOURCES = nm.c budemang.c $(BULIBS)
-objdump_SOURCES = objdump.c budemang.c prdbg.c $(DEBUG_SRCS) $(BULIBS)
+objdump_SOURCES = objdump.c dwarf.c budemang.c prdbg.c $(DEBUG_SRCS) $(BULIBS)
 objdump_LDADD = $(OPCODES) $(BFDLIB) $(LIBIBERTY) $(INTLLIBS)
 cxxfilt_SOURCES = cxxfilt.c $(BULIBS)
 ar_SOURCES = arparse.y arlex.l ar.c not-ranlib.c arsup.c rename.c binemul.c \
--- binutils/objdump.c.dump	2005-08-24 08:26:49.000000000 -0700
+++ binutils/objdump.c	2005-09-14 11:58:58.000000000 -0700
@@ -52,6 +52,7 @@
 #include "bfdver.h"
 #include "progress.h"
 #include "bucomm.h"
+#include "dwarf.h"
 #include "budemang.h"
 #include "getopt.h"
 #include "safe-ctype.h"
@@ -91,6 +92,7 @@ static int prefix_addresses;		/* --prefi
 static int with_line_numbers;		/* -l */
 static bfd_boolean with_source_code;	/* -S */
 static int show_raw_insn;		/* --show-raw-insn */
+static int dump_dwarf_section_info;	/* --dwarf */
 static int dump_stab_section_info;	/* --stabs */
 static int do_demangle;			/* -C, --demangle */
 static bfd_boolean disassemble;		/* -d */
@@ -189,6 +191,7 @@ usage (FILE *stream, int status)
   -g, --debugging          Display debug information in object file\n\
   -e, --debugging-tags     Display debug information using ctags style\n\
   -G, --stabs              Display (in raw form) any STABS info in the file\n\
+  -W, --dwarf              Display DWARF info in the file\n\
   -t, --syms               Display the contents of the symbol table(s)\n\
   -T, --dynamic-syms       Display the contents of the dynamic symbol table\n\
   -r, --reloc              Display the relocation entries in the file\n\
@@ -275,6 +278,7 @@ static struct option long_options[]=
   {"source", no_argument, NULL, 'S'},
   {"special-syms", no_argument, &dump_special_syms, 1},
   {"include", required_argument, NULL, 'I'},
+  {"dwarf", no_argument, NULL, 'W'},
   {"stabs", no_argument, NULL, 'G'},
   {"start-address", required_argument, NULL, OPTION_START_ADDRESS},
   {"stop-address", required_argument, NULL, OPTION_STOP_ADDRESS},
@@ -1965,6 +1969,115 @@ disassemble_data (bfd *abfd)
   free (sorted_syms);
 }
 
+int
+load_debug_section (enum dwarf_section_display_enum debug, void *file)
+{
+  struct dwarf_section *section = &debug_displays [debug].section;
+  bfd *abfd = file;
+  asection *sec;
+  bfd_boolean ret;
+
+  /* If it is already loaded, do nothing.  */
+  if (section->start != NULL)
+    return 1;
+
+  /* Locate the debug section.  */
+  sec = bfd_get_section_by_name (abfd, section->name);
+  if (sec == NULL)
+    return 0;
+
+  section->address = bfd_get_section_vma (abfd, sec);
+  section->size = bfd_get_section_size (sec);
+  section->start = xmalloc (section->size);
+
+  if (is_relocatable && debug_displays [debug].relocate)
+    ret = bfd_simple_get_relocated_section_contents (abfd,
+						     sec,
+						     section->start,
+						     syms) != NULL;
+  else
+    ret = bfd_get_section_contents (abfd, sec, section->start, 0,
+				    section->size);
+
+  if (!ret)
+    {
+      free_debug_section (debug);
+      printf (_("\nCan't get contents for section '%s'.\n"),
+	      section->name);
+    }
+
+  return ret;
+}
+
+void
+free_debug_section (enum dwarf_section_display_enum debug)
+{
+  struct dwarf_section *section = &debug_displays [debug].section;
+
+  if (section->start == NULL)
+    return;
+
+  free ((char *) section->start);
+  section->start = NULL;
+  section->size = 0;
+}
+
+static void
+dump_dwarf_section (bfd *abfd, asection *section,
+		    void *arg ATTRIBUTE_UNUSED)
+{
+  const char *name = bfd_get_section_name (abfd, section);
+  const char *match;
+  enum dwarf_section_display_enum i;
+
+  if (strncmp (name, ".gnu.linkonce.wi.", 17) == 0)
+    match = ".debug_info";
+  else
+    match = name;
+
+  for (i = 0; i < max; i++)
+    if (strcmp (debug_displays[i].section.name, match) == 0)
+      {
+	if (!debug_displays[i].eh_frame)
+	  {
+	    struct dwarf_section *sec = &debug_displays [i].section;
+
+	    if (load_debug_section (i, abfd))
+	      {
+		debug_displays[i].display (sec, abfd);
+
+		if (i != info && i != abbrev)
+		  free_debug_section (i);
+	      }
+	  }
+	break;
+      }
+}
+
+/* Dump the dwarf debugging information.  */
+
+static void
+dump_dwarf (bfd *abfd)
+{
+  is_relocatable = ((abfd->flags & (HAS_RELOC | EXEC_P | DYNAMIC))
+		    == HAS_RELOC);
+
+  /* FIXME: bfd_get_arch_size may return -1.  We assume that 64bit
+     targets will return 64.  */
+  eh_addr_size = bfd_get_arch_size (abfd) == 64 ? 8 : 4;
+
+  if (bfd_big_endian (abfd))
+    byte_get = byte_get_big_endian;
+  else if (bfd_little_endian (abfd))
+    byte_get = byte_get_little_endian;
+  else
+    abort ();
+
+  bfd_map_over_sections (abfd, dump_dwarf_section, NULL);
+
+  free_debug_memory ();
+}
+
 /* Read ABFD's stabs section STABSECT_NAME, and return a pointer to
    it.  Return NULL on failure.   */
 
@@ -2636,7 +2749,11 @@ dump_bfd (bfd *abfd)
   if (dump_section_headers)
     dump_headers (abfd);
 
-  if (dump_symtab || dump_reloc_info || disassemble || dump_debugging)
+  if (dump_symtab
+      || dump_reloc_info
+      || disassemble
+      || dump_debugging
+      || dump_dwarf_section_info)
     syms = slurp_symtab (abfd);
   if (dump_dynamic_symtab || dump_dynamic_reloc_info
       || (disassemble && bfd_get_dynamic_symtab_upper_bound (abfd) > 0))
@@ -2653,6 +2770,8 @@ dump_bfd (bfd *abfd)
     dump_symbols (abfd, FALSE);
   if (dump_dynamic_symtab)
     dump_symbols (abfd, TRUE);
+  if (dump_dwarf_section_info)
+    dump_dwarf (abfd);
   if (dump_stab_section_info)
     dump_stabs (abfd);
   if (dump_reloc_info && ! disassemble)
@@ -2819,7 +2938,7 @@ main (int argc, char **argv)
   bfd_init ();
   set_default_bfd_target ();
 
-  while ((c = getopt_long (argc, argv, "pib:m:M:VvCdDlfaHhrRtTxsSI:j:wE:zgeG",
+  while ((c = getopt_long (argc, argv, "pib:m:M:VvCdDlfaHhrRtTxsSI:j:wE:zgeGW",
 			   long_options, (int *) 0))
 	 != EOF)
     {
@@ -2960,6 +3079,20 @@ main (int argc, char **argv)
 	  do_demangle = TRUE;
 	  seenflag = TRUE;
 	  break;
+	case 'W':
+	  dump_dwarf_section_info = TRUE;
+	  seenflag = TRUE;
+	  do_debug_info = 1;
+	  do_debug_abbrevs = 1;
+	  do_debug_lines = 1;
+	  do_debug_pubnames = 1;
+	  do_debug_aranges = 1;
+	  do_debug_ranges = 1;
+	  do_debug_frames = 1;
+	  do_debug_macinfo = 1;
+	  do_debug_str = 1;
+	  do_debug_loc = 1;
+	  break;
 	case 'G':
 	  dump_stab_section_info = TRUE;
 	  seenflag = TRUE;
-------------- next part --------------
2005-09-15  H.J. Lu  <hongjiu.lu@intel.com>

	* dwarf.c (fetch_indirect_string): Adjust for section address.
	(process_debug_info): Likewise.
	(display_debug_loc): Likewise.
	(display_debug_ranges): Likewise.

	* objdump.c (mach_o_dwarf_sections): New.
	(check_mach_o_dwarf): Likewise.
	(dump_dwarf): Call check_mach_o_dwarf.

--- binutils/dwarf.c.mach-o	2005-09-15 07:29:38.000000000 -0700
+++ binutils/dwarf.c	2005-09-15 07:29:38.000000000 -0700
@@ -284,6 +284,8 @@ fetch_indirect_string (unsigned long off
   if (section->start == NULL)
     return _("<no .debug_str section>");
 
+  /* DWARF sections under Mach-O have non-zero addresses.  */
+  offset -= section->address;
   if (offset > section->size)
     {
       warn (_("DW_FORM_strp offset too big: %lx\n"), offset);
@@ -1642,10 +1644,11 @@ process_debug_info (struct dwarf_section
 
       free_abbrevs ();
 
-      /* Process the abbrevs used by this compilation unit.  */
+      /* Process the abbrevs used by this compilation unit. DWARF
+	 sections under Mach-O have non-zero addresses.  */
       process_abbrev_section
 	((unsigned char *) debug_displays [abbrev].section.start
-	 + compunit.cu_abbrev_offset,
+	 + compunit.cu_abbrev_offset - debug_displays [abbrev].section.address,
 	 (unsigned char *) debug_displays [abbrev].section.start
 	 + debug_displays [abbrev].section.size);
 
@@ -2366,7 +2369,8 @@ display_debug_loc (struct dwarf_section 
   if (!seen_first_offset)
     error (_("No location lists in .debug_info section!\n"));
 
-  if (debug_information [first].loc_offsets [0] != 0)
+  /* DWARF sections under Mach-O have non-zero addresses.  */
+  if (debug_information [first].loc_offsets [0] != section->address)
     warn (_("Location lists in %s section start at 0x%lx\n"),
 	  section->name, debug_information [first].loc_offsets [0]);
 
@@ -2392,7 +2396,8 @@ display_debug_loc (struct dwarf_section 
       for (j = 0; j < debug_information [i].num_loc_offsets; j++)
 	{
 	  has_frame_base = debug_information [i].have_frame_base [j];
-	  offset = debug_information [i].loc_offsets [j];
+	  /* DWARF sections under Mach-O have non-zero addresses.  */
+	  offset = debug_information [i].loc_offsets [j] - section->address; 
 	  next = section_begin + offset;
 	  base_address = debug_information [i].base_address;
 
@@ -2721,7 +2726,8 @@ display_debug_ranges (struct dwarf_secti
   if (!seen_first_offset)
     error (_("No range lists in .debug_info section!\n"));
 
-  if (debug_information [first].range_lists [0] != 0)
+  /* DWARF sections under Mach-O have non-zero addresses.  */
+  if (debug_information [first].range_lists [0] != section->address)
     warn (_("Range lists in %s section start at 0x%lx\n"),
 	  section->name, debug_information [first].range_lists [0]);
 
@@ -2741,7 +2747,8 @@ display_debug_ranges (struct dwarf_secti
 
       for (j = 0; j < debug_information [i].num_range_lists; j++)
 	{
-	  offset = debug_information [i].range_lists [j];
+	  /* DWARF sections under Mach-O have non-zero addresses.  */
+	  offset = debug_information [i].range_lists [j] - section->address;
 	  next = section_begin + offset;
 	  base_address = debug_information [i].base_address;
 
--- binutils/objdump.c.mach-o	2005-09-15 07:29:38.000000000 -0700
+++ binutils/objdump.c	2005-09-15 07:29:38.000000000 -0700
@@ -2054,6 +2054,36 @@ dump_dwarf_section (bfd *abfd, asection 
       }
 }
 
+static const char *mach_o_dwarf_sections [] = {
+  "LC_SEGMENT.__DWARFA.__debug_abbrev",		/* .debug_abbrev */
+  "LC_SEGMENT.__DWARFA.__debug_aranges",	/* .debug_aranges */
+  "LC_SEGMENT.__DWARFA.__debug_frame",		/* .debug_frame */
+  "LC_SEGMENT.__DWARFA.__debug_info",		/* .debug_info */
+  "LC_SEGMENT.__DWARFA.__debug_line",		/* .debug_line */
+  "LC_SEGMENT.__DWARFA.__debug_pubnames",	/* .debug_pubnames */
+  ".eh_frame",					/* .eh_frame */
+  "LC_SEGMENT.__DWARFA.__debug_macinfo",	/* .debug_macinfo */
+  "LC_SEGMENT.__DWARFA.__debug_str",		/* .debug_str */
+  "LC_SEGMENT.__DWARFA.__debug_loc",		/* .debug_loc */
+  "LC_SEGMENT.__DWARFA.__debug_pubtypes",	/* .debug_pubtypes */
+  "LC_SEGMENT.__DWARFA.__debug_ranges",		/* .debug_ranges */
+  "LC_SEGMENT.__DWARFA.__debug_static_func",	/* .debug_static_func */
+  "LC_SEGMENT.__DWARFA.__debug_static_vars",	/* .debug_static_vars */
+  "LC_SEGMENT.__DWARFA.__debug_types",		/* .debug_types */
+  "LC_SEGMENT.__DWARFA.__debug_weaknames"	/* .debug_weaknames */
+};
+
+static void
+check_mach_o_dwarf (bfd *abfd)
+{
+  if (bfd_get_flavour (abfd) == bfd_target_mach_o_flavour)
+    {
+      enum dwarf_section_display_enum i;
+      for (i = 0; i < max; i++)
+	debug_displays[i].section.name = mach_o_dwarf_sections [i];
+    }
+}
+
 /* Dump the dwarf debugging information.  */
 
 static void
@@ -2073,6 +2103,8 @@ dump_dwarf (bfd *abfd)
   else
     abort ();
 
+  check_mach_o_dwarf (abfd);
+
   bfd_map_over_sections (abfd, dump_dwarf_section, NULL);
 
   free_debug_memory ();


More information about the Binutils mailing list