Since it seems to me that some interesting optimizations are held back
by not having out-of-band unwind info, I started looking into the
x86-64 ABI-standard unwind info format: DWARF. It seems to me that
it's a good idea to generate unwind info in the standard platform way,
given that there is a standard. If this is made to work, in addition
to getting an unwinder for free, C++ and lisp exceptions may even be
able to interoperate. (e.g. throw a C++ exception, catch it in lisp,
As far as I can tell, the same unwind info format is actually used on
all gcc-supported platforms except ia64 and arm (and it seems like
it's pretty similar on those, just with some different details). And,
of course, windows will as usual have to be done some completely
So, I've made a (pretty rough) proof of concept for generating the
unwind info. This proof of concept works on linux/x86-64.
* (load "t")
Now, first, asking for a backtrace from glibc's "backtrace" function
shows only the topmost frame (this address is in the function "glibc-
backtrace"). How sad. I'd really like it to go further.
So, I register some DWARF3 unwind-info I wrote for the glibc-backtrace
function, by calling:
The unwind-info I created is pretty much totally bogus, and doesn't
describe anything like the actual stack/register layout of the
function. However, it does describe the location of the return address
at the point at which a call to glibc's backtrace function occurs. So,
it sufficies for this demo.
Now, if I get a backtrace again:
TA-DA! It shows another frame.
Now, that's all well and good, but I've really only done the easy
part. There's some things left to do:
1) Teach the compiler how to generate the unwind info. This should be
such a piece of cake, it hardly deserves further mention. *grin*
2) Figure out how to work around the problem of the unwind-info
registry not being able to handle large numbers of registrations.
The problem here is that the lookup function does a linear search over
each __register_frame registration. So, the more registrations, the
slower an unwind will become. However, each registration can contain
an unlimited number of Frame Description Entries. And *those* are
searched with a binary search.
So, one trick is to combine multiple functions's FDEs into one
registration. (that's how this system is designed to work: each shared
library is one registration containing a bunch of FDEs). But there's a
few issues I can see with actually accomplishing that. First off,
registrations cannot overlap. So, to do one registration containing
FDEs for a bunch of functions, those functions' code really must be
contiguous (or else you can never put other functions between them).
And then, what about if a function's code moves (or is GC'd away).
Presumably you'd want to call __deregister_frame before moving it, and
__register_frame afterwards. But if one registration is shared amongst
many functions, you can't deregister one without deregistering them
all. And calling __[de]register_frame at all at GC time seems iffy,
due to a mutex used in both lookup and registration. Ugh.
Alternatively, SBCL could override the _Unwind_Find_FDE function to
provide its own lookup mechanism. This seems like it'd probably work,
at least for linux/ELF, where an app can override symbols in a shared
Whatever solution is found, it's probably a good idea to bring up the
issue of registering unwind info for dynamically generated functions
on the gcc mailing list, to get this fixed in a better way for future
3) Modify SBCL to take advantage of having out-of-band unwind info
available. E.g. improve the calling convention, make unwind-protect
free in the no-throw case, etc. It might also be possible to make the
GC fully precise (although you'd want to be careful that a foreign
function without unwind-info (and thus causing an unwind failure)
doesn't cause the values on the stack to be ignored).
Anyhow, it does seem to me as if this could work. Unfortunately, I
don't have the time to push this beyond proof of concept stage. Anyone
else interested in running with this?