2
* Copyright (C) 2001-04 Luca Deri <deri@ntop.org>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
This file contains some compatibility functions that are needed for
23
ntop to run on Darwin/MacOS X
28
/* ***************************************************************** */
31
* This file was modified by Christoph Pfisterer <cp@chrisp.de>
32
* on Tue, Jan 23 2001. See the file "ChangeLog" for details of what
36
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
38
* @APPLE_LICENSE_HEADER_START@
40
* Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
41
* Reserved. This file contains Original Code and/or Modifications of
42
* Original Code as defined in and that are subject to the Apple Public
43
* Source License Version 1.1 (the "License"). You may not use this file
44
* except in compliance with the License. Please obtain a copy of the
45
* License at http://www.apple.com/publicsource and read it before using
48
* The Original Code and all software distributed under the License are
49
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
50
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
51
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
52
* FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
53
* License for the specific language governing rights and limitations
56
* @APPLE_LICENSE_HEADER_END@
62
#include <sys/types.h>
65
#include "mach-o/dyld.h"
66
#include "ntop_darwin.h"
72
#define DEBUG_PRINT(format) fprintf(stderr,(format));fflush(stderr)
73
#define DEBUG_PRINT1(format,arg1) fprintf(stderr,(format),(arg1));\
75
#define DEBUG_PRINT2(format,arg1,arg2) fprintf(stderr,(format),\
76
(arg1),(arg2));fflush(stderr)
77
#define DEBUG_PRINT3(format,arg1,arg2,arg3) fprintf(stderr,(format),\
78
(arg1),(arg2),(arg3));fflush(stderr)
80
#define DEBUG_PRINT(format) /**/
81
#define DEBUG_PRINT1(format,arg1) /**/
82
#define DEBUG_PRINT2(format,arg1,arg2) /**/
83
#define DEBUG_PRINT3(format,arg1,arg2,arg3) /**/
88
* The structure of a dlopen() handle.
90
struct dlopen_handle {
91
dev_t dev; /* the path's device and inode number from stat(2) */
93
int dlopen_mode; /* current dlopen mode for this handle */
94
int dlopen_count; /* number of times dlopen() called on this handle */
95
NSModule module; /* the NSModule returned by NSLinkModule() */
96
struct dlopen_handle *prev;
97
struct dlopen_handle *next;
99
static struct dlopen_handle *dlopen_handles = NULL;
100
static const struct dlopen_handle main_program_handle = {NULL};
101
static char *dlerror_pointer = NULL;
104
* NSMakePrivateModulePublic() is not part of the public dyld API so we define
105
* it here. The internal dyld function pointer for
106
* __dyld_NSMakePrivateModulePublic is returned so thats all that maters to get
107
* the functionality need to implement the dlopen() interfaces.
109
static int NSMakePrivateModulePublic(NSModule module)
114
_dyld_func_lookup("__dyld_NSMakePrivateModulePublic", (unsigned long *)&p);
118
printf("_dyld_func_lookup of __dyld_NSMakePrivateModulePublic "
127
* helper routine: search for a named module in various locations
132
const char *filename,
134
struct stat *stat_buf)
136
const char *pathspec;
141
const char *envvars[] = {
142
"$DYLD_LIBRARY_PATH",
148
pathbuf_end = pathbuf + PATH_MAX - 8;
150
for(envvar_index = 0; envvars[envvar_index]; envvar_index++) {
151
if(envvars[envvar_index][0] == '$') {
152
pathspec = getenv(envvars[envvar_index]+1);
155
pathspec = envvars[envvar_index];
158
if(pathspec != NULL) {
161
/* extract path list element */
164
while(*p && *p != ':' && q < pathbuf_end) *q++ = *p++;
165
if(q == pathbuf) { /* empty element */
176
element = p; /* this terminates the loop */
179
/* add slash if neccessary */
180
if(*(q-1) != '/' && q < pathbuf_end) {
184
/* append module name */
186
while(*p && q < pathbuf_end) *q++ = *p++;
189
if(q >= pathbuf_end) {
190
/* maybe add an error message here */
194
if(stat(pathbuf, stat_buf) == 0) {
201
/* we have searched everywhere, now we give up */
206
* dlopen() the MacOS X version of the FreeBSD dlopen() interface.
208
void* dlopen(const char *path, int mode)
210
const char *module_path;
212
struct stat stat_buf;
213
NSObjectFileImage objectFileImage;
214
NSObjectFileImageReturnCode ofile_result_code;
216
struct dlopen_handle *p;
217
unsigned long options;
220
char pathbuf[PATH_MAX];
222
DEBUG_PRINT2("libdl: dlopen(%s,0x%x) -> ", path, (unsigned int)mode);
224
dlerror_pointer = NULL;
226
* A NULL path is to indicate the caller wants a handle for the
230
retval = (void *)&main_program_handle;
231
DEBUG_PRINT1("main / %p\n", retval);
235
/* see if the path exists and if so get the device and inode number */
236
if(stat(path, &stat_buf) == -1) {
237
dlerror_pointer = strerror(errno);
240
DEBUG_PRINT1("ERROR (stat): %s\n", dlerror_pointer);
244
/* search for the module in various places */
245
if(_dl_search_paths(path, pathbuf, &stat_buf)) {
246
/* dlerror_pointer is unmodified */
247
DEBUG_PRINT1("ERROR (stat): %s\n", dlerror_pointer);
250
DEBUG_PRINT1("found %s -> ", pathbuf);
251
module_path = pathbuf;
252
dlerror_pointer = NULL;
259
* If we don't want an unshared handle see if we already have a handle
262
if((mode & RTLD_UNSHARED) != RTLD_UNSHARED) {
265
if(p->dev == stat_buf.st_dev && p->ino == stat_buf.st_ino) {
266
/* skip unshared handles */
267
if((p->dlopen_mode & RTLD_UNSHARED) == RTLD_UNSHARED)
270
* We have already created a handle for this path. The
271
* caller might be trying to promote an RTLD_LOCAL handle
272
* to a RTLD_GLOBAL. Or just looking it up with
275
if((p->dlopen_mode & RTLD_LOCAL) == RTLD_LOCAL &&
276
(mode & RTLD_GLOBAL) == RTLD_GLOBAL) {
277
/* promote the handle */
278
if(NSMakePrivateModulePublic(p->module) == TRUE) {
279
p->dlopen_mode &= ~RTLD_LOCAL;
280
p->dlopen_mode |= RTLD_GLOBAL;
282
DEBUG_PRINT1("%p\n", p);
286
dlerror_pointer = "can't promote handle from "
287
"RTLD_LOCAL to RTLD_GLOBAL";
288
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
293
DEBUG_PRINT1("%p\n", p);
301
* We do not have a handle for this path if we were just trying to
302
* look it up return NULL to indicate we don't have it.
304
if((mode & RTLD_NOLOAD) == RTLD_NOLOAD) {
305
dlerror_pointer = "no existing handle for path RTLD_NOLOAD test";
306
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
310
/* try to create an object file image from this path */
311
ofile_result_code = NSCreateObjectFileImageFromFile(module_path,
313
if(ofile_result_code != NSObjectFileImageSuccess) {
314
switch(ofile_result_code) {
315
case NSObjectFileImageFailure:
316
dlerror_pointer = "object file setup failure";
317
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
319
case NSObjectFileImageInappropriateFile:
320
dlerror_pointer = "not a Mach-O MH_BUNDLE file type";
321
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
323
case NSObjectFileImageArch:
324
dlerror_pointer = "no object for this architecture";
325
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
327
case NSObjectFileImageFormat:
328
dlerror_pointer = "bad object file format";
329
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
331
case NSObjectFileImageAccess:
332
dlerror_pointer = "can't read object file";
333
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
336
dlerror_pointer = "unknown error from "
337
"NSCreateObjectFileImageFromFile()";
338
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
343
/* try to link in this object file image */
344
options = NSLINKMODULE_OPTION_PRIVATE;
345
if((mode & RTLD_NOW) == RTLD_NOW)
346
options |= NSLINKMODULE_OPTION_BINDNOW;
347
module = NSLinkModule(objectFileImage, module_path, options);
348
NSDestroyObjectFileImage(objectFileImage) ;
350
dlerror_pointer = "NSLinkModule() failed for dlopen()";
351
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
356
* If the handle is to be global promote the handle. It is done this
357
* way to avoid multiply defined symbols.
359
if((mode & RTLD_GLOBAL) == RTLD_GLOBAL) {
360
if(NSMakePrivateModulePublic(module) == FALSE) {
361
dlerror_pointer = "can't promote handle from RTLD_LOCAL to "
363
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
368
p = malloc(sizeof(struct dlopen_handle));
370
dlerror_pointer = "can't allocate memory for the dlopen handle";
371
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
375
/* fill in the handle */
376
p->dev = stat_buf.st_dev;
377
p->ino = stat_buf.st_ino;
378
if(mode & RTLD_GLOBAL)
379
p->dlopen_mode = RTLD_GLOBAL;
381
p->dlopen_mode = RTLD_LOCAL;
382
p->dlopen_mode |= (mode & RTLD_UNSHARED) |
383
(mode & RTLD_NODELETE) |
384
(mode & RTLD_LAZY_UNDEF);
388
p->next = dlopen_handles;
389
if(dlopen_handles != NULL)
390
dlopen_handles->prev = p;
393
/* call the init function if one exists */
394
NSSymbol = NSLookupSymbolInModule(p->module, "__init");
395
if(NSSymbol != NULL) {
396
init = NSAddressOfSymbol(NSSymbol);
400
DEBUG_PRINT1("%p\n", p);
405
* dlsym() the MacOS X version of the FreeBSD dlopen() interface.
407
void* dlsym(void * handle, const char *symbol) {
408
struct dlopen_handle *dlopen_handle, *p;
412
DEBUG_PRINT2("libdl: dlsym(%p,%s) -> ", handle, symbol);
414
dlopen_handle = (struct dlopen_handle *)handle;
417
* If this is the handle for the main program do a global lookup.
419
if(dlopen_handle == (struct dlopen_handle *)&main_program_handle) {
420
if(NSIsSymbolNameDefined(symbol) == TRUE) {
421
nsSymbol = NSLookupAndBindSymbol(symbol);
422
address = NSAddressOfSymbol(nsSymbol);
423
dlerror_pointer = NULL;
424
DEBUG_PRINT1("%p\n", address);
428
dlerror_pointer = "symbol not found";
429
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
435
* Find this handle and do a lookup in just this module.
439
if(dlopen_handle == p) {
440
nsSymbol = NSLookupSymbolInModule(p->module, symbol);
441
if(nsSymbol != NULL) {
442
address = NSAddressOfSymbol(nsSymbol);
443
dlerror_pointer = NULL;
444
DEBUG_PRINT1("%p\n", address);
448
dlerror_pointer = "symbol not found";
449
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
456
dlerror_pointer = "bad handle passed to dlsym()";
457
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
462
* dlerror() the MacOS X version of the FreeBSD dlopen() interface.
470
p = (const char *)dlerror_pointer;
471
dlerror_pointer = NULL;
476
* dlclose() the MacOS X version of the FreeBSD dlopen() interface.
482
struct dlopen_handle *p, *q;
483
unsigned long options;
487
DEBUG_PRINT1("libdl: dlclose(%p) -> ", handle);
489
dlerror_pointer = NULL;
490
q = (struct dlopen_handle *)handle;
494
/* if the dlopen() count is not zero we are done */
496
if(p->dlopen_count != 0) {
501
/* call the fini function if one exists */
502
nsSymbol = NSLookupSymbolInModule(p->module, "__fini");
503
if(nsSymbol != NULL) {
504
fini = NSAddressOfSymbol(nsSymbol);
508
/* unlink the module for this handle */
510
if(p->dlopen_mode & RTLD_NODELETE)
511
options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
512
if(p->dlopen_mode & RTLD_LAZY_UNDEF)
513
options |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
514
if(NSUnLinkModule(p->module, options) == FALSE) {
515
dlerror_pointer = "NSUnLinkModule() failed for dlclose()";
516
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
520
p->prev->next = p->next;
522
p->next->prev = p->prev;
523
if(dlopen_handles == p)
524
dlopen_handles = p->next;
531
dlerror_pointer = "invalid handle passed to dlclose()";
532
DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
536
/* ***************************************************************** */