dynamic_fde_registration.cxx [plain text]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <mach/mach.h>
#include <libunwind.h>
#include "unwind.h"
#define KEYMGR_GCC3_DW2_OBJ_LIST 302
extern "C" {
extern void _keymgr_set_and_unlock_processwide_ptr(int key, void* ptr);
extern void* _keymgr_get_and_lock_processwide_ptr(int key);
};
struct libgcc_object
{
void* start;
void* unused1;
void* unused2;
void* fde;
unsigned long encoding;
void* fde_end;
libgcc_object* next;
};
struct libgcc_object_info {
struct libgcc_object* seen_objects;
struct libgcc_object* unseen_objects;
unsigned spare[2];
};
static void my_keymgr_register_frame(void* fde)
{
libgcc_object_info* head = (libgcc_object_info*)_keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST);
libgcc_object* ob = (libgcc_object*)calloc(sizeof(libgcc_object), 1);
ob->fde = fde;
ob->next = head->unseen_objects;
head->unseen_objects = ob;
_keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, head);
}
void check(bool shouldFindMain)
{
unw_cursor_t cursor;
unw_context_t uc;
unw_word_t offset;
bool foundMain = false;
char functionName[256];
int level = 1;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
do {
unw_get_proc_name(&cursor, functionName, 64, &offset);
if ( strcmp(functionName, "main") == 0 )
foundMain = true;
++level;
strcpy(functionName, "junk");
} while (unw_step(&cursor) > 0);
if ( foundMain == shouldFindMain )
return;
fprintf(stderr, "failing because shouldFindMain=%d and foundMain=%d\n", shouldFindMain, foundMain);
exit(1);
}
void foo(bool shouldFindMain, void (*func)(bool))
{
(*func)(shouldFindMain);
__asm__ volatile(""); }
typedef void (*checkFuncProc)(bool shouldFindMain, void (*func)(bool));
int main()
{
struct dwarf_eh_bases junk;
const void* foo_eh_src = _Unwind_Find_FDE((void*)((long)&foo + 1), &junk);
unsigned long deltaToFDE = (uintptr_t)foo_eh_src - (uintptr_t)&foo;
unsigned long size = deltaToFDE + 100;
size = ((size + 4095) & (-4096));
vm_address_t addr = 0;
if ( vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE) != KERN_SUCCESS )
exit(1);
memcpy((void*)addr, (void*)&foo, size);
mprotect((void*)addr, size, PROT_READ|PROT_EXEC);
checkFuncProc checkFunc = (checkFuncProc)addr;
void* foo_eh = (void*)(addr + deltaToFDE);
(*checkFunc)(false, check);
__register_frame(foo_eh);
(*checkFunc)(true, check);
__deregister_frame(foo_eh);
(*checkFunc)(false, check);
my_keymgr_register_frame(foo_eh);
(*checkFunc)(true, check);
return 0;
}