This is the mail archive of the 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

On Mon, 15 Dec 2008 15:43:09 +0100, Daniel Jacobowitz wrote:
> On Sun, Dec 14, 2008 at 01:23:59PM +0100, Mark Wielaard wrote:
> > Another complication might be that if the CIE doesn't yet have a
> > personality routine, you will need to modify the augmentation string and
> > adjust the augmentation data length. If so, you will have to move stuff
> > around to extend the actual augmentation data, which is probably too
> > much work because that means adjusting almost everything in
> > the .eh_frame data. This might be a non-issue if for c++ there always is
> > a personality routine registered already (then you just patch it and
> > store a lookup table somewhere to map the original address), but I
> > didn't actually look if it has or hasn't.
> I've got to say I'm nervous about all this talk of patching CIEs.
> Thread safety is going to be very difficult to preserve in that case.
> Can't we set breakpoints on the involved personality routines
> instead?

As I found out now as I knew only the .eh_frame basics before:

(1) Personality routine (augmentation 'P') is set (probably) in all the cases
    GDB needs it.  (I assumed the reverse before according to a wrong check.)

(2) The personality routine is always `__gxx_personality_v0' (by PLT).
    Trapping it would mean overhead for any exception thrown, even those GDB
    is not interested in (as caught below the current frame).
    (I naively assumed it is already the specific catch { } handler.)

(3) The specific catch { } handler is found by __gxx_personality_v0 through
    an LSDA (language specific data area) found from the augmentation data
    of a specific FDE, LSDA area pointer can be NULL.
    For the attached sample code:
    readelf -Wwf:
    00000000 0000001c 00000000 CIE
      Version:               1
      Augmentation:          "zPLR"
      Augmentation data:     03 20 07 40 00 03 03 = __gxx_personality_v0@plt
    00000038 00000014 0000003c FDE cie=00000000 pc=00400860..00400877 = mid()
      Augmentation data:     00 00 00 00
    00000050 0000001c 00000054 FDE cie=00000000 pc=00400880..004008cd = main()
      Augmentation data:     dc 0a 40 00 = LSDA for main()

    One needs to parse the LSDA and find out landing_pad there.
    Some doc found:
    Producer dw2_output_call_site_table() at `gcc/except.c'.

If user does `next' at line 12 - function mid() - in the attached sample code,
the unwinder will call the catch { } handler from main().

So the optimal way is to place the breakpoint at LSDA of the "current frame".
Expecting in the sample code GDB cannot just place a breakpoint at main()'s
cleanup handler as the frame of mid() would be already unwound/lost that time.

Therefore GDB must trap the unwinding at mid() and therefore to create LSDA and
possible landing_pad for the "current frame" (for mid()) if those are missing.

It may look simpler to catch any exception being thrown (like __cxa_throw@plt
or _Unwind_RaiseException) but on the other hand GDB will need to properly
analyse and possibly rethrow the exceptions it is not interesting in (=being
caught lower than the current frame).  By properly creating and/or patching
LSDAs this selection of exceptions is done automatically.

#include <stdio.h>
func ()
  throw 42;

mid ()
  func ();		/* line 12 */
  puts ("mid passed");

  setbuf (stdout, NULL);

      mid ();		/* line 23 */
      puts ("passed");	/* line 24 */
  catch (...)
      puts ("caught");
  return 0;

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