From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 16604 invoked by alias); 13 May 2003 03:27:34 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 16449 invoked from network); 13 May 2003 03:27:32 -0000 Received: from unknown (HELO mx1.redhat.com) (66.187.233.31) by sources.redhat.com with SMTP; 13 May 2003 03:27:32 -0000 Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com [172.16.52.254]) by mx1.redhat.com (8.11.6/8.11.6) with ESMTP id h4D3RWH32189 for ; Mon, 12 May 2003 23:27:32 -0400 Received: from pobox.corp.redhat.com (pobox.corp.redhat.com [172.16.52.156]) by int-mx1.corp.redhat.com (8.11.6/8.11.6) with ESMTP id h4D3RWI24485 for ; Mon, 12 May 2003 23:27:32 -0400 Received: from localhost.redhat.com (IDENT:ijNhpjR0/IX1DIQfg5iWo7Q7LSK5F0Qq@tooth.toronto.redhat.com [172.16.14.29]) by pobox.corp.redhat.com (8.11.6/8.11.6) with ESMTP id h4D3RUA31327; Mon, 12 May 2003 23:27:30 -0400 Received: by localhost.redhat.com (Postfix, from userid 469) id 3BB9D2C94F; Mon, 12 May 2003 23:32:40 -0400 (EDT) From: Elena Zannoni MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Message-ID: <16064.26455.650498.812097@localhost.redhat.com> Date: Tue, 13 May 2003 03:27:00 -0000 To: Roland McGrath Cc: Mark Kettenis , gdb-patches@sources.redhat.com Subject: Re: [branch patch] dwarf-frame.c support for .eh_frame_hdr In-Reply-To: <200305120946.h4C9ksj17912@magilla.sf.frob.com> References: <200305120946.h4C9ksj17912@magilla.sf.frob.com> X-SW-Source: 2003-05/txt/msg00195.txt.bz2 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 > > * 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