#import <libc.h>
#import <mach-o/loader.h>
#ifndef __OPENSTEP__
extern const struct section *getsectbynamefromheader(
const struct mach_header *mhp,
const char *segname,
const char *sectname);
#endif
#import <stdio.h>
#import <string.h>
#import <mach/mach.h>
#import "stuff/openstep_mach.h"
#import <mach-o/ldsyms.h>
#import <errno.h>
#ifndef __MACH30__
#import "../profileServer/profileServer.h"
#endif
#import "inline_strcmp.h"
#import "dyld_init.h"
#import "images.h"
#import "symbols.h"
#import "errors.h"
#import "reloc.h"
#import "lock.h"
#import "debug.h"
#import "trace.h"
struct host_basic_info host_basic_info = { 0 };
#if (defined(__GONZO_BUNSEN_BEAKER__) || defined(__HERA__)) && defined(__ppc__)
enum bool processor_has_vec = FALSE;
#endif
enum bool executable_bind_at_load = FALSE;
static enum bool dyld_bind_at_launch = FALSE;
enum bool force_flat_namespace = FALSE;
static enum bool dyld_force_flat_namespace = FALSE;
char *home = "/";
char *dyld_framework_path = NULL;
char *dyld_fallback_framework_path = NULL;
char *default_fallback_framework_path = NULL;
char *dyld_library_path = NULL;
char *dyld_fallback_library_path = NULL;
char *default_fallback_library_path = NULL;
char *dyld_image_suffix = NULL;
char *dyld_insert_libraries = NULL;
enum bool dyld_print_libraries = FALSE;
enum bool dyld_trace = FALSE;
enum bool dyld_mem_protect = FALSE;
enum bool dyld_ebadexec_only = FALSE;
enum bool dyld_dead_lock_hang = FALSE;
unsigned long dyld_prebind_debug = 0;
unsigned long dyld_hints_debug = 0;
unsigned long dyld_sample_debug = 0;
enum bool dyld_executable_path_debug = FALSE;
enum bool dyld_two_level_debug = FALSE;
enum bool dyld_abort_multiple_inits = FALSE;
enum bool dyld_new_local_shared_regions = FALSE;
enum bool dyld_no_fix_prebinding = FALSE;
enum bool profile_server = FALSE;
enum bool prebinding = TRUE;
enum bool launched = FALSE;
enum bool executable_prebound = FALSE;
static struct segment_command *data_seg;
#if 0
static void get_data_segment(
void);
#endif
char *executables_path = NULL;
unsigned long executables_pathlen = 0;
char *exec_path = NULL;
static void pickup_environment_variables(
char *envp[]);
unsigned long
_dyld_init(
struct mach_header *mh,
unsigned long argc,
char **argv,
char **envp)
{
unsigned int count;
kern_return_t r;
unsigned long entry_point;
mach_port_t my_mach_host_self;
#ifndef __MACH30__
struct section *s;
#endif
#ifdef MALLOC_DEBUG
extern void cthread_init(void);
cthread_init();
#endif
set_lock();
count = HOST_BASIC_INFO_COUNT;
my_mach_host_self = mach_host_self();
if((r = host_info(my_mach_host_self, HOST_BASIC_INFO, (host_info_t)
(&host_basic_info), &count)) != KERN_SUCCESS){
mach_port_deallocate(mach_task_self(), my_mach_host_self);
mach_error(r, "can't get host basic info");
}
mach_port_deallocate(mach_task_self(), my_mach_host_self);
#if defined(__GONZO_BUNSEN_BEAKER__) && defined(__ppc__)
if(host_basic_info.cpu_type == CPU_TYPE_POWERPC &&
(host_basic_info.cpu_subtype == CPU_SUBTYPE_POWERPC_7400 ||
host_basic_info.cpu_subtype == CPU_SUBTYPE_POWERPC_7450))
processor_has_vec = TRUE;
#endif
pickup_environment_variables(envp);
DYLD_TRACE_INIT_START(0);
if(exec_path != NULL)
create_executables_path(exec_path);
else if(strchr(argv[0], '/') != NULL)
create_executables_path(argv[0]);
if(dyld_executable_path_debug == TRUE)
printf("executables_path = %s\n",
executables_path == NULL ? "NULL" : executables_path);
#ifdef DYLD_PROFILING
s = (struct section *) getsectbynamefromheader(
&_mh_dylinker_header, SEG_TEXT, SECT_TEXT);
monstartup((char *)(s->addr + dyld_image_vmaddr_slide),
(char *)(s->addr + dyld_image_vmaddr_slide + s->size));
#endif
#ifndef __MACH30__
profile_server = profile_server_exists();
if(profile_server == TRUE){
s = (struct section *) getsectbynamefromheader(
&_mh_dylinker_header, SEG_TEXT, SECT_TEXT);
shared_pcsample_buffer("/usr/lib/dyld", s, dyld_image_vmaddr_slide);
}
#endif
if((mh->flags & MH_FORCE_FLAT) != 0 ||
dyld_force_flat_namespace == TRUE)
force_flat_namespace = TRUE;
if((mh->flags & MH_NOFIXPREBINDING) == MH_NOFIXPREBINDING)
dyld_no_fix_prebinding = TRUE;
executable_prebound = (mh->flags & MH_PREBOUND) == MH_PREBOUND;
load_executable_image(argv[0], mh, &entry_point);
if((mh->flags & MH_PREBOUND) != MH_PREBOUND){
if(prebinding == TRUE){
if((mh->flags & MH_NOUNDEFS) == MH_NOUNDEFS){
try_to_use_prebound_libraries();
}
else{
if(dyld_prebind_debug != 0)
print("dyld: %s: prebinding disabled because "
"executable not marked with MH_NOUNDEFS\n",
argv[0]);
prebinding = FALSE;
}
}
}
else if(prebinding == TRUE){
set_images_to_prebound();
}
if(prebinding == FALSE){
if(force_flat_namespace == FALSE)
find_twolevel_prebound_lib_subtrees();
undo_prebound_images();
if((mh->flags & MH_BINDATLOAD) != 0 || dyld_bind_at_launch == TRUE)
executable_bind_at_load = TRUE;
setup_initial_undefined_list(FALSE);
link_in_need_modules(FALSE, FALSE);
}
else{
if(dyld_prebind_debug != 0){
if((mh->flags & MH_PREBOUND) != MH_PREBOUND)
print("dyld: %s: prebinding enabled using only prebound "
"libraries\n", argv[0]);
else
print("dyld: %s: prebinding enabled\n", argv[0]);
}
}
launched = TRUE;
if(dyld_ebadexec_only == TRUE){
error("executable: %s will be launched (DYLD_EBADEXEC_ONLY set, "
"program not started)", argv[0]);
link_edit_error(DYLD_FILE_ACCESS, EBADEXEC, argv[0]);
}
release_lock();
DYLD_TRACE_INIT_END(0);
return(entry_point);
}
static
void
pickup_environment_variables(
char *envp[])
{
char **p;
for(p = envp; *p != NULL; p++){
if(**p == 'D' && strncmp(*p, "DYLD_", sizeof("DYLD_") - 1) == 0){
if(strncmp(*p, "DYLD_FRAMEWORK_PATH=",
sizeof("DYLD_FRAMEWORK_PATH=") - 1) == 0){
if(getuid() != 0 &&
(getuid() != geteuid() || getgid() != getegid()))
(*p)[sizeof("DYLD_FRAMEWORK_PATH=") - 1] = '\0';
else if(*(*p + sizeof("DYLD_FRAMEWORK_PATH=") - 1) != '\0'){
dyld_framework_path =
*p + sizeof("DYLD_FRAMEWORK_PATH=") - 1;
dyld_no_fix_prebinding = TRUE;
}
}
else if(strncmp(*p, "DYLD_FALLBACK_FRAMEWORK_PATH=",
sizeof("DYLD_FALLBACK_FRAMEWORK_PATH=") - 1) == 0){
if(getuid() != 0 &&
(getuid() != geteuid() || getgid() != getegid()))
(*p)[sizeof("DYLD_FALLBACK_FRAMEWORK_PATH=")- 1] = '\0';
else if(*(*p + sizeof(
"DYLD_FALLBACK_FRAMEWORK_PATH=") - 1) != '\0'){
dyld_fallback_framework_path =
*p + sizeof("DYLD_FALLBACK_FRAMEWORK_PATH=") - 1;
dyld_no_fix_prebinding = TRUE;
}
}
else if(strncmp(*p, "DYLD_LIBRARY_PATH=",
sizeof("DYLD_LIBRARY_PATH=") - 1) == 0){
if(getuid() != 0 &&
(getuid() != geteuid() || getgid() != getegid()))
(*p)[sizeof("DYLD_LIBRARY_PATH=") - 1] = '\0';
else if(*(*p + sizeof("DYLD_LIBRARY_PATH=") - 1) != '\0'){
dyld_library_path =
*p + sizeof("DYLD_LIBRARY_PATH=") - 1;
dyld_no_fix_prebinding = TRUE;
}
}
else if(strncmp(*p, "DYLD_FALLBACK_LIBRARY_PATH=",
sizeof("DYLD_FALLBACK_LIBRARY_PATH=") - 1) == 0){
if(getuid() != 0 &&
(getuid() != geteuid() || getgid() != getegid()))
(*p)[sizeof("DYLD_FALLBACK_LIBRARY_PATH=") - 1] = '\0';
else if(*(*p + sizeof(
"DYLD_FALLBACK_LIBRARY_PATH=") - 1) != '\0'){
dyld_fallback_library_path =
*p + sizeof("DYLD_FALLBACK_LIBRARY_PATH=") - 1;
dyld_no_fix_prebinding = TRUE;
}
}
else if(strncmp(*p, "DYLD_IMAGE_SUFFIX=",
sizeof("DYLD_IMAGE_SUFFIX=") - 1) == 0){
if(getuid() != 0 &&
(getuid() != geteuid() || getgid() != getegid()))
(*p)[sizeof("DYLD_IMAGE_SUFFIX=") - 1] = '\0';
else if(*(*p + sizeof("DYLD_IMAGE_SUFFIX=") - 1) != '\0'){
dyld_image_suffix =
*p + sizeof("DYLD_IMAGE_SUFFIX=") - 1;
dyld_no_fix_prebinding = TRUE;
}
}
else if(strncmp(*p, "DYLD_INSERT_LIBRARIES=",
sizeof("DYLD_INSERT_LIBRARIES=") - 1) == 0){
if(getuid() != 0 &&
(getuid() != geteuid() || getgid() != getegid()))
(*p)[sizeof("DYLD_INSERT_LIBRARIES=") - 1] = '\0';
else if(*(*p + sizeof("DYLD_INSERT_LIBRARIES=")- 1) !='\0'){
dyld_insert_libraries = malloc(strlen(
*p + sizeof("DYLD_INSERT_LIBRARIES=") - 1) + 1);
strcpy(dyld_insert_libraries,
*p + sizeof("DYLD_INSERT_LIBRARIES=") - 1);
dyld_no_fix_prebinding = TRUE;
}
}
else if(strncmp(*p, "DYLD_DEBUG_TRACE=",
sizeof("DYLD_DEBUG_TRACE=") - 1) == 0){
dyld_debug_trace = TRUE;
}
else if(strncmp(*p, "DYLD_ERROR_PRINT=",
sizeof("DYLD_ERROR_PRINT=") - 1) == 0){
dyld_error_print = TRUE;
}
else if(strncmp(*p, "DYLD_PRINT_LIBRARIES=",
sizeof("DYLD_PRINT_LIBRARIES=") - 1) == 0){
dyld_print_libraries = TRUE;
}
else if(strncmp(*p, "DYLD_TRACE=",
sizeof("DYLD_TRACE=") - 1) == 0){
dyld_trace = TRUE;
}
#if 0
else if(strncmp(*p, "DYLD_MEM_PROTECT=",
sizeof("DYLD_MEM_PROTECT=") - 1) == 0){
dyld_mem_protect = TRUE;
get_data_segment();
mem_prot_lock = *global_lock;
global_lock = &mem_prot_lock;
mem_prot_debug_lock = *debug_thread_lock;
debug_thread_lock = &mem_prot_debug_lock;
}
#endif
else if(strncmp(*p, "DYLD_EBADEXEC_ONLY=",
sizeof("DYLD_EBADEXEC_ONLY=") - 1) == 0){
dyld_ebadexec_only = TRUE;
}
else if(strncmp(*p, "DYLD_BIND_AT_LAUNCH=",
sizeof("DYLD_BIND_AT_LAUNCH=") - 1) == 0){
dyld_bind_at_launch = TRUE;
}
else if(strncmp(*p, "DYLD_FORCE_FLAT_NAMESPACE=",
sizeof("DYLD_FORCE_FLAT_NAMESPACE=") - 1) == 0){
dyld_force_flat_namespace = TRUE;
}
else if(strncmp(*p, "DYLD_DEAD_LOCK_HANG=",
sizeof("DYLD_DEAD_LOCK_HANG=") - 1) == 0){
dyld_dead_lock_hang = TRUE;
}
else if(strncmp(*p, "DYLD_ABORT_MULTIPLE_INITS=",
sizeof("DYLD_ABORT_MULTIPLE_INITS=") - 1) == 0){
dyld_abort_multiple_inits = TRUE;
}
else if(strncmp(*p, "DYLD_NEW_LOCAL_SHARED_REGIONS=",
sizeof("DYLD_NEW_LOCAL_SHARED_REGIONS=") - 1) == 0){
dyld_new_local_shared_regions = TRUE;
dyld_no_fix_prebinding = TRUE;
}
else if(strncmp(*p, "DYLD_NO_FIX_PREBINDING=",
sizeof("DYLD_NO_FIX_PREBINDING=") - 1) == 0){
dyld_no_fix_prebinding = TRUE;
}
else if(strncmp(*p, "DYLD_PREBIND_DEBUG=",
sizeof("DYLD_PREBIND_DEBUG") - 1) == 0){
if(strcmp("3", *p + sizeof("DYLD_PREBIND_DEBUG=") - 1) == 0)
dyld_prebind_debug = 3;
else if(strcmp("2",
*p + sizeof("DYLD_PREBIND_DEBUG=") - 1) == 0)
dyld_prebind_debug = 2;
else
dyld_prebind_debug = 1;
}
else if(strncmp(*p, "DYLD_HINTS_DEBUG=",
sizeof("DYLD_HINTS_DEBUG") - 1) == 0){
if(strcmp("2", *p + sizeof("DYLD_HINTS_DEBUG=") - 1) == 0)
dyld_hints_debug = 2;
else
dyld_hints_debug = 1;
}
else if(strncmp(*p, "DYLD_SAMPLE_DEBUG=",
sizeof("DYLD_SAMPLE_DEBUG") - 1) == 0){
if(strcmp("2", *p + sizeof("DYLD_SAMPLE_DEBUG=") - 1) == 0)
dyld_sample_debug = 2;
else
dyld_sample_debug = 1;
}
else if(strncmp(*p, "DYLD_EXECUTABLE_PATH_DEBUG=",
sizeof("DYLD_EXECUTABLE_PATH_DEBUG=") - 1) == 0){
dyld_executable_path_debug = TRUE;
}
else if(strncmp(*p, "DYLD_TWO_LEVEL_DEBUG=",
sizeof("DYLD_TWO_LEVEL_DEBUG=") - 1) == 0){
dyld_two_level_debug = TRUE;
}
}
else if(**p == 'H' && strncmp(*p, "HOME=", sizeof("HOME=")-1) == 0){
home = save_string(*p + sizeof("HOME=") - 1);
}
}
#if defined(__MACH30__) && (defined(__ppc__) || defined(__i386__))
exec_path = p[1];
if(dyld_executable_path_debug == TRUE)
printf("exec_path = %s\n", exec_path == NULL ? "NULL" : exec_path);
#endif
}
char *
getenv(const char *name)
{
return(NULL);
}
char ***
_NSGetEnviron(
void)
{
static char *p = NULL;
static char **pp = &p;
return(&pp);
}
#ifdef DYLD_PROFILING
void
profiling_exit(
int status)
{
dyld_monoutput();
_exit(status);
}
void
dyld_monoutput(
void)
{
struct stat stat_buf;
char *p, gmon_out[1024];
static enum bool done = FALSE;
if(done == TRUE)
return;
done = TRUE;
if(stat("/dyld.gmon.out", &stat_buf) == 0){
p = strrchr(executables_name, '/');
if(p == NULL)
p = executables_name;
else
p++;
sprintf(gmon_out, "/dyld.gmon.out/%s.%d", p, getpid());
monoutput(gmon_out);
}
}
#endif
#if 0
static
void
get_data_segment(
void)
{
long i;
data_seg = (struct segment_command *)
((char *)&_mh_dylinker_header + sizeof(struct mach_header));
for(i = 0; i < _mh_dylinker_header.ncmds; i++){
if(data_seg->cmd == LC_SEGMENT){
if(strncmp(data_seg->segname, SEG_DATA,
sizeof(data_seg->segname)) == 0){
return;
}
}
data_seg = (struct segment_command *)
((char *)data_seg + data_seg->cmdsize);
}
data_seg = NULL;
}
#endif
void
protect_data_segment(
void)
{
kern_return_t r;
if((r = vm_protect(mach_task_self(), data_seg->vmaddr +
dyld_image_vmaddr_slide, (vm_size_t)data_seg->vmsize,
FALSE, VM_PROT_READ)) != KERN_SUCCESS){
mach_error(r, "can't vm_protect data segment of dyld");
link_edit_error(DYLD_MACH_RESOURCE, r, "dyld");
}
}
void
unprotect_data_segment(
void)
{
kern_return_t r;
if((r = vm_protect(mach_task_self(), data_seg->vmaddr +
dyld_image_vmaddr_slide, (vm_size_t)data_seg->vmsize,
FALSE, data_seg->initprot)) != KERN_SUCCESS){
mach_error(r, "can't vm_(un)protect data segment of dyld");
link_edit_error(DYLD_MACH_RESOURCE, r, "dyld");
}
}