2 * mono-dl.c: Interface to the dynamic linker
5 * Mono Team (http://www.mono-project.com)
7 * Copyright 2001-2004 Ximian, Inc.
8 * Copyright 2004-2009 Novell, Inc.
11 #include "mono/utils/mono-dl.h"
12 #include "mono/utils/mono-embed.h"
22 static const char suffixes [][5] = {
25 #elif defined(__APPLE__)
26 #define SOPREFIX "lib"
27 static const char suffixes [][8] = {
33 #define SOPREFIX "lib"
34 static const char suffixes [][4] = {
44 #define SO_HANDLE_TYPE HMODULE
45 #define LL_SO_OPEN(file,flags) w32_load_module ((file), (flags))
46 #define LL_SO_CLOSE(module) do { if (!(module)->main_module) FreeLibrary ((module)->handle); } while (0)
47 #define LL_SO_SYMBOL(module, name) w32_find_symbol ((module), (name))
48 #define LL_SO_TRFLAGS(flags) 0
49 #define LL_SO_ERROR() w32_dlerror ()
51 #elif defined (HAVE_DL_LOADER)
57 #endif /* RTLD_LAZY */
59 #define SO_HANDLE_TYPE void*
60 #ifdef PLATFORM_ANDROID
61 /* Bionic doesn't support NULL filenames */
62 # define LL_SO_OPEN(file,flags) ((file) ? dlopen ((file), (flags)) : NULL)
64 # define LL_SO_OPEN(file,flags) dlopen ((file), (flags))
66 #define LL_SO_CLOSE(module) dlclose ((module)->handle)
67 #define LL_SO_SYMBOL(module, name) dlsym ((module)->handle, (name))
68 #define LL_SO_TRFLAGS(flags) convert_flags ((flags))
69 #define LL_SO_ERROR() g_strdup (dlerror ())
72 convert_flags (int flags)
74 int lflags = flags & MONO_DL_LOCAL? 0: RTLD_GLOBAL;
76 if (flags & MONO_DL_LAZY)
84 /* no dynamic loader supported */
85 #define SO_HANDLE_TYPE void*
86 #define LL_SO_OPEN(file,flags) NULL
87 #define LL_SO_CLOSE(module)
88 #define LL_SO_SYMBOL(module, name) NULL
89 #define LL_SO_TRFLAGS(flags) (flags)
90 #define LL_SO_ERROR() g_strdup ("No support for dynamic loader")
94 static GSList *fallback_handlers;
96 struct MonoDlFallbackHandler {
97 MonoDlFallbackLoad load_func;
98 MonoDlFallbackSymbol symbol_func;
99 MonoDlFallbackClose close_func;
104 SO_HANDLE_TYPE handle;
107 /* If not NULL, use the methods in MonoDlFallbackHandler instead of the LL_* methods */
108 MonoDlFallbackHandler *dl_fallback;
118 DWORD code = GetLastError ();
120 if (FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL,
121 code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buf, 0, NULL))
123 ret = g_utf16_to_utf8 (buf, wcslen(buf), NULL, NULL, NULL);
126 g_assert_not_reached ();
132 w32_find_symbol (MonoDl *module, const gchar *symbol_name)
135 DWORD buffer_size = sizeof (HMODULE) * 1024;
137 gpointer proc = NULL;
139 /* get the symbol directly from the specified module */
140 if (!module->main_module)
141 return GetProcAddress (module->handle, symbol_name);
143 /* get the symbol from the main module */
144 proc = GetProcAddress (module->handle, symbol_name);
148 /* get the symbol from the loaded DLLs */
149 modules = (HMODULE *) g_malloc (buffer_size);
153 if (!EnumProcessModules (GetCurrentProcess (), modules,
154 buffer_size, &needed)) {
159 /* check whether the supplied buffer was too small, realloc, retry */
160 if (needed > buffer_size) {
163 buffer_size = needed;
164 modules = (HMODULE *) g_malloc (buffer_size);
169 if (!EnumProcessModules (GetCurrentProcess (), modules,
170 buffer_size, &needed)) {
176 for (i = 0; i < needed / sizeof (HANDLE); i++) {
177 proc = GetProcAddress (modules [i], symbol_name);
190 w32_load_module (const char* file, int flags)
192 gpointer hModule = NULL;
194 gunichar2* file_utf16 = g_utf8_to_utf16 (file, strlen (file), NULL, NULL, NULL);
195 guint last_sem = SetErrorMode (SEM_FAILCRITICALERRORS);
196 guint32 last_error = 0;
198 hModule = LoadLibrary (file_utf16);
200 last_error = GetLastError ();
202 SetErrorMode (last_sem);
206 SetLastError (last_error);
208 hModule = GetModuleHandle (NULL);
215 * read a value string from line with any of the following formats:
218 * \s*=\s*non_white_space_string
221 read_string (char *p, FILE *file)
225 while (*p && isspace (*p))
231 while (*p && isspace (*p))
233 if (*p == '\'' || *p == '"') {
237 endp = strchr (p, t);
238 /* FIXME: may need to read more from file... */
242 return g_memdup (startp, (endp - startp) + 1);
247 while (*p && !isspace (*p))
250 return g_memdup (startp, (p - startp) + 1);
254 * parse a libtool .la file and return the path of the file to dlopen ()
255 * handling both the installed and uninstalled cases
258 get_dl_name_from_libtool (const char *libtool_file)
262 char *line, *dlname = NULL, *libdir = NULL, *installed = NULL;
263 if (!(file = fopen (libtool_file, "r")))
265 while ((line = fgets (buf, 512, file))) {
266 while (*line && isspace (*line))
268 if (*line == '#' || *line == 0)
270 if (strncmp ("dlname", line, 6) == 0) {
272 dlname = read_string (line + 6, file);
273 } else if (strncmp ("libdir", line, 6) == 0) {
275 libdir = read_string (line + 6, file);
276 } else if (strncmp ("installed", line, 9) == 0) {
278 installed = read_string (line + 9, file);
283 if (installed && strcmp (installed, "no") == 0) {
284 char *dir = g_path_get_dirname (libtool_file);
286 line = g_strconcat (dir, G_DIR_SEPARATOR_S ".libs" G_DIR_SEPARATOR_S, dlname, NULL);
289 if (libdir && dlname)
290 line = g_strconcat (libdir, G_DIR_SEPARATOR_S, dlname, NULL);
300 * @name: name of file containing shared module
302 * @error_msg: pointer for error message on failure
304 * Load the given file @name as a shared library or dynamically loadable
305 * module. @name can be NULL to indicate loading the currently executing
307 * @flags can have the MONO_DL_LOCAL bit set to avoid exporting symbols
308 * from the module to the shared namespace. The MONO_DL_LAZY bit can be set
309 * to lazily load the symbols instead of resolving everithing at load time.
310 * @error_msg points to a string where an error message will be stored in
311 * case of failure. The error must be released with g_free.
313 * Returns: a MonoDl pointer on success, NULL on failure.
316 mono_dl_open (const char *name, int flags, char **error_msg)
320 MonoDlFallbackHandler *dl_fallback = NULL;
321 int lflags = LL_SO_TRFLAGS (flags);
326 module = malloc (sizeof (MonoDl));
329 *error_msg = g_strdup ("Out of memory");
332 module->main_module = name == NULL? TRUE: FALSE;
333 lib = LL_SO_OPEN (name, lflags);
336 for (node = fallback_handlers; node != NULL; node = node->next){
337 MonoDlFallbackHandler *handler = (MonoDlFallbackHandler *) node->data;
341 lib = handler->load_func (name, lflags, error_msg, handler->user_data);
342 if (error_msg && *error_msg != NULL)
346 dl_fallback = handler;
351 if (!lib && !dl_fallback) {
356 /* This platform does not support dlopen */
363 ext = strrchr (name, '.');
364 if (ext && strcmp (ext, ".la") == 0)
366 lname = g_strconcat (name, suff, NULL);
367 llname = get_dl_name_from_libtool (lname);
370 lib = LL_SO_OPEN (llname, lflags);
375 *error_msg = LL_SO_ERROR ();
381 module->handle = lib;
382 module->dl_fallback = dl_fallback;
388 * @module: a MonoDl pointer
390 * @symbol: pointer for the result value
392 * Load the address of symbol @name from the given @module.
393 * The address is stored in the pointer pointed to by @symbol.
395 * Returns: NULL on success, an error message on failure
398 mono_dl_symbol (MonoDl *module, const char *name, void **symbol)
403 if (module->dl_fallback) {
404 sym = module->dl_fallback->symbol_func (module->handle, name, &err, module->dl_fallback->user_data);
406 #if MONO_DL_NEED_USCORE
408 char *usname = malloc (strlen (name) + 2);
410 strcpy (usname + 1, name);
411 sym = LL_SO_SYMBOL (module, usname);
415 sym = LL_SO_SYMBOL (module, name);
426 return (module->dl_fallback != NULL) ? err : LL_SO_ERROR ();
431 * @module: a MonoDl pointer
433 * Unload the given module and free the module memory.
435 * Returns: 0 on success.
438 mono_dl_close (MonoDl *module)
440 MonoDlFallbackHandler *dl_fallback = module->dl_fallback;
443 if (dl_fallback->close_func != NULL)
444 dl_fallback->close_func (module->handle, dl_fallback->user_data);
446 LL_SO_CLOSE (module);
452 * mono_dl_build_path:
453 * @directory: optional directory
454 * @name: base name of the library
455 * @iter: iterator token
457 * Given a directory name and the base name of a library, iterate
458 * over the possible file names of the library, taking into account
459 * the possible different suffixes and prefixes on the host platform.
461 * The returned file name must be freed by the caller.
462 * @iter must point to a NULL pointer the first time the function is called
463 * and then passed unchanged to the following calls.
464 * Returns: the filename or NULL at the end of the iteration
467 mono_dl_build_path (const char *directory, const char *name, void **iter)
481 The first time we are called, idx = 0 (as *iter is initialized to NULL). This is our
482 "bootstrap" phase in which we check the passed name verbatim and only if we fail to find
483 the dll thus named, we start appending suffixes, each time increasing idx twice (since now
484 the 0 value became special and we need to offset idx to a 0-based array index). This is
485 done to handle situations when mapped dll name is specified as libsomething.so.1 or
486 libsomething.so.1.1 or libsomething.so - testing it algorithmically would be an overkill
489 idx = GPOINTER_TO_UINT (*iter);
496 if (idx >= G_N_ELEMENTS (suffixes))
499 suffix = suffixes [idx];
500 suffixlen = strlen (suffix);
503 prlen = strlen (SOPREFIX);
504 if (prlen && strncmp (name, SOPREFIX, prlen) != 0)
509 if (first_call || (suffixlen && strstr (name, suffix) == (name + strlen (name) - suffixlen)))
512 if (directory && *directory)
513 res = g_strconcat (directory, G_DIR_SEPARATOR_S, prefix, name, suffix, NULL);
515 res = g_strconcat (prefix, name, suffix, NULL);
519 *iter = GUINT_TO_POINTER (idx);
523 MonoDlFallbackHandler *
524 mono_dl_fallback_register (MonoDlFallbackLoad load_func, MonoDlFallbackSymbol symbol_func, MonoDlFallbackClose close_func, void *user_data)
526 MonoDlFallbackHandler *handler;
528 g_return_val_if_fail (load_func != NULL, NULL);
529 g_return_val_if_fail (symbol_func != NULL, NULL);
531 handler = g_new (MonoDlFallbackHandler, 1);
532 handler->load_func = load_func;
533 handler->symbol_func = symbol_func;
534 handler->close_func = close_func;
535 handler->user_data = user_data;
537 fallback_handlers = g_slist_prepend (fallback_handlers, handler);
543 mono_dl_fallback_unregister (MonoDlFallbackHandler *handler)
547 found = g_slist_find (fallback_handlers, handler);
551 g_slist_remove (fallback_handlers, handler);