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]

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


Roland McGrath writes:
 > [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.)

Is there a way to tell if there is a table? I think that if the
fde_count_enc has a value of 0xff (DW_EH_PE_omit) it means that there
is no table. Same for the table_enc field. (If that's what you mean,
that is).

 > 
 > 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.)
 > 

I see that the symfile.c change is a good way to test the code, and to
verify that the stuff that ends up in the core file makes sense. This
new add-symbol-file command required to read the symbols info from the
core file is however a bit of a departure from the standard way core
files are treated in gdb.  It also not entirely clear to a user that
it would be necessary to issue it.


elena

 > 
 > (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]