[LLVMdev] RFC: New EH representation for MSVC compatibility

Reid Kleckner
Mon, 18 May 2015 22:11:29 -0000

On Mon, May 18, 2015 at 2:42 PM, Steve Cheng <steve.ckp at gmail.com>
wrote:

> Hi Reid,
>
>  Right, __CxxFrameHandler3 is a lot more constraining than
>> __C_specific_handler. The SEH personality doesn't let you rethrow
>> exceptions, so once you catch the exception you're done, you're
in the
>> parent function. My understanding is that C++ works by having an active
>> catch handler on the stack.
>>
>
> Okay, I checked the Wine source code for __CxxFrameHandler3. I stand
> corrected.
>
> While we are on the topic of Windows EH, I like to know your (and
others',
> of course) thoughts on the following. It's my wishlist as a frontend
> implementor :)
>
> - Win32 (x86) frame-based SEH
>
> For __CxxFrameHandler3, since destructors and catch blocks execute as
> funclets while the throwing function's stack frame is still active,
it's
> not going to be a problem right?
>

My understanding is that __CxxFrameHandler3 does something like the
following:

for (void (*Cleanup)(bool, void*) : Cleanups) {
  __try {
    Cleanup(/*AbnormalTermination=*/true, EstablisherFrame);
  } __except(1) {
    std::terminate(); // can't rethrow
  }
}
__try {
  CallCatchBlock();
} __except(__CxxDetectRethrow(), EXCEPTION_CONTINUE_SEARCH) {
}

So I guess it's not really that the catch block has an active frame, and
more that __CxxFrameHandler3 is there saying "hey, I saw a rethrow
exception go by during phase 1, here's what that exception was supposed to
be".

But for __C_specific_handler, I see a potential issue versus x86-64,
in
> that RtlUnwind can't restore non-volatile registers, so when registers
are
> garbage when control is transferred to the landing pad.  When I read the
> Itanium ABI documentation, it says that landing pads do get non-volatile
> registers restored, so I guess that's probably the working assumption
of
> LLVM.
>

That's pretty frustrating, given that the xdata unwinder already knows
where the non-volatile registers are saved. Anyway, I think it can be
overcome in the backend with the right register allocation constraints.


> __C_specific_handler's registration frame saves down EBP, but no other
> registers, even ESP. If we use dynamic alloca or frame pointer omission, we
> are dead in the water, right?
>

Are you sure the unwinder doesn't restore RSP? Anyway, the address of a
dynamic alloca can easily be spilled to the stack and reloaded.


> - Writing one's own personality functions
>
> This makes a lot of sense if one is implementing a different language than
> C++ that has exceptions, and is prepared to provide their own run-time
> support.
>
> Say, if the language supports resuming from exceptions, or can query type
> information in more flexible ways than C++'s std::type_info matching.
Does
> it really make sense for the backend, LLVM, to hard-code knowledge about
> the language-specific data area (LSDA)? Even in the Itanium ABI it's
> explicitly stated that the personality is specific to the source language,
> yet multiple personalities can interoperate in the same program. Ideally, I
> would prefer the backend to take control of everything to do with arranging
> the landing pads, branches within landing pads, and so on, but NOT the
> language-dependent exception matching.
>
> Taken to the extreme, LLVM would have to expose tables that the LLVM
> client would have to translate to their own formats, like the garbage
> collection "unwind" tables. If that's too complicated at
least it would be
> nice to supply custom filter functions for catch clauses. Inspired by SEH
> filters obviously, but we might devise a slightly more portable version.
>

I think LLVM has to know about the table format and landingpad PC values,
because that's its business. The RTTI data, though, is completely between
the frontend and the EH personality. I could imagine a personality that
uses an Itanium LSDA, but the RTTI pointers are really pointers to
functions that get called during phase 1 to implement SEH filters. The new
representation will actually allow you to pass more data here to support
passing in "adjectives" as required for MSVC, but LLVM will have to
know
where to put it in the table and there's no way to avoid that.


> Even for C++ I actually wouldn't mind being able to arbitrarily replace
> the personality, and/or the runtime functions for throwing and resuming. In
> my C++ source code I always throw exceptions wrapped in a macro, because I
> want to instrument all my throw statements. In particular, I can construct
> a reliable stack trace on the spot with RtlVirtualUnwind (or walking the
> EBP chain on x86). It would be a nice bonus if we could implement this kind
> of instrumentation with Clang. Encouragement to switch from MSVC :)
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://lists.llvm.org/pipermail/llvm-dev/attachments/20150518/4088f1e0/attachment.html>