#import <stdio.h>
#import <mach/mach.h>
#import "register_funcs.h"
#import "images.h"
#import "allocate.h"
#import "lock.h"
#import "trace.h"
struct add_image_func {
void (*func)(struct mach_header *mh, unsigned long vmaddr_slide);
struct add_image_func *next;
};
static struct add_image_func add_image_func_list = { NULL, NULL };
struct remove_image_func {
void (*func)(struct mach_header *mh, unsigned long vmaddr_slide);
struct remove_image_func *next;
};
static struct remove_image_func remove_image_func_list = { NULL, NULL };
struct link_module_func {
void (*func)(module_state *module);
struct link_module_func *next;
};
static struct link_module_func link_module_func_list = { NULL, NULL };
struct unlink_module_func {
void (*func)(module_state *module);
struct unlink_module_func *next;
};
static struct unlink_module_func unlink_module_func_list = { NULL, NULL };
struct replace_module_func {
void (*func)(module_state *oldmodule, module_state *newmodule);
struct replace_module_func *next;
};
static struct replace_module_func replace_module_func_list = { NULL, NULL };
static enum bool call_registered_funcs_for_add_images_in_objects(
void);
static void call_funcs_for_add_image(
struct mach_header *mh,
unsigned long vmaddr_slide);
static enum bool call_registered_funcs_for_linked_modules_in_objects(
void);
static void call_funcs_for_link_module(
module_state *module);
void
register_func_for_add_image(
void (*func)(struct mach_header *mh, unsigned long vmaddr_slide))
{
struct add_image_func *add_image_func;
unsigned long i;
struct object_images *p;
struct library_images *q;
enum link_state link_state;
set_lock();
if(add_image_func_list.func == NULL){
add_image_func_list.func = func;
}
else{
add_image_func = allocate(sizeof(struct add_image_func));
add_image_func->func = func;
add_image_func->next = add_image_func_list.next;
add_image_func_list.next = add_image_func;
}
for(p = &object_images ; ; p = p->next_images){
for(i = 0; i < p->nimages; i++){
link_state = GET_LINK_STATE(p->images[i].module);
if(link_state == UNUSED)
continue;
DYLD_TRACE_CALLOUT_START(DYLD_TRACE_object_func, func);
release_lock();
func(p->images[i].image.mh, p->images[i].image.vmaddr_slide);
set_lock();
DYLD_TRACE_CALLOUT_END(DYLD_TRACE_object_func, func);
}
if(p->next_images == NULL)
break;
}
for(q = &library_images ; ; q = q->next_images){
for(i = 0; i < q->nimages; i++){
release_lock();
DYLD_TRACE_CALLOUT_START(DYLD_TRACE_library_func, func);
func(q->images[i].image.mh, q->images[i].image.vmaddr_slide);
DYLD_TRACE_CALLOUT_END(DYLD_TRACE_library_func, func);
set_lock();
}
if(q->next_images == NULL)
break;
}
release_lock();
}
void
register_func_for_remove_image(
void (*func)(struct mach_header *mh, unsigned long vmaddr_slide))
{
struct remove_image_func *remove_image_func;
set_lock();
if(remove_image_func_list.func == NULL){
remove_image_func_list.func = func;
}
else{
remove_image_func = allocate(sizeof(struct remove_image_func));
remove_image_func->func = func;
remove_image_func->next = remove_image_func_list.next;
remove_image_func_list.next = remove_image_func;
}
release_lock();
}
void
call_registered_funcs_for_add_images(
void)
{
unsigned long i;
struct library_images *q;
while(call_registered_funcs_for_add_images_in_objects() == TRUE)
;
q = &library_images;
do{
for(i = 0; i < q->nimages; i++){
if(q->images[i].image.registered == FALSE){
q->images[i].image.registered = TRUE;
call_funcs_for_add_image(q->images[i].image.mh,
q->images[i].image.vmaddr_slide);
}
}
q = q->next_images;
}while(q != NULL);
}
static
enum bool
call_registered_funcs_for_add_images_in_objects(
void)
{
unsigned long i;
struct object_images *p;
enum link_state link_state;
p = &object_images;
do{
for(i = 0; i < p->nimages; i++){
link_state = GET_LINK_STATE(p->images[i].module);
if(link_state == UNUSED)
continue;
if(p->images[i].image.registered == FALSE){
p->images[i].image.registered = TRUE;
call_funcs_for_add_image(p->images[i].image.mh,
p->images[i].image.vmaddr_slide);
return(TRUE);
}
}
p = p->next_images;
}while(p != NULL);
return(FALSE);
}
static
void
call_funcs_for_add_image(
struct mach_header *mh,
unsigned long vmaddr_slide)
{
struct add_image_func *add_image_func;
for(add_image_func = &add_image_func_list;
add_image_func != NULL && add_image_func->func != NULL;
add_image_func = add_image_func->next){
release_lock();
DYLD_TRACE_CALLOUT_START(DYLD_TRACE_add_image_func,
add_image_func->func);
add_image_func->func(mh, vmaddr_slide);
DYLD_TRACE_CALLOUT_END(DYLD_TRACE_add_image_func,
add_image_func->func);
set_lock();
}
}
void
call_funcs_for_remove_image(
struct mach_header *mh,
unsigned long vmaddr_slide)
{
struct remove_image_func *remove_image_func;
for(remove_image_func = &remove_image_func_list;
remove_image_func != NULL && remove_image_func->func != NULL;
remove_image_func = remove_image_func->next){
DYLD_TRACE_CALLOUT_START(DYLD_TRACE_remove_image_func,
remove_image_func->func);
release_lock();
remove_image_func->func(mh, vmaddr_slide);
set_lock();
DYLD_TRACE_CALLOUT_END(DYLD_TRACE_remove_image_func,
remove_image_func->func);
}
}
void
register_func_for_link_module(
void (*func)(module_state *module))
{
struct link_module_func *link_module_func;
unsigned long i, j;
struct object_images *p;
struct library_images *q;
enum link_state link_state;
set_lock();
if(link_module_func_list.func == NULL){
link_module_func_list.func = func;
}
else{
link_module_func = allocate(sizeof(struct link_module_func));
link_module_func->func = func;
link_module_func->next = link_module_func_list.next;
link_module_func_list.next = link_module_func;
}
for(p = &object_images ; ; p = p->next_images){
for(i = 0; i < p->nimages; i++){
link_state = GET_LINK_STATE(p->images[i].module);
if(link_state != LINKED && link_state != FULLY_LINKED)
continue;
DYLD_TRACE_CALLOUT_START(DYLD_TRACE_link_object_module_func,
func);
release_lock();
func(&(p->images[i].module));
set_lock();
DYLD_TRACE_CALLOUT_END(DYLD_TRACE_link_object_module_func,
func);
}
if(p->next_images == NULL)
break;
}
for(q = &library_images ; ; q = q->next_images){
for(i = 0; i < q->nimages; i++){
for(j = 0; j < q->images[i].image.dyst->nmodtab; j++){
link_state = GET_LINK_STATE(q->images[i].modules[j]);
if(link_state != LINKED && link_state != FULLY_LINKED)
continue;
DYLD_TRACE_CALLOUT_START(
DYLD_TRACE_link_library_module_func, func);
release_lock();
func(q->images[i].modules + j);
set_lock();
DYLD_TRACE_CALLOUT_END(
DYLD_TRACE_link_library_module_func, func);
}
}
if(q->next_images == NULL)
break;
}
release_lock();
}
void
call_registered_funcs_for_linked_modules(
void)
{
unsigned long i, j;
enum link_state link_state;
struct library_images *q;
struct segment_command *linkedit_segment;
struct dysymtab_command *dyst;
struct dylib_module *dylib_modules;
while(call_registered_funcs_for_linked_modules_in_objects() == TRUE)
;
q = &library_images;
do{
for(i = 0; i < q->nimages; i++){
linkedit_segment = q->images[i].image.linkedit_segment;
dyst = q->images[i].image.dyst;
dylib_modules = (struct dylib_module *)
(q->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
dyst->modtaboff -
linkedit_segment->fileoff);
for(j = 0; j < dyst->nmodtab; j++){
link_state = GET_LINK_STATE(q->images[i].modules[j]);
if(link_state != RELOCATED)
continue;
SET_LINK_STATE(q->images[i].modules[j], REGISTERING);
if(link_module_func_list.func == NULL)
continue;
call_funcs_for_link_module(q->images[i].modules + j);
}
}
q = q->next_images;
}while(q != NULL);
}
static
enum bool
call_registered_funcs_for_linked_modules_in_objects(
void)
{
unsigned long i;
enum link_state link_state;
struct object_images *p;
p = &object_images;
do{
for(i = 0; i < p->nimages; i++){
link_state = GET_LINK_STATE(p->images[i].module);
if(link_state != RELOCATED)
continue;
SET_LINK_STATE(p->images[i].module, REGISTERING);
if(link_module_func_list.func == NULL)
continue;
call_funcs_for_link_module(&(p->images[i].module));
return(TRUE);
}
p = p->next_images;
}while(p != NULL);
return(FALSE);
}
static
void
call_funcs_for_link_module(
module_state *module)
{
struct link_module_func *link_module_func;
for(link_module_func = &link_module_func_list;
link_module_func != NULL && link_module_func->func != NULL;
link_module_func = link_module_func->next){
DYLD_TRACE_CALLOUT_START(DYLD_TRACE_link_module_func,
link_module_func->func);
release_lock();
link_module_func->func(module);
set_lock();
DYLD_TRACE_CALLOUT_END(DYLD_TRACE_link_module_func,
link_module_func->func);
}
}
void
register_func_for_unlink_module(
void (*func)(module_state *module))
{
struct unlink_module_func *unlink_module_func;
set_lock();
if(unlink_module_func_list.func == NULL){
unlink_module_func_list.func = func;
}
else{
unlink_module_func = allocate(sizeof(struct unlink_module_func));
unlink_module_func->func = func;
unlink_module_func->next = unlink_module_func_list.next;
unlink_module_func_list.next = unlink_module_func;
}
release_lock();
}
void
register_func_for_replace_module(
void (*func)(module_state *oldmodule, module_state *newmodule))
{
struct replace_module_func *replace_module_func;
set_lock();
if(replace_module_func_list.func == NULL){
replace_module_func_list.func = func;
}
else{
replace_module_func = allocate(sizeof(struct replace_module_func));
replace_module_func->func = func;
replace_module_func->next = replace_module_func_list.next;
replace_module_func_list.next = replace_module_func;
}
release_lock();
}