This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[branch patch] dwarf-frame.c support for .eh_frame_hdr


[Please note that I am not on the mailing list, and keep me CC'd.]

These patches to kettenis_i386newframe-20030419-branch gdb make
dwarf-frame.c support .eh_frame_hdr format.  

This is more complex than what I had anticipated writing.  I had expected to
decode the .eh_frame_hdr contents only to locate the .eh_frame section and
then just read that as is done when the section is known by name.  However,
AFAICT there is no way to tell from the contents of .eh_frame where it ends.
When you don't know the exact bounds of the section, you can try to read off
the end of it and become confused.  When you have only .eh_frame_hdr
information to go on, you know where .eh_frame starts but not where it ends,
so you don't know how much to decode.  The only thing I can find that works
is to follow the FDE quick-lookup table in the .eh_frame_hdr section,
reading the FDEs pointed to and the CIEs they point to, rather than reading
the whole .eh_frame section from start to finish.  I implemented that.
(Though the description of the .eh_frame_hdr format calls the lookup table
"optional", from looking at the libgcc code, I think it may well wind up
crashing in some cases if there is an .eh_frame_hdr section without a lookup
table, because it can read off the end of the .eh_frame section.)

The symfile.c change is necessary for "add-symbol-file" to be usable, which
is how I tested the new code.  The following snippet of a gdb session using
this patch demonstrates how adding the core file as a symfile and thus
reading its .eh_frame_hdr table makes backtraces from vsyscall PCs suddenly
start working right.  (I editted out some boring messges.)


(gdb) core ./core.23363 
Core was generated by `/home/roland/build/newthreads-libc/elf/ld-linux.so.2 --library-path /home/rolan'.
Program terminated with signal 3, Quit.
#0  0xffffe410 in ?? ()
(gdb) bt
#0  0xffffe410 in ?? ()
(gdb) i fr 0
Stack frame at 0x0:
 eip = 0xffffe410; saved eip 0xbffff698
 Arglist at 0xbffff664, args: 
 Locals at 0xbffff664, Previous frame's sp is 0xbffff66c
 Saved registers:
  eip at 0xbffff668
(gdb) add-symbol-file core.23363 
add symbol table from file "core.23363" at
(y or n) y
Reading symbols from core.23363...done.
(gdb) bt
#0  0xffffe410 in _r_debug ()
#1  0x400cd473 in read () at ctype.h:51
#2  0x40070012 in _IO_file_read (fp=0xfffffe00, buf=0xfffffe00, size=-512) at fileops.c:1208
#3  0x4006ed9c in _IO_new_file_underflow (fp=0x401294a0) at fileops.c:591
#4  0x4007122d in _IO_default_uflow (fp=0x401294a0) at genops.c:430
#5  0x40071076 in *__GI___uflow (fp=0x401294a0) at genops.c:384
#6  0x4006af9f in getchar () at getchar.c:44
#7  0x0804834d in main () at loser.c:1
(gdb) i fr 0
Stack frame at 0xbffff678:
 eip = 0xffffe410 in _r_debug; saved eip 0x400cd473
 called by frame at 0xbffff680
 Arglist at 0xbffff664, args: 
 Locals at 0xbffff664, Previous frame's sp is 0xbffff678
 Saved registers:
  ebp at 0xbffff668, eip at 0xbffff674
(gdb)


(Of course "_r_debug" is bogus, it's just the highest-addressed candidate
symbol or something or other.  gdb really ought to notice that it's not in
the same symfile section and not use that symbol for that address.)


Thanks,
Roland


2003-05-12  Roland McGrath  <roland@redhat.com>

	* dwarf2read.c (dwarf_eh_frame_hdr_offset, dwarf_eh_frame_hdr_size,
	dwarf_eh_frame_hdr_section): New variables.
	(dwarf2_locate_sections): Match a section whose name starts with
	"eh_frame_hdr", and set those.
	(dwarf2_has_info): Clear dwarf_eh_frame_hdr_offset here.
	* dwarf-frame.c (decode_eh_frame_hdr): New function.
	(dwarf2_build_frame_info): Call it when dwarf_eh_frame_hdr_offset
	is set but dwarf_eh_frame_offset is not.

	* symfile.c (symfile_bfd_open): Try bfd_check_format with bfd_core
	if bfd_object fails.

Index: dwarf-frame.c
===================================================================
RCS file: /cvs/src/src/gdb/Attic/dwarf-frame.c,v
retrieving revision 1.1.2.3
diff -b -B -p -u -r1.1.2.3 dwarf-frame.c
--- dwarf-frame.c	10 May 2003 15:49:09 -0000	1.1.2.3
+++ dwarf-frame.c	12 May 2003 09:17:02 -0000
@@ -697,8 +697,9 @@ struct comp_unit
   /* Length of the loaded .debug_frame section.  */
   unsigned long dwarf_frame_size;
 
-  /* Pointer to the .debug_frame section.  */
-  asection *dwarf_frame_section;
+  /* VMA corresponding to the beginning of the buffer,
+     for relative addressing calculations.  */
+  bfd_vma dwarf_frame_vma;
 };
 
 static unsigned int
@@ -851,8 +852,7 @@ read_encoded_value (struct comp_unit *un
       base = 0;
       break;
     case DW_EH_PE_pcrel:
-      base = bfd_get_section_vma (unit->bfd, unit->dwarf_frame_section);
-      base += (buf - unit->dwarf_frame_buffer);
+      base = unit->dwarf_frame_vma + (buf - unit->dwarf_frame_buffer);
       break;
     default:
       internal_error (__FILE__, __LINE__, "Invalid or unsupported encoding");
@@ -958,7 +958,7 @@ add_fde (struct comp_unit *unit, struct 
 #define DW64_CIE_ID ~0
 #endif
 
-/* Read and the CIE or FDE in BUF and decode it.  */
+/* Read the CIE or FDE in BUF and decode it.  */
 
 static char *
 decode_frame_entry (struct comp_unit *unit, char *buf, int eh_frame_p)
@@ -1161,11 +1161,170 @@ extern asection *dwarf_frame_section;
 extern file_ptr dwarf_eh_frame_offset;
 extern unsigned int dwarf_eh_frame_size;
 extern asection *dwarf_eh_frame_section;
+extern file_ptr dwarf_eh_frame_hdr_offset;
+extern unsigned int dwarf_eh_frame_hdr_size;
+extern asection *dwarf_eh_frame_hdr_section;
 
 /* Imported from dwarf2read.c.  */
 extern char *dwarf2_read_section (struct objfile *objfile, file_ptr offset,
 				  unsigned int size, asection *sectp);
 
+/* Decode .eh_frame_hdr format in dwarf_eh_frame_hdr_section.  */
+static void
+decode_eh_frame_hdr (struct comp_unit *unit)
+{
+  char hdr[4], buf[16];
+  ufile_ptr posn;
+  CORE_ADDR eh_frame_addr;
+  CORE_ADDR fde_count;
+  unsigned int len, element_size;
+  asection *sec;
+  struct comp_unit dummy;
+
+  if (bfd_seek (unit->abfd, dwarf_eh_frame_hdr_offset, SEEK_SET)
+      || bfd_bread (hdr, sizeof hdr, unit->abfd) != sizeof hdr)
+    {
+      error ("Dwarf Error: Can't read DWARF data from '%s'",
+	     bfd_get_filename (unit->abfd));
+      return;
+    }
+  if (hdr[0] != 1)
+    {
+      warning ("Dwarf Error: %s: %s header version %d (expected %d)",
+	       bfd_get_filename (unit->abfd),
+	       dwarf_eh_frame_hdr_section->name,
+	       hdr[0], 1);
+      return;
+    }
+
+  len = size_of_encoded_value (hdr[1]);
+  gdb_assert (len <= sizeof buf);
+  if (bfd_bread (buf, len, unit->abfd) != len)
+    {
+      error ("Dwarf Error: Can't read DWARF data from '%s'",
+	     bfd_get_filename (unit->abfd));
+      return;
+    }
+
+  /* read_encoded_value uses these to calculate the vma.  */
+  dummy.abfd = unit->abfd;
+  dummy.dwarf_frame_vma = (bfd_get_section_vma (unit->abfd,
+						dwarf_eh_frame_hdr_section)
+			   + sizeof hdr);
+  dummy.dwarf_frame_buffer = buf;
+
+  eh_frame_addr = read_encoded_value (&dummy, hdr[1], buf, &len);
+  gdb_assert (len <= sizeof buf);
+
+  len = size_of_encoded_value (hdr[2]);
+  if (len == 0)
+    /* No FDE table, and no way to know where .eh_frame ends!
+       We cannot use this.  */
+    return;
+
+  dummy.dwarf_frame_vma += len;
+  gdb_assert (len <= sizeof buf);
+  if (bfd_bread (buf, len, unit->abfd) != len)
+    {
+      error ("Dwarf Error: Can't read DWARF data from '%s'",
+	     bfd_get_filename (unit->abfd));
+      return;
+    }
+  fde_count = read_encoded_value (&dummy, hdr[2], buf, &len);
+  gdb_assert (len <= sizeof buf);
+  dummy.dwarf_frame_vma += len;
+
+  element_size = size_of_encoded_value (hdr[3]);
+  if (element_size == 0 || fde_count == 0)
+    /* No FDE table, and no way to know where .eh_frame ends!
+       We cannot use this.  */
+    return;
+
+  /* Save the position of the FDE table.  */
+  posn = bfd_tell (unit->abfd);
+
+  /* Now EH_FRAME_ADDR tells us where a .eh_frame section lies.  We
+     presumably don't have real section headers or we would have seen
+     it by the name ".eh_frame" already.  The BFD sections we have are
+     probably synthesized from ELF phdrs, as for a core file or a
+     stripped executable or DSO, i.e.  the section we find corresponds
+     to our whole text segment.  We have no way of knowing how large
+     the .eh_frame section should be, so we have to read through til
+     the end of the segment.  Fortunately, .eh_frame_hdr is usually
+     the last thing in text, so we likely won't read much extra.  */
+  for (sec = unit->abfd->sections; sec != NULL; sec = sec->next)
+    if ((sec->flags & SEC_ALLOC)
+	&& sec->vma <= eh_frame_addr
+	&& (sec->vma + bfd_get_section_size_before_reloc (sec)
+	    > eh_frame_addr))
+      break;
+  if (sec == NULL)
+    {
+      warning ("\
+Dwarf Error: No section contains eh_frame address 0x%08lx [in module %s]",
+	       (long) eh_frame_addr, bfd_get_filename (unit->abfd));
+      return;
+    }
+
+  unit->dwarf_frame_vma = eh_frame_addr;
+  eh_frame_addr -= bfd_get_section_vma (unit->abfd, sec);
+  unit->dwarf_frame_size = (bfd_get_section_size_before_reloc (sec)
+			    - eh_frame_addr);
+  unit->dwarf_frame_buffer = dwarf2_read_section (unit->objfile,
+						  sec->filepos + eh_frame_addr,
+						  unit->dwarf_frame_size,
+						  sec);
+
+
+  /* Now that we have read in the whole .eh_frame section, we cannot
+     just feed it all to decode_frame_entry, unfortunately.  We don't
+     actually know where the .eh_frame section ends, and it contains
+     no internal end marker.  So instead we have to work from the FDE
+     quick-lookup table in .eh_frame_hdr, whose size we do know.  */
+  if (bfd_seek (unit->abfd, posn, SEEK_SET))
+    {
+      error ("Dwarf Error: Can't read DWARF data from '%s'",
+	     bfd_get_filename (unit->abfd));
+      return;
+    }
+  while (fde_count-- > 0)
+    {
+      CORE_ADDR fde_pointer;
+
+      if (bfd_bread (buf, element_size * 2, unit->abfd) != element_size * 2)
+	{
+	  error ("Dwarf Error: Can't read DWARF data from '%s'",
+		 bfd_get_filename (unit->abfd));
+	  return;
+	}
+
+      if ((hdr[3] & 0x70) == DW_EH_PE_datarel)
+	/* In this case, it's relative to the vma of .eh_frame_hdr.  */
+	fde_pointer = (bfd_get_section_vma (unit->abfd,
+					    dwarf_eh_frame_hdr_section)
+		       + read_encoded_value (&dummy,
+					     DW_EH_PE_absptr | (hdr[3] & 0x0f),
+					     &buf[element_size], &len));
+      else
+	fde_pointer = read_encoded_value (&dummy, hdr[3],
+					  &buf[element_size], &len);
+      gdb_assert (len == element_size);
+      dummy.dwarf_frame_vma += element_size * 2;
+
+      if (fde_pointer < unit->dwarf_frame_vma
+	  || fde_pointer > unit->dwarf_frame_vma + unit->dwarf_frame_size)
+	{
+	  warning ("Dwarf Error: \
+Bogus FDE pointer 0x%08lx from .eh_frame_hdr table [in module %s]",
+		   (long) fde_pointer, bfd_get_filename (unit->abfd));
+	  continue;
+	}
+      fde_pointer -= unit->dwarf_frame_vma;
+      (void) decode_frame_entry (unit,
+				 unit->dwarf_frame_buffer + fde_pointer, 1);
+    }
+}
+
 void
 dwarf2_build_frame_info (struct objfile *objfile)
 {
@@ -1176,34 +1335,39 @@ dwarf2_build_frame_info (struct objfile 
   unit.abfd = objfile->obfd;
   unit.objfile = objfile;
   unit.addr_size = objfile->obfd->arch_info->bits_per_address / 8;
+  unit.cie = NULL;
 
   /* First add the information from the .eh_frame section.  That way,
      the FDEs from that section are searched last.  */
   if (dwarf_eh_frame_offset)
     {
-      unit.cie = NULL;
       unit.dwarf_frame_buffer = dwarf2_read_section (objfile,
 						     dwarf_eh_frame_offset,
 						     dwarf_eh_frame_size,
 						     dwarf_eh_frame_section);
 
       unit.dwarf_frame_size = dwarf_eh_frame_size;
-      unit.dwarf_frame_section = dwarf_eh_frame_section;
+      unit.dwarf_frame_vma = bfd_get_section_vma (unit.bfd,
+						  dwarf_eh_frame_section);
 
       frame_ptr = unit.dwarf_frame_buffer;
       while (frame_ptr < unit.dwarf_frame_buffer + unit.dwarf_frame_size)
 	frame_ptr = decode_frame_entry (&unit, frame_ptr, 1);
     }
+  else if (dwarf_eh_frame_hdr_offset)
+    /* We didn't find the .eh_frame section but found .eh_frame_hdr,
+       decode it to locate the .eh_frame section that actually exists.  */
+    decode_eh_frame_hdr (&unit);
 
   if (dwarf_frame_offset)
     {
-      unit.cie = NULL;
       unit.dwarf_frame_buffer = dwarf2_read_section (objfile,
 						     dwarf_frame_offset,
 						     dwarf_frame_size,
 						     dwarf_frame_section);
       unit.dwarf_frame_size = dwarf_frame_size;
-      unit.dwarf_frame_section = dwarf_frame_section;
+      unit.dwarf_frame_vma = bfd_get_section_vma (unit.bfd,
+						  dwarf_frame_section);
 
       frame_ptr = unit.dwarf_frame_buffer;
       while (frame_ptr < unit.dwarf_frame_buffer + unit.dwarf_frame_size)
Index: dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.90
diff -b -B -p -u -r1.90 dwarf2read.c
--- dwarf2read.c	15 Apr 2003 23:07:11 -0000	1.90
+++ dwarf2read.c	12 May 2003 09:17:06 -0000
@@ -139,6 +139,7 @@ static file_ptr dwarf_str_offset;
 static file_ptr dwarf_ranges_offset;
 file_ptr dwarf_frame_offset;
 file_ptr dwarf_eh_frame_offset;
+file_ptr dwarf_eh_frame_hdr_offset;
 
 static unsigned int dwarf_info_size;
 static unsigned int dwarf_abbrev_size;
@@ -151,6 +152,7 @@ static unsigned int dwarf_str_size;
 static unsigned int dwarf_ranges_size;
 unsigned int dwarf_frame_size;
 unsigned int dwarf_eh_frame_size;
+unsigned int dwarf_eh_frame_hdr_size;
 
 static asection *dwarf_info_section;
 static asection *dwarf_abbrev_section;
@@ -163,6 +165,7 @@ static asection *dwarf_str_section;
 static asection *dwarf_ranges_section;
 asection *dwarf_frame_section;
 asection *dwarf_eh_frame_section;
+asection *dwarf_eh_frame_hdr_section;
 
 /* names of the debugging sections */
 
@@ -944,6 +947,7 @@ dwarf2_has_info (bfd *abfd)
   dwarf_macinfo_offset = 0;
   dwarf_frame_offset = 0;
   dwarf_eh_frame_offset = 0;
+  dwarf_eh_frame_hdr_offset = 0;
   dwarf_ranges_offset = 0;
   dwarf_loc_offset = 0;
   
@@ -1025,6 +1029,12 @@ dwarf2_locate_sections (bfd *ignore_abfd
       dwarf_eh_frame_size = bfd_get_section_size_before_reloc (sectp);
       dwarf_eh_frame_section = sectp;
     }
+  else if (!strncmp (sectp->name, "eh_frame_hdr", 12))
+    {
+      dwarf_eh_frame_hdr_offset = sectp->filepos;
+      dwarf_eh_frame_hdr_size = bfd_get_section_size_before_reloc (sectp);
+      dwarf_eh_frame_hdr_section = sectp;
+    }
   else if (STREQ (sectp->name, RANGES_SECTION))
     {
       dwarf_ranges_offset = sectp->filepos;
Index: symfile.c
===================================================================
RCS file: /cvs/src/src/gdb/symfile.c,v
retrieving revision 1.93
diff -b -B -p -u -r1.93 symfile.c
--- symfile.c	1 Apr 2003 14:17:20 -0000	1.93
+++ symfile.c	12 May 2003 09:17:08 -0000
@@ -1338,7 +1338,9 @@ symfile_bfd_open (char *name)
     }
   sym_bfd->cacheable = 1;
 
-  if (!bfd_check_format (sym_bfd, bfd_object))
+  if (!bfd_check_format (sym_bfd, bfd_object)
+      /* Yes, Virginia, core files can have symbols!  */
+      && !bfd_check_format (sym_bfd, bfd_core))
     {
       /* FIXME: should be checking for errors from bfd_close (for one thing,
          on error it does not free all the storage associated with the


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]