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 }