#ifdef PART_OF_SYSTEM_FRAMEWORK
#include <mach-o/dyld.h>
#endif
#include "keymgr.h"
#include <pthread.h>
#include <stdlib.h>
extern void *__eh_global_dataptr ;
extern void *__keymgr_global[3] ;
#define GET_KEYMGR_LIST_ROOT() ((_Tkey_Data *)__keymgr_global[1])
#define SET_KEYMGR_LIST_ROOT(ptr) (__keymgr_global[1] = ((void *) (ptr)))
#define GET_KEYMGR_LIST_MUTEX_PTR() ((pthread_mutex_t *) __keymgr_global[0])
#define SET_KEYMGR_LIST_MUTEX_PTR(ptr) (__keymgr_global[0] = (void *)(ptr))
#define INIT_KEYMGR_LIST_MUTEX() (SET_KEYMGR_LIST_MUTEX_PTR(malloc(sizeof(pthread_mutex_t))), \
(*GET_KEYMGR_LIST_MUTEX_PTR() = _local_mutex_initializer))
#define LOCK_KEYMGR_LIST_MUTEX() (pthread_mutex_lock(GET_KEYMGR_LIST_MUTEX_PTR()) ? \
(abort(), 0) : 0 )
#define UNLOCK_KEYMGR_LIST_MUTEX() (pthread_mutex_unlock(GET_KEYMGR_LIST_MUTEX_PTR()) ? \
(abort(), 0) : 0 )
#define LOCK_KEYMGR_INIT() (pthread_mutex_lock(&_keymgr_init_lock) ? (abort(), 0) : 0 )
#define UNLOCK_KEYMGR_INIT() (pthread_mutex_unlock(&_keymgr_init_lock) ? (abort(), 0) : 0 )
#define KEYMGR_CREATE_THREAD_DATA_KEY(thread_key) \
((pthread_key_create(&thread_key,NULL) != 0) ? \
(abort(),0) : 0)
#define KEYMGR_CREATE_MALLOCED_THREAD_DATA_KEY(thread_key) \
((pthread_key_create(&thread_key, free) != 0) ? \
(abort(),0) : 0)
#define KEYMGR_SET_THREAD_DATA(key,data) \
((pthread_setspecific((key), (data)) != 0) ? \
(abort(),0) : 0)
#define KEYMGR_GET_THREAD_DATA(key) (pthread_getspecific(key))
#define INIT_KEYMGR_NODE_LOCK(node) (node->thread_lock = _local_mutex_initializer)
#define LOCK_KEYMGR_NODE(node) \
((pthread_mutex_lock(&(node->thread_lock)) ? \
(abort(), 0) : 0 ),((node)->flags |= NM_LOCKED),\
((node)->owning_thread = pthread_self()),node->refcount++)
#define UNLOCK_KEYMGR_NODE(node) \
(((node)->flags &= ~NM_LOCKED),((node)->refcount--),\
(pthread_mutex_unlock(&(node->thread_lock)) ? \
(abort(), 0) : 0 ))
#define LOCK_IS_MINE(node) (((node)->flags & NM_LOCKED)&& \
((node)->owning_thread == pthread_self()))
#define GET_KEYMGR_INFO_NODE_PTR() ((_Tinfo_Node *)__keymgr_global[2])
#define SET_KEYMGR_INFO_NODE_PTR(ptr) (__keymgr_global[2] = (void *)(ptr))
#define CHECK_KEYMGR_INIT() if (!_keymgr_init_mutex) _init_keymgr() ;
#define KEYMGR_NODE_FLAGS(node,pflags) ((node)->flags & (pflags))
static int _keymgr_init_mutex = 0 ;
static pthread_mutex_t _keyArray_lock=PTHREAD_MUTEX_INITIALIZER ;
static pthread_mutex_t *_keyArray_lock_ptr=&_keyArray_lock ;
static pthread_mutex_t _local_mutex_initializer = PTHREAD_MUTEX_INITIALIZER ;
static pthread_mutex_t _keymgr_init_lock = PTHREAD_MUTEX_INITIALIZER ;
typedef struct _Skey_data {
struct _Skey_data *next ;
unsigned int handle ;
void *ptr ;
int node_kind ;
pthread_mutex_t thread_lock ;
pthread_t owning_thread ;
unsigned int refcount ;
unsigned int flags ;
} _Tkey_Data ;
typedef struct _Sinfo_Node {
unsigned int size ;
unsigned short major_version ;
unsigned short minor_version ;
} _Tinfo_Node ;
void _init_keymgr(void) {
_Tinfo_Node *ti ;
unsigned long address ;
void *module ;
if (_keymgr_init_mutex)
return ;
#ifdef PART_OF_SYSTEM_FRAMEWORK
_dyld_lookup_and_bind_fully("__init_keymgr", &address, &module);
if (_keymgr_init_mutex)
return ;
LOCK_KEYMGR_INIT() ;
if (_keymgr_init_mutex) {
UNLOCK_KEYMGR_INIT() ;
return ;
}
#endif
_keymgr_init_mutex++ ;
if (GET_KEYMGR_INFO_NODE_PTR()) {
#ifdef PART_OF_SYSTEM_FRAMEWORK
UNLOCK_KEYMGR_INIT() ;
#endif
return ;
}
INIT_KEYMGR_LIST_MUTEX() ;
LOCK_KEYMGR_LIST_MUTEX() ;
ti = malloc(sizeof(_Tinfo_Node)) ;
ti->size = sizeof(_Tinfo_Node) ;
ti->major_version = KEYMGR_API_REV_MAJOR ;
ti->minor_version = KEYMGR_API_REV_MINOR ;
SET_KEYMGR_INFO_NODE_PTR(ti) ;
UNLOCK_KEYMGR_LIST_MUTEX() ;
#ifdef PART_OF_SYSTEM_FRAMEWORK
UNLOCK_KEYMGR_INIT() ;
#endif
}
#pragma CALL_ON_LOAD _init_keymgr
static void _keymgr_lock(_Tkey_Data *node) {
if (KEYMGR_NODE_FLAGS(node,NM_ENHANCED_LOCKING)) {
if (LOCK_IS_MINE(node)) {
if (KEYMGR_NODE_FLAGS(node,NM_RECURSION_ILLEGAL)) {
abort() ;
}
else if (KEYMGR_NODE_FLAGS(node,NM_ALLOW_RECURSION)) {
if(node->refcount) {
node->refcount++ ;
return ;
}
}
else ;
}
}
else ;
LOCK_KEYMGR_NODE(node) ;
}
static void _keymgr_unlock(_Tkey_Data *node) {
if (node->refcount > 1) {
node->refcount-- ;
return ;
}
UNLOCK_KEYMGR_NODE(node) ;
}
static _Tkey_Data *_keymgr_get_key_element(unsigned int key) {
_Tkey_Data *keyArray ;
for (keyArray = GET_KEYMGR_LIST_ROOT() ; keyArray != NULL ; keyArray = keyArray->next) {
if (keyArray->handle == key)
break ;
}
return(keyArray) ;
}
static _Tkey_Data *_keymgr_create_key_element(unsigned int key, void *ptr, TnodeKind kind) {
_Tkey_Data *keyArray ;
keyArray = (_Tkey_Data *) malloc(sizeof(_Tkey_Data)) ;
keyArray->handle = key ;
keyArray->ptr = ptr ;
keyArray->node_kind = kind ;
keyArray->owning_thread = pthread_self() ;
keyArray->refcount = 0;
keyArray->flags = 0 ;
INIT_KEYMGR_NODE_LOCK(keyArray) ;
keyArray->next = GET_KEYMGR_LIST_ROOT() ;
SET_KEYMGR_LIST_ROOT(keyArray) ;
return(keyArray) ;
}
static _Tkey_Data *_keymgr_set_key_element(unsigned int key, void *ptr, TnodeKind kind) {
_Tkey_Data *keyArray ;
keyArray = _keymgr_get_key_element(key) ;
if (keyArray == NULL) {
keyArray = _keymgr_create_key_element(key,ptr,kind) ;
}
else if (keyArray->node_kind != kind) {
abort() ;
}
else {
keyArray->ptr = ptr ;
}
return(keyArray) ;
}
static _Tkey_Data *_keymgr_get_or_create_key_element(unsigned int key, TnodeKind kind) {
_Tkey_Data *keyArray ;
LOCK_KEYMGR_LIST_MUTEX() ;
keyArray = _keymgr_get_key_element(key) ;
if (keyArray == NULL) {
keyArray = _keymgr_create_key_element(key, NULL, kind) ;
}
else if (kind && (keyArray->node_kind != kind))
abort() ;
else ;
UNLOCK_KEYMGR_LIST_MUTEX() ;
return(keyArray) ;
}
static void *_keymgr_get_and_lock_key(unsigned int key, TnodeKind kind) {
_Tkey_Data *keyArray ;
void *retptr ;
keyArray = _keymgr_get_or_create_key_element(key,kind) ;
_keymgr_lock(keyArray) ;
retptr = keyArray->ptr ;
return(retptr) ;
}
static void _keymgr_unlock_key(unsigned int key) {
_Tkey_Data *keyArray ;
LOCK_KEYMGR_LIST_MUTEX() ;
keyArray = _keymgr_get_key_element(key) ;
UNLOCK_KEYMGR_LIST_MUTEX() ;
if (keyArray)
_keymgr_unlock(keyArray) ;
}
static void *_keymgr_set_and_unlock_key(unsigned int key, void *ptr, TnodeKind kind) {
_Tkey_Data *keyArray ;
void * retptr ;
LOCK_KEYMGR_LIST_MUTEX() ;
keyArray = _keymgr_set_key_element(key, ptr, kind) ;
retptr = keyArray->ptr ;
UNLOCK_KEYMGR_LIST_MUTEX() ;
_keymgr_unlock(keyArray) ;
return(retptr) ;
}
static void _keymgr_init_per_thread_data(unsigned int key) {
void * pthread_data ;
pthread_key_t pthread_key ;
_Tkey_Data *keyArray ;
LOCK_KEYMGR_LIST_MUTEX() ;
keyArray = _keymgr_get_key_element(key) ;
UNLOCK_KEYMGR_LIST_MUTEX() ;
pthread_key = (pthread_key_t) keyArray->ptr ;
if (pthread_key == NULL) {
switch (key) {
case KEYMGR_EH_CONTEXT_KEY:
KEYMGR_CREATE_MALLOCED_THREAD_DATA_KEY (pthread_key);
break;
default:
KEYMGR_CREATE_THREAD_DATA_KEY(pthread_key) ;
break;
}
_keymgr_set_and_unlock_key(key,(void *) pthread_key, NODE_THREAD_SPECIFIC_DATA) ;
}
else {
_keymgr_unlock(keyArray) ;
KEYMGR_SET_THREAD_DATA(pthread_key, NULL) ;
}
}
void * _keymgr_get_per_thread_data(unsigned int key) {
pthread_key_t pthread_key ;
void * pthread_data ;
_init_keymgr() ;
pthread_key = (pthread_key_t) _keymgr_get_and_lock_key(key,NODE_THREAD_SPECIFIC_DATA) ;
if (pthread_key == NULL) {
_keymgr_init_per_thread_data(key) ;
pthread_data = NULL ;
}
else {
_keymgr_unlock_key(key) ;
pthread_data = KEYMGR_GET_THREAD_DATA(pthread_key) ;
}
return(pthread_data) ;
}
void _keymgr_set_per_thread_data(unsigned int key, void *keydata) {
pthread_key_t pthread_key ;
_init_keymgr() ;
pthread_key = (pthread_key_t) _keymgr_get_and_lock_key(key,NODE_THREAD_SPECIFIC_DATA) ;
if (pthread_key == NULL) {
_keymgr_init_per_thread_data(key) ;
}
_keymgr_unlock_key(key) ;
KEYMGR_SET_THREAD_DATA(pthread_key, keydata) ;
}
void *_keymgr_get_and_lock_processwide_ptr(unsigned int key) {
void * retptr ;
_init_keymgr() ;
retptr = _keymgr_get_and_lock_key(key,NODE_PROCESSWIDE_PTR) ;
return(retptr) ;
}
void _keymgr_set_and_unlock_processwide_ptr(unsigned int key, void *ptr) {
_init_keymgr() ;
_keymgr_set_and_unlock_key(key,ptr,NODE_PROCESSWIDE_PTR) ;
}
void _keymgr_unlock_processwide_ptr(unsigned int key) {
_init_keymgr() ;
_keymgr_unlock_key(key) ;
}
void _keymgr_set_lockmode_processwide_ptr(unsigned int key, unsigned int mode) {
_Tkey_Data *keyArray ;
_init_keymgr() ;
keyArray = _keymgr_get_or_create_key_element(key,NODE_PROCESSWIDE_PTR) ;
keyArray->flags = (keyArray->flags & ~NM_ENHANCED_LOCKING) | mode ;
}
unsigned int _keymgr_get_lockmode_processwide_ptr(unsigned int key) {
_Tkey_Data *keyArray ;
_init_keymgr() ;
keyArray = _keymgr_get_or_create_key_element(key,NODE_PROCESSWIDE_PTR) ;
return(keyArray->flags) ;
}
int _keymgr_get_lock_count_processwide_ptr(unsigned int key) {
_Tkey_Data *keyArray ;
_init_keymgr() ;
keyArray = _keymgr_get_or_create_key_element(key,NODE_PROCESSWIDE_PTR) ;
return(keyArray->refcount) ;
}
struct mach_header;
extern char *getsectdatafromheader();
#define FRAME_SECTION_DESCRIPTOR long section_size;
#define FIRST_PSEUDO_REGISTER 1
#include "gcc/frame.h"
static const char __DWARF2_UNWIND_SECTION_TYPE[] = "__TEXT";
static const char __DWARF2_UNWIND_SECTION_NAME[] = "__dwarf2_unwind";
static void dwarf2_unwind_dyld_add_image_hook (struct mach_header *mh,
unsigned long vm_slide)
{
unsigned long sz;
char *fde;
fde = getsectdatafromheader (mh, __DWARF2_UNWIND_SECTION_TYPE,
__DWARF2_UNWIND_SECTION_NAME, &sz);
if (0) printf ("add_image_hook: mach_header %08x vm_slide %08x "
"<fde %08x>\n", mh, vm_slide, fde);
if (fde != 0)
{
struct object *obp;
obp = (struct object *) calloc (1, sizeof (struct object) + 8);
obp->pc_begin = obp->pc_end = 0;
obp->fde_array = 0;
obp->count = 0;
obp->section_size = sz;
obp->fde_begin = (struct dwarf_fde *) (fde + vm_slide);
obp->next = (struct object *)
_keymgr_get_and_lock_processwide_ptr (KEYMGR_ZOE_IMAGE_LIST);
_keymgr_set_and_unlock_processwide_ptr (KEYMGR_ZOE_IMAGE_LIST, obp);
}
}
static void
dwarf2_unwind_dyld_remove_image_hook (struct mach_header *mh,
unsigned long vm_slide)
{
unsigned long sz;
char *fde;
fde = getsectdatafromheader (mh, __DWARF2_UNWIND_SECTION_TYPE,
__DWARF2_UNWIND_SECTION_NAME, &sz);
if (fde != 0)
{
struct object *objlist, **obp;
objlist = (struct object *)
_keymgr_get_and_lock_processwide_ptr (KEYMGR_ZOE_IMAGE_LIST);
for (obp = &objlist; *obp; obp = &(*obp)->next)
if ((char *)(*obp)->fde_begin == fde + vm_slide)
{
struct object *p = *obp;
*obp = p->next;
if (p->pc_begin)
free (p->fde_array);
free (p);
break;
}
_keymgr_set_and_unlock_processwide_ptr (KEYMGR_ZOE_IMAGE_LIST, objlist);
}
}
void __keymgr_dwarf2_register_sections (void)
{
_dyld_register_func_for_add_image (dwarf2_unwind_dyld_add_image_hook);
_dyld_register_func_for_remove_image (dwarf2_unwind_dyld_remove_image_hook);
}