No worries. I actually want to apologize for my tone in that email; looking back, it feels over-the-top and rude. I’m sorry about that. You’d asked for my opinion in an area where I have a lot of expertise, which is supposed to be a reasonable thing to do.
If I remember correctly, ARM actually documents their C++ LSDA layout, but that’s really just ARM indulging their habit of over-documenting stuff.
The key point here is to understand the designed separation between the C++ ABI, libUnwind, and the C++ runtime. It’s easy to conflate them; the first two were really designed together, and in fact are specified together, and the compiler has to know about several different parts simultaneously.
It’s best to think of libUnwind (the “base exceptions ABI”, in the Itanium ABI’s terminology) as being its own, independent thing. It’s deliberately designed to be language-independent, even to the point of supporting exception mechanisms (continuable exceptions) that AFAIK aren’t needed by any of the languages they were directly trying to support (C++, Ada). libUnwind dictates some things as platform ABI, but only what it absolutely needs:
- the process through which EH tables are found at all,
- the CFI header on the EH tables, which includes basic information on how to unwind and where to find the personality function,
- the basic structure of a language-independent exception object, and
- the basic runtime interface to the unwind library.
Itanium then adds only a pretty small amount of extra, C+±specific ABI to this:
- some additional structure of C++ exception objects and
- some additional runtime functions which wrap libUnwind and track whether an exception is currently unwinding (for the purposes of std::uncaught_exception()).
Crucially, Itanium doesn’t describe the language-specific area of C++ EH tables. Now, this is a part of the ABI document that’s sometimes just incomplete, but in this case, I’m fairly certain that not specifying the layout is intentional. The ABI specifies the additional structure of C++ exception objects, with the intent that that should be sufficient for an arbitrary personality function to correctly recognize and handle a C++ exception, which is important for language interoperation. I think the Itanium committee was more concerned about Ada/C++ interop, but to use an example closer to my heart: consider the Objective-C personality function, which is used even in Objective-C++ modes and must therefore allow both Objective-C and C++ exceptions to be caught.
The C++ runtime library then just implements those functions. libsupc++ / libc++abi also provide a default personality function, which then implies a particular LSDA layout; we decided to use the same LSDA layout as libsupc++ when implementing libc++abi because it simplified deployment and didn’t require additional compiler support. But there’s no reason that you couldn’t have multiple “competing” C++ personality functions, because there’s not supposed to be a private contract between the C++ runtime and its personality function; that would preclude other languages from compatibly working with C++ exception objects.
The only things preventing us from using a new personality function for clang are:
- deployment issues; the new function wouldn’t be guaranteed to exist in the C++ library, so we’d either need to provide it in compiler-rt or restrict it by deployment target, and
- the usual small issues of finding time to design and implement a new LSDA layout.