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"
21 struct MonoDlFallbackHandler {
22 MonoDlFallbackLoad load_func;
23 MonoDlFallbackSymbol symbol_func;
24 MonoDlFallbackClose close_func;
28 static GSList *fallback_handlers;
31 * read a value string from line with any of the following formats:
34 * \s*=\s*non_white_space_string
37 read_string (char *p, FILE *file)
41 while (*p && isspace (*p))
47 while (*p && isspace (*p))
49 if (*p == '\'' || *p == '"') {
54 /* FIXME: may need to read more from file... */
58 return g_memdup (startp, (endp - startp) + 1);
63 while (*p && !isspace (*p))
66 return g_memdup (startp, (p - startp) + 1);
70 * parse a libtool .la file and return the path of the file to dlopen ()
71 * handling both the installed and uninstalled cases
74 get_dl_name_from_libtool (const char *libtool_file)
78 char *line, *dlname = NULL, *libdir = NULL, *installed = NULL;
79 if (!(file = fopen (libtool_file, "r")))
81 while ((line = fgets (buf, 512, file))) {
82 while (*line && isspace (*line))
84 if (*line == '#' || *line == 0)
86 if (strncmp ("dlname", line, 6) == 0) {
88 dlname = read_string (line + 6, file);
89 } else if (strncmp ("libdir", line, 6) == 0) {
91 libdir = read_string (line + 6, file);
92 } else if (strncmp ("installed", line, 9) == 0) {
94 installed = read_string (line + 9, file);
99 if (installed && strcmp (installed, "no") == 0) {
100 char *dir = g_path_get_dirname (libtool_file);
102 line = g_strconcat (dir, G_DIR_SEPARATOR_S ".libs" G_DIR_SEPARATOR_S, dlname, NULL);
105 if (libdir && dlname)
106 line = g_strconcat (libdir, G_DIR_SEPARATOR_S, dlname, NULL);
116 * @name: name of file containing shared module
118 * @error_msg: pointer for error message on failure
120 * Load the given file @name as a shared library or dynamically loadable
121 * module. @name can be NULL to indicate loading the currently executing
123 * @flags can have the MONO_DL_LOCAL bit set to avoid exporting symbols
124 * from the module to the shared namespace. The MONO_DL_LAZY bit can be set
125 * to lazily load the symbols instead of resolving everithing at load time.
126 * @error_msg points to a string where an error message will be stored in
127 * case of failure. The error must be released with g_free.
129 * Returns: a MonoDl pointer on success, NULL on failure.
132 mono_dl_open (const char *name, int flags, char **error_msg)
136 MonoDlFallbackHandler *dl_fallback = NULL;
137 int lflags = mono_dl_convert_flags (flags);
142 module = malloc (sizeof (MonoDl));
145 *error_msg = g_strdup ("Out of memory");
148 module->main_module = name == NULL? TRUE: FALSE;
150 lib = mono_dl_open_file (name, lflags);
154 for (node = fallback_handlers; node != NULL; node = node->next){
155 MonoDlFallbackHandler *handler = (MonoDlFallbackHandler *) node->data;
159 lib = handler->load_func (name, lflags, error_msg, handler->user_data);
160 if (error_msg && *error_msg != NULL)
164 dl_fallback = handler;
169 if (!lib && !dl_fallback) {
174 /* This platform does not support dlopen */
181 ext = strrchr (name, '.');
182 if (ext && strcmp (ext, ".la") == 0)
184 lname = g_strconcat (name, suff, NULL);
185 llname = get_dl_name_from_libtool (lname);
188 lib = mono_dl_open_file (llname, lflags);
193 *error_msg = mono_dl_current_error_string ();
199 module->handle = lib;
200 module->dl_fallback = dl_fallback;
206 * @module: a MonoDl pointer
208 * @symbol: pointer for the result value
210 * Load the address of symbol @name from the given @module.
211 * The address is stored in the pointer pointed to by @symbol.
213 * Returns: NULL on success, an error message on failure
216 mono_dl_symbol (MonoDl *module, const char *name, void **symbol)
221 if (module->dl_fallback) {
222 sym = module->dl_fallback->symbol_func (module->handle, name, &err, module->dl_fallback->user_data);
224 #if MONO_DL_NEED_USCORE
226 char *usname = malloc (strlen (name) + 2);
228 strcpy (usname + 1, name);
229 sym = mono_dl_lookup_symbol (module, usname);
233 sym = mono_dl_lookup_symbol (module, name);
244 return (module->dl_fallback != NULL) ? err : mono_dl_current_error_string ();
249 * @module: a MonoDl pointer
251 * Unload the given module and free the module memory.
253 * Returns: 0 on success.
256 mono_dl_close (MonoDl *module)
258 MonoDlFallbackHandler *dl_fallback = module->dl_fallback;
261 if (dl_fallback->close_func != NULL)
262 dl_fallback->close_func (module->handle, dl_fallback->user_data);
264 mono_dl_close_handle (module);
270 * mono_dl_build_path:
271 * @directory: optional directory
272 * @name: base name of the library
273 * @iter: iterator token
275 * Given a directory name and the base name of a library, iterate
276 * over the possible file names of the library, taking into account
277 * the possible different suffixes and prefixes on the host platform.
279 * The returned file name must be freed by the caller.
280 * @iter must point to a NULL pointer the first time the function is called
281 * and then passed unchanged to the following calls.
282 * Returns: the filename or NULL at the end of the iteration
285 mono_dl_build_path (const char *directory, const char *name, void **iter)
299 The first time we are called, idx = 0 (as *iter is initialized to NULL). This is our
300 "bootstrap" phase in which we check the passed name verbatim and only if we fail to find
301 the dll thus named, we start appending suffixes, each time increasing idx twice (since now
302 the 0 value became special and we need to offset idx to a 0-based array index). This is
303 done to handle situations when mapped dll name is specified as libsomething.so.1 or
304 libsomething.so.1.1 or libsomething.so - testing it algorithmically would be an overkill
307 idx = GPOINTER_TO_UINT (*iter);
314 if (mono_dl_get_so_suffixes () [idx][0] == '\0')
317 suffix = mono_dl_get_so_suffixes () [idx];
318 suffixlen = strlen (suffix);
321 prlen = strlen (mono_dl_get_so_prefix ());
322 if (prlen && strncmp (name, mono_dl_get_so_prefix (), prlen) != 0)
323 prefix = mono_dl_get_so_prefix ();
327 if (first_call || (suffixlen && strstr (name, suffix) == (name + strlen (name) - suffixlen)))
330 if (directory && *directory)
331 res = g_strconcat (directory, G_DIR_SEPARATOR_S, prefix, name, suffix, NULL);
333 res = g_strconcat (prefix, name, suffix, NULL);
337 *iter = GUINT_TO_POINTER (idx);
341 MonoDlFallbackHandler *
342 mono_dl_fallback_register (MonoDlFallbackLoad load_func, MonoDlFallbackSymbol symbol_func, MonoDlFallbackClose close_func, void *user_data)
344 MonoDlFallbackHandler *handler;
346 g_return_val_if_fail (load_func != NULL, NULL);
347 g_return_val_if_fail (symbol_func != NULL, NULL);
349 handler = g_new (MonoDlFallbackHandler, 1);
350 handler->load_func = load_func;
351 handler->symbol_func = symbol_func;
352 handler->close_func = close_func;
353 handler->user_data = user_data;
355 fallback_handlers = g_slist_prepend (fallback_handlers, handler);
361 mono_dl_fallback_unregister (MonoDlFallbackHandler *handler)
365 found = g_slist_find (fallback_handlers, handler);
369 g_slist_remove (fallback_handlers, handler);
374 try_load (const char *lib_name, char *dir, int flags, char **err)
381 while ((path = mono_dl_build_path (dir, lib_name, &iter))) {
383 runtime_lib = mono_dl_open (path, flags, err);
392 mono_dl_open_runtime_lib (const char* lib_name, int flags, char **error_msg)
394 MonoDl *runtime_lib = NULL;
399 binl = mono_dl_get_executable_path (buf, sizeof (buf));
403 char *resolvedname, *name;
405 resolvedname = mono_path_resolve_symlinks (buf);
406 base = g_path_get_dirname (resolvedname);
407 name = g_strdup_printf ("%s/.libs", base);
408 runtime_lib = try_load (lib_name, name, flags, error_msg);
411 char *newbase = g_path_get_dirname (base);
412 name = g_strdup_printf ("%s/lib", newbase);
413 runtime_lib = try_load (lib_name, name, flags, error_msg);
418 char *newbase = g_path_get_dirname (base);
419 name = g_strdup_printf ("%s/Libraries", newbase);
420 runtime_lib = try_load (lib_name, name, flags, error_msg);
425 g_free (resolvedname);
428 runtime_lib = try_load (lib_name, NULL, flags, error_msg);