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"
13 #include "mono/utils/mono-path.h"
23 static const char suffixes [][5] = {
26 #elif defined(__APPLE__)
27 #define SOPREFIX "lib"
28 static const char suffixes [][8] = {
34 #define SOPREFIX "lib"
35 static const char suffixes [][4] = {
45 #define SO_HANDLE_TYPE HMODULE
46 #define LL_SO_OPEN(file,flags) w32_load_module ((file), (flags))
47 #define LL_SO_CLOSE(module) do { if (!(module)->main_module) FreeLibrary ((module)->handle); } while (0)
48 #define LL_SO_SYMBOL(module, name) w32_find_symbol ((module), (name))
49 #define LL_SO_TRFLAGS(flags) 0
50 #define LL_SO_ERROR() w32_dlerror ()
52 #elif defined (HAVE_DL_LOADER)
58 #include <mach-o/dyld.h>
64 #endif /* RTLD_LAZY */
66 #define SO_HANDLE_TYPE void*
67 #ifdef PLATFORM_ANDROID
68 /* Bionic doesn't support NULL filenames */
69 # define LL_SO_OPEN(file,flags) ((file) ? dlopen ((file), (flags)) : NULL)
71 # define LL_SO_OPEN(file,flags) dlopen ((file), (flags))
73 #define LL_SO_CLOSE(module) dlclose ((module)->handle)
74 #define LL_SO_SYMBOL(module, name) dlsym ((module)->handle, (name))
75 #define LL_SO_TRFLAGS(flags) convert_flags ((flags))
76 #define LL_SO_ERROR() g_strdup (dlerror ())
79 convert_flags (int flags)
81 int lflags = flags & MONO_DL_LOCAL? 0: RTLD_GLOBAL;
83 if (flags & MONO_DL_LAZY)
91 /* no dynamic loader supported */
92 #define SO_HANDLE_TYPE void*
93 #define LL_SO_OPEN(file,flags) NULL
94 #define LL_SO_CLOSE(module)
95 #define LL_SO_SYMBOL(module, name) NULL
96 #define LL_SO_TRFLAGS(flags) (flags)
97 #define LL_SO_ERROR() g_strdup ("No support for dynamic loader")
101 static GSList *fallback_handlers;
103 struct MonoDlFallbackHandler {
104 MonoDlFallbackLoad load_func;
105 MonoDlFallbackSymbol symbol_func;
106 MonoDlFallbackClose close_func;
111 SO_HANDLE_TYPE handle;
114 /* If not NULL, use the methods in MonoDlFallbackHandler instead of the LL_* methods */
115 MonoDlFallbackHandler *dl_fallback;
125 DWORD code = GetLastError ();
127 if (FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL,
128 code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buf, 0, NULL))
130 ret = g_utf16_to_utf8 (buf, wcslen(buf), NULL, NULL, NULL);
133 g_assert_not_reached ();
139 w32_find_symbol (MonoDl *module, const gchar *symbol_name)
142 DWORD buffer_size = sizeof (HMODULE) * 1024;
144 gpointer proc = NULL;
146 /* get the symbol directly from the specified module */
147 if (!module->main_module)
148 return GetProcAddress (module->handle, symbol_name);
150 /* get the symbol from the main module */
151 proc = GetProcAddress (module->handle, symbol_name);
155 /* get the symbol from the loaded DLLs */
156 modules = (HMODULE *) g_malloc (buffer_size);
160 if (!EnumProcessModules (GetCurrentProcess (), modules,
161 buffer_size, &needed)) {
166 /* check whether the supplied buffer was too small, realloc, retry */
167 if (needed > buffer_size) {
170 buffer_size = needed;
171 modules = (HMODULE *) g_malloc (buffer_size);
176 if (!EnumProcessModules (GetCurrentProcess (), modules,
177 buffer_size, &needed)) {
183 for (i = 0; i < needed / sizeof (HANDLE); i++) {
184 proc = GetProcAddress (modules [i], symbol_name);
197 w32_load_module (const char* file, int flags)
199 gpointer hModule = NULL;
201 gunichar2* file_utf16 = g_utf8_to_utf16 (file, strlen (file), NULL, NULL, NULL);
202 guint last_sem = SetErrorMode (SEM_FAILCRITICALERRORS);
203 guint32 last_error = 0;
205 hModule = LoadLibrary (file_utf16);
207 last_error = GetLastError ();
209 SetErrorMode (last_sem);
213 SetLastError (last_error);
215 hModule = GetModuleHandle (NULL);
222 * read a value string from line with any of the following formats:
225 * \s*=\s*non_white_space_string
228 read_string (char *p, FILE *file)
232 while (*p && isspace (*p))
238 while (*p && isspace (*p))
240 if (*p == '\'' || *p == '"') {
244 endp = strchr (p, t);
245 /* FIXME: may need to read more from file... */
249 return g_memdup (startp, (endp - startp) + 1);
254 while (*p && !isspace (*p))
257 return g_memdup (startp, (p - startp) + 1);
261 * parse a libtool .la file and return the path of the file to dlopen ()
262 * handling both the installed and uninstalled cases
265 get_dl_name_from_libtool (const char *libtool_file)
269 char *line, *dlname = NULL, *libdir = NULL, *installed = NULL;
270 if (!(file = fopen (libtool_file, "r")))
272 while ((line = fgets (buf, 512, file))) {
273 while (*line && isspace (*line))
275 if (*line == '#' || *line == 0)
277 if (strncmp ("dlname", line, 6) == 0) {
279 dlname = read_string (line + 6, file);
280 } else if (strncmp ("libdir", line, 6) == 0) {
282 libdir = read_string (line + 6, file);
283 } else if (strncmp ("installed", line, 9) == 0) {
285 installed = read_string (line + 9, file);
290 if (installed && strcmp (installed, "no") == 0) {
291 char *dir = g_path_get_dirname (libtool_file);
293 line = g_strconcat (dir, G_DIR_SEPARATOR_S ".libs" G_DIR_SEPARATOR_S, dlname, NULL);
296 if (libdir && dlname)
297 line = g_strconcat (libdir, G_DIR_SEPARATOR_S, dlname, NULL);
307 * @name: name of file containing shared module
309 * @error_msg: pointer for error message on failure
311 * Load the given file @name as a shared library or dynamically loadable
312 * module. @name can be NULL to indicate loading the currently executing
314 * @flags can have the MONO_DL_LOCAL bit set to avoid exporting symbols
315 * from the module to the shared namespace. The MONO_DL_LAZY bit can be set
316 * to lazily load the symbols instead of resolving everithing at load time.
317 * @error_msg points to a string where an error message will be stored in
318 * case of failure. The error must be released with g_free.
320 * Returns: a MonoDl pointer on success, NULL on failure.
323 mono_dl_open (const char *name, int flags, char **error_msg)
327 MonoDlFallbackHandler *dl_fallback = NULL;
328 int lflags = LL_SO_TRFLAGS (flags);
333 module = malloc (sizeof (MonoDl));
336 *error_msg = g_strdup ("Out of memory");
339 module->main_module = name == NULL? TRUE: FALSE;
340 lib = LL_SO_OPEN (name, lflags);
343 for (node = fallback_handlers; node != NULL; node = node->next){
344 MonoDlFallbackHandler *handler = (MonoDlFallbackHandler *) node->data;
348 lib = handler->load_func (name, lflags, error_msg, handler->user_data);
349 if (error_msg && *error_msg != NULL)
353 dl_fallback = handler;
358 if (!lib && !dl_fallback) {
363 /* This platform does not support dlopen */
370 ext = strrchr (name, '.');
371 if (ext && strcmp (ext, ".la") == 0)
373 lname = g_strconcat (name, suff, NULL);
374 llname = get_dl_name_from_libtool (lname);
377 lib = LL_SO_OPEN (llname, lflags);
382 *error_msg = LL_SO_ERROR ();
388 module->handle = lib;
389 module->dl_fallback = dl_fallback;
395 * @module: a MonoDl pointer
397 * @symbol: pointer for the result value
399 * Load the address of symbol @name from the given @module.
400 * The address is stored in the pointer pointed to by @symbol.
402 * Returns: NULL on success, an error message on failure
405 mono_dl_symbol (MonoDl *module, const char *name, void **symbol)
410 if (module->dl_fallback) {
411 sym = module->dl_fallback->symbol_func (module->handle, name, &err, module->dl_fallback->user_data);
413 #if MONO_DL_NEED_USCORE
415 char *usname = malloc (strlen (name) + 2);
417 strcpy (usname + 1, name);
418 sym = LL_SO_SYMBOL (module, usname);
422 sym = LL_SO_SYMBOL (module, name);
433 return (module->dl_fallback != NULL) ? err : LL_SO_ERROR ();
438 * @module: a MonoDl pointer
440 * Unload the given module and free the module memory.
442 * Returns: 0 on success.
445 mono_dl_close (MonoDl *module)
447 MonoDlFallbackHandler *dl_fallback = module->dl_fallback;
450 if (dl_fallback->close_func != NULL)
451 dl_fallback->close_func (module->handle, dl_fallback->user_data);
453 LL_SO_CLOSE (module);
459 * mono_dl_build_path:
460 * @directory: optional directory
461 * @name: base name of the library
462 * @iter: iterator token
464 * Given a directory name and the base name of a library, iterate
465 * over the possible file names of the library, taking into account
466 * the possible different suffixes and prefixes on the host platform.
468 * The returned file name must be freed by the caller.
469 * @iter must point to a NULL pointer the first time the function is called
470 * and then passed unchanged to the following calls.
471 * Returns: the filename or NULL at the end of the iteration
474 mono_dl_build_path (const char *directory, const char *name, void **iter)
488 The first time we are called, idx = 0 (as *iter is initialized to NULL). This is our
489 "bootstrap" phase in which we check the passed name verbatim and only if we fail to find
490 the dll thus named, we start appending suffixes, each time increasing idx twice (since now
491 the 0 value became special and we need to offset idx to a 0-based array index). This is
492 done to handle situations when mapped dll name is specified as libsomething.so.1 or
493 libsomething.so.1.1 or libsomething.so - testing it algorithmically would be an overkill
496 idx = GPOINTER_TO_UINT (*iter);
503 if (idx >= G_N_ELEMENTS (suffixes))
506 suffix = suffixes [idx];
507 suffixlen = strlen (suffix);
510 prlen = strlen (SOPREFIX);
511 if (prlen && strncmp (name, SOPREFIX, prlen) != 0)
516 if (first_call || (suffixlen && strstr (name, suffix) == (name + strlen (name) - suffixlen)))
519 if (directory && *directory)
520 res = g_strconcat (directory, G_DIR_SEPARATOR_S, prefix, name, suffix, NULL);
522 res = g_strconcat (prefix, name, suffix, NULL);
526 *iter = GUINT_TO_POINTER (idx);
530 MonoDlFallbackHandler *
531 mono_dl_fallback_register (MonoDlFallbackLoad load_func, MonoDlFallbackSymbol symbol_func, MonoDlFallbackClose close_func, void *user_data)
533 MonoDlFallbackHandler *handler;
535 g_return_val_if_fail (load_func != NULL, NULL);
536 g_return_val_if_fail (symbol_func != NULL, NULL);
538 handler = g_new (MonoDlFallbackHandler, 1);
539 handler->load_func = load_func;
540 handler->symbol_func = symbol_func;
541 handler->close_func = close_func;
542 handler->user_data = user_data;
544 fallback_handlers = g_slist_prepend (fallback_handlers, handler);
550 mono_dl_fallback_unregister (MonoDlFallbackHandler *handler)
554 found = g_slist_find (fallback_handlers, handler);
558 g_slist_remove (fallback_handlers, handler);
563 #if defined (HAVE_DL_LOADER)
566 try_load (const char *lib_name, char *dir, int flags, char **err)
573 while ((path = mono_dl_build_path (dir, lib_name, &iter))) {
575 runtime_lib = mono_dl_open (path, flags, err);
584 mono_dl_open_runtime_lib (const char* lib_name, int flags, char **error_msg)
586 MonoDl *runtime_lib = NULL;
589 binl = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
594 uint32_t bsize = sizeof (buf);
595 if (_NSGetExecutablePath (buf, &bsize) == 0) {
602 char *resolvedname, *name;
604 resolvedname = mono_path_resolve_symlinks (buf);
605 base = g_path_get_dirname (resolvedname);
606 name = g_strdup_printf ("%s/.libs", base);
607 runtime_lib = try_load (lib_name, name, flags, error_msg);
610 char *newbase = g_path_get_dirname (base);
611 name = g_strdup_printf ("%s/lib", newbase);
612 runtime_lib = try_load (lib_name, name, flags, error_msg);
617 char *newbase = g_path_get_dirname (base);
618 name = g_strdup_printf ("%s/Libraries", newbase);
619 runtime_lib = try_load (lib_name, name, flags, error_msg);
624 g_free (resolvedname);
627 runtime_lib = try_load (lib_name, NULL, flags, error_msg);
635 mono_dl_open_runtime_lib (const char* lib_name, int flags, char **error_msg)