Doxygen Source Code Documentation
Main Page Alphabetical List Data Structures File List Data Fields Globals Search
dlopen.c
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #include <errno.h>
00033 #include <sys/types.h>
00034 #include <sys/stat.h>
00035 #include <limits.h>
00036 #include "mach-o/dyld.h"
00037 #include "dlfcn.h"
00038
00039
00040
00041
00042 #if DEBUG > 0
00043 #define DEBUG_PRINT(format) fprintf(stderr,(format));fflush(stderr)
00044 #define DEBUG_PRINT1(format,arg1) fprintf(stderr,(format),(arg1));\
00045 fflush(stderr)
00046 #define DEBUG_PRINT2(format,arg1,arg2) fprintf(stderr,(format),\
00047 (arg1),(arg2));fflush(stderr)
00048 #define DEBUG_PRINT3(format,arg1,arg2,arg3) fprintf(stderr,(format),\
00049 (arg1),(arg2),(arg3));fflush(stderr)
00050 #else
00051 #define DEBUG_PRINT(format)
00052 #define DEBUG_PRINT1(format,arg1)
00053 #define DEBUG_PRINT2(format,arg1,arg2)
00054 #define DEBUG_PRINT3(format,arg1,arg2,arg3)
00055 #undef DEBUG
00056 #endif
00057
00058
00059
00060
00061 struct dlopen_handle {
00062 dev_t dev;
00063 ino_t ino;
00064 int dlopen_mode;
00065 int dlopen_count;
00066 NSModule module;
00067 struct dlopen_handle *prev;
00068 struct dlopen_handle *next;
00069 };
00070 static struct dlopen_handle *dlopen_handles = NULL;
00071 static const struct dlopen_handle main_program_handle = {NULL};
00072 static char *dlerror_pointer = NULL;
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083 static enum DYLD_BOOL
00084 NSMakePrivateModulePublic(
00085 NSModule module)
00086 {
00087 static enum DYLD_BOOL (*p)(NSModule module) = NULL;
00088
00089 if(p == NULL)
00090 _dyld_func_lookup("__dyld_NSMakePrivateModulePublic",
00091 (unsigned long *)&p);
00092 if(p == NULL){
00093 #ifdef DEBUG
00094 printf("_dyld_func_lookup of __dyld_NSMakePrivateModulePublic "
00095 "failed\n");
00096 #endif
00097 return(FALSE);
00098 }
00099 return(p(module));
00100 }
00101
00102
00103
00104
00105 static
00106 int
00107 _dl_search_paths(
00108 const char *filename,
00109 char *pathbuf,
00110 struct stat *stat_buf)
00111 {
00112 const char *pathspec;
00113 const char *element;
00114 const char *p;
00115 char *q;
00116 char *pathbuf_end;
00117 const char *envvars[] = {
00118 "$DYLD_LIBRARY_PATH",
00119 "$LD_LIBRARY_PATH",
00120 "/usr/lib:/lib",
00121 NULL };
00122 int envvar_index;
00123
00124 pathbuf_end = pathbuf + PATH_MAX - 8;
00125
00126 for(envvar_index = 0; envvars[envvar_index]; envvar_index++){
00127 if(envvars[envvar_index][0] == '$'){
00128 pathspec = getenv(envvars[envvar_index]+1);
00129 }
00130 else {
00131 pathspec = envvars[envvar_index];
00132 }
00133
00134 if(pathspec != NULL){
00135 element = pathspec;
00136 while(*element){
00137
00138 p = element;
00139 q = pathbuf;
00140 while(*p && *p != ':' && q < pathbuf_end) *q++ = *p++;
00141 if(q == pathbuf){
00142 if(*p){
00143 element = p+1;
00144 continue;
00145 }
00146 break;
00147 }
00148 if (*p){
00149 element = p+1;
00150 }
00151 else{
00152 element = p;
00153 }
00154
00155
00156 if(*(q-1) != '/' && q < pathbuf_end){
00157 *q++ = '/';
00158 }
00159
00160
00161 p = filename;
00162 while(*p && q < pathbuf_end) *q++ = *p++;
00163 *q++ = 0;
00164
00165 if(q >= pathbuf_end){
00166
00167 break;
00168 }
00169
00170 if(stat(pathbuf, stat_buf) == 0){
00171 return 0;
00172 }
00173 }
00174 }
00175 }
00176
00177
00178 return -1;
00179 }
00180
00181
00182
00183
00184 void *
00185 dlopen(
00186 const char *path,
00187 int mode)
00188 {
00189 const char *module_path;
00190 void *retval;
00191 struct stat stat_buf;
00192 NSObjectFileImage objectFileImage;
00193 NSObjectFileImageReturnCode ofile_result_code;
00194 NSModule module;
00195 struct dlopen_handle *p;
00196 unsigned long options;
00197 NSSymbol NSSymbol;
00198 void (*init)(void);
00199 char pathbuf[PATH_MAX];
00200
00201 DEBUG_PRINT2("libdl: dlopen(%s,0x%x) -> ", path, (unsigned int)mode);
00202
00203 dlerror_pointer = NULL;
00204
00205
00206
00207
00208 if(path == NULL){
00209 retval = (void *)&main_program_handle;
00210 DEBUG_PRINT1("main / %p\n", retval);
00211 return(retval);
00212 }
00213
00214
00215 if(stat(path, &stat_buf) == -1){
00216 dlerror_pointer = strerror(errno);
00217
00218 if(path[0] == '/'){
00219 DEBUG_PRINT1("ERROR (stat): %s\n", dlerror_pointer);
00220 return(NULL);
00221 }
00222
00223
00224 if(_dl_search_paths(path, pathbuf, &stat_buf)){
00225
00226 DEBUG_PRINT1("ERROR (stat): %s\n", dlerror_pointer);
00227 return(NULL);
00228 }
00229 DEBUG_PRINT1("found %s -> ", pathbuf);
00230 module_path = pathbuf;
00231 dlerror_pointer = NULL;
00232 }
00233 else{
00234 module_path = path;
00235 }
00236
00237
00238
00239
00240
00241 if((mode & RTLD_UNSHARED) != RTLD_UNSHARED){
00242 p = dlopen_handles;
00243 while(p != NULL){
00244 if(p->dev == stat_buf.st_dev && p->ino == stat_buf.st_ino){
00245
00246 if((p->dlopen_mode & RTLD_UNSHARED) == RTLD_UNSHARED)
00247 continue;
00248
00249
00250
00251
00252
00253
00254 if((p->dlopen_mode & RTLD_LOCAL) == RTLD_LOCAL &&
00255 (mode & RTLD_GLOBAL) == RTLD_GLOBAL){
00256
00257 if(NSMakePrivateModulePublic(p->module) == TRUE){
00258 p->dlopen_mode &= ~RTLD_LOCAL;
00259 p->dlopen_mode |= RTLD_GLOBAL;
00260 p->dlopen_count++;
00261 DEBUG_PRINT1("%p\n", p);
00262 return(p);
00263 }
00264 else{
00265 dlerror_pointer = "can't promote handle from "
00266 "RTLD_LOCAL to RTLD_GLOBAL";
00267 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
00268 return(NULL);
00269 }
00270 }
00271 p->dlopen_count++;
00272 DEBUG_PRINT1("%p\n", p);
00273 return(p);
00274 }
00275 p = p->next;
00276 }
00277 }
00278
00279
00280
00281
00282
00283 if((mode & RTLD_NOLOAD) == RTLD_NOLOAD){
00284 dlerror_pointer = "no existing handle for path RTLD_NOLOAD test";
00285 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
00286 return(NULL);
00287 }
00288
00289
00290 ofile_result_code = NSCreateObjectFileImageFromFile(module_path,
00291 &objectFileImage);
00292 if(ofile_result_code != NSObjectFileImageSuccess){
00293 switch(ofile_result_code){
00294 case NSObjectFileImageFailure:
00295 dlerror_pointer = "object file setup failure";
00296 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
00297 return(NULL);
00298 case NSObjectFileImageInappropriateFile:
00299 dlerror_pointer = "not a Mach-O MH_BUNDLE file type";
00300 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
00301 return(NULL);
00302 case NSObjectFileImageArch:
00303 dlerror_pointer = "no object for this architecture";
00304 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
00305 return(NULL);
00306 case NSObjectFileImageFormat:
00307 dlerror_pointer = "bad object file format";
00308 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
00309 return(NULL);
00310 case NSObjectFileImageAccess:
00311 dlerror_pointer = "can't read object file";
00312 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
00313 return(NULL);
00314 default:
00315 dlerror_pointer = "unknown error from "
00316 "NSCreateObjectFileImageFromFile()";
00317 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
00318 return(NULL);
00319 }
00320 }
00321
00322
00323 options = NSLINKMODULE_OPTION_PRIVATE;
00324 if((mode & RTLD_NOW) == RTLD_NOW)
00325 options |= NSLINKMODULE_OPTION_BINDNOW;
00326 module = NSLinkModule(objectFileImage, module_path, options);
00327 NSDestroyObjectFileImage(objectFileImage) ;
00328 if(module == NULL){
00329 dlerror_pointer = "NSLinkModule() failed for dlopen()";
00330 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
00331 return(NULL);
00332 }
00333
00334
00335
00336
00337
00338 if((mode & RTLD_GLOBAL) == RTLD_GLOBAL){
00339 if(NSMakePrivateModulePublic(module) == FALSE){
00340 dlerror_pointer = "can't promote handle from RTLD_LOCAL to "
00341 "RTLD_GLOBAL";
00342 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
00343 return(NULL);
00344 }
00345 }
00346
00347 p = malloc(sizeof(struct dlopen_handle));
00348 if(p == NULL){
00349 dlerror_pointer = "can't allocate memory for the dlopen handle";
00350 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
00351 return(NULL);
00352 }
00353
00354
00355 p->dev = stat_buf.st_dev;
00356 p->ino = stat_buf.st_ino;
00357 if(mode & RTLD_GLOBAL)
00358 p->dlopen_mode = RTLD_GLOBAL;
00359 else
00360 p->dlopen_mode = RTLD_LOCAL;
00361 p->dlopen_mode |= (mode & RTLD_UNSHARED) |
00362 (mode & RTLD_NODELETE) |
00363 (mode & RTLD_LAZY_UNDEF);
00364 p->dlopen_count = 1;
00365 p->module = module;
00366 p->prev = NULL;
00367 p->next = dlopen_handles;
00368 if(dlopen_handles != NULL)
00369 dlopen_handles->prev = p;
00370 dlopen_handles = p;
00371
00372
00373 NSSymbol = NSLookupSymbolInModule(p->module, "__init");
00374 if(NSSymbol != NULL){
00375 init = NSAddressOfSymbol(NSSymbol);
00376 init();
00377 }
00378
00379 DEBUG_PRINT1("%p\n", p);
00380 return(p);
00381 }
00382
00383
00384
00385
00386 void *
00387 dlsym(
00388 void * handle,
00389 const char *symbol)
00390 {
00391 struct dlopen_handle *dlopen_handle, *p;
00392 NSSymbol NSSymbol;
00393 void *address;
00394
00395 DEBUG_PRINT2("libdl: dlsym(%p,%s) -> ", handle, symbol);
00396
00397 dlopen_handle = (struct dlopen_handle *)handle;
00398
00399
00400
00401
00402 if(dlopen_handle == (struct dlopen_handle *)&main_program_handle){
00403 if(NSIsSymbolNameDefined(symbol) == TRUE){
00404 NSSymbol = NSLookupAndBindSymbol(symbol);
00405 address = NSAddressOfSymbol(NSSymbol);
00406 dlerror_pointer = NULL;
00407 DEBUG_PRINT1("%p\n", address);
00408 return(address);
00409 }
00410 else{
00411 dlerror_pointer = "symbol not found";
00412 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
00413 return(NULL);
00414 }
00415 }
00416
00417
00418
00419
00420 p = dlopen_handles;
00421 while(p != NULL){
00422 if(dlopen_handle == p){
00423 NSSymbol = NSLookupSymbolInModule(p->module, symbol);
00424 if(NSSymbol != NULL){
00425 address = NSAddressOfSymbol(NSSymbol);
00426 dlerror_pointer = NULL;
00427 DEBUG_PRINT1("%p\n", address);
00428 return(address);
00429 }
00430 else{
00431 dlerror_pointer = "symbol not found";
00432 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
00433 return(NULL);
00434 }
00435 }
00436 p = p->next;
00437 }
00438
00439 dlerror_pointer = "bad handle passed to dlsym()";
00440 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
00441 return(NULL);
00442 }
00443
00444
00445
00446
00447 const char *
00448 dlerror(
00449 void)
00450 {
00451 const char *p;
00452
00453 p = (const char *)dlerror_pointer;
00454 dlerror_pointer = NULL;
00455 return(p);
00456 }
00457
00458
00459
00460
00461 int
00462 dlclose(
00463 void * handle)
00464 {
00465 struct dlopen_handle *p, *q;
00466 unsigned long options;
00467 NSSymbol NSSymbol;
00468 void (*fini)(void);
00469
00470 DEBUG_PRINT1("libdl: dlclose(%p) -> ", handle);
00471
00472 dlerror_pointer = NULL;
00473 q = (struct dlopen_handle *)handle;
00474 p = dlopen_handles;
00475 while(p != NULL){
00476 if(p == q){
00477
00478 p->dlopen_count--;
00479 if(p->dlopen_count != 0){
00480 DEBUG_PRINT("OK");
00481 return(0);
00482 }
00483
00484
00485 NSSymbol = NSLookupSymbolInModule(p->module, "__fini");
00486 if(NSSymbol != NULL){
00487 fini = NSAddressOfSymbol(NSSymbol);
00488 fini();
00489 }
00490
00491
00492 options = 0;
00493 if(p->dlopen_mode & RTLD_NODELETE)
00494 options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
00495 if(p->dlopen_mode & RTLD_LAZY_UNDEF)
00496 options |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
00497 if(NSUnLinkModule(p->module, options) == FALSE){
00498 dlerror_pointer = "NSUnLinkModule() failed for dlclose()";
00499 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
00500 return(-1);
00501 }
00502 if(p->prev != NULL)
00503 p->prev->next = p->next;
00504 if(p->next != NULL)
00505 p->next->prev = p->prev;
00506 if(dlopen_handles == p)
00507 dlopen_handles = p->next;
00508 free(p);
00509 DEBUG_PRINT("OK");
00510 return(0);
00511 }
00512 p = p->next;
00513 }
00514 dlerror_pointer = "invalid handle passed to dlclose()";
00515 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
00516 return(-1);
00517 }