Your changes make sense to me, as do your concerns about accessing memory past the end of the synthetic frame header.
The only change I can suggest is that you should take the opportunity to stop the explicit bytes offsets in the code and write something like struct dwarf_eh_frame_hdr *synth_eh_frame_hdr; unsigned char synth_eh_frame_space[sizeof(*synth_eh_frame_hdr)+sizeof(Elf_W(Addr))]; synth_eh_frame_hdr = (struct_dwarf_eh_frame_hdr *) synth_eh_frame_space; … synth_eh_frame_hdr->version = DW_EH_VERSION; synth_eh_frame_hdr->eh_frame_ptr_enc = … etc. because I don’t understand why the original code used the struct member names in comments and not in the actual code. Doug > On Jun 30, 2017, at 10:57 AM, Ben Avison <bavi...@riscosopen.org> wrote: > > Thanks, that does appear to fix things in my case. I thought I would do a > little more investigating in case it is useful in justifying your proposed > patch. > > Whenever we use synth_eh_frame_hdr, then hdr is pointed at it, so > hdr->table_enc can only be DW_EH_PR_omit, and the FDE length word pointer > which is ultimately dereferenced by dwarf_extract_proc_info_from_fde() is > the one (returned from dwarf_find_eh_frame_section()) which > dwarf_callback() sticks into the word after synth_eh_frame_hdr. In my case, > it seems that whenever eh_frame_start is read from the word after > synth_eh_frame_hdr like this, the FDE length word read by > dwarf_extract_proc_info_from_fde() is always 0, irrespective of object > file. As a result, it always returns -UNW_ENOINFO, so linear_search() also > always fails. Does that make sense? > > In passing, I notice that at lines 547 and 584, we're referencing an > address beyond the bounds of synth_eh_frame_hdr, which could cause stack > corruption, depending on architecture and compiler. Wouldn't something like > this be better? > > > --- a/src/dwarf/Gfind_proc_info-lsb.c > +++ b/src/dwarf/Gfind_proc_info-lsb.c > @@ -482,7 +482,7 @@ dwarf_callback (struct dl_phdr_info *info, size_t size, > void *ptr) > unw_accessors_t *a; > long n; > int found = 0; > - struct dwarf_eh_frame_hdr synth_eh_frame_hdr; > + unsigned char synth_eh_frame_hdr[sizeof (struct dwarf_eh_frame_hdr) + > sizeof (Elf_W (Addr))]; > #ifdef CONFIG_DEBUG_FRAME > unw_word_t start, end; > #endif /* CONFIG_DEBUG_FRAME*/ > @@ -537,15 +537,14 @@ dwarf_callback (struct dl_phdr_info *info, size_t size, > void *ptr) > eh_frame = dwarf_find_eh_frame_section (info); > if (eh_frame) > { > - unsigned char *p = (unsigned char *) &synth_eh_frame_hdr; > Debug (1, "using synthetic .eh_frame_hdr section for %s\n", > info->dlpi_name); > - /* synth_eh_frame_hdr.version */ p[0] = DW_EH_VERSION; > - /* synth_eh_frame_hdr.eh_frame_ptr_enc */ p[1] = DW_EH_PE_absptr | > ((sizeof(Elf_W (Addr)) == 4) ? DW_EH_PE_udata4 : DW_EH_PE_udata8); > - /* synth_eh_frame_hdr.fde_count_enc */ p[2] = DW_EH_PE_omit; > - /* synth_eh_frame_hdr.table_enc */ p[3] = DW_EH_PE_omit; > - *(Elf_W (Addr) *)(&p[4]) = eh_frame; > - hdr = &synth_eh_frame_hdr; > + /* version */ synth_eh_frame_hdr[0] = DW_EH_VERSION; > + /* eh_frame_ptr_enc */ synth_eh_frame_hdr[1] = DW_EH_PE_absptr | > ((sizeof(Elf_W (Addr)) == 4) ? DW_EH_PE_udata4 : DW_EH_PE_udata8); > + /* fde_count_enc */ synth_eh_frame_hdr[2] = DW_EH_PE_omit; > + /* table_enc */ synth_eh_frame_hdr[3] = DW_EH_PE_omit; > + hdr = (struct dwarf_eh_frame_hdr *)synth_eh_frame_hdr; > + *(Elf_W (Addr) *)(hdr + 1) = eh_frame; > } > } > > > I'm not 100% sure whether that last word shouldn't be accessed via the > unw_word_t type though, as that's how it's accessed when the value is read > back again. > > Ben > > > > On Fri, 30 Jun 2017 06:08:18 +0100, Doug Moore <do...@rice.edu > <mailto:do...@rice.edu>> wrote: > >> I didn't invent the single_fde field, but I wonder is it was intended to be >> set in a case where the linear search failed and no unwind info was >> obtained. So, I wonder if this patch >> >> --- a/src/dwarf/Gfind_proc_info-lsb.c >> +++ b/src/dwarf/Gfind_proc_info-lsb.c >> @@ -618,12 +618,13 @@ dwarf_callback (struct dl_phdr_info *info, size_t >> size, void *ptr) >> >> /* XXX we know how to build a local binary search table for >> .debug_frame, so we could do that here too. */ >> - cb_data->single_fde = 1; >> found = linear_search (unw_local_addr_space, ip, >> eh_frame_start, eh_frame_end, fde_count, >> pi, need_unwind_info, NULL); >> if (found != 1) >> found = 0; >> + else >> + cb_data->single_fde = 1; >> } >> else >> { >> >> addresses the problem, while being consistent with the greater purpose of >> single_fde. >> >> Doug Moore >> >> >> >> Quoting libunwind-devel-requ...@nongnu.org: >> >>> Send Libunwind-devel mailing list submissions to >>> libunwind-devel@nongnu.org >>> >>> To subscribe or unsubscribe via the World Wide Web, visit >>> https://lists.nongnu.org/mailman/listinfo/libunwind-devel >>> or, via email, send a message with subject or body 'help' to >>> libunwind-devel-requ...@nongnu.org >>> >>> You can reach the person managing the list at >>> libunwind-devel-ow...@nongnu.org >>> >>> When replying, please edit your Subject line so it is more specific >>> than "Re: Contents of Libunwind-devel digest..." >>> >>> >>> Today's Topics: >>> >>> 1. Help please with debugging DWARF unwinding on ARM (Ben Avison) >>> >>> >>> ---------------------------------------------------------------------- >>> >>> Message: 1 >>> Date: Thu, 29 Jun 2017 01:56:06 +0100 >>> From: "Ben Avison" <bavi...@riscosopen.org> >>> To: libunwind-devel@nongnu.org >>> Subject: [Libunwind-devel] Help please with debugging DWARF unwinding >>> on ARM >>> Message-ID: <op.y2kkvsell0n...@amoe.lan> >>> Content-Type: text/plain; charset=iso-8859-15; format=flowed; >>> delsp=yes >>> >>> Hi all, >>> >>> First a quick typo to report: at src/dwarf/Gparser.c:281, the memcpy() >>> statement is lacking a trailing semicolon - this doesn't become apparent >>> until you enable debugging. >>> >>> I have previously used libunwind successfully as the backend for >>> gperftools, however I just get segfaults with the latest version. >>> >>> Some background: I'm running on ARM, and I configure libunwind with >>> --enable-debug-frame then run the executable with UNW_ARM_UNWIND_METHOD=1 >>> to force DWARF unwinding. >>> >>> The revision in git which introduced the bug is 25413c7 (dwarf: Improve >>> support for binaries missing the GNU_EH_FRAME segment). >>> >>> Ultimately, the segfault is triggered at the end of fetch_proc_info() where >>> c->pi is uninitialised when it tried to dereference it. However, I'm having >>> a hard time understanding the code well enough to know how to ensure it is >>> initialised correctly. >>> >>> Gperftools always starts skipping through the call stack from an initial >>> cursor position set up by unw_init_local(). The very first call to >>> unw_step() is the one that fails. >>> >>> If I back out the changes from that git revision, the pi struct is >>> initialised towards the end of dwarf_extract_proc_info_from_fde(), which is >>> called from dwarf_search_unwind_table(), in the second such call from >>> dwarf_find_proc_info(). >>> >>> But using the head of git, dwarf_find_proc_info() exits early because >>> cb_data.single_fde is set, so it never calls dwarf_search_unwind_table(). >>> single_fde is only set in one place, in dwarf_callback() - in a bit of code >>> that was never previously called when no .eh_frame_hdr section is found >>> (which appears to be true in my case). However, if single_fde is set then >>> control flow has unavoidably also passed through linear_search(), which >>> also calls dwarf_extract_proc_info_from_fde(). >>> >>> It appears to me that the problem is that sometimes, the first time >>> dwarf_extract_proc_info_from_fde() is called for a given pi struct, it is >>> called with need_unwind_info=0, but then dwarf_find_proc_info() is later >>> called with need_unwind_info=1 but due to single_fde being set, we never >>> get the pi struct initialised by anyone. >>> >>> It's possible I've got the wrong end of the stick here, but I'm also far >>> from sure what the best way to fix this is. Any advice gratefully received! >>> Please bear in mind I have rather limited working knowledge of the DWARF >>> spec. >>> >>> Thanks in advance, >>> Ben >>> >>> >>> >>> ------------------------------ >>> >>> Subject: Digest Footer >>> >>> _______________________________________________ >>> Libunwind-devel mailing list >>> Libunwind-devel@nongnu.org >>> https://lists.nongnu.org/mailman/listinfo/libunwind-devel >>> >>> >>> ------------------------------ >>> >>> End of Libunwind-devel Digest, Vol 124, Issue 11 >>> ************************************************ >>> >> >> >> >> >> _______________________________________________ >> Libunwind-devel mailing list >> Libunwind-devel@nongnu.org <mailto:Libunwind-devel@nongnu.org> >> https://lists.nongnu.org/mailman/listinfo/libunwind-devel >> <https://lists.nongnu.org/mailman/listinfo/libunwind-devel> > > !DSPAM:10223,595678b5326342783720507!
_______________________________________________ Libunwind-devel mailing list Libunwind-devel@nongnu.org https://lists.nongnu.org/mailman/listinfo/libunwind-devel