[xbuild] Fix assembly name comparison when resolving references.
[mono.git] / mono / utils / mono-dl.c
index 9d45ddfc4982de1ad0e2ddc30f36f1d1ab2db0f6..2b9d518f4b0660f361737e09f8227e7621ad18d7 100644 (file)
@@ -29,11 +29,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] = {
@@ -80,15 +75,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 +86,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 +312,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 +327,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 +374,7 @@ mono_dl_open (const char *name, int flags, char **error_msg)
                }
        }
        module->handle = lib;
+       module->dl_fallback = dl_fallback;
        return module;
 }
 
@@ -376,18 +393,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 +418,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 +432,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 +464,85 @@ 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, suffix, NULL);
        else
                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);
 
-void *
-LL_SO_OPEN (const char *file, int flag)
-{
-       void *mappings;
+       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);
        
-       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;
+       return handler;
 }
 
-int LL_SO_CLOSE (void *handle)
+void
+mono_dl_fallback_unregister (MonoDlFallbackHandler *handler)
 {
-       // No-op
-       return 0;
-}
+       GSList *found;
 
-void *
-_LL_SO_SYMBOL (void *handle, const char *symbol)
-{
-       MonoDlMapping *mappings = (MonoDlMapping *) handle;
-       
-       for (;mappings->name; mappings++){
-               if (strcmp (symbol, mappings->name) == 0){
-                       ll_last_error = "";
-                       return mappings->addr;
-               }
-       }
-       ll_last_error = "Symbol not found";
-       return NULL;
-}
+       found = g_slist_find (fallback_handlers, handler);
+       if (found == NULL)
+               return;
 
-char *
-LL_SO_ERROR (void)
-{
-       return g_strdup (ll_last_error);
+       g_slist_remove (fallback_handlers, handler);
+       g_free (handler);
 }
-#endif