#ifndef __OPENSTEP__
#define NO_INDR_LIBC
#endif
#import <stdio.h>
#import <stdarg.h>
#import <string.h>
#import <libc.h>
#import <mach/mach.h>
#import "stuff/openstep_mach.h"
#define mach_error mach_error_not_used
#import <mach/mach_error.h>
#undef mach_error
#import <mach-o/nlist.h>
#import "images.h"
#import "symbols.h"
#import "errors.h"
#import "debug.h"
#import "lock.h"
#import "dyld_init.h"
enum bool dyld_error_print = FALSE;
unsigned long undefined_handler_recursion_level = 0;
void (*user_undefined_handler)(
const char *symbol_name) = NULL;
module_state * (*user_multiple_handler)(
struct nlist *symbol,
module_state *old_module,
module_state *new_module) = NULL;
void (*user_linkEdit_handler)(
enum link_edit_error_class error_class,
int error_number,
const char *file_name,
const char *error_string) = NULL;
static char *last;
static unsigned long left;
static void print_error_class(
enum link_edit_error_class error_class);
static void print_error_number(
enum link_edit_error_class error_class,
int error_number);
enum bool return_on_error = FALSE;
extern char NSLinkEditError_fileName[MAXPATHLEN + 1];
enum link_edit_error_class NSLinkEditError_errorClass = 0;
int NSLinkEditError_errorNumber = 0;
enum bool
check_and_report_undefineds(
enum bool invoke_user_handler_with_last_undefined)
{
struct symbol_list *undefined;
struct image *primary_image;
if(undefined_list.next == &undefined_list)
return(TRUE);
if(user_undefined_handler != NULL && return_on_error == FALSE){
while(undefined_list.next != &undefined_list &&
user_undefined_handler != NULL){
linkedit_error_enter();
undefined_handler_recursion_level++;
release_lock();
if(invoke_user_handler_with_last_undefined)
user_undefined_handler((const char *)undefined_list.prev->name);
else
user_undefined_handler((const char *)undefined_list.next->name);
set_lock();
undefined_handler_recursion_level--;
}
}
if(undefined_list.next == &undefined_list)
return(TRUE);
error("Undefined symbols:");
for(undefined = undefined_list.next;
undefined != &undefined_list;
undefined = undefined->next){
if(undefined->image != NULL && undefined->symbol != NULL &&
force_flat_namespace == FALSE &&
(undefined->image->mh->flags & MH_TWOLEVEL) == MH_TWOLEVEL){
if(undefined->image->umbrella_name != NULL)
add_error_string("%.*s undefined reference to %s expected "
"to be defined in ",
(int)undefined->image->name_size,
undefined->image->umbrella_name, undefined->name);
else
add_error_string("%s undefined reference to %s expected "
"to be defined in ", undefined->image->name,
undefined->name);
if(GET_LIBRARY_ORDINAL(undefined->symbol->n_desc) ==
EXECUTABLE_ORDINAL)
add_error_string("the executable\n");
else if(GET_LIBRARY_ORDINAL(undefined->symbol->n_desc) ==
SELF_LIBRARY_ORDINAL){
if(undefined->image->umbrella_name != NULL)
add_error_string("%.*s\n",
(int)undefined->image->name_size,
undefined->image->umbrella_name);
else
add_error_string("%s\n", undefined->image->name);
}
else if(GET_LIBRARY_ORDINAL(undefined->symbol->n_desc) ==
DYNAMIC_LOOKUP_ORDINAL){
add_error_string("a dynamic image\n");
}
else{
primary_image = undefined->image->dependent_images[
GET_LIBRARY_ORDINAL(undefined->symbol->n_desc) - 1];
if(primary_image->umbrella_name != NULL)
add_error_string("%.*s\n",
(int)primary_image->name_size,
primary_image->umbrella_name);
else
add_error_string("%s\n", primary_image->name);
}
}
else{
add_error_string("%s\n", undefined->name);
}
}
if(return_on_error == TRUE){
NSLinkEditError_fileName[0] = '\0';
NSLinkEditError_errorClass = DYLD_UNDEFINED;
NSLinkEditError_errorNumber = 0;
return(FALSE);
}
write(2, error_string, ERROR_STRING_SIZE - left);
halt();
exit(DYLD_EXIT_FAILURE_BASE + DYLD_UNDEFINED);
return(FALSE);
}
void
multiply_defined_error(
char *symbol_name,
struct image *new_image,
struct nlist *new_symbol,
module_state *new_module,
char *new_library_name,
char *new_module_name,
struct image *prev_image,
struct nlist *prev_symbol,
module_state *prev_module,
char *prev_library_name,
char *prev_module_name)
{
module_state *user_module;
unsigned long symbol_value;
if(user_multiple_handler != NULL && return_on_error == FALSE){
multiply_defined_enter();
user_module = user_multiple_handler(prev_symbol, prev_module,
new_module);
multiply_defined_exit();
if(user_module == new_module){
discard_symbol(prev_image, prev_symbol);
symbol_value = new_symbol->n_value;
if((new_symbol->n_type & N_TYPE) != N_ABS)
symbol_value += new_image->vmaddr_slide;
change_symbol_pointers_in_flat_images(symbol_name, symbol_value,
FALSE);
}
return;
}
error("multiple definitions of symbol %s", symbol_name);
if(prev_library_name != NULL)
add_error_string("%s(%s) definition of %s\n", prev_library_name,
prev_module_name, symbol_name);
else
add_error_string("%s definition of %s\n", prev_module_name,
symbol_name);
if(new_library_name != NULL)
add_error_string("%s(%s) definition of %s\n", new_library_name,
new_module_name, symbol_name);
else
add_error_string("%s definition of %s\n", new_module_name,
symbol_name);
if(return_on_error == TRUE){
NSLinkEditError_fileName[0] = '\0';
NSLinkEditError_errorClass = DYLD_MULTIPLY_DEFINED;
NSLinkEditError_errorNumber = 0;
return;
}
write(2, error_string, ERROR_STRING_SIZE - left);
halt();
exit(DYLD_EXIT_FAILURE_BASE + DYLD_MULTIPLY_DEFINED);
}
void
unlinked_lazy_pointer_handler(
void)
{
error("Call to undefined routine after a NSUnLinkModule with the "
"NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES option");
link_edit_error(DYLD_OTHER_ERROR, DYLD_LAZY_BIND, NULL);
halt();
exit(DYLD_EXIT_FAILURE_BASE + DYLD_OTHER_ERROR);
}
void
dead_lock_error(
void)
{
extern enum bool dyld_dead_lock_hang;
error("dead lock (dyld operation attempted in a thread already doing "
"a dyld operation)");
write(2, error_string, ERROR_STRING_SIZE - left);
if(dyld_dead_lock_hang){
for(;;)
;
}
halt();
exit(DYLD_EXIT_FAILURE_BASE + DYLD_DEAD_LOCK);
}
void
link_edit_error(
enum link_edit_error_class error_class,
int error_number,
char *file_name)
{
enum bool recoverable;
recoverable = FALSE;
if(error_class == DYLD_MACH_RESOURCE_RECOVERABLE){
error_class = DYLD_MACH_RESOURCE;
if(return_on_error == TRUE)
recoverable = TRUE;
}
if(error_class == DYLD_OTHER_ERROR &&
error_number == DYLD_INVALID_ARGS &&
return_on_error == TRUE){
recoverable = TRUE;
}
if(user_linkEdit_handler != NULL && return_on_error == FALSE){
linkedit_error_enter();
user_linkEdit_handler(error_class, error_number,
(const char *)file_name,
(const char *)error_string);
if(error_class == DYLD_FILE_ACCESS ||
error_class == DYLD_FILE_FORMAT ||
error_class == DYLD_WARNING)
return;
}
if(return_on_error == TRUE &&
(error_class == DYLD_FILE_ACCESS ||
error_class == DYLD_FILE_FORMAT ||
error_class == DYLD_WARNING ||
recoverable == TRUE)){
if(file_name == NULL)
NSLinkEditError_fileName[0] = '\0';
else{
strncpy(NSLinkEditError_fileName, file_name, MAXPATHLEN);
NSLinkEditError_fileName[MAXPATHLEN] = '\0';
}
NSLinkEditError_errorClass = error_class;
NSLinkEditError_errorNumber = error_number;
return;
}
if(error_class == DYLD_WARNING){
write(2, error_string, ERROR_STRING_SIZE - left);
reset_error_string();
return;
}
write(2, error_string, ERROR_STRING_SIZE - left);
if(dyld_error_print){
print_error_class(error_class);
print_error_number(error_class, error_number);
}
halt();
exit(DYLD_EXIT_FAILURE_BASE + error_class);
}
void
abort(
void)
{
kill(getpid(), SIGABRT);
halt();
exit(DYLD_EXIT_FAILURE_BASE + DYLD_UNIX_RESOURCE);
}
void
reset_error_string(
void)
{
last = error_string;
left = ERROR_STRING_SIZE;
error_string[0] = '\0';
}
void
error(
const char *format,
...)
{
va_list ap;
va_start(ap, format);
set_error_string("dyld: ");
add_error_string("%s ", executables_name);
vadd_error_string(format, ap);
add_error_string("\n");
va_end(ap);
}
void
system_error(
int errnum,
const char *format,
...)
{
va_list ap;
va_start(ap, format);
set_error_string("dyld: ");
add_error_string("%s ", executables_name);
vadd_error_string(format, ap);
add_error_string(" (%s, errno = %d)\n", strerror(errnum), errnum);
va_end(ap);
}
void
mach_error(
kern_return_t r,
char *format,
...)
{
va_list ap;
va_start(ap, format);
set_error_string("dyld: ");
add_error_string("%s ", executables_name);
vadd_error_string(format, ap);
#ifdef NO_INDR_LIBC
add_error_string(" (kern return = %d)\n", r);
#else
add_error_string(" (%s, kern return = %d)\n", mach_error_string(r), r);
#endif
va_end(ap);
}
void
set_error_string(
const char *format,
...)
{
va_list ap;
va_start(ap, format);
vset_error_string(format, ap);
va_end(ap);
}
void
vset_error_string(
const char *format,
va_list ap)
{
unsigned long new;
last = error_string;
left = ERROR_STRING_SIZE;
#ifdef __OPENSTEP__
new = vsprintf(error_string, format, ap);
#else
new = vsnprintf(last, left, format, ap);
#endif
last += new;
left -= new;
}
void
add_error_string(
const char *format,
...)
{
va_list ap;
va_start(ap, format);
vadd_error_string(format, ap);
va_end(ap);
}
void
vadd_error_string(
const char *format,
va_list ap)
{
unsigned long new;
#ifdef __OPENSTEP__
new = vsprintf(last, format, ap);
#else
new = vsnprintf(last, left, format, ap);
#endif
last += new;
left -= new;
}
static const char * const link_edit_error_class_names[] = {
"DYLD_FILE_ACCESS",
"DYLD_FILE_FORMAT",
"DYLD_MACH_RESOURCE",
"DYLD_UNIX_RESOURCE",
"DYLD_OTHER_ERROR",
"DYLD_WARNING"
};
static
void
print_error_class(
enum link_edit_error_class error_class)
{
if(error_class <= DYLD_WARNING)
print("error_class = %s\n",
link_edit_error_class_names[error_class]);
else
print("error_class = %u\n", error_class);
}
#import <errno.h>
static void print_error_number(
enum link_edit_error_class error_class,
int error_number)
{
if(error_class == DYLD_OTHER_ERROR){
if(error_number == DYLD_RELOCATION)
print("error_number = DYLD_RELOCATION\n");
else if(error_number == DYLD_LAZY_BIND)
print("error_number = DYLD_LAZY_BIND\n");
else if(error_number == DYLD_INDR_LOOP)
print("error_number = DYLD_INDR_LOOP\n");
else
print("error_number = %d\n", error_number);
}
else{
if(error_number == EBADMACHO)
print("error_number = EBADMACHO\n");
else if(error_number == EBADEXEC)
print("error_number = EBADEXEC\n");
else if(error_number == EBADARCH)
print("error_number = EBADARCH\n");
else if(error_number == ESHLIBVERS)
print("error_number = ESHLIBVERS\n");
else
print("error_number = %d\n", error_number);
}
}
void
print(
const char *format,
...)
{
va_list ap;
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
}