This is the mail archive of the archer@sourceware.org mailing list for the Archer 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: C++ exceptions catching through GDB-patched .eh_frame


Jan Kratochvil wrote:
Hi Phil,



Hi Jan,

Thanks for the prompt note following on from the call. I found it thorough and a thoughtful email. Just as a note on the branches ....


the branches discussed are:
archer-pmuldoon-exception-rewind Recover from fatal signals delivered via C++ exceptions in an inferior
function call


... this branch is completed, with a test-case and a review. I've no plans to work on it further at the moment. (And reading down your email, the eh_frame approach won't work here anyway). The following branch ...


archer-pmuldoon-next-over-throw
Teach GDB to stop correctly after using a "next" over a throw
statement


This is my current development branch addressing "next over throw". This branch is very unstable, subject to the whims of my git pushes. What you see here might be entirely different tomorrow ;)


Found out now (again; forgot in the call) .eh_frame for
archer-pmuldoon-exception-rewind as I recommended in the call in fact does not
help at all because:

(1) I assumed during an inferior call the unwinder will jump into a catch()
handler registered even above the dummy frame (the point where the
inferior call was started). This is not true, unwinder always stops at
the dummy frame and does not continue the unwinding (calls
std::terminate() there).

Yeah, the dummy frame dismantles the unwinder's approach to finding the exception handler. It only looks in the dummy frame, and nowhere else (it can't look anywhere else as GDB has tinkered with the call stack).


(2) std::terminate() is a public function (no debuginfo needed):
$ nm -C --dynamic /usr/lib64/libstdc++.so.6|grep std::terminate
00000034ddac3d00 T std::terminate()

Agreed, this in fact is where the momentary breakpoint is set now.


(3) The method using .eh_frame is a bit complicated that while the .eh_frame
    approach I find more clean the .eh_frame handling can bring more runtime
    difficulties.



Yeah, I'd basically concluded the same, and I felt the breakpoint approach was simpler and (just) enough to fix the problem. It's good to get peer review on all aspects and approaches to the solution, so I am glad we considered it anyway.

Anyway onto the current problem...

But for solving the archer-pmuldoon-next-over-throw problem is some .eh_frame
based solution IMO the only way out.  Some clear facts:

(1) GDB cannot alter the the stack pointer and/or stack content in any way
before PTRACE_CONTing the inferior as it could alter the inferior
behavior.


I did not know that, good to know.

(2) Altering the return address from the current function (where the user
    typed "next") is no help as we can be in a try { } block existing already
    in the current function.  catch { } block in the current function would
    catch the exception thrown somewhere during the execution and GDB would
    lost the control.

(3) GDB cannot alter the return address to the current function as just it is
    created already when the inferior is left running.



Yes agreed here. The breakpoint approach I was pursuing in this problem was to figure out the where the unwinder was going to install the context in Unwind_RaiseException. This is passed to uw_install_context. If one could peek in that Unwind_Context structure before it is passed to uw_install_context one could theoretically "know" where to set the breakpoint to catch the inferior post context change. But as I said on the call, this seems more and more fragile.

.eh_frame section is like .debug_frame section but it has partially different
format (the format is IMO best described by checking the GDB parser
differences against the DWARF-documented .debug_frame format).  .eh_frame is
present in each C++ program even if no debuginfos are installed as .eh_frame
is required for the runtime C++ exceptions unwinding.  One can check the
.eh_frame content using `readelf -Wwf'.  We are interested in `Augmentation:
"...P..."' for the `personality' address (which is contained in `Augmentation
data:' there but this part is not decoded by `readelf').


GDB can find .eh_frame associated with the current function (where "next" is being run) - it even already has an existing infrastructure for it as it can unwind frames using .eh_frame (when no .debug_frame is available). There always exists such .eh_frame for any called function/library in a C++ program. And GDB can patch in the `personality' function into this .eh_frame to trap any attempt to call even a catch { } block located in the current function for the current try { } block we may be in. It will need to put the 'P' character into the Augmentation string of the CIE associated with the FDE for the current function and also put some address with a GDB breakpoint at the right position of the Augmentation data at that CIE.

Unfortunately GDB would have to patch the existing in-memory .eh_frame as
registering a new one using inferior call of __register_frame_info() would
have no effect as the existing .eh_frame would be preferred by
gcc/unwind-dw2-fde.c _Unwind_Find_FDE() (`seen_objects' is preferred over
`unseen_objects').

Another problem are recursive functions - if the current function is later
called again, the unwinding trap there should happen for the toplevel function
call.  But this is already being solved during "next" for the placed
breakpoint so this handling needs to be extended even for .eh_frame.


I've read this and I'm pursuing the .eh_frame unwinding code in GDB. Thanks for the pointers. I'll reply back when I have more information.


Regards

Phil


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