CXX Exceptions

Contents

Possible Methods

Method 1 (using Apple libunwind)

  1. Build LLVM libc++
  2. Build Apple libunwind (gives us _Unwind_RaiseException & friends API) - needs to be ported!, define FOR_DYLD
  3. Build LLVM libcxxabi against libc++ and libunwind (gives us __cxa_throw & friends)
  4. Bind __cxa_throw to Darling dyld

Required features in Darling dyld

  • dyld_exceptions_init()
  • _dyld_find_unwind_sections()
  • __Unwind_SjLj_GetTopOfFunctionStack() - do we do SJLJ exceptions?
  • __Unwind_SjLj_SetTopOfFunctionStack() - ?
  • dladdr
  • _dyld_register_func_for_remove_image()

Method 2 (using GCC's support code - gcc_s)

  1. Extract unwind and throw source code from GCC.
  2. Provide void* _keymgr_get_and_lock_processwide_ptr(void), void _keymgr_set_and_unlock_processwide_ptr(int,void*), _keymgr_unlock_processwide_ptr(int) and getsectdatafromheader[64].


Method 3 (using Savannah libunwind)

libunwind could be extended to support Mach-O. Advantage: available in distributions. Could also be extended via the public "remote" API only without any modification to its source code. But we probably couldn't replace __gxx_personality_routine_v0() without touching the source.

Method 4 (registering Mach-O objects with gcc_eh)

Try calling __register_frame(eh_frame) for every loaded Mach-O object. Call __deregister_frame upon unload.

Problems

  • GCC's libunwind doesn't take a length/end pointer. Darwin's __eh_frames don't have a terminating entry. Hence the __eh_frame must be copied elsewhere and relocated.
  • On i386, esp and ebp register numbers are swapped. This needs to be fixed in all Call Frame Instructions (as per DWARF documentation).

Development and Testing

Method 1

Method 1 has been chosen for the first attempts. Works if __gxx_personality_routine_v0() is replaced with our own personality routine that uses our unwind code.

Doesn't work on x86 - starts looking for a FDE for a PC on the heap. (Incorrectly processed previous FDE?) Need to check DwarfInstructions<>::stepWithDwarf / getCFA.

#0  _dyld_find_unwind_sections (addr=0x80d48c7, info=0xffffb318) at /home/lubos/Projects/darling/src/dyld/public.cpp:214
#1  0xf7f2198d in libunwind::LocalAddressSpace::findUnwindSections (this=0xf7f830b1 <sThisAddressSpace>, addr=135088327, mh=@0xffffbfbc: 4160237745, dwarfStart=@0xffffbfb8: 0, dwarfLen=@0xffffbfb4: 0, compactStart=@0xffffbfb0: 0)
    at /home/lubos/Projects/darling/src/libcxxdarwin/src-unwind/AddressSpace.hpp:253
#2  0xf7f21405 in libunwind::UnwindCursor<libunwind::LocalAddressSpace, libunwind::Registers_x86>::setInfoBasedOnIPRegister (this=0xffffc360, isReturnAddress=true) at /home/lubos/Projects/darling/src/libcxxdarwin/src-unwind/UnwindCursor.hpp:754
#3  0xf7f21198 in libunwind::UnwindCursor<libunwind::LocalAddressSpace, libunwind::Registers_x86>::step (this=0xffffc360) at /home/lubos/Projects/darling/src/libcxxdarwin/src-unwind/UnwindCursor.hpp:874
#4  0xf7f1f784 in unw_step (cursor=0xffffc360) at /home/lubos/Projects/darling/src/libcxxdarwin/src-unwind/libuwind.cxx:259
#5  0xf7f1be39 in unwind_phase1 (uc=0xffffc808, exception_object=0x80d48c8) at /home/lubos/Projects/darling/src/libcxxdarwin/src-unwind/UnwindLevel1.c:59
#6  0xf7f1bd68 in _Unwind_RaiseException (exception_object=0x80d48c8) at /home/lubos/Projects/darling/src/libcxxdarwin/src-unwind/UnwindLevel1.c:335
#7  0xf7f607bf in __cxa_throw (thrown_object=0x80d48e8, tinfo=0x4ce2eee0 <typeinfo for int>, dest=0x0) at /home/lubos/Projects/darling/src/libcxxdarwin/src-cxxabi/cxa_exception.cpp:238
#8  0x00001bd7 in ?? ()
#9  0x0808388e in MachOLoader::run (this=0x80c9530, mach=..., argc=1, argv=0xffffcf78, envp=0xffffcf80) at /home/lubos/Projects/darling/src/dyld/MachOLoader.cpp:544
#10 0x080a20e2 in main (argc=2, argv=0xffffcf74, envp=0xffffcf80) at /home/lubos/Projects/darling/src/dyld/dyld.cpp:98

Method 4

Worked straight away.

Resources