/*
* Copyright (C) 2001-05 Luca Deri <deri@ntop.org>
*
* http://www.ntop.org/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
This file contains some compatibility functions that are needed for
ntop to run on Darwin/MacOS X
*/
#if defined(DARWIN) && (!defined(TIGER))
/* ***************************************************************** */
/*
* This file was modified by Christoph Pfisterer <cp@chrisp.de>
* on Tue, Jan 23 2001. See the file "ChangeLog" for details of what
* was changed.
*
*
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
* Reserved. This file contains Original Code and/or Modifications of
* Original Code as defined in and that are subject to the Apple Public
* Source License Version 1.1 (the "License"). You may not use this file
* except in compliance with the License. Please obtain a copy of the
* License at http://www.apple.com/publicsource and read it before using
* this file.
*
* The Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include "mach-o/dyld.h"
#include "ntop_darwin.h"
/*
* debugging macros
*/
#if DEBUG > 0
#define DEBUG_PRINT(format) fprintf(stderr,(format));fflush(stderr)
#define DEBUG_PRINT1(format,arg1) fprintf(stderr,(format),(arg1));\
fflush(stderr)
#define DEBUG_PRINT2(format,arg1,arg2) fprintf(stderr,(format),\
(arg1),(arg2));fflush(stderr)
#define DEBUG_PRINT3(format,arg1,arg2,arg3) fprintf(stderr,(format),\
(arg1),(arg2),(arg3));fflush(stderr)
#else
#define DEBUG_PRINT(format) /**/
#define DEBUG_PRINT1(format,arg1) /**/
#define DEBUG_PRINT2(format,arg1,arg2) /**/
#define DEBUG_PRINT3(format,arg1,arg2,arg3) /**/
#undef DEBUG
#endif
/*
* The structure of a dlopen() handle.
*/
struct dlopen_handle {
dev_t dev; /* the path's device and inode number from stat(2) */
ino_t ino;
int dlopen_mode; /* current dlopen mode for this handle */
int dlopen_count; /* number of times dlopen() called on this handle */
NSModule module; /* the NSModule returned by NSLinkModule() */
struct dlopen_handle *prev;
struct dlopen_handle *next;
};
static struct dlopen_handle *dlopen_handles = NULL;
static const struct dlopen_handle main_program_handle = {NULL};
static char *dlerror_pointer = NULL;
/*
* NSMakePrivateModulePublic() is not part of the public dyld API so we define
* it here. The internal dyld function pointer for
* __dyld_NSMakePrivateModulePublic is returned so thats all that maters to get
* the functionality need to implement the dlopen() interfaces.
*/
static int NSMakePrivateModulePublic(NSModule module)
{
static NSModule *p;
if(p == NULL)
_dyld_func_lookup("__dyld_NSMakePrivateModulePublic", (unsigned long *)&p);
if(p == NULL) {
#ifdef DEBUG
printf("_dyld_func_lookup of __dyld_NSMakePrivateModulePublic "
"failed\n");
#endif
return(FALSE);
} else
return(TRUE);
}
/*
* helper routine: search for a named module in various locations
*/
static
int
_dl_search_paths(
const char *filename,
char *pathbuf,
struct stat *stat_buf)
{
const char *pathspec;
const char *element;
const char *p;
char *q;
char *pathbuf_end;
const char *envvars[] = {
"$DYLD_LIBRARY_PATH",
"$LD_LIBRARY_PATH",
"/usr/lib:/lib",
NULL };
int envvar_index;
pathbuf_end = pathbuf + PATH_MAX - 8;
for(envvar_index = 0; envvars[envvar_index]; envvar_index++) {
if(envvars[envvar_index][0] == '$') {
pathspec = getenv(envvars[envvar_index]+1);
}
else {
pathspec = envvars[envvar_index];
}
if(pathspec != NULL) {
element = pathspec;
while(*element) {
/* extract path list element */
p = element;
q = pathbuf;
while(*p && *p != ':' && q < pathbuf_end) *q++ = *p++;
if(q == pathbuf) { /* empty element */
if(*p) {
element = p+1;
continue;
}
break;
}
if (*p) {
element = p+1;
}
else{
element = p; /* this terminates the loop */
}
/* add slash if neccessary */
if(*(q-1) != '/' && q < pathbuf_end) {
*q++ = '/';
}
/* append module name */
p = filename;
while(*p && q < pathbuf_end) *q++ = *p++;
*q++ = 0;
if(q >= pathbuf_end) {
/* maybe add an error message here */
break;
}
if(stat(pathbuf, stat_buf) == 0) {
return 0;
}
}
}
}
/* we have searched everywhere, now we give up */
return -1;
}
/*
* dlopen() the MacOS X version of the FreeBSD dlopen() interface.
*/
void* dlopen(const char *path, int mode)
{
const char *module_path;
void *retval;
struct stat stat_buf;
NSObjectFileImage objectFileImage;
NSObjectFileImageReturnCode ofile_result_code;
NSModule module;
struct dlopen_handle *p;
unsigned long options;
NSSymbol NSSymbol;
void (*init)(void);
char pathbuf[PATH_MAX];
DEBUG_PRINT2("libdl: dlopen(%s,0x%x) -> ", path, (unsigned int)mode);
dlerror_pointer = NULL;
/*
* A NULL path is to indicate the caller wants a handle for the
* main program.
*/
if(path == NULL) {
retval = (void *)&main_program_handle;
DEBUG_PRINT1("main / %p\n", retval);
return(retval);
}
/* see if the path exists and if so get the device and inode number */
if(stat(path, &stat_buf) == -1) {
dlerror_pointer = strerror(errno);
if(path[0] == '/') {
DEBUG_PRINT1("ERROR (stat): %s\n", dlerror_pointer);
return(NULL);
}
/* search for the module in various places */
if(_dl_search_paths(path, pathbuf, &stat_buf)) {
/* dlerror_pointer is unmodified */
DEBUG_PRINT1("ERROR (stat): %s\n", dlerror_pointer);
return(NULL);
}
DEBUG_PRINT1("found %s -> ", pathbuf);
module_path = pathbuf;
dlerror_pointer = NULL;
}
else{
module_path = path;
}
/*
* If we don't want an unshared handle see if we already have a handle
* for this path.
*/
if((mode & RTLD_UNSHARED) != RTLD_UNSHARED) {
p = dlopen_handles;
while(p != NULL) {
if(p->dev == stat_buf.st_dev && p->ino == stat_buf.st_ino) {
/* skip unshared handles */
if((p->dlopen_mode & RTLD_UNSHARED) == RTLD_UNSHARED)
continue;
/*
* We have already created a handle for this path. The
* caller might be trying to promote an RTLD_LOCAL handle
* to a RTLD_GLOBAL. Or just looking it up with
* RTLD_NOLOAD.
*/
if((p->dlopen_mode & RTLD_LOCAL) == RTLD_LOCAL &&
(mode & RTLD_GLOBAL) == RTLD_GLOBAL) {
/* promote the handle */
if(NSMakePrivateModulePublic(p->module) == TRUE) {
p->dlopen_mode &= ~RTLD_LOCAL;
p->dlopen_mode |= RTLD_GLOBAL;
p->dlopen_count++;
DEBUG_PRINT1("%p\n", p);
return(p);
}
else{
dlerror_pointer = "can't promote handle from "
"RTLD_LOCAL to RTLD_GLOBAL";
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
return(NULL);
}
}
p->dlopen_count++;
DEBUG_PRINT1("%p\n", p);
return(p);
}
p = p->next;
}
}
/*
* We do not have a handle for this path if we were just trying to
* look it up return NULL to indicate we don't have it.
*/
if((mode & RTLD_NOLOAD) == RTLD_NOLOAD) {
dlerror_pointer = "no existing handle for path RTLD_NOLOAD test";
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
return(NULL);
}
/* try to create an object file image from this path */
ofile_result_code = NSCreateObjectFileImageFromFile(module_path,
&objectFileImage);
if(ofile_result_code != NSObjectFileImageSuccess) {
switch(ofile_result_code) {
case NSObjectFileImageFailure:
dlerror_pointer = "object file setup failure";
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
return(NULL);
case NSObjectFileImageInappropriateFile:
dlerror_pointer = "not a Mach-O MH_BUNDLE file type";
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
return(NULL);
case NSObjectFileImageArch:
dlerror_pointer = "no object for this architecture";
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
return(NULL);
case NSObjectFileImageFormat:
dlerror_pointer = "bad object file format";
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
return(NULL);
case NSObjectFileImageAccess:
dlerror_pointer = "can't read object file";
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
return(NULL);
default:
dlerror_pointer = "unknown error from "
"NSCreateObjectFileImageFromFile()";
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
return(NULL);
}
}
/* try to link in this object file image */
options = NSLINKMODULE_OPTION_PRIVATE;
if((mode & RTLD_NOW) == RTLD_NOW)
options |= NSLINKMODULE_OPTION_BINDNOW;
module = NSLinkModule(objectFileImage, module_path, options);
NSDestroyObjectFileImage(objectFileImage) ;
if(module == NULL) {
dlerror_pointer = "NSLinkModule() failed for dlopen()";
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
return(NULL);
}
/*
* If the handle is to be global promote the handle. It is done this
* way to avoid multiply defined symbols.
*/
if((mode & RTLD_GLOBAL) == RTLD_GLOBAL) {
if(NSMakePrivateModulePublic(module) == FALSE) {
dlerror_pointer = "can't promote handle from RTLD_LOCAL to "
"RTLD_GLOBAL";
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
return(NULL);
}
}
p = malloc(sizeof(struct dlopen_handle));
if(p == NULL) {
dlerror_pointer = "can't allocate memory for the dlopen handle";
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
return(NULL);
}
/* fill in the handle */
p->dev = stat_buf.st_dev;
p->ino = stat_buf.st_ino;
if(mode & RTLD_GLOBAL)
p->dlopen_mode = RTLD_GLOBAL;
else
p->dlopen_mode = RTLD_LOCAL;
p->dlopen_mode |= (mode & RTLD_UNSHARED) |
(mode & RTLD_NODELETE) |
(mode & RTLD_LAZY_UNDEF);
p->dlopen_count = 1;
p->module = module;
p->prev = NULL;
p->next = dlopen_handles;
if(dlopen_handles != NULL)
dlopen_handles->prev = p;
dlopen_handles = p;
/* call the init function if one exists */
NSSymbol = NSLookupSymbolInModule(p->module, "__init");
if(NSSymbol != NULL) {
init = NSAddressOfSymbol(NSSymbol);
init();
}
DEBUG_PRINT1("%p\n", p);
return(p);
}
/*
* dlsym() the MacOS X version of the FreeBSD dlopen() interface.
*/
void* dlsym(void * handle, const char *symbol) {
struct dlopen_handle *dlopen_handle, *p;
NSSymbol nsSymbol;
void *address;
DEBUG_PRINT2("libdl: dlsym(%p,%s) -> ", handle, symbol);
dlopen_handle = (struct dlopen_handle *)handle;
/*
* If this is the handle for the main program do a global lookup.
*/
if(dlopen_handle == (struct dlopen_handle *)&main_program_handle) {
if(NSIsSymbolNameDefined(symbol) == TRUE) {
nsSymbol = NSLookupAndBindSymbol(symbol);
address = NSAddressOfSymbol(nsSymbol);
dlerror_pointer = NULL;
DEBUG_PRINT1("%p\n", address);
return(address);
}
else{
dlerror_pointer = "symbol not found";
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
return(NULL);
}
}
/*
* Find this handle and do a lookup in just this module.
*/
p = dlopen_handles;
while(p != NULL) {
if(dlopen_handle == p) {
nsSymbol = NSLookupSymbolInModule(p->module, symbol);
if(nsSymbol != NULL) {
address = NSAddressOfSymbol(nsSymbol);
dlerror_pointer = NULL;
DEBUG_PRINT1("%p\n", address);
return(address);
}
else{
dlerror_pointer = "symbol not found";
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
return(NULL);
}
}
p = p->next;
}
dlerror_pointer = "bad handle passed to dlsym()";
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
return(NULL);
}
/*
* dlerror() the MacOS X version of the FreeBSD dlopen() interface.
*/
const char *
dlerror(
void)
{
const char *p;
p = (const char *)dlerror_pointer;
dlerror_pointer = NULL;
return(p);
}
/*
* dlclose() the MacOS X version of the FreeBSD dlopen() interface.
*/
int
dlclose(
void * handle)
{
struct dlopen_handle *p, *q;
unsigned long options;
NSSymbol nsSymbol;
void (*fini)(void);
DEBUG_PRINT1("libdl: dlclose(%p) -> ", handle);
dlerror_pointer = NULL;
q = (struct dlopen_handle *)handle;
p = dlopen_handles;
while(p != NULL) {
if(p == q) {
/* if the dlopen() count is not zero we are done */
p->dlopen_count--;
if(p->dlopen_count != 0) {
DEBUG_PRINT("OK");
return(0);
}
/* call the fini function if one exists */
nsSymbol = NSLookupSymbolInModule(p->module, "__fini");
if(nsSymbol != NULL) {
fini = NSAddressOfSymbol(nsSymbol);
fini();
}
/* unlink the module for this handle */
options = 0;
if(p->dlopen_mode & RTLD_NODELETE)
options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
if(p->dlopen_mode & RTLD_LAZY_UNDEF)
options |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
if(NSUnLinkModule(p->module, options) == FALSE) {
dlerror_pointer = "NSUnLinkModule() failed for dlclose()";
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
return(-1);
}
if(p->prev != NULL)
p->prev->next = p->next;
if(p->next != NULL)
p->next->prev = p->prev;
if(dlopen_handles == p)
dlopen_handles = p->next;
free(p);
DEBUG_PRINT("OK");
return(0);
}
p = p->next;
}
dlerror_pointer = "invalid handle passed to dlclose()";
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
return(-1);
}
/* ***************************************************************** */
#endif
syntax highlighted by Code2HTML, v. 0.9.1