Imported Upstream version 0.63.0
[hcoop/debian/courier-authlib.git] / libltdl / loaders / dyld.c
diff --git a/libltdl/loaders/dyld.c b/libltdl/loaders/dyld.c
new file mode 100644 (file)
index 0000000..b139d6c
--- /dev/null
@@ -0,0 +1,511 @@
+/* loader-dyld.c -- dynamic linking on darwin and OS X
+
+   Copyright (C) 1998, 1999, 2000, 2004, 2006,
+                 2007, 2008 Free Software Foundation, Inc.
+   Written by Peter O'Gorman, 1998
+
+   NOTE: The canonical source of this file is maintained with the
+   GNU Libtool package.  Report bugs to bug-libtool@gnu.org.
+
+GNU Libltdl is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+As a special exception to the GNU Lesser General Public License,
+if you distribute this file as part of a program or library that
+is built using GNU Libtool, you may include this file under the
+same distribution terms that you use for the rest of that program.
+
+GNU Libltdl 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with GNU Libltdl; see the file COPYING.LIB.  If not, a
+copy can be downloaded from  http://www.gnu.org/licenses/lgpl.html,
+or obtained by writing to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include "lt__private.h"
+#include "lt_dlloader.h"
+
+/* Use the preprocessor to rename non-static symbols to avoid namespace
+   collisions when the loader code is statically linked into libltdl.
+   Use the "<module_name>_LTX_" prefix so that the symbol addresses can
+   be fetched from the preloaded symbol list by lt_dlsym():  */
+#define get_vtable     dyld_LTX_get_vtable
+
+LT_BEGIN_C_DECLS
+LT_SCOPE lt_dlvtable *get_vtable (lt_user_data loader_data);
+LT_END_C_DECLS
+
+
+/* Boilerplate code to set up the vtable for hooking this loader into
+   libltdl's loader list:  */
+static int      vl_init  (lt_user_data loader_data);
+static int      vl_exit  (lt_user_data loader_data);
+static lt_module vm_open  (lt_user_data loader_data, const char *filename,
+                           lt_dladvise advise);
+static int      vm_close (lt_user_data loader_data, lt_module module);
+static void *   vm_sym   (lt_user_data loader_data, lt_module module,
+                         const char *symbolname);
+
+static lt_dlvtable *vtable = 0;
+
+/* Return the vtable for this loader, only the name and sym_prefix
+   attributes (plus the virtual function implementations, obviously)
+   change between loaders.  */
+lt_dlvtable *
+get_vtable (lt_user_data loader_data)
+{
+  if (!vtable)
+    {
+      vtable = lt__zalloc (sizeof *vtable);
+    }
+
+  if (vtable && !vtable->name)
+    {
+      vtable->name             = "lt_dyld";
+      vtable->sym_prefix       = "_";
+      vtable->dlloader_init    = vl_init;
+      vtable->module_open      = vm_open;
+      vtable->module_close     = vm_close;
+      vtable->find_sym         = vm_sym;
+      vtable->dlloader_exit    = vl_exit;
+      vtable->dlloader_data    = loader_data;
+      vtable->priority         = LT_DLLOADER_APPEND;
+    }
+
+  if (vtable && (vtable->dlloader_data != loader_data))
+    {
+      LT__SETERROR (INIT_LOADER);
+      return 0;
+    }
+
+  return vtable;
+}
+
+
+
+/* --- IMPLEMENTATION --- */
+
+
+#if defined(HAVE_MACH_O_DYLD_H)
+#  if !defined(__APPLE_CC__) && !defined(__MWERKS__) && !defined(__private_extern__)
+  /* Is this correct? Does it still function properly? */
+#    define __private_extern__ extern
+#  endif
+#  include <mach-o/dyld.h>
+#endif
+
+#include <mach-o/getsect.h>
+
+/* We have to put some stuff here that isn't in older dyld.h files */
+#if !defined(ENUM_DYLD_BOOL)
+# define ENUM_DYLD_BOOL
+# undef FALSE
+# undef TRUE
+ enum DYLD_BOOL {
+    FALSE,
+    TRUE
+ };
+#endif
+#if !defined(LC_REQ_DYLD)
+# define LC_REQ_DYLD 0x80000000
+#endif
+#if !defined(LC_LOAD_WEAK_DYLIB)
+# define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD)
+#endif
+
+#if !defined(NSADDIMAGE_OPTION_NONE)
+#  define NSADDIMAGE_OPTION_NONE                          0x0
+#endif
+#if !defined(NSADDIMAGE_OPTION_RETURN_ON_ERROR)
+#  define NSADDIMAGE_OPTION_RETURN_ON_ERROR               0x1
+#endif
+#if !defined(NSADDIMAGE_OPTION_WITH_SEARCHING)
+#  define NSADDIMAGE_OPTION_WITH_SEARCHING                0x2
+#endif
+#if !defined(NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED)
+#  define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED         0x4
+#endif
+#if !defined(NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME)
+#  define NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME 0x8
+#endif
+
+#if !defined(NSLOOKUPSYMBOLINIMAGE_OPTION_BIND)
+#  define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND               0x0
+#endif
+#if !defined(NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW)
+#  define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW           0x1
+#endif
+#if !defined(NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY)
+#  define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY         0x2
+#endif
+#if !defined(NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR)
+#  define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR    0x4
+#endif
+
+#define LT__SYMLOOKUP_OPTS     (NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW \
+                               | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR)
+
+#if defined(__BIG_ENDIAN__)
+#  define LT__MAGIC    MH_MAGIC
+#else
+#  define LT__MAGIC    MH_CIGAM
+#endif
+
+#define DYLD__SETMYERROR(errmsg)    LT__SETERRORSTR (dylderror (errmsg))
+#define DYLD__SETERROR(errcode)            DYLD__SETMYERROR (LT__STRERROR (errcode))
+
+typedef struct mach_header mach_header;
+typedef struct dylib_command dylib_command;
+
+static const char *dylderror (const char *errmsg);
+static const mach_header *lt__nsmodule_get_header (NSModule module);
+static const char *lt__header_get_instnam (const mach_header *mh);
+static const mach_header *lt__match_loadedlib (const char *name);
+static NSSymbol lt__linkedlib_symbol (const char *symname, const mach_header *mh);
+
+static const mach_header *(*lt__addimage)      (const char *image_name,
+                                                unsigned long options) = 0;
+static NSSymbol        (*lt__image_symbol)             (const mach_header *image,
+                                                const char *symbolName,
+                                                unsigned long options) = 0;
+static enum DYLD_BOOL (*lt__image_symbol_p)    (const mach_header *image,
+                                                const char *symbolName) = 0;
+static enum DYLD_BOOL (*lt__module_export)     (NSModule module) = 0;
+
+static int dyld_cannot_close                             = 0;
+
+
+/* A function called through the vtable when this loader is no
+   longer needed by the application.  */
+static int
+vl_exit (lt_user_data LT__UNUSED loader_data)
+{
+  vtable = NULL;
+  return 0;
+}
+
+/* A function called through the vtable to initialise this loader.  */
+static int
+vl_init (lt_user_data loader_data)
+{
+  int errors = 0;
+
+  if (! dyld_cannot_close)
+    {
+      if (!_dyld_present ())
+       {
+         ++errors;
+       }
+      else
+       {
+         (void) _dyld_func_lookup ("__dyld_NSAddImage",
+                                   (unsigned long*) &lt__addimage);
+         (void) _dyld_func_lookup ("__dyld_NSLookupSymbolInImage",
+                                   (unsigned long*)&lt__image_symbol);
+         (void) _dyld_func_lookup ("__dyld_NSIsSymbolNameDefinedInImage",
+                                   (unsigned long*) &lt__image_symbol_p);
+         (void) _dyld_func_lookup ("__dyld_NSMakePrivateModulePublic",
+                                   (unsigned long*) &lt__module_export);
+         dyld_cannot_close = lt_dladderror ("can't close a dylib");
+       }
+    }
+
+  return errors;
+}
+
+
+/* A function called through the vtable to open a module with this
+   loader.  Returns an opaque representation of the newly opened
+   module for processing with this loader's other vtable functions.  */
+static lt_module
+vm_open (lt_user_data loader_data, const char *filename,
+         lt_dladvise LT__UNUSED advise)
+{
+  lt_module module = 0;
+  NSObjectFileImage ofi = 0;
+
+  if (!filename)
+    {
+      return (lt_module) -1;
+    }
+
+  switch (NSCreateObjectFileImageFromFile (filename, &ofi))
+    {
+    case NSObjectFileImageSuccess:
+      module = NSLinkModule (ofi, filename, NSLINKMODULE_OPTION_RETURN_ON_ERROR
+                                           | NSLINKMODULE_OPTION_PRIVATE
+                                           | NSLINKMODULE_OPTION_BINDNOW);
+      NSDestroyObjectFileImage (ofi);
+
+      if (module)
+       {
+         lt__module_export (module);
+       }
+      break;
+
+    case NSObjectFileImageInappropriateFile:
+      if (lt__image_symbol_p && lt__image_symbol)
+       {
+         module = (lt_module) lt__addimage(filename,
+                                           NSADDIMAGE_OPTION_RETURN_ON_ERROR);
+       }
+      break;
+
+    case NSObjectFileImageFailure:
+    case NSObjectFileImageArch:
+    case NSObjectFileImageFormat:
+    case NSObjectFileImageAccess:
+      /*NOWORK*/
+      break;
+    }
+
+  if (!module)
+    {
+      DYLD__SETERROR (CANNOT_OPEN);
+    }
+
+  return module;
+}
+
+
+/* A function called through the vtable when a particular module
+   should be unloaded.  */
+static int
+vm_close (lt_user_data loader_data, lt_module module)
+{
+  int errors = 0;
+
+  if (module != (lt_module) -1)
+    {
+      const mach_header *mh = (const mach_header *) module;
+      int flags = 0;
+      if (mh->magic == LT__MAGIC)
+       {
+         lt_dlseterror (dyld_cannot_close);
+         ++errors;
+       }
+      else
+       {
+         /* Currently, if a module contains c++ static destructors and it
+            is unloaded, we get a segfault in atexit(), due to compiler and
+            dynamic loader differences of opinion, this works around that.  */
+         if ((const struct section *) NULL !=
+             getsectbynamefromheader (lt__nsmodule_get_header (module),
+                                      "__DATA", "__mod_term_func"))
+           {
+             flags |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
+           }
+#if defined(__ppc__)
+         flags |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
+#endif
+         if (!NSUnLinkModule (module, flags))
+           {
+             DYLD__SETERROR (CANNOT_CLOSE);
+             ++errors;
+           }
+       }
+    }
+
+  return errors;
+}
+
+/* A function called through the vtable to get the address of
+   a symbol loaded from a particular module.  */
+static void *
+vm_sym (lt_user_data loader_data, lt_module module, const char *name)
+{
+  NSSymbol *nssym = 0;
+  const mach_header *mh = (const mach_header *) module;
+  char saveError[256] = "Symbol not found";
+
+  if (module == (lt_module) -1)
+    {
+      void *address, *unused;
+      _dyld_lookup_and_bind (name, (unsigned long*) &address, &unused);
+      return address;
+    }
+
+  if (mh->magic == LT__MAGIC)
+    {
+      if (lt__image_symbol_p && lt__image_symbol)
+       {
+         if (lt__image_symbol_p (mh, name))
+           {
+             nssym = lt__image_symbol (mh, name, LT__SYMLOOKUP_OPTS);
+           }
+       }
+
+    }
+  else
+    {
+      nssym = NSLookupSymbolInModule (module, name);
+    }
+
+  if (!nssym)
+    {
+      strncpy (saveError, dylderror (LT__STRERROR (SYMBOL_NOT_FOUND)), 255);
+      saveError[255] = 0;
+      if (!mh)
+       {
+         mh = (mach_header *)lt__nsmodule_get_header (module);
+       }
+      nssym = lt__linkedlib_symbol (name, mh);
+    }
+
+  if (!nssym)
+    {
+      LT__SETERRORSTR (saveError);
+    }
+
+  return nssym ? NSAddressOfSymbol (nssym) : 0;
+}
+
+
+
+
+/* --- HELPER FUNCTIONS --- */
+
+
+/* Return the dyld error string, or the passed in error string if none. */
+static const char *
+dylderror (const char *errmsg)
+{
+  NSLinkEditErrors ler;
+  int lerno;
+  const char *file;
+  const char *errstr;
+
+  NSLinkEditError (&ler, &lerno, &file, &errstr);
+
+  if (! (errstr && *errstr))
+    {
+      errstr = errmsg;
+    }
+
+  return errstr;
+}
+
+/* There should probably be an apple dyld api for this. */
+static const mach_header *
+lt__nsmodule_get_header (NSModule module)
+{
+  int i = _dyld_image_count();
+  const char *modname = NSNameOfModule (module);
+  const mach_header *mh = 0;
+
+  if (!modname)
+    return NULL;
+
+  while (i > 0)
+    {
+      --i;
+      if (strneq (_dyld_get_image_name (i), modname))
+       {
+         mh = _dyld_get_image_header (i);
+         break;
+       }
+    }
+
+  return mh;
+}
+
+/* NSAddImage is also used to get the loaded image, but it only works if
+   the lib is installed, for uninstalled libs we need to check the
+   install_names against each other.  Note that this is still broken if
+   DYLD_IMAGE_SUFFIX is set and a different lib was loaded as a result.  */
+static const char *
+lt__header_get_instnam (const mach_header *mh)
+{
+  unsigned long offset = sizeof(mach_header);
+  const char* result   = 0;
+  int j;
+
+  for (j = 0; j < mh->ncmds; j++)
+    {
+      struct load_command *lc;
+
+      lc = (struct load_command*) (((unsigned long) mh) + offset);
+      if (LC_ID_DYLIB == lc->cmd)
+       {
+         result=(char*)(((dylib_command*) lc)->dylib.name.offset +
+                        (unsigned long) lc);
+       }
+      offset += lc->cmdsize;
+    }
+
+  return result;
+}
+
+static const mach_header *
+lt__match_loadedlib (const char *name)
+{
+  const mach_header *mh        = 0;
+  int i = _dyld_image_count();
+
+  while (i > 0)
+    {
+      const char *id;
+
+      --i;
+      id = lt__header_get_instnam (_dyld_get_image_header (i));
+      if (id && strneq (id, name))
+       {
+         mh = _dyld_get_image_header (i);
+         break;
+       }
+    }
+
+  return mh;
+}
+
+/* Safe to assume our mh is good. */
+static NSSymbol
+lt__linkedlib_symbol (const char *symname, const mach_header *mh)
+{
+  NSSymbol symbol = 0;
+
+  if (lt__image_symbol && NSIsSymbolNameDefined (symname))
+    {
+      unsigned long offset = sizeof(mach_header);
+      struct load_command *lc;
+      int j;
+
+      for (j = 0; j < mh->ncmds; j++)
+       {
+         lc = (struct load_command*) (((unsigned long) mh) + offset);
+         if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd))
+           {
+             unsigned long base = ((dylib_command *) lc)->dylib.name.offset;
+             char *name = (char *) (base + (unsigned long) lc);
+             const mach_header *mh1 = lt__match_loadedlib (name);
+
+             if (!mh1)
+               {
+                 /* Maybe NSAddImage can find it */
+                 mh1 = lt__addimage (name,
+                                     NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
+                                     | NSADDIMAGE_OPTION_WITH_SEARCHING
+                                     | NSADDIMAGE_OPTION_RETURN_ON_ERROR);
+               }
+
+             if (mh1)
+               {
+                 symbol = lt__image_symbol (mh1, symname, LT__SYMLOOKUP_OPTS);
+                 if (symbol)
+                   break;
+               }
+           }
+
+         offset += lc->cmdsize;
+       }
+    }
+
+  return symbol;
+}