3 * Interface to the dynamic linker
6 * Mono Team (http://www.mono-project.com)
8 * Copyright 2001-2004 Ximian, Inc.
9 * Copyright 2004-2009 Novell, Inc.
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13 #include "mono/utils/mono-dl.h"
14 #include "mono/utils/mono-embed.h"
15 #include "mono/utils/mono-path.h"
23 struct MonoDlFallbackHandler {
24 MonoDlFallbackLoad load_func;
25 MonoDlFallbackSymbol symbol_func;
26 MonoDlFallbackClose close_func;
30 static GSList *fallback_handlers;
33 * read a value string from line with any of the following formats:
36 * \s*=\s*non_white_space_string
39 read_string (char *p, FILE *file)
43 while (*p && isspace (*p))
49 while (*p && isspace (*p))
51 if (*p == '\'' || *p == '"') {
56 /* FIXME: may need to read more from file... */
60 return (char *) g_memdup (startp, (endp - startp) + 1);
65 while (*p && !isspace (*p))
68 return (char *) g_memdup (startp, (p - startp) + 1);
72 * parse a libtool .la file and return the path of the file to dlopen ()
73 * handling both the installed and uninstalled cases
76 get_dl_name_from_libtool (const char *libtool_file)
80 char *line, *dlname = NULL, *libdir = NULL, *installed = NULL;
81 if (!(file = fopen (libtool_file, "r")))
83 while ((line = fgets (buf, 512, file))) {
84 while (*line && isspace (*line))
86 if (*line == '#' || *line == 0)
88 if (strncmp ("dlname", line, 6) == 0) {
90 dlname = read_string (line + 6, file);
91 } else if (strncmp ("libdir", line, 6) == 0) {
93 libdir = read_string (line + 6, file);
94 } else if (strncmp ("installed", line, 9) == 0) {
96 installed = read_string (line + 9, file);
101 if (installed && strcmp (installed, "no") == 0) {
102 char *dir = g_path_get_dirname (libtool_file);
104 line = g_strconcat (dir, G_DIR_SEPARATOR_S ".libs" G_DIR_SEPARATOR_S, dlname, NULL);
107 if (libdir && dlname)
108 line = g_strconcat (libdir, G_DIR_SEPARATOR_S, dlname, NULL);
118 * \param name name of file containing shared module
120 * \param error_msg pointer for error message on failure
122 * Load the given file \p name as a shared library or dynamically loadable
123 * module. \p name can be NULL to indicate loading the currently executing
125 * \p flags can have the \c MONO_DL_LOCAL bit set to avoid exporting symbols
126 * from the module to the shared namespace. The \c MONO_DL_LAZY bit can be set
127 * to lazily load the symbols instead of resolving everithing at load time.
128 * \p error_msg points to a string where an error message will be stored in
129 * case of failure. The error must be released with \c g_free.
130 * \returns a \c MonoDl pointer on success, NULL on failure.
133 mono_dl_open (const char *name, int flags, char **error_msg)
137 MonoDlFallbackHandler *dl_fallback = NULL;
138 int lflags = mono_dl_convert_flags (flags);
143 module = (MonoDl *) g_malloc (sizeof (MonoDl));
146 *error_msg = g_strdup ("Out of memory");
149 module->main_module = name == NULL? TRUE: FALSE;
151 lib = mono_dl_open_file (name, lflags);
155 for (node = fallback_handlers; node != NULL; node = node->next){
156 MonoDlFallbackHandler *handler = (MonoDlFallbackHandler *) node->data;
160 lib = handler->load_func (name, lflags, error_msg, handler->user_data);
161 if (error_msg && *error_msg != NULL)
165 dl_fallback = handler;
170 if (!lib && !dl_fallback) {
175 /* This platform does not support dlopen */
182 ext = strrchr (name, '.');
183 if (ext && strcmp (ext, ".la") == 0)
185 lname = g_strconcat (name, suff, NULL);
186 llname = get_dl_name_from_libtool (lname);
189 lib = mono_dl_open_file (llname, lflags);
194 *error_msg = mono_dl_current_error_string ();
200 module->handle = lib;
201 module->dl_fallback = dl_fallback;
207 * \param module a MonoDl pointer
208 * \param name symbol name
209 * \param symbol pointer for the result value
210 * Load the address of symbol \p name from the given \p module.
211 * The address is stored in the pointer pointed to by \p symbol.
212 * \returns NULL on success, an error message on failure
215 mono_dl_symbol (MonoDl *module, const char *name, void **symbol)
220 if (module->dl_fallback) {
221 sym = module->dl_fallback->symbol_func (module->handle, name, &err, module->dl_fallback->user_data);
223 #if MONO_DL_NEED_USCORE
225 char *usname = g_malloc (strlen (name) + 2);
227 strcpy (usname + 1, name);
228 sym = mono_dl_lookup_symbol (module, usname);
232 sym = mono_dl_lookup_symbol (module, name);
243 return (module->dl_fallback != NULL) ? err : mono_dl_current_error_string ();
248 * \param module a \c MonoDl pointer
249 * Unload the given module and free the module memory.
250 * \returns \c 0 on success.
253 mono_dl_close (MonoDl *module)
255 MonoDlFallbackHandler *dl_fallback = module->dl_fallback;
258 if (dl_fallback->close_func != NULL)
259 dl_fallback->close_func (module->handle, dl_fallback->user_data);
261 mono_dl_close_handle (module);
267 * mono_dl_build_path:
268 * \param directory optional directory
269 * \param name base name of the library
270 * \param iter iterator token
271 * Given a directory name and the base name of a library, iterate
272 * over the possible file names of the library, taking into account
273 * the possible different suffixes and prefixes on the host platform.
275 * The returned file name must be freed by the caller.
276 * \p iter must point to a NULL pointer the first time the function is called
277 * and then passed unchanged to the following calls.
278 * \returns the filename or NULL at the end of the iteration
281 mono_dl_build_path (const char *directory, const char *name, void **iter)
295 The first time we are called, idx = 0 (as *iter is initialized to NULL). This is our
296 "bootstrap" phase in which we check the passed name verbatim and only if we fail to find
297 the dll thus named, we start appending suffixes, each time increasing idx twice (since now
298 the 0 value became special and we need to offset idx to a 0-based array index). This is
299 done to handle situations when mapped dll name is specified as libsomething.so.1 or
300 libsomething.so.1.1 or libsomething.so - testing it algorithmically would be an overkill
303 idx = GPOINTER_TO_UINT (*iter);
310 if (mono_dl_get_so_suffixes () [idx][0] == '\0')
313 suffix = mono_dl_get_so_suffixes () [idx];
314 suffixlen = strlen (suffix);
317 prlen = strlen (mono_dl_get_so_prefix ());
318 if (prlen && strncmp (name, mono_dl_get_so_prefix (), prlen) != 0)
319 prefix = mono_dl_get_so_prefix ();
323 if (first_call || (suffixlen && strstr (name, suffix) == (name + strlen (name) - suffixlen)))
326 if (directory && *directory)
327 res = g_strconcat (directory, G_DIR_SEPARATOR_S, prefix, name, suffix, NULL);
329 res = g_strconcat (prefix, name, suffix, NULL);
333 *iter = GUINT_TO_POINTER (idx);
337 MonoDlFallbackHandler *
338 mono_dl_fallback_register (MonoDlFallbackLoad load_func, MonoDlFallbackSymbol symbol_func, MonoDlFallbackClose close_func, void *user_data)
340 MonoDlFallbackHandler *handler;
342 g_return_val_if_fail (load_func != NULL, NULL);
343 g_return_val_if_fail (symbol_func != NULL, NULL);
345 handler = g_new (MonoDlFallbackHandler, 1);
346 handler->load_func = load_func;
347 handler->symbol_func = symbol_func;
348 handler->close_func = close_func;
349 handler->user_data = user_data;
351 fallback_handlers = g_slist_prepend (fallback_handlers, handler);
357 mono_dl_fallback_unregister (MonoDlFallbackHandler *handler)
361 found = g_slist_find (fallback_handlers, handler);
365 g_slist_remove (fallback_handlers, handler);
370 try_load (const char *lib_name, char *dir, int flags, char **err)
377 while ((path = mono_dl_build_path (dir, lib_name, &iter))) {
379 runtime_lib = mono_dl_open (path, flags, err);
388 mono_dl_open_runtime_lib (const char* lib_name, int flags, char **error_msg)
390 MonoDl *runtime_lib = NULL;
395 binl = mono_dl_get_executable_path (buf, sizeof (buf));
399 char *resolvedname, *name;
400 char *baseparent = NULL;
402 resolvedname = mono_path_resolve_symlinks (buf);
403 base = g_path_get_dirname (resolvedname);
404 name = g_strdup_printf ("%s/.libs", base);
405 runtime_lib = try_load (lib_name, name, flags, error_msg);
408 baseparent = g_path_get_dirname (base);
410 name = g_strdup_printf ("%s/lib", baseparent);
411 runtime_lib = try_load (lib_name, name, flags, error_msg);
416 name = g_strdup_printf ("%s/Libraries", baseparent);
417 runtime_lib = try_load (lib_name, name, flags, error_msg);
422 name = g_strdup_printf ("%s/profiler/.libs", baseparent);
423 runtime_lib = try_load (lib_name, name, flags, error_msg);
427 g_free (resolvedname);
431 runtime_lib = try_load (lib_name, NULL, flags, error_msg);