#include <stdlib.h>
#include <string.h>
#include <mach-o/loader.h>
#include <unistd.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdarg.h>
#include <pthread.h>
#include "mach-o/dyld_priv.h"
#include "dyldLibSystemInterface.h"
extern void _ZN4dyld3logEPKcz(const char*, ...);
extern struct LibSystemHelpers* _ZN4dyld17gLibSystemHelpersE;
#if __LP64__
#define LC_SEGMENT_COMMAND LC_SEGMENT_64
#define macho_header mach_header_64
#define macho_segment_command segment_command_64
#define macho_section section_64
#define getsectdatafromheader getsectdatafromheader_64
#else
#define LC_SEGMENT_COMMAND LC_SEGMENT
#define macho_header mach_header
#define macho_segment_command segment_command
#define macho_section section
#endif
#if __i386__ || __x86_64 || __ppc__
static struct dyld_unwind_sections sDyldInfo;
static void* sDyldTextEnd;
static pthread_key_t sCxaKey = 0;
static char sPreMainCxaGlobals[2*sizeof(long)];
void dyld_exceptions_init(struct mach_header* mh, intptr_t slide)
{
sDyldInfo.mh = mh;
const struct load_command* cmd;
unsigned long i;
cmd = (struct load_command*) ((char *)mh + sizeof(struct macho_header));
for(i = 0; i < mh->ncmds; i++) {
if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
if ( strcmp(seg->segname, "__TEXT") == 0 ) {
const struct macho_section* sect = (struct macho_section*)( (char*)seg + sizeof(struct macho_segment_command) );
unsigned long j;
for (j = 0; j < seg->nsects; j++) {
if ( strcmp(sect[j].sectname, "__eh_frame") == 0 ) {
sDyldInfo.dwarf_section = (void*)(sect[j].addr + slide);
sDyldInfo.dwarf_section_length = sect[j].size;
}
else if ( strcmp(sect[j].sectname, "__unwind_info") == 0 ) {
sDyldInfo.compact_unwind_section = (void*)(sect[j].addr + slide);
sDyldInfo.compact_unwind_section_length = sect[j].size;
}
}
sDyldTextEnd = (void*)(seg->vmaddr + seg->vmsize + slide);
}
}
cmd = (struct load_command*)( (char*)cmd + cmd->cmdsize );
}
}
bool _dyld_find_unwind_sections(void* addr, struct dyld_unwind_sections* info)
{
if ( ((void*)sDyldInfo.mh < addr) && (addr < sDyldTextEnd) ) {
*info = sDyldInfo;
return true;
}
else {
return false;
}
}
char* __cxa_get_globals()
{
if ( (_ZN4dyld17gLibSystemHelpersE == NULL) || (_ZN4dyld17gLibSystemHelpersE->version < 5) )
return sPreMainCxaGlobals;
if ( sCxaKey == 0 ) {
_ZN4dyld17gLibSystemHelpersE->pthread_key_create(&sCxaKey, &free);
}
char* data = (char*)pthread_getspecific(sCxaKey);
if ( data == NULL ) {
data = calloc(2,sizeof(void*));
_ZN4dyld17gLibSystemHelpersE->pthread_setspecific(sCxaKey, data);
}
return data;
}
char* __cxa_get_globals_fast()
{
if ( (_ZN4dyld17gLibSystemHelpersE == NULL) || (_ZN4dyld17gLibSystemHelpersE->version < 5) )
return sPreMainCxaGlobals;
return pthread_getspecific(sCxaKey);
}
#if __ppc__
void* _Znwm(size_t size) { return malloc(size); }
#endif
#else
#define KEYMGR_API_MAJOR_GCC3 3
#define KEYMGR_GCC3_LIVE_IMAGE_LIST 301
#define KEYMGR_GCC3_DW2_OBJ_LIST 302
#define KEYMGR_EH_GLOBALS_KEY 13
struct live_images {
unsigned long this_size;
struct mach_header *mh;
unsigned long vm_slide;
void (*destructor)(struct live_images *);
struct live_images *next;
unsigned int examined_p;
void *fde;
void *object_info;
unsigned long info[2];
};
static struct live_images sDyldImage; static void* sObjectList = NULL;
#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4))
static void* sEHGlobals = NULL;
#endif
void dyld_exceptions_init(struct mach_header *mh, uintptr_t slide)
{
sDyldImage.this_size = sizeof(struct live_images);
sDyldImage.mh = mh;
sDyldImage.vm_slide = slide;
}
#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4))
typedef struct Sinfo_Node {
uint32_t size;
uint16_t major_version;
uint16_t minor_version;
} Tinfo_Node;
static const Tinfo_Node keymgr_info = { sizeof (Tinfo_Node), KEYMGR_API_MAJOR_GCC3, 0 };
const Tinfo_Node* __keymgr_global[3] = { NULL, NULL, &keymgr_info };
#endif
static __attribute__((noreturn))
void dyld_abort()
{
_exit(1);
}
void* _keymgr_get_and_lock_processwide_ptr(unsigned int key)
{
if ( key == KEYMGR_GCC3_LIVE_IMAGE_LIST ) {
return &sDyldImage;
}
else if ( key == KEYMGR_GCC3_DW2_OBJ_LIST ) {
return sObjectList;
}
dyld_abort();
}
void _keymgr_set_and_unlock_processwide_ptr(unsigned int key, void* value)
{
if ( key == KEYMGR_GCC3_DW2_OBJ_LIST ) {
sObjectList = value;
return;
}
dyld_abort();
}
void _keymgr_unlock_processwide_ptr(unsigned int key)
{
if ( key == KEYMGR_GCC3_LIVE_IMAGE_LIST ) {
return;
}
dyld_abort();
}
void* _keymgr_get_per_thread_data(unsigned int key)
{
#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4))
if ( key == KEYMGR_EH_GLOBALS_KEY )
return sEHGlobals;
#endif
dyld_abort();
}
void _keymgr_set_per_thread_data(unsigned int key, void *keydata)
{
#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4))
if ( key == KEYMGR_EH_GLOBALS_KEY ) {
sEHGlobals = keydata;
return;
}
#endif
dyld_abort();
}
const void* getsectdatafromheader(struct mach_header* mh, const char* segname, const char* sectname, unsigned long* size)
{
const struct load_command* cmd;
unsigned long i;
cmd = (struct load_command*) ((char *)mh + sizeof(struct macho_header));
for(i = 0; i < mh->ncmds; i++) {
if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
if ( strcmp(seg->segname, segname) == 0 ) {
const struct macho_section* sect = (struct macho_section*)( (char*)seg + sizeof(struct macho_segment_command) );
unsigned long j;
for (j = 0; j < seg->nsects; j++) {
if ( strcmp(sect[j].sectname, sectname) == 0 ) {
*size = sect[j].size;
return (void*)(sect[j].addr);
}
}
}
}
cmd = (struct load_command*)( (char*)cmd + cmd->cmdsize );
}
return NULL;
}
#if __LP64__
#undef getsectdatafromheader
const void* getsectdatafromheader(struct mach_header* mh, const char* segname, const char* sectname, unsigned long* size)
{
return getsectdatafromheader_64(mh, segname, sectname, size);
}
#endif
#endif