Unfortunately, exception handling in LLVM is a bit of a mess with
several “secret” handshakes in play that’s not well-documented in
general. I myself am not the most well-versed in this topic, but let me
provide what information again.
The basic structure of exception handling is described in the Itanium
C++ ABI [1] here: C++ ABI for Itanium: Exception Handling.
There are several slightly different variations (e.g., ARM C++ exception
handling is different), but the core idea is essentially this:
- There’s a core, effectively OS-provided, library for unwinding the
stack with an “exception object” (this is the_Unwind_RaiseException
function). This function knows how to do the necessary stack walking for
the target in question. - That library relies on the existence of a function, provided by the
language support library, to work out what needs to be done based on the
kind of exception being thrown. This function is the “personality function.” - The personality function will essentially look in a table to map the
return address and the “type” of exception to the action that needs to
be done (return to this stack frame, potentially after tweaking
registers somewhat, or continue unwinding).
As you can see, there’s essentially some amount of secret handshake
going on, with LLVM needing to generate a special exception-handling
table, the format of which is largely dictated by the personality
function, although most of them are in practice basically the same as
the one used by __gxx_personality_v0 (I don’t know the degree to which
LLVM supports unknown personality functions).
The way LLVM handles Itanium-style exception handling is to use the
landingpad to define essentially what the entry in the special lookup
table should look like, and the result of the instruction itself is the
registers set up by the personality function before returning control to
(the exceptional return address of) the function. It’s probably best to
look at how Clang actually generates the LLVM code to get an
understanding of what code looks like: Compiler Explorer
(I’ve disabled demangling so that you don’t get confused as to what the
output looks like, given that the _ZTI* names all demangle as “typeinfo
for xyz”).
For the standard __gxx_personality_v0, the first return value is the
_Unwind_Exception * object passed into _Unwind_RaiseException (which
is not the same as the address of the object being thrown!), and the
second return value is the type index of the handler.
As for the values you should fill in into the catch lines of the
landingpad… that’s part of the secret handshake between you and your
personality function!
[1] Despite its name, the Itanium ABI is the C++ ABI that is common
essentially for every platform except compiling with MSVC.