X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Futils%2Fmono-dl.c;h=b59ab2d5aae0de5322e91c8f626010e934fad50e;hb=506cd5e9f0f01c439c6d03136ef6104ca8554efe;hp=7b68e7aee24d4a4e4a70e108a9ff3b7ac4eb4e6f;hpb=c8a2d6adfe80dbf97bfe8fe926fe3d45314a40d0;p=mono.git diff --git a/mono/utils/mono-dl.c b/mono/utils/mono-dl.c index 7b68e7aee24..b59ab2d5aae 100644 --- a/mono/utils/mono-dl.c +++ b/mono/utils/mono-dl.c @@ -10,6 +10,7 @@ #include "config.h" #include "mono/utils/mono-dl.h" #include "mono/utils/mono-embed.h" +#include "mono/utils/mono-path.h" #include #include @@ -29,11 +30,6 @@ static const char suffixes [][8] = { ".so", ".bundle" }; -#elif EMBEDDED_PINVOKE -#define SOPREFIX "" -static const char suffixes [][1] = { - "" -}; #else #define SOPREFIX "lib" static const char suffixes [][4] = { @@ -56,13 +52,24 @@ static const char suffixes [][4] = { #elif defined (HAVE_DL_LOADER) #include +#include + +#ifdef __MACH__ +#include +#endif + #ifndef RTLD_LAZY #define RTLD_LAZY 1 #endif /* RTLD_LAZY */ #define SO_HANDLE_TYPE void* -#define LL_SO_OPEN(file,flags) dlopen ((file), (flags)) +#ifdef PLATFORM_ANDROID +/* Bionic doesn't support NULL filenames */ +# define LL_SO_OPEN(file,flags) ((file) ? dlopen ((file), (flags)) : NULL) +#else +# define LL_SO_OPEN(file,flags) dlopen ((file), (flags)) +#endif #define LL_SO_CLOSE(module) dlclose ((module)->handle) #define LL_SO_SYMBOL(module, name) dlsym ((module)->handle, (name)) #define LL_SO_TRFLAGS(flags) convert_flags ((flags)) @@ -80,15 +87,6 @@ convert_flags (int flags) return lflags; } -#elif EMBEDDED_PINVOKE -#define SO_HANDLE_TYPE void* -void *LL_SO_OPEN (const char *file, int flags); -int LL_SO_CLOSE (void *handle); -#define LL_SO_SYMBOL(module,symbol) _LL_SO_SYMBOL((module)->handle, (symbol)) -void *_LL_SO_SYMBOL (void *handle, const char *symbol); -char *LL_SO_ERROR(); -#define LL_SO_TRFLAGS(flags) 0 - #else /* no dynamic loader supported */ #define SO_HANDLE_TYPE void* @@ -100,9 +98,21 @@ char *LL_SO_ERROR(); #endif +static GSList *fallback_handlers; + +struct MonoDlFallbackHandler { + MonoDlFallbackLoad load_func; + MonoDlFallbackSymbol symbol_func; + MonoDlFallbackClose close_func; + void *user_data; +}; + struct _MonoDl { SO_HANDLE_TYPE handle; int main_module; + + /* If not NULL, use the methods in MonoDlFallbackHandler instead of the LL_* methods */ + MonoDlFallbackHandler *dl_fallback; }; #ifdef TARGET_WIN32 @@ -314,6 +324,7 @@ mono_dl_open (const char *name, int flags, char **error_msg) { MonoDl *module; void *lib; + MonoDlFallbackHandler *dl_fallback = NULL; int lflags = LL_SO_TRFLAGS (flags); if (error_msg) @@ -328,6 +339,23 @@ mono_dl_open (const char *name, int flags, char **error_msg) module->main_module = name == NULL? TRUE: FALSE; lib = LL_SO_OPEN (name, lflags); if (!lib) { + GSList *node; + for (node = fallback_handlers; node != NULL; node = node->next){ + MonoDlFallbackHandler *handler = (MonoDlFallbackHandler *) node->data; + if (error_msg) + *error_msg = NULL; + + lib = handler->load_func (name, lflags, error_msg, handler->user_data); + if (error_msg && *error_msg != NULL) + g_free (*error_msg); + + if (lib != NULL){ + dl_fallback = handler; + break; + } + } + } + if (!lib && !dl_fallback) { char *lname; char *llname; const char *suff; @@ -358,6 +386,7 @@ mono_dl_open (const char *name, int flags, char **error_msg) } } module->handle = lib; + module->dl_fallback = dl_fallback; return module; } @@ -376,18 +405,24 @@ char* mono_dl_symbol (MonoDl *module, const char *name, void **symbol) { void *sym; + char *err = NULL; + if (module->dl_fallback) { + sym = module->dl_fallback->symbol_func (module->handle, name, &err, module->dl_fallback->user_data); + } else { #if MONO_DL_NEED_USCORE - { - char *usname = malloc (strlen (name) + 2); - *usname = '_'; - strcpy (usname + 1, name); - sym = LL_SO_SYMBOL (module, usname); - free (usname); - } + { + char *usname = malloc (strlen (name) + 2); + *usname = '_'; + strcpy (usname + 1, name); + sym = LL_SO_SYMBOL (module, usname); + free (usname); + } #else - sym = LL_SO_SYMBOL (module, name); + sym = LL_SO_SYMBOL (module, name); #endif + } + if (sym) { if (symbol) *symbol = sym; @@ -395,7 +430,7 @@ mono_dl_symbol (MonoDl *module, const char *name, void **symbol) } if (symbol) *symbol = NULL; - return LL_SO_ERROR (); + return (module->dl_fallback != NULL) ? err : LL_SO_ERROR (); } /** @@ -409,7 +444,14 @@ mono_dl_symbol (MonoDl *module, const char *name, void **symbol) void mono_dl_close (MonoDl *module) { - LL_SO_CLOSE (module); + MonoDlFallbackHandler *dl_fallback = module->dl_fallback; + + if (dl_fallback){ + if (dl_fallback->close_func != NULL) + dl_fallback->close_func (module->handle, dl_fallback->user_data); + } else + LL_SO_CLOSE (module); + free (module); } @@ -434,119 +476,165 @@ mono_dl_build_path (const char *directory, const char *name, void **iter) int idx; const char *prefix; const char *suffix; + gboolean first_call; int prlen; + int suffixlen; char *res; + if (!iter) return NULL; + + /* + The first time we are called, idx = 0 (as *iter is initialized to NULL). This is our + "bootstrap" phase in which we check the passed name verbatim and only if we fail to find + the dll thus named, we start appending suffixes, each time increasing idx twice (since now + the 0 value became special and we need to offset idx to a 0-based array index). This is + done to handle situations when mapped dll name is specified as libsomething.so.1 or + libsomething.so.1.1 or libsomething.so - testing it algorithmically would be an overkill + here. + */ idx = GPOINTER_TO_UINT (*iter); - if (idx >= G_N_ELEMENTS (suffixes)) - return NULL; + if (idx == 0) { + first_call = TRUE; + suffix = ""; + suffixlen = 0; + } else { + idx--; + if (idx >= G_N_ELEMENTS (suffixes)) + return NULL; + first_call = FALSE; + suffix = suffixes [idx]; + suffixlen = strlen (suffix); + } prlen = strlen (SOPREFIX); if (prlen && strncmp (name, SOPREFIX, prlen) != 0) prefix = SOPREFIX; else prefix = ""; - /* if the platform prefix is already provided, we suppose the caller knows the full name already */ - if (prlen && strncmp (name, SOPREFIX, prlen) == 0) + + if (first_call || (suffixlen && strstr (name, suffix) == (name + strlen (name) - suffixlen))) suffix = ""; - else - suffix = suffixes [idx]; + if (directory && *directory) - res = g_strconcat (directory, G_DIR_SEPARATOR_S, prefix, name, suffixes [idx], NULL); + res = g_strconcat (directory, G_DIR_SEPARATOR_S, prefix, name, suffix, NULL); else - res = g_strconcat (prefix, name, suffixes [idx], NULL); + res = g_strconcat (prefix, name, suffix, NULL); ++idx; + if (!first_call) + idx++; *iter = GUINT_TO_POINTER (idx); return res; } -#if EMBEDDED_PINVOKE -static GHashTable *mono_dls; -static char *ll_last_error = ""; - -/** - * mono_dl_register_library: - * @name: Library name, this is the name used by the DllImport as the external library name - * @mappings: the mappings to register for P/Invoke. - * - * This function is only available on builds that define - * EMBEDDED_PINVOKE, this is available for systems that do not provide - * a dynamic linker but still want to use DllImport to easily invoke - * code from the managed side into the unmanaged world. - * - * Mappings is a pointer to the first element of an array of - * MonoDlMapping values. The list must be terminated with both - * the name and addr fields set to NULL. - * - * This is typically used like this: - * MonoDlMapping sample_library_mappings [] = { - * { "CallMe", CallMe }, - * { NULL, NULL } - * }; - * - * ... - * main () - * { - * ... - * mono_dl_register_library ("sample", sample_library_mappings); - * ... - * } - * - * Then the C# code can use this P/Invoke signature: - * - * [DllImport ("sample")] - * extern static int CallMe (int f); - */ -void -mono_dl_register_library (const char *name, MonoDlMapping *mappings) +MonoDlFallbackHandler * +mono_dl_fallback_register (MonoDlFallbackLoad load_func, MonoDlFallbackSymbol symbol_func, MonoDlFallbackClose close_func, void *user_data) { - if (mono_dls == NULL) - mono_dls = g_hash_table_new (g_str_hash, g_str_equal); + MonoDlFallbackHandler *handler; - printf ("Inserting: 0x%p\n", mappings); - g_hash_table_insert (mono_dls, g_strdup (name), mappings); + g_return_val_if_fail (load_func != NULL, NULL); + g_return_val_if_fail (symbol_func != NULL, NULL); + + handler = g_new (MonoDlFallbackHandler, 1); + handler->load_func = load_func; + handler->symbol_func = symbol_func; + handler->close_func = close_func; + handler->user_data = user_data; + + fallback_handlers = g_slist_prepend (fallback_handlers, handler); + + return handler; } -void * -LL_SO_OPEN (const char *file, int flag) +void +mono_dl_fallback_unregister (MonoDlFallbackHandler *handler) { - void *mappings; - - if (mono_dls == NULL){ - ll_last_error = "Library not registered"; - return NULL; - } - - mappings = g_hash_table_lookup (mono_dls, file); - ll_last_error = mappings == NULL ? "File not registered" : ""; - return mappings; + GSList *found; + + found = g_slist_find (fallback_handlers, handler); + if (found == NULL) + return; + + g_slist_remove (fallback_handlers, handler); + g_free (handler); } -int LL_SO_CLOSE (void *handle) + +#if defined (HAVE_DL_LOADER) + +static MonoDl* +try_load (const char *lib_name, char *dir, int flags, char **err) { - // No-op - return 0; + gpointer iter; + MonoDl *runtime_lib; + char *path; + iter = NULL; + *err = NULL; + while ((path = mono_dl_build_path (dir, lib_name, &iter))) { + g_free (*err); + runtime_lib = mono_dl_open (path, flags, err); + g_free (path); + if (runtime_lib) + return runtime_lib; + } + return NULL; } -void * -_LL_SO_SYMBOL (void *handle, const char *symbol) +MonoDl* +mono_dl_open_runtime_lib (const char* lib_name, int flags, char **error_msg) { - MonoDlMapping *mappings = (MonoDlMapping *) handle; - - for (;mappings->name; mappings++){ - if (strcmp (symbol, mappings->name) == 0){ - ll_last_error = ""; - return mappings->addr; + MonoDl *runtime_lib = NULL; + char buf [4096]; + int binl; + binl = readlink ("/proc/self/exe", buf, sizeof (buf)-1); + *error_msg = NULL; + +#ifdef __MACH__ + if (binl == -1) { + uint32_t bsize = sizeof (buf); + if (_NSGetExecutablePath (buf, &bsize) == 0) { + binl = strlen (buf); } } - ll_last_error = "Symbol not found"; - return NULL; +#endif + if (binl != -1) { + char *base; + char *resolvedname, *name; + buf [binl] = 0; + resolvedname = mono_path_resolve_symlinks (buf); + base = g_path_get_dirname (resolvedname); + name = g_strdup_printf ("%s/.libs", base); + runtime_lib = try_load (lib_name, name, flags, error_msg); + g_free (name); + if (!runtime_lib) { + char *newbase = g_path_get_dirname (base); + name = g_strdup_printf ("%s/lib", newbase); + runtime_lib = try_load (lib_name, name, flags, error_msg); + g_free (name); + } +#ifdef __MACH__ + if (!runtime_lib) { + char *newbase = g_path_get_dirname (base); + name = g_strdup_printf ("%s/Libraries", newbase); + runtime_lib = try_load (lib_name, name, flags, error_msg); + g_free (name); + } +#endif + g_free (base); + g_free (resolvedname); + } + if (!runtime_lib) + runtime_lib = try_load (lib_name, NULL, flags, error_msg); + + return runtime_lib; } -char * -LL_SO_ERROR (void) +#else + +MonoDl* +mono_dl_open_runtime_lib (const char* lib_name, int flags, char **error_msg) { - return g_strdup (ll_last_error); + return NULL; } + #endif