#ifdef SHLIB
#include "shlib.h"
#endif
static const char* nlist_bsearch_strings;
static const char* toc_bsearch_strings;
static const struct nlist* toc_bsearch_symbols;
#include "inline_strcmp.h"
#include "inline_bsearch.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#ifndef __OPENSTEP__
#include <crt_externs.h>
#endif
#include <mach/mach.h>
#include "stuff/openstep_mach.h"
#include <unistd.h>
#ifdef _POSIX_THREADS
#include <pthread.h>
#else
#include <mach/cthreads.h>
#endif
#include <mach/mach_error.h>
#include "stuff/bool.h"
#include "mach-o/dyld.h"
#include "mach-o/getsect.h"
#include "mach-o/dyld_priv.h"
#include "stuff/ofile.h"
#include "stuff/arch.h"
#include "stuff/errors.h"
#include "ofi.h"
__private_extern__ char *progname = NULL;
__private_extern__ unsigned long errors = 0;
#ifdef _POSIX_THREADS
static pthread_mutex_t ofi_error_printing_mutex = PTHREAD_MUTEX_INITIALIZER;
#else
static mutex_t ofi_error_printing_mutex = NULL;
#endif
#ifdef __MACH30__
static thread_port_t thread_printing_error = MACH_PORT_NULL;
#else
static port_t thread_printing_error = MACH_PORT_NULL;
#endif
#ifdef _POSIX_THREADS
static pthread_mutex_t ofi_alloc_mutex = PTHREAD_MUTEX_INITIALIZER;
#else
static mutex_t ofi_alloc_mutex = NULL;
#endif
#define N_OFI 10
struct ofi_list {
struct ofi list[N_OFI];
enum bool used[N_OFI];
struct ofi_list *next;
};
static struct ofi_list *ofi_lists = NULL;
static struct ofi * ofi_alloc(
void);
static enum bool ofi_free(
struct ofi *ofi);
static enum bool ofi_valid(
struct ofi *ofi);
static NSObjectFileImageReturnCode NSCreateImageFromFileOrMemory(
enum bool coreFile,
const char *pathName,
void *address,
unsigned long size,
NSObjectFileImage *objectFileImage);
NSObjectFileImageReturnCode
NSCreateObjectFileImageFromFile(
const char *pathName,
NSObjectFileImage *objectFileImage)
{
return(NSCreateImageFromFileOrMemory(FALSE, pathName, NULL, 0,
objectFileImage));
}
NSObjectFileImageReturnCode
NSCreateObjectFileImageFromMemory(
void *address,
unsigned long size,
NSObjectFileImage *objectFileImage)
{
return(NSCreateImageFromFileOrMemory(FALSE,
"NSCreateObjectFileImageFromMemory() call",
address, size, objectFileImage));
}
NSObjectFileImageReturnCode
NSCreateCoreFileImageFromFile(
const char *pathName,
NSObjectFileImage *objectFileImage)
{
return(NSCreateImageFromFileOrMemory(TRUE, pathName, NULL, 0,
objectFileImage));
}
static
NSObjectFileImageReturnCode
NSCreateImageFromFileOrMemory(
enum bool coreFile,
const char *pathName,
void *address,
unsigned long size,
NSObjectFileImage *objectFileImage)
{
struct arch_flag host_arch_flag;
NSObjectFileImageReturnCode o;
struct ofi *ofi;
#ifndef __OPENSTEP__
static char ***NXArgv_pointer = NULL;
if(NXArgv_pointer == NULL)
NXArgv_pointer = _NSGetArgv();
progname = (*NXArgv_pointer)[0];
#else
#ifndef __DYNAMIC__
extern char **NXArgv;
progname = NXArgv[0];
#else
static char ***NXArgv_pointer = NULL;
if(NXArgv_pointer == NULL)
_dyld_lookup_and_bind("_NXArgv",
(unsigned long *)&NXArgv_pointer, NULL);
progname = (*NXArgv_pointer)[0];
#endif
#endif
*objectFileImage = NULL;
if(get_arch_from_host(&host_arch_flag, NULL) == 0){
error("can't determine the host architecture (fix "
"get_arch_from_host() )");
o = NSObjectFileImageFailure;
goto done;
}
ofi = ofi_alloc();
if(ofi == NULL){
error("can't allocate memory for NSObjectFileImage");
o = NSObjectFileImageFailure;
goto done;
}
if(address != NULL)
o = ofile_map_from_memory(address, size, pathName, &host_arch_flag,
NULL, &(ofi->ofile),FALSE);
else
o = ofile_map(pathName, &host_arch_flag, NULL, &(ofi->ofile),FALSE);
if(o != NSObjectFileImageSuccess){
(void)ofi_free(ofi);
goto done;
}
if(ofi->ofile.file_type != OFILE_Mach_O &&
(ofi->ofile.file_type != OFILE_FAT ||
ofi->ofile.arch_type != OFILE_Mach_O)){
o = NSObjectFileImageInappropriateFile;
ofile_unmap(&(ofi->ofile));
(void)ofi_free(ofi);
goto done;
}
if(ofi->ofile.mh->filetype == MH_FVMLIB ||
(ofi->ofile.mh->filetype == MH_CORE && coreFile == FALSE) ||
ofi->ofile.mh->filetype == MH_DYLIB ||
ofi->ofile.mh->filetype == MH_DYLINKER){
o = NSObjectFileImageInappropriateFile;
ofile_unmap(&(ofi->ofile));
(void)ofi_free(ofi);
goto done;
}
if(coreFile == FALSE && ofi->ofile.mh->filetype != MH_BUNDLE){
if(ofi->ofile.mh->filetype == MH_OBJECT ||
ofi->ofile.mh->filetype == MH_EXECUTE ||
ofi->ofile.mh->filetype == MH_PRELOAD){
o = NSObjectFileImageInappropriateFile;
ofile_unmap(&(ofi->ofile));
(void)ofi_free(ofi);
goto done;
}
else{
o = NSObjectFileImageInappropriateFile;
ofile_unmap(&(ofi->ofile));
(void)ofi_free(ofi);
goto done;
}
}
*objectFileImage = (NSObjectFileImage)ofi;
done:
if(thread_printing_error == mach_thread_self()){
thread_printing_error = MACH_PORT_NULL;
#ifdef _POSIX_THREADS
pthread_mutex_unlock(&ofi_error_printing_mutex);
#else
mutex_unlock(ofi_error_printing_mutex);
#endif
}
return(o);
}
static
struct ofi *
ofi_alloc(void)
{
struct ofi_list **p, *ofi_list;
unsigned long i;
#ifdef _POSIX_THREADS
pthread_mutex_lock(&ofi_alloc_mutex);
#else
if(ofi_alloc_mutex == NULL)
ofi_alloc_mutex = mutex_alloc();
mutex_lock(ofi_alloc_mutex);
#endif
for(p = &ofi_lists; ; p = &((*p)->next)){
if(*p == NULL){
ofi_list = malloc(sizeof(struct ofi_list));
if(ofi_list == NULL){
#ifdef _POSIX_THREADS
pthread_mutex_unlock(&ofi_alloc_mutex);
#else
mutex_unlock(ofi_alloc_mutex);
#endif
return(NULL);
}
*p = ofi_list;
memset(ofi_list, '\0', sizeof(struct ofi_list));
ofi_list->used[0] = TRUE;
#ifdef _POSIX_THREADS
pthread_mutex_unlock(&ofi_alloc_mutex);
#else
mutex_unlock(ofi_alloc_mutex);
#endif
return(ofi_list->list);
}
ofi_list = *p;
for(i = 0; i < N_OFI; i++){
if(ofi_list->used[i] == FALSE){
memset(ofi_list->list + i, '\0', sizeof(struct ofi));
ofi_list->used[i] = TRUE;
#ifdef _POSIX_THREADS
pthread_mutex_unlock(&ofi_alloc_mutex);
#else
mutex_unlock(ofi_alloc_mutex);
#endif
return(ofi_list->list + i);
}
}
}
#ifdef _POSIX_THREADS
pthread_mutex_unlock(&ofi_alloc_mutex);
#else
mutex_unlock(ofi_alloc_mutex);
#endif
return(NULL);
}
static
enum bool
ofi_free(
struct ofi *ofi)
{
struct ofi_list **p, *ofi_list, *prev;
unsigned long i, used;
enum bool return_value;
#ifdef _POSIX_THREADS
pthread_mutex_lock(&ofi_alloc_mutex);
#else
if(ofi_alloc_mutex == NULL)
ofi_alloc_mutex = mutex_alloc();
mutex_lock(ofi_alloc_mutex);
#endif
return_value = FALSE;
prev = NULL;
for(p = &ofi_lists; *p != NULL; p = &((*p)->next)){
ofi_list = *p;
used = 0;
for(i = 0; i < N_OFI; i++){
if(ofi_list->used[i] == TRUE){
if(ofi == ofi_list->list + i){
ofi_list->used[i] = FALSE;
memset(ofi_list->list + i, '\0', sizeof(struct ofi));
return_value = TRUE;
}
else{
used++;
}
}
}
if(used == 0){
if(prev == NULL){
ofi_lists = ofi_list->next;
}
else{
prev->next = ofi_list->next;
}
free(ofi_list);
break;
}
prev = ofi_list;
}
#ifdef _POSIX_THREADS
pthread_mutex_unlock(&ofi_alloc_mutex);
#else
mutex_unlock(ofi_alloc_mutex);
#endif
return(return_value);
}
static
enum bool
ofi_valid(
struct ofi *ofi)
{
struct ofi_list *ofi_list;
unsigned long i;
for(ofi_list = ofi_lists; ofi_list != NULL; ofi_list = ofi_list->next){
for(i = 0; i < N_OFI; i++){
if(ofi_list->list + i == ofi)
return(TRUE);
}
}
return(FALSE);
}
__private_extern__
void
vprint(
const char *format,
va_list ap)
{
#ifndef _POSIX_THREADS
if(ofi_error_printing_mutex == NULL)
ofi_error_printing_mutex = mutex_alloc();
#endif
if(thread_printing_error != mach_thread_self()){
#ifdef _POSIX_THREADS
pthread_mutex_lock(&ofi_error_printing_mutex);
#else
mutex_lock(ofi_error_printing_mutex);
#endif
thread_printing_error = mach_thread_self();
}
vfprintf(stderr, format, ap);
}
__private_extern__
void
print(
const char *format,
...)
{
va_list ap;
va_start(ap, format);
vprint(format, ap);
va_end(ap);
}
__private_extern__
void
error(
const char *format,
...)
{
va_list ap;
va_start(ap, format);
print("%s: ", progname);
vprint(format, ap);
print("\n");
va_end(ap);
errors++;
}
__private_extern__
void
system_error(
const char *format,
...)
{
va_list ap;
va_start(ap, format);
print("%s: ", progname);
vprint(format, ap);
print(" (%s)\n", strerror(errno));
va_end(ap);
errors++;
}
__private_extern__
void
my_mach_error(
kern_return_t r,
char *format,
...)
{
va_list ap;
va_start(ap, format);
print("%s: ", progname);
vprint(format, ap);
print(" (%s)\n", mach_error_string(r));
va_end(ap);
errors++;
}
__private_extern__
char *
savestr(
const char *s)
{
long len;
char *r;
len = strlen(s) + 1;
r = (char *)malloc(len);
if(r == NULL)
return(NULL);
strcpy(r, s);
return(r);
}
enum bool
NSDestroyObjectFileImage(
NSObjectFileImage objectFileImage)
{
struct ofi *ofi;
ofi = (struct ofi *)objectFileImage;
if(ofi_valid(ofi) == FALSE)
return(FALSE);
ofile_unmap(&(ofi->ofile));
if(ofi_free(ofi) == FALSE)
return(FALSE);
return(TRUE);
}
static
enum bool
GetObjectFileImageSymbols(
NSObjectFileImage objectFileImage,
const struct dysymtab_command **dyst,
const struct nlist **symbols,
const char **strings)
{
const struct ofile *ofile;
const struct load_command *lc;
const struct symtab_command *st;
unsigned long i;
st = NULL;
*dyst = NULL;
ofile = (struct ofile *)objectFileImage;
lc = ofile->load_commands;
for(i = 0; i < ofile->mh->ncmds; i++){
switch(lc->cmd){
case LC_SYMTAB:
st = (struct symtab_command *)lc;
*symbols = (struct nlist *)(ofile->object_addr + st->symoff);
*strings = ofile->object_addr + st->stroff;
break;
case LC_DYSYMTAB:
*dyst = (struct dysymtab_command *)lc;
break;
}
if((st != NULL) && (*dyst != NULL)){
return(TRUE);
}
lc = (struct load_command *)(((char *)lc)+ lc->cmdsize);
}
*dyst = NULL;
*symbols = NULL;
*strings = NULL;
return(FALSE);
}
unsigned long
NSSymbolDefinitionCountInObjectFileImage(
NSObjectFileImage objectFileImage)
{
const struct dysymtab_command *dyst;
const struct nlist *symbols;
const char *strings;
if(GetObjectFileImageSymbols(objectFileImage, &dyst, &symbols,&strings))
return(dyst->nextdefsym);
return(0);
}
const char *
NSSymbolDefinitionNameInObjectFileImage(
NSObjectFileImage objectFileImage,
unsigned long ordinal)
{
const struct dysymtab_command *dyst;
const struct nlist *symbols;
const char *strings;
if(GetObjectFileImageSymbols(objectFileImage, &dyst, &symbols,
&strings)){
if(ordinal < dyst->nextdefsym){
return(strings +
symbols[dyst->iextdefsym + ordinal].n_un.n_strx);
}
}
return(NULL);
}
unsigned long
NSSymbolReferenceCountInObjectFileImage(
NSObjectFileImage objectFileImage)
{
const struct dysymtab_command *dyst;
const struct nlist *symbols;
const char *strings;
if(GetObjectFileImageSymbols(objectFileImage, &dyst, &symbols,&strings))
return(dyst->nundefsym);
return(0);
}
const char *
NSSymbolReferenceNameInObjectFileImage(
NSObjectFileImage objectFileImage,
unsigned long ordinal,
enum bool *tentative_definition)
{
const struct dysymtab_command *dyst;
const struct nlist *symbols, *symbol;
const char *strings;
if(GetObjectFileImageSymbols(objectFileImage, &dyst, &symbols,
&strings)){
if(ordinal < dyst->nundefsym){
symbol = symbols + dyst->iundefsym + ordinal;
if(tentative_definition != NULL){
if((symbol->n_type & N_TYPE) == N_UNDF &&
symbol->n_value != 0)
*tentative_definition = TRUE;
else
*tentative_definition = FALSE;
}
return(strings + symbol->n_un.n_strx);
}
}
if(tentative_definition != NULL)
*tentative_definition = FALSE;
return(NULL);
}
enum bool
NSIsSymbolDefinedInObjectFileImage(
NSObjectFileImage objectFileImage,
const char *symbolName)
{
const struct dysymtab_command *dyst;
const struct nlist *symbols, *symbol;
const char *strings;
if(GetObjectFileImageSymbols(objectFileImage, &dyst, &symbols,
&strings)){
nlist_bsearch_strings = strings;
symbol = inline_bsearch_nlist(symbolName,
symbols + dyst->iextdefsym,
dyst->nextdefsym);
if(symbol != NULL)
return(TRUE);
}
return(FALSE);
}
void *
NSGetSectionDataInObjectFileImage(
NSObjectFileImage objectFileImage,
const char *segmentName,
const char *sectionName,
unsigned long *size)
{
const struct ofile *ofile;
struct load_command *lc;
struct segment_command *sg;
struct section *s;
unsigned long i, j;
ofile = (struct ofile *)objectFileImage;
lc = ofile->load_commands;
for(i = 0; i < ofile->mh->ncmds; i++){
switch(lc->cmd){
case LC_SEGMENT:
sg = (struct segment_command *)lc;
s = (struct section *)
((char *)sg + sizeof(struct segment_command));
for(j = 0; j < sg->nsects; j++){
if(strncmp(s->segname, segmentName,
sizeof(s->segname)) == 0 &&
strncmp(s->sectname, sectionName,
sizeof(s->sectname)) == 0){
if((s->flags & SECTION_TYPE) == S_ZEROFILL){
if(size != NULL)
*size = 0;
return(NULL);
}
if(size != NULL)
*size = s->size;
return((void *)((unsigned long)(ofile->mh) +
s->offset));
}
s++;
}
}
lc = (struct load_command *)(((char *)lc)+ lc->cmdsize);
}
if(size != NULL)
*size = 0;
return(NULL);
}
enum DYLD_BOOL
NSFindSectionAndOffsetInObjectFileImage(
NSObjectFileImage objectFileImage,
unsigned long imageOffset,
const char** segmentName,
const char** sectionName,
unsigned long* sectionOffset)
{
const struct ofile *ofile;
const struct load_command *lc;
const struct mach_header *mh;
const struct segment_command *sg;
const struct section *s;
unsigned long i, j;
ofile = (struct ofile *)objectFileImage;
mh = ofile->mh;
lc = ofile->load_commands;
for(i = 0; i < mh->ncmds; i++){
switch(lc->cmd){
case LC_SEGMENT:
sg = (struct segment_command *)lc;
s = (struct section *)((char *)sg +
sizeof(struct segment_command));
for(j = 0; j < sg->nsects; j++){
if((s->addr <= imageOffset) &&
(imageOffset < (s->addr+s->size))) {
if(segmentName != NULL)
*segmentName = s->segname;
if(sectionName != NULL)
*sectionName = s->sectname;
if(sectionOffset != NULL)
*sectionOffset = imageOffset - s->addr;
return(TRUE);
}
s++;
}
}
lc = (struct load_command *)(((char *)lc)+ lc->cmdsize);
}
return(FALSE);
}
enum bool
NSHasModInitObjectFileImage(
NSObjectFileImage objectFileImage)
{
const struct ofile *ofile;
struct load_command *lc;
struct segment_command *sg;
struct section *s;
unsigned long i, j;
ofile = (struct ofile *)objectFileImage;
lc = ofile->load_commands;
for(i = 0; i < ofile->mh->ncmds; i++){
switch(lc->cmd){
case LC_SEGMENT:
sg = (struct segment_command *)lc;
s = (struct section *)
((char *)sg + sizeof(struct segment_command));
for(j = 0; j < sg->nsects; j++){
if((s->flags & SECTION_TYPE) == S_MOD_INIT_FUNC_POINTERS)
return(TRUE);
s++;
}
}
lc = (struct load_command *)(((char *)lc)+ lc->cmdsize);
}
return(FALSE);
}