[LLVMdev] One way to support unwind on x86
baldrick at free.fr
Tue Mar 3 03:26:24 CST 2009
> * Provide an efficient runtime implementation that does not
> depend on reading the DWARF EH information.
why? The DWARF EH info encodes two things: (1) how to restore
registers; and (2) matching rules for exception objects, and
what to do with them. You will need something along the lines
of (1) if you unwind out of the middle of functions. As for (2),
if you don't do any matching of exceptions against types, this is
an extremely minimal amount of info. In any case, it is entirely
up to the personality function what happens here - you can always
write your own. Check out the C personality function (yes, C not
C++!) in gcc/unwind-c.c to get an idea of what a small personality
function looks like.
> * It should be self hosted, meaning the runtime is static
> linked in. I want to use it kernel mode.
You can link statically with libgcc.
> * Unwinding should be a read-only operation regarding the
> stack, so I can create a stack dump in the landing pad.
You can get stack dumps with gcc dwarf eh. The Ada front-end
does this for example - very convenient.
> * Provide a pass that raises C++ exception handling to just
> unwind instructions and thread-local data.
Take a look at libunwind (http://www.hpl.hp.com/research/linux/libunwind/).
Another possibility, very close you yours and currently used by the vmkit
project, is to modify all functions so they return two values, the usual
return value and an additional boolean value indicating whether an exception
was thrown during the call or not. Callers then branch to an appropriate
place based on this value. Thus there is no special stack unwinding, it
is just functions returning. This adds some distributed overhead, but
unwinding is fast. You can always return something more complicated than
a boolean of course.
> My idea on handling the DWARF EH actions is to compile it to machine
> instructions. Fx. given an Instruction Pointer, unwinding a call frame
> might be described as:
> add esp, 12 ; Remove the current call frame.
> jmp unwind ; Continue the unwinding process.
This is a lot like what you get using the "function returns an extra
> Other call frames might be more complex to handle. It depends on the
> moves needed to restore the registers of the previous call frame (the
> caller) and to remove the current frame.
If you really plan to unwind out of the middle of functions you will
have to do magic to restore registers. Do you plan to use the dwarf
frame moves info for this? If you use the "functions return an
extra boolean" method then you don't have to do anything, since
functions return and have registers restored in the usual way.
> I want to tag all calls and invokes in a manner that can be easily
> recognized by a runtime. I can tolerate a small overhead on calls. The
> idea is to do something like this:
> call some_function
> jmp continue
> jmp case_of_unwinding
This again looks a lot like the "have functions return an extra boolean"
> The case-of-unwinding will either unwind the current call frame or
> jump to the landing pad (if it was an invoke instruction). I think the
> overhead will in fact be quite small because of branch prediction on
> modern processors. The size overhead by tagging all calls, compared to
> only tagging unwind areas and actions in DWARF, does not matter much
> to me.
The vmkit experience is that unwinding using their method is a lot faster
than using the dwarf unwinder. I don't know if the distributed overhead
is noticeable or not.
More information about the LLVMdev