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.
9 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
12 #include "mono/utils/mono-dl.h"
13 #include "mono/utils/mono-embed.h"
14 #include "mono/utils/mono-path.h"
22 struct MonoDlFallbackHandler
{
23 MonoDlFallbackLoad load_func
;
24 MonoDlFallbackSymbol symbol_func
;
25 MonoDlFallbackClose close_func
;
29 static GSList
*fallback_handlers
;
32 * read a value string from line with any of the following formats:
35 * \s*=\s*non_white_space_string
38 read_string (char *p
, FILE *file
)
42 while (*p
&& isspace (*p
))
48 while (*p
&& isspace (*p
))
50 if (*p
== '\'' || *p
== '"') {
55 /* FIXME: may need to read more from file... */
59 return (char *) g_memdup (startp
, (endp
- startp
) + 1);
64 while (*p
&& !isspace (*p
))
67 return (char *) g_memdup (startp
, (p
- startp
) + 1);
71 * parse a libtool .la file and return the path of the file to dlopen ()
72 * handling both the installed and uninstalled cases
75 get_dl_name_from_libtool (const char *libtool_file
)
79 char *line
, *dlname
= NULL
, *libdir
= NULL
, *installed
= NULL
;
80 if (!(file
= fopen (libtool_file
, "r")))
82 while ((line
= fgets (buf
, 512, file
))) {
83 while (*line
&& isspace (*line
))
85 if (*line
== '#' || *line
== 0)
87 if (strncmp ("dlname", line
, 6) == 0) {
89 dlname
= read_string (line
+ 6, file
);
90 } else if (strncmp ("libdir", line
, 6) == 0) {
92 libdir
= read_string (line
+ 6, file
);
93 } else if (strncmp ("installed", line
, 9) == 0) {
95 installed
= read_string (line
+ 9, file
);
100 if (installed
&& strcmp (installed
, "no") == 0) {
101 char *dir
= g_path_get_dirname (libtool_file
);
103 line
= g_strconcat (dir
, G_DIR_SEPARATOR_S
".libs" G_DIR_SEPARATOR_S
, dlname
, NULL
);
106 if (libdir
&& dlname
)
107 line
= g_strconcat (libdir
, G_DIR_SEPARATOR_S
, dlname
, NULL
);
117 * @name: name of file containing shared module
119 * @error_msg: pointer for error message on failure
121 * Load the given file @name as a shared library or dynamically loadable
122 * module. @name can be NULL to indicate loading the currently executing
124 * @flags can have the MONO_DL_LOCAL bit set to avoid exporting symbols
125 * from the module to the shared namespace. The MONO_DL_LAZY bit can be set
126 * to lazily load the symbols instead of resolving everithing at load time.
127 * @error_msg points to a string where an error message will be stored in
128 * case of failure. The error must be released with g_free.
130 * Returns: a 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
*) 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 * @module: a MonoDl pointer
209 * @symbol: pointer for the result value
211 * Load the address of symbol @name from the given @module.
212 * The address is stored in the pointer pointed to by @symbol.
214 * Returns: NULL on success, an error message on failure
217 mono_dl_symbol (MonoDl
*module
, const char *name
, void **symbol
)
222 if (module
->dl_fallback
) {
223 sym
= module
->dl_fallback
->symbol_func (module
->handle
, name
, &err
, module
->dl_fallback
->user_data
);
225 #if MONO_DL_NEED_USCORE
227 char *usname
= malloc (strlen (name
) + 2);
229 strcpy (usname
+ 1, name
);
230 sym
= mono_dl_lookup_symbol (module
, usname
);
234 sym
= mono_dl_lookup_symbol (module
, name
);
245 return (module
->dl_fallback
!= NULL
) ? err
: mono_dl_current_error_string ();
250 * @module: a MonoDl pointer
252 * Unload the given module and free the module memory.
254 * Returns: 0 on success.
257 mono_dl_close (MonoDl
*module
)
259 MonoDlFallbackHandler
*dl_fallback
= module
->dl_fallback
;
262 if (dl_fallback
->close_func
!= NULL
)
263 dl_fallback
->close_func (module
->handle
, dl_fallback
->user_data
);
265 mono_dl_close_handle (module
);
271 * mono_dl_build_path:
272 * @directory: optional directory
273 * @name: base name of the library
274 * @iter: iterator token
276 * Given a directory name and the base name of a library, iterate
277 * over the possible file names of the library, taking into account
278 * the possible different suffixes and prefixes on the host platform.
280 * The returned file name must be freed by the caller.
281 * @iter must point to a NULL pointer the first time the function is called
282 * and then passed unchanged to the following calls.
283 * Returns: the filename or NULL at the end of the iteration
286 mono_dl_build_path (const char *directory
, const char *name
, void **iter
)
300 The first time we are called, idx = 0 (as *iter is initialized to NULL). This is our
301 "bootstrap" phase in which we check the passed name verbatim and only if we fail to find
302 the dll thus named, we start appending suffixes, each time increasing idx twice (since now
303 the 0 value became special and we need to offset idx to a 0-based array index). This is
304 done to handle situations when mapped dll name is specified as libsomething.so.1 or
305 libsomething.so.1.1 or libsomething.so - testing it algorithmically would be an overkill
308 idx
= GPOINTER_TO_UINT (*iter
);
315 if (mono_dl_get_so_suffixes () [idx
][0] == '\0')
318 suffix
= mono_dl_get_so_suffixes () [idx
];
319 suffixlen
= strlen (suffix
);
322 prlen
= strlen (mono_dl_get_so_prefix ());
323 if (prlen
&& strncmp (name
, mono_dl_get_so_prefix (), prlen
) != 0)
324 prefix
= mono_dl_get_so_prefix ();
328 if (first_call
|| (suffixlen
&& strstr (name
, suffix
) == (name
+ strlen (name
) - suffixlen
)))
331 if (directory
&& *directory
)
332 res
= g_strconcat (directory
, G_DIR_SEPARATOR_S
, prefix
, name
, suffix
, NULL
);
334 res
= g_strconcat (prefix
, name
, suffix
, NULL
);
338 *iter
= GUINT_TO_POINTER (idx
);
342 MonoDlFallbackHandler
*
343 mono_dl_fallback_register (MonoDlFallbackLoad load_func
, MonoDlFallbackSymbol symbol_func
, MonoDlFallbackClose close_func
, void *user_data
)
345 MonoDlFallbackHandler
*handler
;
347 g_return_val_if_fail (load_func
!= NULL
, NULL
);
348 g_return_val_if_fail (symbol_func
!= NULL
, NULL
);
350 handler
= g_new (MonoDlFallbackHandler
, 1);
351 handler
->load_func
= load_func
;
352 handler
->symbol_func
= symbol_func
;
353 handler
->close_func
= close_func
;
354 handler
->user_data
= user_data
;
356 fallback_handlers
= g_slist_prepend (fallback_handlers
, handler
);
362 mono_dl_fallback_unregister (MonoDlFallbackHandler
*handler
)
366 found
= g_slist_find (fallback_handlers
, handler
);
370 g_slist_remove (fallback_handlers
, handler
);
375 try_load (const char *lib_name
, char *dir
, int flags
, char **err
)
382 while ((path
= mono_dl_build_path (dir
, lib_name
, &iter
))) {
384 runtime_lib
= mono_dl_open (path
, flags
, err
);
393 mono_dl_open_runtime_lib (const char* lib_name
, int flags
, char **error_msg
)
395 MonoDl
*runtime_lib
= NULL
;
400 binl
= mono_dl_get_executable_path (buf
, sizeof (buf
));
404 char *resolvedname
, *name
;
405 char *baseparent
= NULL
;
407 resolvedname
= mono_path_resolve_symlinks (buf
);
408 base
= g_path_get_dirname (resolvedname
);
409 name
= g_strdup_printf ("%s/.libs", base
);
410 runtime_lib
= try_load (lib_name
, name
, flags
, error_msg
);
413 baseparent
= g_path_get_dirname (base
);
415 name
= g_strdup_printf ("%s/lib", baseparent
);
416 runtime_lib
= try_load (lib_name
, name
, flags
, error_msg
);
421 name
= g_strdup_printf ("%s/Libraries", baseparent
);
422 runtime_lib
= try_load (lib_name
, name
, flags
, error_msg
);
427 name
= g_strdup_printf ("%s/profiler/.libs", baseparent
);
428 runtime_lib
= try_load (lib_name
, name
, flags
, error_msg
);
432 g_free (resolvedname
);
436 runtime_lib
= try_load (lib_name
, NULL
, flags
, error_msg
);