Posts for 2013 April

Tip to migrate from VMWare to VirtualBox

Post by Nico Brailovsky @ 2013-04-30 | Permalink | Leave a comment

Some times (most times?) migrating from VMWare to VirtualBox can get quite complicated. Mounting a disk from one into the other nowadays usualy works but network stuff seems to break more often than not.

Here's a little tip for those times when you are trying to get the network for a VMW image working in VBox: try using the third network adapter, that seems to be the same PCI address VMWare uses (in my machine... results might vary).


C++ exceptions under the hood 13: setting the context for a landing pad

Post by Nico Brailovsky @ 2013-04-25 | Permalink | Leave a comment

Last time we finally wrote an almost working personality function. We can detect for each stack frame which landing pads are available and then tell _Unwind_ we want to run a specific landing pad. We hit a small issue, though: although we set the context for _Unwind_ to continue executing on the correct landing pad we didn't set the current exception on the register. This, in turn, means that the landing pad won't know which exception should be handling, so it will say "I can't handle this". _Unwind_ will then say "please try the next landing pad" but our ABI is so simple that it has no idea how it should find another landing pad and just tries the same. Over and over again. We have probably invented the most contrived example for a while(true)!

Let's set the correct context for the landing pad and clean up a bit our ABI:

#include 
#include 
#include 
#include 
namespace __cxxabiv1 {
    struct __class_type_info {
        virtual void foo() {}
    } ti;
}
#define EXCEPTION_BUFF_SIZE 255
char exception_buff[EXCEPTION_BUFF_SIZE];
extern "C" {
void __cxa_allocate_exception(size_t thrown_size)
{
    printf("alloc ex %i\n", thrown_size);
    if (thrown_size > EXCEPTION_BUFF_SIZE) printf("Exception too big");
    return &exception_buff;
}
void __cxa_free_exception(void thrown_exception);
#include 
typedef void (unexpected_handler)(void);
typedef void (terminate_handler)(void);
struct __cxa_exception {
    std::type_info *    exceptionType;
    void (exceptionDestructor) (void );
    unexpected_handler  unexpectedHandler;
    terminate_handler   terminateHandler;
    __cxa_exception *   nextException;
    int         handlerCount;
    int         handlerSwitchValue;
    const char *        actionRecord;
    const char *        languageSpecificData;
    void *          catchTemp;
    void *          adjustedPtr;
    _Unwind_Exception   unwindHeader;
};
void __cxa_throw(void thrown_exception,
                 struct type_info tinfo,
                 void (dest)(void))
{
    printf("__cxa_throw called\n");
    __cxa_exception header = ((__cxa_exception ) thrown_exception - 1);
    _Unwind_RaiseException(&header->unwindHeader);
    // __cxa_throw never returns
    printf("no one handled __cxa_throw, terminate!\n");
    exit(0);
}
void __cxa_begin_catch()
{
    printf("begin FTW\n");
}
void __cxa_end_catch()
{
    printf("end FTW\n");
}
/**********/
/
 * The LSDA is a read only place in memory; we'll create a typedef for
 * this to avoid a const mess later on; LSDA_ptr refers to readonly and
 * &LSDA_ptr will be a non-const pointer to a const place in memory
 /
typedef const uint8_t LSDA_ptr;
struct LSDA_Header {
    /
     * Read the LSDA table into a struct; advances the lsda pointer
     * as many bytes as read
     /
    LSDA_Header(LSDA_ptr lsda) {
        LSDA_ptr read_ptr = lsda;
        // Copy the LSDA fields
        start_encoding = read_ptr[0];
        type_encoding = read_ptr[1];
        ttype = read_ptr[2];
        // Advance the lsda pointer
        lsda = read_ptr + sizeof(LSDA_Header);
    }
    uint8_t start_encoding;
    uint8_t type_encoding;
    uint8_t ttype;
};
struct LSDA_CS_Header {
    // Same as other LSDA constructors
    LSDA_CS_Header(LSDA_ptr lsda) {
        LSDA_ptr read_ptr = lsda;
        encoding = read_ptr[0];
        length = read_ptr[1];
        lsda = read_ptr + sizeof(LSDA_CS_Header);
    }
    uint8_t encoding;
    uint8_t length;
};
struct LSDA_CS {
    // Same as other LSDA constructors
    LSDA_CS(LSDA_ptr lsda) {
        LSDA_ptr read_ptr = lsda;
        start = read_ptr[0];
        len = read_ptr[1];
        lp = read_ptr[2];
        action = read_ptr[3];
        lsda = read_ptr + sizeof(LSDA_CS);
    }
    // Note start, len and lp would be void's, but they are actually relative
    // addresses: start and lp are relative to the start of the function, len
    // is relative to start
    // Offset into function from which we could handle a throw
    uint8_t start;
    // Length of the block that might throw
    uint8_t len;
    // Landing pad
    uint8_t lp;
    // Offset into action table + 1 (0 means no action)
    // Used to run destructors
    uint8_t action;
};
/**********/
_Unwind_Reason_Code __gxx_personality_v0 (
                             int version,
                             _Unwind_Action actions,
                             uint64_t exceptionClass,
                             _Unwind_Exception unwind_exception,
                             _Unwind_Context context)
{
    if (actions & _UA_SEARCH_PHASE)
    {
        printf("Personality function, lookup phase\n");
        return _URC_HANDLER_FOUND;
    } else if (actions & _UA_CLEANUP_PHASE) {
        printf("Personality function, cleanup\n");
        // Pointer to the beginning of the raw LSDA
        LSDA_ptr lsda = (uint8_t)_Unwind_GetLanguageSpecificData(context);
        // Read LSDA headerfor the LSDA
        LSDA_Header header(&lsda);
        // Read the LSDA CS header
        LSDA_CS_Header cs_header(&lsda);
        // Calculate where the end of the LSDA CS table is
        const LSDA_ptr lsda_cs_table_end = lsda + cs_header.length;
        // Loop through each entry in the CS table
        while (lsda < lsda_cs_table_end)
        {
            LSDA_CS cs(&lsda);
            if (cs.lp)
            {
                int r0 = __builtin_eh_return_data_regno(0);
                int r1 = __builtin_eh_return_data_regno(1);
                _Unwind_SetGR(context, r0, (uintptr_t)(unwind_exception));
                // Note the following code hardcodes the exception type;
                // we'll fix that later on
                _Unwind_SetGR(context, r1, (uintptr_t)(1));
                uintptr_t func_start = _Unwind_GetRegionStart(context);
                _Unwind_SetIP(context, func_start + cs.lp);
                break;
            }
        }
        return _URC_INSTALL_CONTEXT;
    } else {
        printf("Personality function, error\n");
        return _URC_FATAL_PHASE1_ERROR;
    }
}
}

Note: For a more detailed description of the LSDA tables check here and for the full source code check my github repo.

Finally, it worked. You should see something like this if you run it:

./app
alloc ex 1
__cxa_throw called
Personality function, lookup phase
Personality function, cleanup
begin FTW
Caught a Fake_Exception!
end FTW
try_but_dont_catch handled the exception
catchit handled the exception

Of course we are lying a bit to _Unwind_: we are saying here that we will handle every exception, no mater what. This turns our catch(Exception&) into a catch(...), and all hell will break loose if the first function up in the call frame doesn't have a catch statement. But still, we reached the first milestone for a very simple ABI.

Can we now improve it and make it handle the correct exception on the correct frame? May be next time.


C++ exceptions under the hood 14: multiple landing pads & the teachings of the guru

Post by Nico Brailovsky @ 2013-04-23 | Permalink | Leave a comment

After a lot of hard work, last time we finally got a working personality function capable of handling exceptions without help of libstdc++. It will indiscriminately handle all exceptions, but it does work. There is a big question we haven't answered yet: if we go back to the LSDA (language specific data area) we'll see something like this:

.local_lsda_call_site_table:
    .uleb128 .LEHB0-.LFB1
    .uleb128 .LEHE0-.LEHB0
    .uleb128 .L8-.LFB1
    .uleb128 0x1
    .uleb128 .LEHB1-.LFB1
    .uleb128 .LEHE1-.LEHB1
    .uleb128 0
    .uleb128 0
  .uleb128 .LEHB2-.LFB1
    .uleb128 .LEHE2-.LEHB2
    .uleb128 .L9-.LFB1
    .uleb128 0
.local_lsda_call_site_table_end:

There are 3 landing pads defined there, even though we wrote a single try/catch statement. What is going on there?

If you read carefully the last entry on this topic maybe you noticed I added some comments to the definition of struct LSDA_CS:

struct LSDA_CS {
    // Note start, len and lp would be void*'s, but they are actually relative
    // addresses: start and lp are relative to the start of the function, len
    // is relative to start
    // Offset into function from which we could handle a throw
    uint8_t start;
    // Length of the block that might throw
    uint8_t len;
    // Landing pad
    uint8_t lp;
    // Offset into action table + 1 (0 means no action)
    // Used to run destructors
    uint8_t action;
};

Note: You can download the full sourcecode for this project in my github repo.

Something very interesting is going on here, but lets first analyze this struct field by field with the following example:

void foo() {
    L0:
        try {
            do_something();
    L1:
        } catch (const Exception1& ex) {
            ...
        } catch (const Exception2& ex) {
            ...
        } catch (const ExceptionN& ex) {
            ...
        } catch (...) {
        }
    L2:
}

The interesting fields now are start and len: in a function with multiple try/catch blocks we can know whether we should handle an exception by checking if the instruction pointer for the current frame is between start and start + len.

That solves the mystery of how a function with multiple try/catch blocks can handle an exception but we still have another question: why are there three call sites when we only specified a single landing pad? The other three are places where an exception might be thrown so they get added as a possible place for cleanup actions or landing pads. If we learned anything from GOTW it should be that exceptions can be thrown in the places we least expect. There is an entry in the call site table for our throw because it's a block that might throw; the compiler also detected another three.

Now that we know what the start and len fields do, let's change our personality function so the correct landing pad can handle the exception being thrown. Go ahead. My implementation for the next time.


Learning misspells: thanks Vim!

Post by Nico Brailovsky @ 2013-04-18 | Permalink | Leave a comment

I just noticed a very silly "pattern" I usually fall into: since I like vim (perhaps a bit too much) to work with text, even free-form text like this blog post, most of the times I type a lot of text which then must be spell checked (so far I haven't found a spell checking extension I like for vim). While spell checking I correct the original text in vim, and to do this I usually search for the mispel in Vim, thus typing the wrong spelling one more time. This has the side effect of reinforcing the bad spell instead of forcing me to type the correct spelling.

I wonder how can I fix this problem without a spellchecker for vim.


C++ exceptions under the hood 12: and suddenly, reflexion in C++

Post by Nico Brailovsky @ 2013-04-16 | Permalink | Leave a comment

We left our mini-ABI project (link) capable of throwing exceptions, and we are now working on catching them; we implemented a personality function last time which was capable of detecting and handling exceptions but it was still a bit incomplete: even though it can properly notify the stack unwinder when it should stop but our version of __gxx_personality_v0 can't run the code inside a catch block. We learned last time how to read the LSDA, so now it's only a problem of putting all the pieces together to read the .gcc_except_table from within our personality function.

Let's recap a bit: we figured out last time that our LSDA for the function which has the catch we want to run has the following call site table (that is, the following landing pads [that is, the following catch blocks]):

.local_lsda_call_site_table:
    .uleb128 .LEHB0-.LFB1
    .uleb128 .LEHE0-.LEHB0
    .uleb128 .L8-.LFB1
    .uleb128 0x1
    .uleb128 .LEHB1-.LFB1
    .uleb128 .LEHE1-.LEHB1
    .uleb128 0
    .uleb128 0
    .uleb128 .LEHB2-.LFB1
    .uleb128 .LEHE2-.LEHB2
    .uleb128 .L9-.LFB1
    .uleb128 0
.local_lsda_call_site_table_end:

All those labels can be mapped to different places in the assembly of our function, but it's a bit too messy for a blog post (I do recommend you to disassemble the function yourself and try to match each label, a lot can be learned from doing it). Also, thanks to some random Internet page, we learned the format for this table.

Let's do something like this to see if we're on the right track (beware of read-alignment issues and keep in mind that defining CFI structures like this will only work for uint8's and is probably not portable):

struct LSDA_Header {
    uint8_t lsda_start_encoding;
    uint8_t lsda_type_encoding;
    uint8_t lsda_call_site_table_length;
};
struct LSDA_Call_Site_Header {
    uint8_t encoding;
    uint8_t length;
};
struct LSDA_Call_Site {
    LSDA_Call_Site(const uint8_t ptr) {
        cs_start = ptr[0];
        cs_len = ptr[1];
        cs_lp = ptr[2];
        cs_action = ptr[3];
    }
    uint8_t cs_start;
    uint8_t cs_len;
    uint8_t cs_lp;
    uint8_t cs_action;
};
_Unwind_Reason_Code __gxx_personality_v0 (
                     int version, _Unwind_Action actions, uint64_t exceptionClass,
                     _Unwind_Exception unwind_exception, _Unwind_Context context)
{
    if (actions & _UA_SEARCH_PHASE)
    {
        printf("Personality function, lookup phase\n");
        return _URC_HANDLER_FOUND;
    } else if (actions & _UA_CLEANUP_PHASE) {
        printf("Personality function, cleanup\n");
        const uint8_t lsda = (const uint8_t)
                                    _Unwind_GetLanguageSpecificData(context);
        LSDA_Header header = (LSDA_Header)(lsda);
        LSDA_Call_Site_Header cs_header = (LSDA_Call_Site_Header)
                                                (lsda + sizeof(LSDA_Header));
        size_t cs_in_table = cs_header->length / sizeof(LSDA_Call_Site);
        // We must declare cs_table_base as uint8, otherwise we risk an
        // unaligned access
        const uint8_t cs_table_base = lsda + sizeof(LSDA_Header)
                                            + sizeof(LSDA_Call_Site_Header);
        // Go through every entry on the call site table
        for (size_t i=0; i <: cs_in_table; ++i)
        {
            const uint8_t *offset = &cs_table_base[i * sizeof(LSDA_Call_Site)];
            LSDA_Call_Site cs(offset);
            printf("Found a CS:\n");
            printf("\tcs_start: %i\n", cs.cs_start);
            printf("\tcs_len: %i\n", cs.cs_len);
            printf("\tcs_lp: %i\n", cs.cs_lp);
            printf("\tcs_action: %i\n", cs.cs_action);
        }
        uintptr_t ip = _Unwind_GetIP(context);
        uintptr_t funcStart = _Unwind_GetRegionStart(context);
        uintptr_t ipOffset = ip - funcStart;
        return _URC_INSTALL_CONTEXT;
    } else {
        printf("Personality function, error\n");
        return _URC_FATAL_PHASE1_ERROR;
    }
}

Note: You can download the full sourcecode for this project in my github repo.

As you can see if you run this code, all entries in the call site table are relative. Relative to what? To the start of function. That means that if we want to get the EIP for a specific landing pad all we have to do is _Unwind_GetRegionStart + LSDA_Call_Site.cs_lp!

We should now be able to solve our exceptional problem: let's try to modify our personality function to run the correct landing pad. We'll now need to use another _Unwind_ function to specify where we want to resume execution: _Unwind_SetIP. Let's change the personality function again to run the first landing pad available, which by inspecting the assembly we already know is the one we want:

        ...
        const uint8_t cs_table_base = lsda + sizeof(LSDA_Header)
                                            + sizeof(LSDA_Call_Site_Header);
        for (size_t i=0; i <: cs_in_table; ++i)
        {
            const uint8_t offset = &cs_table_base[i * sizeof(LSDA_Call_Site)];
            LSDA_Call_Site cs(offset);
            if (cs.cs_lp)
            {
                uintptr_t func_start = _Unwind_GetRegionStart(context);
                _Unwind_SetIP(context, func_start + cs.cs_lp);
                break;
            }
        }
        return _URC_INSTALL_CONTEXT;

Try to run it, and watch a beautiful infinite loop. Can you guess what went wrong? The answer on the next article.


C++ exceptions under the hood 11: reading a CFI table

Post by Nico Brailovsky @ 2013-04-11 | Permalink | Leave a comment

To properly handle exceptions from within the personality function we've been implementing for our ABI, we need to read the LSDA (language specific data area) to know which call frame (ie which function) can handle which exception, and to know where a landing pad (catch block) can be found). The LSDA table is in CFI format, and we'll see in this chapter how to read it.

Reading the CFI data can be rather straight forward, but there are a few pitfalls we need to consider first. Two, actually: 1. There is very little documentation about the .gcc_except_table format (actually, I only found some mails about it) so we'll need to read a lot of source code and disassembles to understand it. 2. Although the format itself is not terribly complicated, it uses a LEB encoding that makes reading this table not quite straightforward.

As far as I know most DWARF data is encoded like this, using a LEB format, which seems to be great for confusing programmers and to save code space while encoding arbitrary length ints. Luckily, we can cheat a bit in here: most of the time the LEB encoded numbers will readble with a plain uint8_t, because we won't be dealing with large exception tables or anything like that.

Note: You can download the full sourcecode for this project in my github repo.

Let's start by analyzing the CFI data directly from the disassembly, we'll then see if we can build something to read it on our personality function. I'll rename the labels to make them a bit more human-friendly. The LSDA will have three sections, try to spot them below:

.local_frame_entry:
    .globl  __gxx_personality_v0
    .section    .gcc_except_table,"a",@progbits
    .align 4

This one is very easy: it's just a header to declare we're going to use __gxx_personality_v0 as a global and to let the linker know we're going to be declaring stuff for the .gcc_except_table section. Moving on:

.local_lsda_1:
    # This declares the encoding type. We don't care.
    .byte   0xff
    # This specifies the landing pads start; if zero, the func's ptr is
    # assumed (_Unwind_GetRegionStart)
    .byte   0
    # Length of the LSDA area: check that LLSDATT1 and LLSDATTD1 point to the
    # end and the beginning of the LSDA, respectively
    .uleb128 .local_lsda_end - .local_lsda_call_site_table_header

This now has some more info. Those labels are quite obscure but they do follow a pattern. LSDA means language specific data area, the L in front means local, so this is the local (to the translation unit, the .o file) language specific data area number one. Other labels follow similar patterns but I haven't taken the job of figuring them out. We don't really need to, anyway.

.local_lsda_call_site_table_header:
    # Encoding of items in the landing pad table. Again, we don't care.
    .byte   0x1.
    # The length of the call site table (ie the landing pads)
    .uleb128 .local_lsda_call_site_table_end - .local_lsda_call_site_table

Another boring header. Moving on:

.local_lsda_call_site_table:
    .uleb128 .LEHB0-.LFB1
    .uleb128 .LEHE0-.LEHB0
    .uleb128 .L8-.LFB1
    .uleb128 0x1
    .uleb128 .LEHB1-.LFB1
    .uleb128 .LEHE1-.LEHB1
    .uleb128 0
    .uleb128 0
    .uleb128 .LEHB2-.LFB1
    .uleb128 .LEHE2-.LEHB2
    .uleb128 .L9-.LFB1
    .uleb128 0
.local_lsda_call_site_table_end:

This is much more interesting, now we're seeing the call site table itself. Somehow, in all these entries, we should be able to find our landing pad. According to some random internet page, the format for each call site entry should be:

struct lsda_call_site_entry {
    // Start of the IP range
    size_t cs_start;
    // Length of the IP range
    size_t cs_len;
    // Landing pad address
    size_t cs_lp;
    // Offset into action table
    size_t cs_action;
};

So we seem to be on the right track, though we don't know yet why there are 3 call site entries when we only defined a single landing pad. In any case, we can cheat a little: by looking at the disassembly we can deduce that all the values on the CFI will be less than 128 and this means that in LEB encoding they can be read as plain uchars. This makes our CFI reading code so much easier, and we will see how to use it in our personality function next time.


C++ exceptions under the hood 10: Unwind and call frame info

Post by Nico Brailovsky @ 2013-04-09 | Permalink | Leave a comment

We left our mini-ABI project (link) capable of throwing exceptions, and we are now working on catching them; we implemented a personality function last time which was capable of detecting and handling exceptions but it was still a bit incomplete: even though it can properly notify the stack unwinder when it should stop but our version of __gxx_personality_v0 can't run the code inside a catch block. It's better than a coredump one might argue, but still a long way from a useful exception handling ABI. Can we improve it?

How can we tell _Unwind_ where is our landing pad, so we can execute the code inside the catch statement? If we go back to the ABI specification, there are a few context management functions which might help us:

Note: You can download the full sourcecode for this project in my github repo.

Let's check these functions with gdb. On my machine:

Breakpoint 1, __gxx_personality_v0 (version=1, actions=6, exceptionClass=134515400, unwind_exception=0x804a060, context=0xbffff0f0)
    at mycppabi.cpp:77
84          const uint8_t lsda = (const uint8_t)_Unwind_GetLanguageSpecificData(context);
85          uintptr_t ip = _Unwind_GetIP(context) - 1;
86          uintptr_t funcStart = _Unwind_GetRegionStart(context);
87          uintptr_t ipOffset = ip - funcStart;

If we inspect those variables we can see that indeed _Unwind_GetRegionStart points to the current stack frame (try_but_dont_catch) and that _Unwind_GetIP is the IP for the position where the call to the next stack frame was done. The _Unwind_GetRegionStart is pointing us to the place where the exception was first thrown; it's a bit complicated to explain and we'll use that later, not now. Also, we don't see the LSDA here, but we can deduce it's after the function's code since _Unwind_GetLanguageSpecificData points directly after the function's end:

_Unwind_GetIP = (void ) 0x804861d
_Unwind_GetRegionStart = (void ) 0x8048612
_Unwind_GetLanguageSpecificData = (void *) 0x8048e3c
function pointer to try_but_dont_catch = 0x8048612 <:try_but_dont_catch()>
(gdb) disassemble /m try_but_dont_catch
Dump of assembler code for function try_but_dont_catch():
10  void try_but_dont_catch() {
        [...]
11      try {
12          raise();
   0x08048619 <:+7>:    call   0x80485e8 <:raise()>
13      } catch(Fake_Exception&) {
   0x08048651 <:+63>:   call   0x804874a <:__cxa_begin_catch()>
   0x08048665 <:+83>:   call   0x804875e <:__cxa_end_catch()>
   0x0804866a <:+88>:   jmp    0x804861e <:try_but_dont_catch()+12>
14          printf("Caught a Fake_Exception!\n");
   0x08048659 <:+71>:   movl   $0x8048971,(%esp)
   0x08048660 <:+78>:   call   0x80484c0 :puts@plt
15      }
16
17      printf("try_but_dont_catch handled the exception\n");
   0x0804861e <:+12>:   movl   $0x8048948,(%esp)
   0x08048625 <:+19>:   call   0x80484c0 :puts@plt
18  }
   0x0804862a <:+24>:   add    $0x24,%esp

With the help of _Unwind_ we are now able to get enough information about the current stack frame to decide whether we can or not handle an exception, an also how should we handle it. One more step is needed before we can detect the landing pad we want: we will need to interpret the CFI (call frame information) at the end of the function. This is part of the DWARF spec, the same gdb uses for debugging purposes, and it's not an easy spec to implement. Like we are doing with our ABI, we'll keep this to the bare minimum.


Vim tips: my github's vimrc

Post by Nico Brailovsky @ 2013-04-04 | Permalink | Leave a comment

It's been a while since I posted my Vimrc. That's probably because I don't really need to back it up in my blog anymore, now I just keep it in my github repo.

Now whenever I get a new computer I just clone my repo and get for free my vimrc, my terminator rc and a bunch of useful scripts I regularly use on bash.


C++ exceptions under the hood 9: catching our first exception

Post by Nico Brailovsky @ 2013-04-02 | Permalink | Leave a comment

We finished last chapter on the series about C++ exceptions by adding a personality function that _Unwind_ was able to call and then analyzing the parameters that the personality function receives. Now it's time to begin adding some real behavior to __gxx_personality_v0: when __gxx_personality_v0 is called we should say "yes, this stack frame can indeed handle this exception".

We have been building up to this point quite a bit: the time where we can implement for the first time a personality function capable of detecting when an exception is thrown, and then saying "yes, I will handle this exception". For that we had to learn how the two-phase lookup work, so we can now reimplement our personality function and our throw test file:

#include 
#include "throw.h"
struct Fake_Exception {};
void raise() {
    throw Exception();
}
void try_but_dont_catch() {
    try {
        raise();
    } catch(Fake_Exception&) {
        printf("Caught a Fake_Exception!\n");
    }
    printf("try_but_dont_catch handled the exception\n");
}
void catchit() {
    try {
        try_but_dont_catch();
    } catch(Exception&) {
        printf("Caught an Exception!\n");
    }
    printf("catchit handled the exception\n");
}
extern "C" {
    void seppuku() {
        catchit();
    }
}

And our personality function:

_Unwind_Reason_Code __gxx_personality_v0 (
                     int version, _Unwind_Action actions, uint64_t exceptionClass,
                     _Unwind_Exception unwind_exception, _Unwind_Context context)
{
    if (actions & _UA_SEARCH_PHASE)
    {
        printf("Personality function, lookup phase\n");
        return _URC_HANDLER_FOUND;
    } else if (actions & _UA_CLEANUP_PHASE) {
        printf("Personality function, cleanup\n");
        return _URC_INSTALL_CONTEXT;
    } else {
        printf("Personality function, error\n");
        return _URC_FATAL_PHASE1_ERROR;
    }
}

Note: You can download the full sourcecode for this project in my github repo.

Let's run it, see what happens:

alloc ex 1
__cxa_throw called
Personality function, lookup phase
Personality function, cleanup
try_but_dont_catch handled the exception
catchit handled the exception

It works, but something is missing: the catch inside the catch/try block is not being executed! This is happening because the personality function tells Unwind to "install a context" (ie to resume execution) but it never says which context. In this case it's probably resuming executing from after the landing pad, but I'd bet this is actually undefined behavior. We'll see next time how we can specify we want to resume executing from a specific landing pad using the information available on .gcc_except_table (our old friend, the LSDA).