Sun Aug 6 15:02:40 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

dlfcn.c

Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2002 Jorge Acereda  <jacereda@users.sourceforge.net> &
00003                    Peter O'Gorman <ogorman@users.sourceforge.net>
00004                    
00005 Portions may be copyright others, see the AUTHORS file included with this
00006 distribution.                  
00007 
00008 Maintained by Peter O'Gorman <ogorman@users.sourceforge.net>
00009 
00010 Bug Reports and other queries should go to <ogorman@users.sourceforge.net>
00011 
00012 Permission is hereby granted, free of charge, to any person obtaining
00013 a copy of this software and associated documentation files (the
00014 "Software"), to deal in the Software without restriction, including
00015 without limitation the rights to use, copy, modify, merge, publish,
00016 distribute, sublicense, and/or sell copies of the Software, and to
00017 permit persons to whom the Software is furnished to do so, subject to
00018 the following conditions:
00019 
00020 The above copyright notice and this permission notice shall be
00021 included in all copies or substantial portions of the Software.
00022 
00023 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00024 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00025 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00026 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00027 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00028 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00029 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00030 */
00031 
00032 #include <pthread.h>
00033 #include <stdio.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036 #include <sys/types.h>
00037 #include <sys/stat.h>
00038 #include <stdarg.h>
00039 #include <limits.h>
00040 #include <mach-o/dyld.h>
00041 #include <mach-o/nlist.h>
00042 #include <mach-o/getsect.h>
00043 /* Just playing to see if it would compile with the freebsd headers, it does,
00044  * but because of the different values for RTLD_LOCAL etc, it would break binary
00045  * compat... oh well
00046  */
00047 #ifndef __BSD_VISIBLE
00048 #define __BSD_VISIBLE 1
00049 #endif
00050 
00051 #include "asterisk/dlfcn-compat.h"
00052 
00053 #ifndef dl_restrict
00054 #define dl_restrict __restrict
00055 #endif
00056 /* This is not available on 10.1 */
00057 #ifndef LC_LOAD_WEAK_DYLIB
00058 #define  LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD)
00059 #endif
00060 
00061 /* With this stuff here, this thing may actually compile/run on 10.0 systems
00062  * Not that I have a 10.0 system to test it on anylonger
00063  */
00064 #ifndef LC_REQ_DYLD
00065 #define LC_REQ_DYLD 0x80000000
00066 #endif
00067 #ifndef NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
00068 #define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 0x4
00069 #endif
00070 #ifndef NSADDIMAGE_OPTION_RETURN_ON_ERROR
00071 #define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1
00072 #endif
00073 #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
00074 #define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 0x0
00075 #endif
00076 #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
00077 #define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4
00078 #endif
00079 /* These symbols will be looked for in dyld */
00080 static const struct mach_header *(*dyld_NSAddImage) (const char *, unsigned long) = 0;
00081 static int (*dyld_NSIsSymbolNameDefinedInImage) (const struct mach_header *, const char *) = 0;
00082 static NSSymbol(*dyld_NSLookupSymbolInImage)
00083    (const struct mach_header *, const char *, unsigned long) = 0;
00084 
00085 /* Define this to make dlcompat reuse data block. This way in theory we save
00086  * a little bit of overhead. However we then couldn't correctly catch excess
00087  * calls to dlclose(). Hence we don't use this feature
00088  */
00089 #undef REUSE_STATUS
00090 
00091 /* Size of the internal error message buffer (used by dlerror()) */
00092 #define ERR_STR_LEN        251
00093 
00094 /* Maximum number of search paths supported by getSearchPath */
00095 #define MAX_SEARCH_PATHS   32
00096 
00097 
00098 #define MAGIC_DYLIB_OFI ((NSObjectFileImage) 'DYOF')
00099 #define MAGIC_DYLIB_MOD ((NSModule) 'DYMO')
00100 
00101 /* internal flags */
00102 #define DL_IN_LIST 0x01
00103 
00104 /* our mutex */
00105 static pthread_mutex_t dlcompat_mutex;
00106 /* Our thread specific storage
00107  */
00108 static pthread_key_t dlerror_key;
00109 
00110 struct dlthread
00111 {
00112    int lockcnt;
00113    unsigned char errset;
00114    char errstr[ERR_STR_LEN];
00115 };
00116 
00117 /* This is our central data structure. Whenever a module is loaded via
00118  * dlopen(), we create such a struct.
00119  */
00120 struct dlstatus
00121 {
00122    struct dlstatus *next;     /* pointer to next element in the linked list */
00123    NSModule module;
00124    const struct mach_header *lib;
00125    int refs;               /* reference count */
00126    int mode;               /* mode in which this module was loaded */
00127    dev_t device;
00128    ino_t inode;
00129    int flags;              /* Any internal flags we may need */
00130 };
00131 
00132 /* Head node of the dlstatus list */
00133 static struct dlstatus mainStatus = { 0, MAGIC_DYLIB_MOD, NULL, -1, RTLD_GLOBAL, 0, 0, 0 };
00134 static struct dlstatus *stqueue = &mainStatus;
00135 
00136 
00137 /* Storage for the last error message (used by dlerror()) */
00138 /* static char err_str[ERR_STR_LEN]; */
00139 /* static int err_filled = 0; */
00140 
00141 /* Prototypes to internal functions */
00142 static void debug(const char *fmt, ...);
00143 static void error(const char *str, ...);
00144 static const char *safegetenv(const char *s);
00145 static const char *searchList(void);
00146 static const char *getSearchPath(int i);
00147 static const char *getFullPath(int i, const char *file);
00148 static const struct stat *findFile(const char *file, const char **fullPath);
00149 static int isValidStatus(struct dlstatus *status);
00150 static inline int isFlagSet(int mode, int flag);
00151 static struct dlstatus *lookupStatus(const struct stat *sbuf);
00152 static void insertStatus(struct dlstatus *dls, const struct stat *sbuf);
00153 static int promoteLocalToGlobal(struct dlstatus *dls);
00154 static void *reference(struct dlstatus *dls, int mode);
00155 static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError);
00156 static struct dlstatus *allocStatus(void);
00157 static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode);
00158 static NSSymbol *search_linked_libs(const struct mach_header *mh, const char *symbol);
00159 static const char *get_lib_name(const struct mach_header *mh);
00160 static const struct mach_header *get_mach_header_from_NSModule(NSModule * mod);
00161 static void dlcompat_init_func(void);
00162 static inline void dolock(void);
00163 static inline void dounlock(void);
00164 static void dlerrorfree(void *data);
00165 static void resetdlerror(void);
00166 static const struct mach_header *my_find_image(const char *name);
00167 static const struct mach_header *image_for_address(const void *address);
00168 static void dlcompat_cleanup(void);
00169 static inline const char *dyld_error_str(void);
00170 
00171 #if FINK_BUILD
00172 /* Two Global Functions */
00173 void *dlsym_prepend_underscore(void *handle, const char *symbol);
00174 void *dlsym_auto_underscore(void *handle, const char *symbol);
00175 
00176 /* And their _intern counterparts */
00177 static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol);
00178 static void *dlsym_auto_underscore_intern(void *handle, const char *symbol);
00179 #endif
00180 
00181 /* Functions */
00182 
00183 static void debug(const char *fmt, ...)
00184 {
00185 #if DEBUG > 1
00186    va_list arg;
00187    va_start(arg, fmt);
00188    fprintf(stderr, "DLDEBUG: ");
00189    vfprintf(stderr, fmt, arg);
00190    fprintf(stderr, "\n");
00191    fflush(stderr);
00192    va_end(arg);
00193 #endif
00194 }
00195 
00196 static void error(const char *str, ...)
00197 {
00198    va_list arg;
00199    struct dlthread  *tss;
00200    char * err_str;
00201    va_start(arg, str);
00202    tss = pthread_getspecific(dlerror_key);
00203    err_str = tss->errstr;
00204    strncpy(err_str, "dlcompat: ", ERR_STR_LEN);
00205    vsnprintf(err_str + 10, ERR_STR_LEN - 10, str, arg);
00206    va_end(arg);
00207    debug("ERROR: %s\n", err_str);
00208    tss->errset = 1;
00209 }
00210 
00211 static void warning(const char *str)
00212 {
00213 #if DEBUG > 0
00214    fprintf(stderr, "WARNING: dlcompat: %s\n", str);
00215 #endif
00216 }
00217 
00218 static const char *safegetenv(const char *s)
00219 {
00220    const char *ss = getenv(s);
00221    return ss ? ss : "";
00222 }
00223 
00224 /* because this is only used for debugging and error reporting functions, we
00225  * don't really care about how elegant it is... it could use the load
00226  * commands to find the install name of the library, but...
00227  */
00228 static const char *get_lib_name(const struct mach_header *mh)
00229 {
00230    unsigned long count = _dyld_image_count();
00231    unsigned long i;
00232    const char *val = NULL;
00233    if (mh)
00234    {
00235       for (i = 0; i < count; i++)
00236       {
00237          if (mh == _dyld_get_image_header(i))
00238          {
00239             val = _dyld_get_image_name(i);
00240             break;
00241          }
00242       }
00243    }
00244    return val;
00245 }
00246 
00247 /* Returns the mach_header for the module bu going through all the loaded images
00248  * and finding the one with the same name as the module. There really ought to be
00249  * an api for doing this, would be faster, but there isn't one right now
00250  */
00251 static const struct mach_header *get_mach_header_from_NSModule(NSModule * mod)
00252 {
00253    const char *mod_name = NSNameOfModule(mod);
00254    struct mach_header *mh = NULL;
00255    unsigned long count = _dyld_image_count();
00256    unsigned long i;
00257    debug("Module name: %s", mod_name);
00258    for (i = 0; i < count; i++)
00259    {
00260       if (!strcmp(mod_name, _dyld_get_image_name(i)))
00261       {
00262          mh = _dyld_get_image_header(i);
00263          break;
00264       }
00265    }
00266    return mh;
00267 }
00268 
00269 
00270 /* Compute and return a list of all directories that we should search when
00271  * trying to locate a module. We first look at the values of LD_LIBRARY_PATH
00272  * and DYLD_LIBRARY_PATH, and then finally fall back to looking into
00273  * /usr/lib and /lib. Since both of the environments variables can contain a
00274  * list of colon separated paths, we simply concat them and the two other paths
00275  * into one big string, which we then can easily parse.
00276  * Splitting this string into the actual path list is done by getSearchPath()
00277  */
00278 static const char *searchList()
00279 {
00280    size_t buf_size;
00281    static char *buf=NULL;
00282    const char *ldlp = safegetenv("LD_LIBRARY_PATH");
00283    const char *dyldlp = safegetenv("DYLD_LIBRARY_PATH");
00284    const char *stdpath = getenv("DYLD_FALLBACK_LIBRARY_PATH");
00285    if (!stdpath)
00286       stdpath = "/usr/local/lib:/lib:/usr/lib";
00287    if (!buf)
00288    {  
00289       buf_size = strlen(ldlp) + strlen(dyldlp) + strlen(stdpath) + 4;
00290       buf = malloc(buf_size);
00291       snprintf(buf, buf_size, "%s%s%s%s%s%c", dyldlp, (dyldlp[0] ? ":" : ""), ldlp, (ldlp[0] ? ":" : ""),
00292              stdpath, '\0');
00293    }
00294    return buf;
00295 }
00296 
00297 /* Returns the ith search path from the list as computed by searchList() */
00298 static const char *getSearchPath(int i)
00299 {
00300    static const char *list = 0;
00301    static char **path = (char **)0;
00302    static int end = 0;
00303    static int numsize = MAX_SEARCH_PATHS;
00304    static char **tmp;
00305    /* So we can call free() in the "destructor" we use i=-1 to return the alloc'd array */
00306    if (i == -1)
00307    {
00308       return (const char*)path;
00309    }
00310    if (!path)
00311    {
00312       path = (char **)calloc(MAX_SEARCH_PATHS, sizeof(char **));
00313    }
00314    if (!list && !end)
00315       list = searchList();
00316    if (i >= (numsize))
00317    {
00318       debug("Increasing size for long PATH");
00319       tmp = (char **)calloc((MAX_SEARCH_PATHS + numsize), sizeof(char **));
00320       if (tmp)
00321       {
00322          memcpy(tmp, path, sizeof(char **) * numsize);
00323          free(path);
00324          path = tmp;
00325          numsize += MAX_SEARCH_PATHS;
00326       }
00327       else
00328       {
00329          return 0;
00330       }
00331    }
00332 
00333    while (!path[i] && !end)
00334    {
00335       path[i] = strsep((char **)&list, ":");
00336 
00337       if (path[i][0] == 0)
00338          path[i] = 0;
00339       end = (list == 0);
00340    }
00341    return path[i];
00342 }
00343 
00344 static const char *getFullPath(int i, const char *file)
00345 {
00346    static char buf[PATH_MAX];
00347    const char *path = getSearchPath(i);
00348    if (path)
00349    {
00350       snprintf(buf, PATH_MAX, "%s/%s", path, file);
00351    }
00352    return path ? buf : 0;
00353 }
00354 
00355 /* Given a file name, try to determine the full path for that file. Starts
00356  * its search in the current directory, and then tries all paths in the 
00357  * search list in the order they are specified there.
00358  */
00359 static const struct stat *findFile(const char *file, const char **fullPath)
00360 {
00361    int i = 0;
00362    static struct stat sbuf;
00363    char *fileName;
00364    debug("finding file %s", file);
00365    *fullPath = file;
00366    if (0 == stat(file, &sbuf))
00367       return &sbuf;
00368    if (strchr(file, '/'))
00369       return 0;            /* If the path had a / we don't look in env var places */
00370    fileName = NULL;
00371    if (!fileName)
00372       fileName = (char *)file;
00373    while ((*fullPath = getFullPath(i++, fileName)))
00374    {
00375       if (0 == stat(*fullPath, &sbuf))
00376          return &sbuf;
00377    }
00378    ;
00379    return 0;
00380 }
00381 
00382 /* Determine whether a given dlstatus is valid or not */
00383 static int isValidStatus(struct dlstatus *status)
00384 {
00385    /* Walk the list to verify status is contained in it */
00386    struct dlstatus *dls = stqueue;
00387    while (dls && status != dls)
00388       dls = dls->next;
00389    if (dls == 0)
00390       error("invalid handle");
00391    else if ((dls->module == 0) || (dls->refs == 0))
00392       error("handle to closed library");
00393    else
00394       return TRUE;
00395    return FALSE;
00396 }
00397 
00398 static inline int isFlagSet(int mode, int flag)
00399 {
00400    return (mode & flag) == flag;
00401 }
00402 
00403 static struct dlstatus *lookupStatus(const struct stat *sbuf)
00404 {
00405    struct dlstatus *dls = stqueue;
00406    debug("looking for status");
00407    while (dls && ( /* isFlagSet(dls->mode, RTLD_UNSHARED) */ 0
00408                || sbuf->st_dev != dls->device || sbuf->st_ino != dls->inode))
00409       dls = dls->next;
00410    return dls;
00411 }
00412 
00413 static void insertStatus(struct dlstatus *dls, const struct stat *sbuf)
00414 {
00415    debug("inserting status");
00416    dls->inode = sbuf->st_ino;
00417    dls->device = sbuf->st_dev;
00418    dls->refs = 0;
00419    dls->mode = 0;
00420    if ((dls->flags & DL_IN_LIST) == 0)
00421    {
00422       dls->next = stqueue;
00423       stqueue = dls;
00424       dls->flags |= DL_IN_LIST;
00425    }
00426 }
00427 
00428 static struct dlstatus *allocStatus()
00429 {
00430    struct dlstatus *dls;
00431 #ifdef REUSE_STATUS
00432    dls = stqueue;
00433    while (dls && dls->module)
00434       dls = dls->next;
00435    if (!dls)
00436 #endif
00437       dls = malloc(sizeof(*dls));
00438    dls->flags = 0;
00439    return dls;
00440 }
00441 
00442 static int promoteLocalToGlobal(struct dlstatus *dls)
00443 {
00444    static int (*p) (NSModule module) = 0;
00445    debug("promoting");
00446    if (!p)
00447       _dyld_func_lookup("__dyld_NSMakePrivateModulePublic", (unsigned long *)&p);
00448    return (dls->module == MAGIC_DYLIB_MOD) || (p && p(dls->module));
00449 }
00450 
00451 static void *reference(struct dlstatus *dls, int mode)
00452 {
00453    if (dls)
00454    {
00455       if (dls->module == MAGIC_DYLIB_MOD && !isFlagSet(mode, RTLD_GLOBAL))
00456       {
00457          warning("trying to open a .dylib with RTLD_LOCAL");
00458          error("unable to open a .dylib with RTLD_LOCAL");
00459          return NULL;
00460       }
00461       if (isFlagSet(mode, RTLD_GLOBAL) &&
00462          !isFlagSet(dls->mode, RTLD_GLOBAL) && !promoteLocalToGlobal(dls))
00463       {
00464          error("unable to promote local module to global");
00465          return NULL;
00466       }
00467       dls->mode |= mode;
00468       dls->refs++;
00469    }
00470    else
00471       debug("reference called with NULL argument");
00472 
00473    return dls;
00474 }
00475 
00476 static const struct mach_header *my_find_image(const char *name)
00477 {
00478    const struct mach_header *mh = 0;
00479    const char *id = NULL;
00480    int i = _dyld_image_count();
00481    int j;
00482    mh = (struct mach_header *)
00483       dyld_NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED |
00484                   NSADDIMAGE_OPTION_RETURN_ON_ERROR);
00485    if (!mh)
00486    {
00487       for (j = 0; j < i; j++)
00488       {
00489          id = _dyld_get_image_name(j);
00490          if (!strcmp(id, name))
00491          {
00492             mh = _dyld_get_image_header(j);
00493             break;
00494          }
00495       }
00496    }
00497    return mh;
00498 }
00499 
00500 /*
00501  * dyld adds libraries by first adding the directly dependant libraries in link order, and
00502  * then adding the dependencies for those libraries, so we should do the same... but we don't
00503  * bother adding the extra dependencies, if the symbols are neither in the loaded image nor
00504  * any of it's direct dependencies, then it probably isn't there.
00505  */
00506 NSSymbol *search_linked_libs(const struct mach_header * mh, const char *symbol)
00507 {
00508    int n;
00509    struct load_command *lc = 0;
00510    struct mach_header *wh;
00511    NSSymbol *nssym = 0;
00512    if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
00513    {
00514       lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
00515       for (n = 0; n < mh->ncmds; n++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
00516       {
00517          if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd))
00518          {
00519             if ((wh = (struct mach_header *)
00520                 my_find_image((char *)(((struct dylib_command *)lc)->dylib.name.offset +
00521                                  (char *)lc))))
00522             {
00523                if (dyld_NSIsSymbolNameDefinedInImage(wh, symbol))
00524                {
00525                   nssym = dyld_NSLookupSymbolInImage(wh,
00526                                              symbol,
00527                                              NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
00528                                              NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
00529                   break;
00530                }
00531             }
00532          }
00533       }
00534       if ((!nssym) && NSIsSymbolNameDefined(symbol))
00535       {
00536          /* I've never seen this debug message...*/
00537          debug("Symbol \"%s\" is defined but was not found", symbol);
00538       }
00539    }
00540    return nssym;
00541 }
00542 
00543 /* Up to the caller to free() returned string */
00544 static inline const char *dyld_error_str()
00545 {
00546    NSLinkEditErrors dylder;
00547    int dylderno;
00548    const char *dylderrstr;
00549    const char *dyldfile;
00550    const char* retStr = NULL;
00551    NSLinkEditError(&dylder, &dylderno, &dyldfile, &dylderrstr);
00552    if (dylderrstr && strlen(dylderrstr))
00553    {
00554       retStr = malloc(strlen(dylderrstr) +1);
00555       strcpy((char*)retStr,dylderrstr);
00556    }
00557    return retStr;
00558 }
00559 
00560 static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError)
00561 {
00562    NSSymbol *nssym = 0;
00563    void *caller = __builtin_return_address(1);  /* Be *very* careful about inlining */
00564    const struct mach_header *caller_mh = 0;
00565    const char* savedErrorStr = NULL;
00566    resetdlerror();
00567 #ifndef RTLD_SELF
00568 #define  RTLD_SELF      ((void *) -3)
00569 #endif
00570    if (NULL == dls)
00571       dls = RTLD_SELF;
00572    if ((RTLD_NEXT == dls) || (RTLD_SELF == dls))
00573    {
00574       if (dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
00575       {
00576          caller_mh = image_for_address(caller);
00577          if (RTLD_SELF == dls)
00578          {
00579             /* FIXME: We should be using the NSModule api, if SELF is an MH_BUNDLE
00580              * But it appears to work anyway, and looking at the code in dyld_libfuncs.c
00581              * this is acceptable.
00582              */
00583             if (dyld_NSIsSymbolNameDefinedInImage(caller_mh, symbol))
00584             {
00585                nssym = dyld_NSLookupSymbolInImage(caller_mh,
00586                                           symbol,
00587                                           NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
00588                                           NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
00589             }
00590          }
00591          if (!nssym)
00592          {
00593             if (RTLD_SELF == dls)
00594                savedErrorStr = dyld_error_str();
00595             nssym = search_linked_libs(caller_mh, symbol);
00596          }
00597       }
00598       else
00599       {
00600          if (canSetError)
00601             error("RTLD_SELF and RTLD_NEXT are not supported");
00602          return NULL;
00603       }
00604    }
00605    if (!nssym)
00606    {
00607 
00608       if (RTLD_DEFAULT == dls)
00609       {
00610          dls = &mainStatus;
00611       }
00612       if (!isValidStatus(dls))
00613          return NULL;
00614 
00615       if (dls->module != MAGIC_DYLIB_MOD)
00616       {
00617          nssym = NSLookupSymbolInModule(dls->module, symbol);
00618          if (!nssym && NSIsSymbolNameDefined(symbol))
00619          {
00620             debug("Searching dependencies");
00621             savedErrorStr = dyld_error_str();
00622             nssym = search_linked_libs(get_mach_header_from_NSModule(dls->module), symbol);
00623          }
00624       }
00625       else if (dls->lib && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
00626       {
00627          if (dyld_NSIsSymbolNameDefinedInImage(dls->lib, symbol))
00628          {
00629             nssym = dyld_NSLookupSymbolInImage(dls->lib,
00630                                        symbol,
00631                                        NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
00632                                        NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
00633          }
00634          else if (NSIsSymbolNameDefined(symbol))
00635          {
00636             debug("Searching dependencies");
00637             savedErrorStr = dyld_error_str();
00638             nssym = search_linked_libs(dls->lib, symbol);
00639          }
00640       }
00641       else if (dls->module == MAGIC_DYLIB_MOD)
00642       {
00643          /* Global context, use NSLookupAndBindSymbol */
00644          if (NSIsSymbolNameDefined(symbol))
00645          {
00646             /* There doesn't seem to be a return on error option for this call???
00647                this is potentially broken, if binding fails, it will improperly
00648                exit the application. */
00649             nssym = NSLookupAndBindSymbol(symbol);
00650          }
00651          else
00652          {
00653             if (savedErrorStr)
00654                free((char*)savedErrorStr);         
00655             savedErrorStr = malloc(256);
00656             snprintf((char*)savedErrorStr, 256, "Symbol \"%s\" not in global context",symbol);  
00657          }
00658       }
00659    }
00660    /* Error reporting */
00661    if (!nssym)
00662    {
00663       if (!savedErrorStr || !strlen(savedErrorStr))
00664       {
00665          if (savedErrorStr)
00666             free((char*)savedErrorStr);
00667          savedErrorStr = malloc(256);
00668          snprintf((char*)savedErrorStr, 256,"Symbol \"%s\" not found",symbol);
00669       }
00670       if (canSetError)
00671       {
00672          error(savedErrorStr);
00673       }
00674       else
00675       {
00676          debug(savedErrorStr);
00677       }
00678       if (savedErrorStr)
00679          free((char*)savedErrorStr);
00680       return NULL;
00681    }
00682    return NSAddressOfSymbol(nssym);
00683 }
00684 
00685 static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode)
00686 {
00687    NSObjectFileImage ofi = 0;
00688    NSObjectFileImageReturnCode ofirc;
00689    struct dlstatus *dls;
00690    NSLinkEditErrors ler;
00691    int lerno;
00692    const char *errstr;
00693    const char *file;
00694    void (*init) (void);
00695    ofirc = NSCreateObjectFileImageFromFile(path, &ofi);
00696    switch (ofirc)
00697    {
00698       case NSObjectFileImageSuccess:
00699          break;
00700       case NSObjectFileImageInappropriateFile:
00701          if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
00702          {
00703             if (!isFlagSet(mode, RTLD_GLOBAL))
00704             {
00705                warning("trying to open a .dylib with RTLD_LOCAL");
00706                error("unable to open this file with RTLD_LOCAL");
00707                return NULL;
00708             }
00709          }
00710          else
00711          {
00712             error("opening this file is unsupported on this system");
00713             return NULL;
00714          }
00715          break;
00716       case NSObjectFileImageFailure:
00717          error("object file setup failure");
00718          return NULL;
00719       case NSObjectFileImageArch:
00720          error("no object for this architecture");
00721          return NULL;
00722       case NSObjectFileImageFormat:
00723          error("bad object file format");
00724          return NULL;
00725       case NSObjectFileImageAccess:
00726          error("can't read object file");
00727          return NULL;
00728       default:
00729          error("unknown error from NSCreateObjectFileImageFromFile()");
00730          return NULL;
00731    }
00732    dls = lookupStatus(sbuf);
00733    if (!dls)
00734    {
00735       dls = allocStatus();
00736    }
00737    if (!dls)
00738    {
00739       error("unable to allocate memory");
00740       return NULL;
00741    }
00742    dls->lib = 0;
00743    if (ofirc == NSObjectFileImageInappropriateFile)
00744    {
00745       if ((dls->lib = dyld_NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR)))
00746       {
00747          debug("Dynamic lib loaded at %ld", dls->lib);
00748          ofi = MAGIC_DYLIB_OFI;
00749          dls->module = MAGIC_DYLIB_MOD;
00750          ofirc = NSObjectFileImageSuccess;
00751          /* Although it is possible with a bit of work to modify this so it works and
00752             functions with RTLD_NOW, I don't deem it necessary at the moment */
00753       }
00754       if (!(dls->module))
00755       {
00756          NSLinkEditError(&ler, &lerno, &file, &errstr);
00757          if (!errstr || (!strlen(errstr)))
00758             error("Can't open this file type");
00759          else
00760             error(errstr);
00761          if ((dls->flags & DL_IN_LIST) == 0)
00762          {
00763             free(dls);
00764          }
00765          return NULL;
00766       }
00767    }
00768    else
00769    {
00770       dls->module = NSLinkModule(ofi, path,
00771                            NSLINKMODULE_OPTION_RETURN_ON_ERROR |
00772                            NSLINKMODULE_OPTION_PRIVATE |
00773                            (isFlagSet(mode, RTLD_NOW) ? NSLINKMODULE_OPTION_BINDNOW : 0));
00774       NSDestroyObjectFileImage(ofi);
00775       if (dls->module)
00776       {
00777          dls->lib = get_mach_header_from_NSModule(dls->module);
00778       }
00779    }
00780    if (!dls->module)
00781    {
00782       NSLinkEditError(&ler, &lerno, &file, &errstr);
00783       if ((dls->flags & DL_IN_LIST) == 0)
00784       {
00785          free(dls);
00786       }
00787       error(errstr);
00788       return NULL;
00789    }
00790 
00791    insertStatus(dls, sbuf);
00792    dls = reference(dls, mode);
00793    if ((init = dlsymIntern(dls, "__init", 0)))
00794    {
00795       debug("calling _init()");
00796       init();
00797    }
00798    return dls;
00799 }
00800 
00801 static void dlcompat_init_func(void)
00802 {
00803    static int inited = 0;
00804    if (!inited)
00805    {
00806       inited = 1;
00807       _dyld_func_lookup("__dyld_NSAddImage", (unsigned long *)&dyld_NSAddImage);
00808       _dyld_func_lookup("__dyld_NSIsSymbolNameDefinedInImage",
00809                     (unsigned long *)&dyld_NSIsSymbolNameDefinedInImage);
00810       _dyld_func_lookup("__dyld_NSLookupSymbolInImage", (unsigned long *)&dyld_NSLookupSymbolInImage);
00811       if (pthread_mutex_init(&dlcompat_mutex, NULL))
00812          exit(1);
00813       if (pthread_key_create(&dlerror_key, &dlerrorfree))
00814          exit(1);
00815       /* And be neat and tidy and clean up after ourselves */  
00816       atexit(dlcompat_cleanup);
00817    }
00818 }
00819 
00820 #if 0
00821 #pragma CALL_ON_LOAD dlcompat_init_func
00822 #endif
00823 
00824 static void dlcompat_cleanup(void)
00825 {
00826    struct dlstatus *dls;
00827    struct dlstatus *next;
00828    char *data;
00829    data = (char *)searchList();
00830    if ( data )
00831       free( data );
00832    data =   (char *)getSearchPath(-1);
00833    if ( data )
00834       free( data );
00835    pthread_mutex_destroy(&dlcompat_mutex);
00836    pthread_key_delete(dlerror_key);
00837    next = stqueue;
00838    while (next && (next != &mainStatus))
00839    {
00840       dls = next;
00841       next = dls->next;
00842       free(dls);
00843    }
00844 }
00845 
00846 static void resetdlerror()
00847 {
00848    struct dlthread *tss;
00849    tss = pthread_getspecific(dlerror_key);
00850    tss->errset = 0;
00851 }
00852 
00853 static void dlerrorfree(void *data)
00854 {
00855    free(data);
00856 }
00857 
00858 /* We kind of want a recursive lock here, but meet a little trouble
00859  * because they are not available pre OS X 10.2, so we fake it
00860  * using thread specific storage to keep a lock count
00861  */ 
00862 static inline void dolock(void)
00863 {
00864    int err = 0;
00865    struct dlthread *tss;
00866    tss = pthread_getspecific(dlerror_key);
00867    if (!tss)
00868    {
00869       tss = malloc(sizeof(struct dlthread));
00870       tss->lockcnt = 0;
00871       tss->errset = 0;
00872       if (pthread_setspecific(dlerror_key, tss))
00873       {
00874          fprintf(stderr,"dlcompat: pthread_setspecific failed\n");
00875          exit(1);
00876       }
00877    }
00878    if (!tss->lockcnt)
00879       err = pthread_mutex_lock(&dlcompat_mutex);
00880    tss->lockcnt = tss->lockcnt +1;  
00881    if (err)
00882       exit(err);
00883 }
00884 
00885 static inline void dounlock(void)
00886 {
00887    int err = 0;
00888    struct dlthread *tss;
00889    tss = pthread_getspecific(dlerror_key);
00890    tss->lockcnt = tss->lockcnt -1;
00891    if (!tss->lockcnt)
00892       err = pthread_mutex_unlock(&dlcompat_mutex);
00893    if (err)
00894       exit(err);
00895 }
00896 
00897 void *dlopen(const char *path, int mode)
00898 {
00899    const struct stat *sbuf;
00900    struct dlstatus *dls;
00901    const char *fullPath;
00902    dlcompat_init_func();      /* Just in case */
00903    dolock();
00904    resetdlerror();
00905    if (!path)
00906    {
00907       dls = &mainStatus;
00908       goto dlopenok;
00909    }
00910    if (!(sbuf = findFile(path, &fullPath)))
00911    {
00912       error("file \"%s\" not found", path);
00913       goto dlopenerror;
00914    }
00915    /* Now checks that it hasn't been closed already */
00916    if ((dls = lookupStatus(sbuf)) && (dls->refs > 0))
00917    {
00918       /* debug("status found"); */
00919       dls = reference(dls, mode);
00920       goto dlopenok;
00921    }
00922 #ifdef   RTLD_NOLOAD
00923    if (isFlagSet(mode, RTLD_NOLOAD))
00924    {
00925       error("no existing handle and RTLD_NOLOAD specified");
00926       goto dlopenerror;
00927    }
00928 #endif
00929    if (isFlagSet(mode, RTLD_LAZY) && isFlagSet(mode, RTLD_NOW))
00930    {
00931       error("how can I load something both RTLD_LAZY and RTLD_NOW?");
00932       goto dlopenerror;
00933    }
00934    dls = loadModule(fullPath, sbuf, mode);
00935    
00936   dlopenok:
00937    dounlock();
00938    return (void *)dls;
00939   dlopenerror:
00940    dounlock();
00941    return NULL;
00942 }
00943 
00944 #if !FINK_BUILD
00945 void *dlsym(void * dl_restrict handle, const char * dl_restrict symbol)
00946 {
00947    int sym_len = strlen(symbol);
00948    void *value = NULL;
00949    char *malloc_sym = NULL;
00950    dolock();
00951    malloc_sym = malloc(sym_len + 2);
00952    if (malloc_sym)
00953    {
00954       sprintf(malloc_sym, "_%s", symbol);
00955       value = dlsymIntern(handle, malloc_sym, 1);
00956       free(malloc_sym);
00957    }
00958    else
00959    {
00960       error("Unable to allocate memory");
00961       goto dlsymerror;
00962    }
00963    dounlock();
00964    return value;
00965   dlsymerror:
00966    dounlock();
00967    return NULL;
00968 }
00969 #endif
00970 
00971 #if FINK_BUILD
00972 
00973 void *dlsym_prepend_underscore(void *handle, const char *symbol)
00974 {
00975    void *answer;
00976    dolock();
00977    answer = dlsym_prepend_underscore_intern(handle, symbol);
00978    dounlock();
00979    return answer;
00980 }
00981 
00982 static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol)
00983 {
00984 /*
00985  * A quick and easy way for porting packages which call dlsym(handle,"sym")
00986  * If the porter adds -Ddlsym=dlsym_prepend_underscore to the CFLAGS then
00987  * this function will be called, and will add the required underscore.
00988  * 
00989  * Note that I haven't figured out yet which should be "standard", prepend
00990  * the underscore always, or not at all. These global functions need to go away
00991  * for opendarwin.
00992  */
00993    int sym_len = strlen(symbol);
00994    void *value = NULL;
00995    char *malloc_sym = NULL;
00996    malloc_sym = malloc(sym_len + 2);
00997    if (malloc_sym)
00998    {
00999       sprintf(malloc_sym, "_%s", symbol);
01000       value = dlsymIntern(handle, malloc_sym, 1);
01001       free(malloc_sym);
01002    }
01003    else
01004    {
01005       error("Unable to allocate memory");
01006    }
01007    return value;
01008 }
01009 
01010 void *dlsym_auto_underscore(void *handle, const char *symbol)
01011 {
01012    void *answer;
01013    dolock();
01014    answer = dlsym_auto_underscore_intern(handle, symbol);
01015    dounlock();
01016    return answer;
01017 
01018 }
01019 static void *dlsym_auto_underscore_intern(void *handle, const char *symbol)
01020 {
01021    struct dlstatus *dls = handle;
01022    void *addr = 0;
01023    addr = dlsymIntern(dls, symbol, 0);
01024    if (!addr)
01025       addr = dlsym_prepend_underscore_intern(handle, symbol);
01026    return addr;
01027 }
01028 
01029 
01030 void *dlsym(void * dl_restrict handle, const char * dl_restrict symbol)
01031 {
01032    struct dlstatus *dls = handle;
01033    void *addr = 0;
01034    dolock();
01035    addr = dlsymIntern(dls, symbol, 1);
01036    dounlock();
01037    return addr;
01038 }
01039 #endif
01040 
01041 int dlclose(void *handle)
01042 {
01043    struct dlstatus *dls = handle;
01044    dolock();
01045    resetdlerror();
01046    if (!isValidStatus(dls))
01047    {
01048       goto dlcloseerror;
01049    }
01050    if (dls->module == MAGIC_DYLIB_MOD)
01051    {
01052       const char *name;
01053       if (!dls->lib)
01054       {
01055          name = "global context";
01056       }
01057       else
01058       {
01059          name = get_lib_name(dls->lib);
01060       }
01061       warning("trying to close a .dylib!");
01062       error("Not closing \"%s\" - dynamic libraries cannot be closed", name);
01063       goto dlcloseerror;
01064    }
01065    if (!dls->module)
01066    {
01067       error("module already closed");
01068       goto dlcloseerror;
01069    }
01070    
01071    if (dls->refs == 1)
01072    {
01073       unsigned long options = 0;
01074       void (*fini) (void);
01075       if ((fini = dlsymIntern(dls, "__fini", 0)))
01076       {
01077          debug("calling _fini()");
01078          fini();
01079       }
01080 #ifdef __ppc__
01081       options |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
01082 #endif
01083 #if 1
01084 /*  Currently, if a module contains c++ static destructors and it is unloaded, we
01085  *  get a segfault in atexit(), due to compiler and dynamic loader differences of
01086  *  opinion, this works around that.
01087  *  I really need a way to figure out from code if this is still necessary.
01088  */
01089       if ((const struct section *)NULL !=
01090          getsectbynamefromheader(get_mach_header_from_NSModule(dls->module),
01091                            "__DATA", "__mod_term_func"))
01092       {
01093          options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
01094       }
01095 #endif
01096 #ifdef RTLD_NODELETE
01097       if (isFlagSet(dls->mode, RTLD_NODELETE))
01098          options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
01099 #endif
01100       if (!NSUnLinkModule(dls->module, options))
01101       {
01102          error("unable to unlink module");
01103          goto dlcloseerror;
01104       }
01105       dls->refs--;
01106       dls->module = 0;
01107       /* Note: the dlstatus struct dls is neither removed from the list
01108        * nor is the memory it occupies freed. This shouldn't pose a 
01109        * problem in mostly all cases, though.
01110        */
01111    }
01112    dounlock();
01113    return 0;
01114   dlcloseerror:
01115    dounlock();
01116    return 1;
01117 }
01118 
01119 const char *dlerror(void)
01120 {
01121    struct dlthread  *tss;
01122    char * err_str;
01123    tss = pthread_getspecific(dlerror_key);
01124    err_str = tss->errstr;
01125    tss = pthread_getspecific(dlerror_key);
01126    if (tss->errset == 0)
01127       return 0;
01128    tss->errset = 0;  
01129    return (err_str );
01130 }
01131 
01132 /* Given an address, return the mach_header for the image containing it
01133  * or zero if the given address is not contained in any loaded images.
01134  */
01135 const struct mach_header *image_for_address(const void *address)
01136 {
01137    unsigned long i;
01138    unsigned long j;
01139    unsigned long count = _dyld_image_count();
01140    struct mach_header *mh = 0;
01141    struct load_command *lc = 0;
01142    unsigned long addr = NULL;
01143    for (i = 0; i < count; i++)
01144    {
01145       addr = (unsigned long)address - _dyld_get_image_vmaddr_slide(i);
01146       mh = _dyld_get_image_header(i);
01147       if (mh)
01148       {
01149          lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
01150          for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
01151          {
01152             if (LC_SEGMENT == lc->cmd &&
01153                addr >= ((struct segment_command *)lc)->vmaddr &&
01154                addr <
01155                ((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize)
01156             {
01157                goto image_found;
01158             }
01159          }
01160       }
01161       mh = 0;
01162    }
01163   image_found:
01164    return mh;
01165 }
01166 
01167 int dladdr(const void * dl_restrict p, Dl_info * dl_restrict info)
01168 {
01169 /*
01170    FIXME: USe the routine image_for_address.
01171 */
01172    unsigned long i;
01173    unsigned long j;
01174    unsigned long count = _dyld_image_count();
01175    struct mach_header *mh = 0;
01176    struct load_command *lc = 0;
01177    unsigned long addr = NULL;
01178    unsigned long table_off = (unsigned long)0;
01179    int found = 0;
01180    if (!info)
01181       return 0;
01182    dolock();
01183    resetdlerror();
01184    info->dli_fname = 0;
01185    info->dli_fbase = 0;
01186    info->dli_sname = 0;
01187    info->dli_saddr = 0;
01188 /* Some of this was swiped from code posted by Douglas Davidson <ddavidso AT apple DOT com>
01189  * to darwin-development AT lists DOT apple DOT com and slightly modified
01190  */
01191    for (i = 0; i < count; i++)
01192    {
01193       addr = (unsigned long)p - _dyld_get_image_vmaddr_slide(i);
01194       mh = _dyld_get_image_header(i);
01195       if (mh)
01196       {
01197          lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
01198          for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
01199          {
01200             if (LC_SEGMENT == lc->cmd &&
01201                addr >= ((struct segment_command *)lc)->vmaddr &&
01202                addr <
01203                ((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize)
01204             {
01205                info->dli_fname = _dyld_get_image_name(i);
01206                info->dli_fbase = (void *)mh;
01207                found = 1;
01208                break;
01209             }
01210          }
01211          if (found)
01212             break;
01213       }
01214    }
01215    if (!found)
01216    {
01217       dounlock();
01218       return 0;
01219    }
01220    lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
01221    for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
01222    {
01223       if (LC_SEGMENT == lc->cmd)
01224       {
01225          if (!strcmp(((struct segment_command *)lc)->segname, "__LINKEDIT"))
01226             break;
01227       }
01228    }
01229    table_off =
01230       ((unsigned long)((struct segment_command *)lc)->vmaddr) -
01231       ((unsigned long)((struct segment_command *)lc)->fileoff) + _dyld_get_image_vmaddr_slide(i);
01232    debug("table off %x", table_off);
01233 
01234    lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
01235    for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
01236    {
01237       if (LC_SYMTAB == lc->cmd)
01238       {
01239 
01240          struct nlist *symtable = (struct nlist *)(((struct symtab_command *)lc)->symoff + table_off);
01241          unsigned long numsyms = ((struct symtab_command *)lc)->nsyms;
01242          struct nlist *nearest = NULL;
01243          unsigned long diff = 0xffffffff;
01244          unsigned long strtable = (unsigned long)(((struct symtab_command *)lc)->stroff + table_off);
01245          debug("symtable %x", symtable);
01246          for (i = 0; i < numsyms; i++)
01247          {
01248             /* Ignore the following kinds of Symbols */
01249             if ((!symtable->n_value)   /* Undefined */
01250                || (symtable->n_type >= N_PEXT)  /* Debug symbol */
01251                || (!(symtable->n_type & N_EXT)) /* Local Symbol */
01252                )
01253             {
01254                symtable++;
01255                continue;
01256             }
01257             if ((addr >= symtable->n_value) && (diff >= (symtable->n_value - addr)))
01258             {
01259                diff = (unsigned long)symtable->n_value - addr;
01260                nearest = symtable;
01261             }
01262             symtable++;
01263          }
01264          if (nearest)
01265          {
01266             info->dli_saddr = nearest->n_value + ((void *)p - addr);
01267             info->dli_sname = (char *)(strtable + nearest->n_un.n_strx);
01268          }
01269       }
01270    }
01271    dounlock();
01272    return 1;
01273 }
01274 
01275 
01276 /*
01277  * Implement the dlfunc() interface, which behaves exactly the same as
01278  * dlsym() except that it returns a function pointer instead of a data
01279  * pointer.  This can be used by applications to avoid compiler warnings
01280  * about undefined behavior, and is intended as prior art for future
01281  * POSIX standardization.  This function requires that all pointer types
01282  * have the same representation, which is true on all platforms FreeBSD
01283  * runs on, but is not guaranteed by the C standard.
01284  */
01285 #if 0 
01286 dlfunc_t dlfunc(void * dl_restrict handle, const char * dl_restrict symbol)
01287 {
01288    union
01289    {
01290       void *d;
01291       dlfunc_t f;
01292    } rv;
01293    int sym_len = strlen(symbol);
01294    char *malloc_sym = NULL;
01295    dolock();
01296    malloc_sym = malloc(sym_len + 2);
01297    if (malloc_sym)
01298    {
01299       sprintf(malloc_sym, "_%s", symbol);
01300       rv.d = dlsymIntern(handle, malloc_sym, 1);
01301       free(malloc_sym);
01302    }
01303    else
01304    {
01305       error("Unable to allocate memory");
01306       goto dlfuncerror;
01307    }
01308    dounlock();
01309    return rv.f;
01310   dlfuncerror:
01311    dounlock();
01312    return NULL;
01313 }
01314 #endif

Generated on Sun Aug 6 15:02:40 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.2