+/*
+ * mono-dl.c: Interface to the dynamic linker
+ *
+ * Author:
+ * Mono Team (http://www.mono-project.com)
+ *
+ * Copyright 2001-2004 Ximian, Inc.
+ * Copyright 2004-2009 Novell, Inc.
+ */
#include "config.h"
#include "mono/utils/mono-dl.h"
+#include "mono/utils/mono-embed.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <glib.h>
-#ifdef PLATFORM_WIN32
+#ifdef TARGET_WIN32
#define SOPREFIX ""
static const char suffixes [][5] = {
".dll"
".so",
".bundle"
};
+#elif EMBEDDED_PINVOKE
+#define SOPREFIX ""
+static const char suffixes [][1] = {
+ ""
+};
#else
#define SOPREFIX "lib"
static const char suffixes [][4] = {
};
#endif
-#ifdef PLATFORM_WIN32
+#ifdef TARGET_WIN32
#include <windows.h>
+#include <psapi.h>
#define SO_HANDLE_TYPE HMODULE
-#define LL_SO_OPEN(file,flags) (file)? LoadLibrary ((file)): GetModuleHandle (NULL)
-#define LL_SO_CLOSE(module) do { if ((module)->main_module) FreeLibrary ((module)->handle); } while (0)
-#define LL_SO_SYMBOL(handle, name) GetProcAddress ((handle), (name))
+#define LL_SO_OPEN(file,flags) w32_load_module ((file), (flags))
+#define LL_SO_CLOSE(module) do { if (!(module)->main_module) FreeLibrary ((module)->handle); } while (0)
+#define LL_SO_SYMBOL(module, name) w32_find_symbol ((module), (name))
#define LL_SO_TRFLAGS(flags) 0
#define LL_SO_ERROR() w32_dlerror ()
-static char*
-w32_dlerror (void)
-{
- char* ret;
- TCHAR* buf = NULL;
- DWORD code = GetLastError ();
-
- FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL,
- code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 0, NULL);
-
- ret = g_strdup (buf);
- LocalFree (buf);
- return ret;
-}
-
#elif defined (HAVE_DL_LOADER)
#include <dlfcn.h>
#define SO_HANDLE_TYPE void*
#define LL_SO_OPEN(file,flags) dlopen ((file), (flags))
-#define LL_SO_CLOSE(handle) dlclose ((handle))
-#define LL_SO_SYMBOL(handle, name) dlsym ((handle), (name))
+#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))
#define LL_SO_ERROR() g_strdup (dlerror ())
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 duynamic loader supported */
+/* no dynamic loader supported */
#define SO_HANDLE_TYPE void*
#define LL_SO_OPEN(file,flags) NULL
-#define LL_SO_CLOSE(handle)
-#define LL_SO_SYMBOL(handle, name) NULL
+#define LL_SO_CLOSE(module)
+#define LL_SO_SYMBOL(module, name) NULL
#define LL_SO_TRFLAGS(flags) (flags)
#define LL_SO_ERROR() g_strdup ("No support for dynamic loader")
int main_module;
};
+#ifdef TARGET_WIN32
+
+static char*
+w32_dlerror (void)
+{
+ char* ret = NULL;
+ wchar_t* buf = NULL;
+ DWORD code = GetLastError ();
+
+ if (FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL,
+ code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buf, 0, NULL))
+ {
+ ret = g_utf16_to_utf8 (buf, wcslen(buf), NULL, NULL, NULL);
+ LocalFree (buf);
+ } else {
+ g_assert_not_reached ();
+ }
+ return ret;
+}
+
+static gpointer
+w32_find_symbol (MonoDl *module, const gchar *symbol_name)
+{
+ HMODULE *modules;
+ DWORD buffer_size = sizeof (HMODULE) * 1024;
+ DWORD needed, i;
+ gpointer proc = NULL;
+
+ /* get the symbol directly from the specified module */
+ if (!module->main_module)
+ return GetProcAddress (module->handle, symbol_name);
+
+ /* get the symbol from the main module */
+ proc = GetProcAddress (module->handle, symbol_name);
+ if (proc != NULL)
+ return proc;
+
+ /* get the symbol from the loaded DLLs */
+ modules = (HMODULE *) g_malloc (buffer_size);
+ if (modules == NULL)
+ return NULL;
+
+ if (!EnumProcessModules (GetCurrentProcess (), modules,
+ buffer_size, &needed)) {
+ g_free (modules);
+ return NULL;
+ }
+
+ /* check whether the supplied buffer was too small, realloc, retry */
+ if (needed > buffer_size) {
+ g_free (modules);
+
+ buffer_size = needed;
+ modules = (HMODULE *) g_malloc (buffer_size);
+
+ if (modules == NULL)
+ return NULL;
+
+ if (!EnumProcessModules (GetCurrentProcess (), modules,
+ buffer_size, &needed)) {
+ g_free (modules);
+ return NULL;
+ }
+ }
+
+ for (i = 0; i < needed / sizeof (HANDLE); i++) {
+ proc = GetProcAddress (modules [i], symbol_name);
+ if (proc != NULL) {
+ g_free (modules);
+ return proc;
+ }
+ }
+
+ g_free (modules);
+ return NULL;
+}
+
+
+static gpointer
+w32_load_module (const char* file, int flags)
+{
+ gpointer hModule = NULL;
+ if (file) {
+ gunichar2* file_utf16 = g_utf8_to_utf16 (file, strlen (file), NULL, NULL, NULL);
+ guint last_sem = SetErrorMode (SEM_FAILCRITICALERRORS);
+ guint32 last_error = 0;
+
+ hModule = LoadLibrary (file_utf16);
+ if (!hModule)
+ last_error = GetLastError ();
+
+ SetErrorMode (last_sem);
+ g_free (file_utf16);
+
+ if (!hModule)
+ SetLastError (last_error);
+ } else {
+ hModule = GetModuleHandle (NULL);
+ }
+ return hModule;
+}
+#endif
/*
* read a value string from line with any of the following formats:
* from the module to the shared namespace. The MONO_DL_LAZY bit can be set
* to lazily load the symbols instead of resolving everithing at load time.
* @error_msg points to a string where an error message will be stored in
- * case of failure.
+ * case of failure. The error must be released with g_free.
*
* Returns: a MonoDl pointer on success, NULL on failure.
*/
if (!lib) {
char *lname;
char *llname;
- const char *suff = ".la";
- const char *ext = strrchr (name, '.');
+ const char *suff;
+ const char *ext;
+ /* This platform does not support dlopen */
+ if (name == NULL) {
+ free (module);
+ return NULL;
+ }
+
+ suff = ".la";
+ ext = strrchr (name, '.');
if (ext && strcmp (ext, ".la") == 0)
suff = "";
lname = g_strconcat (name, suff, NULL);
char *usname = malloc (strlen (name) + 2);
*usname = '_';
strcpy (usname + 1, name);
- sym = LL_SO_SYMBOL (module->handle, usname);
+ sym = LL_SO_SYMBOL (module, usname);
free (usname);
}
#else
- sym = LL_SO_SYMBOL (module->handle, name);
+ sym = LL_SO_SYMBOL (module, name);
#endif
if (sym) {
if (symbol)
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)
+{
+ if (mono_dls == NULL)
+ mono_dls = g_hash_table_new (g_str_hash, g_str_equal);
+
+ printf ("Inserting: 0x%p\n", mappings);
+ g_hash_table_insert (mono_dls, g_strdup (name), mappings);
+}
+
+void *
+LL_SO_OPEN (const char *file, int flag)
+{
+ 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" : "";
+ printf ("Returning mappings=0x%p\n", mappings);
+ return mappings;
+}
+
+int LL_SO_CLOSE (void *handle)
+{
+ // No-op
+ return 0;
+}
+
+void *
+_LL_SO_SYMBOL (void *handle, const char *symbol)
+{
+ MonoDlMapping *mappings = (MonoDlMapping *) handle;
+
+ printf ("During lookup: 0x%p\n", 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;
+}
+
+char *
+LL_SO_ERROR (void)
+{
+ return g_strdup (ll_last_error);
+}
+#endif