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-compiler.h"
14 #include "mono/utils/mono-dl.h"
15 #include "mono/utils/mono-embed.h"
16 #include "mono/utils/mono-path.h"
17 #include "mono/utils/mono-threads-api.h"
25 struct MonoDlFallbackHandler
{
26 MonoDlFallbackLoad load_func
;
27 MonoDlFallbackSymbol symbol_func
;
28 MonoDlFallbackClose close_func
;
32 static GSList
*fallback_handlers
;
35 * read a value string from line with any of the following formats:
38 * \s*=\s*non_white_space_string
41 read_string (char *p
, FILE *file
)
45 while (*p
&& isspace (*p
))
51 while (*p
&& isspace (*p
))
53 if (*p
== '\'' || *p
== '"') {
58 /* FIXME: may need to read more from file... */
62 return (char *) g_memdup (startp
, (endp
- startp
) + 1);
67 while (*p
&& !isspace (*p
))
70 return (char *) g_memdup (startp
, (p
- startp
) + 1);
74 * parse a libtool .la file and return the path of the file to dlopen ()
75 * handling both the installed and uninstalled cases
78 get_dl_name_from_libtool (const char *libtool_file
)
82 char *line
, *dlname
= NULL
, *libdir
= NULL
, *installed
= NULL
;
83 if (!(file
= fopen (libtool_file
, "r")))
85 while ((line
= fgets (buf
, 512, file
))) {
86 while (*line
&& isspace (*line
))
88 if (*line
== '#' || *line
== 0)
90 if (strncmp ("dlname", line
, 6) == 0) {
92 dlname
= read_string (line
+ 6, file
);
93 } else if (strncmp ("libdir", line
, 6) == 0) {
95 libdir
= read_string (line
+ 6, file
);
96 } else if (strncmp ("installed", line
, 9) == 0) {
98 installed
= read_string (line
+ 9, file
);
103 if (installed
&& strcmp (installed
, "no") == 0) {
104 char *dir
= g_path_get_dirname (libtool_file
);
106 line
= g_strconcat (dir
, G_DIR_SEPARATOR_S
".libs" G_DIR_SEPARATOR_S
, dlname
, NULL
);
109 if (libdir
&& dlname
)
110 line
= g_strconcat (libdir
, G_DIR_SEPARATOR_S
, dlname
, NULL
);
120 * \param name name of file containing shared module
122 * \param error_msg pointer for error message on failure
124 * Load the given file \p name as a shared library or dynamically loadable
125 * module. \p name can be NULL to indicate loading the currently executing
127 * \p flags can have the \c MONO_DL_LOCAL bit set to avoid exporting symbols
128 * from the module to the shared namespace. The \c MONO_DL_LAZY bit can be set
129 * to lazily load the symbols instead of resolving everithing at load time.
130 * \p error_msg points to a string where an error message will be stored in
131 * case of failure. The error must be released with \c g_free.
132 * \returns a \c MonoDl pointer on success, NULL on failure.
135 mono_dl_open (const char *name
, int flags
, char **error_msg
)
139 MonoDlFallbackHandler
*dl_fallback
= NULL
;
140 int lflags
= mono_dl_convert_flags (flags
);
145 module
= (MonoDl
*) g_malloc (sizeof (MonoDl
));
148 *error_msg
= g_strdup ("Out of memory");
151 module
->main_module
= name
== NULL
? TRUE
: FALSE
;
153 lib
= mono_dl_open_file (name
, lflags
);
157 for (node
= fallback_handlers
; node
!= NULL
; node
= node
->next
){
158 MonoDlFallbackHandler
*handler
= (MonoDlFallbackHandler
*) node
->data
;
162 lib
= handler
->load_func (name
, lflags
, error_msg
, handler
->user_data
);
163 if (error_msg
&& *error_msg
!= NULL
)
167 dl_fallback
= handler
;
172 if (!lib
&& !dl_fallback
) {
177 /* This platform does not support dlopen */
184 ext
= strrchr (name
, '.');
185 if (ext
&& strcmp (ext
, ".la") == 0)
187 lname
= g_strconcat (name
, suff
, NULL
);
188 llname
= get_dl_name_from_libtool (lname
);
191 lib
= mono_dl_open_file (llname
, lflags
);
196 *error_msg
= mono_dl_current_error_string ();
202 module
->handle
= lib
;
203 module
->dl_fallback
= dl_fallback
;
209 * \param module a MonoDl pointer
210 * \param name symbol name
211 * \param symbol pointer for the result value
212 * Load the address of symbol \p name from the given \p module.
213 * The address is stored in the pointer pointed to by \p 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
= g_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 * \param module a \c MonoDl pointer
251 * Unload the given module and free the module memory.
252 * \returns \c 0 on success.
255 mono_dl_close (MonoDl
*module
)
257 MonoDlFallbackHandler
*dl_fallback
= module
->dl_fallback
;
260 if (dl_fallback
->close_func
!= NULL
)
261 dl_fallback
->close_func (module
->handle
, dl_fallback
->user_data
);
263 mono_dl_close_handle (module
);
269 * mono_dl_build_path:
270 * \param directory optional directory
271 * \param name base name of the library
272 * \param iter iterator token
273 * Given a directory name and the base name of a library, iterate
274 * over the possible file names of the library, taking into account
275 * the possible different suffixes and prefixes on the host platform.
277 * The returned file name must be freed by the caller.
278 * \p iter must point to a NULL pointer the first time the function is called
279 * and then passed unchanged to the following calls.
280 * \returns the filename or NULL at the end of the iteration
283 mono_dl_build_path (const char *directory
, const char *name
, void **iter
)
288 gboolean need_prefix
= TRUE
, need_suffix
= TRUE
;
298 The first time we are called, idx = 0 (as *iter is initialized to NULL). This is our
299 "bootstrap" phase in which we check the passed name verbatim and only if we fail to find
300 the dll thus named, we start appending suffixes, each time increasing idx twice (since now
301 the 0 value became special and we need to offset idx to a 0-based array index). This is
302 done to handle situations when mapped dll name is specified as libsomething.so.1 or
303 libsomething.so.1.1 or libsomething.so - testing it algorithmically would be an overkill
306 iteration
= GPOINTER_TO_UINT (*iter
);
313 } else if (idx
== 1) {
314 #ifdef ENABLE_NETCORE
315 /* netcore system libs have a suffix but no prefix */
318 suffix
= mono_dl_get_so_suffixes () [0];
319 suffixlen
= strlen (suffix
);
321 suffix
= mono_dl_get_so_suffixes () [idx
- 1];
322 if (suffix
[0] == '\0')
326 /* Prefix.Name.suffix */
327 suffix
= mono_dl_get_so_suffixes () [idx
- 2];
328 if (suffix
[0] == '\0')
333 prlen
= strlen (mono_dl_get_so_prefix ());
334 if (prlen
&& strncmp (name
, mono_dl_get_so_prefix (), prlen
) != 0)
335 prefix
= mono_dl_get_so_prefix ();
342 suffixlen
= strlen (suffix
);
343 if (need_suffix
&& (suffixlen
&& strstr (name
, suffix
) == (name
+ strlen (name
) - suffixlen
)))
346 if (directory
&& *directory
)
347 res
= g_strconcat (directory
, G_DIR_SEPARATOR_S
, prefix
, name
, suffix
, NULL
);
349 res
= g_strconcat (prefix
, name
, suffix
, NULL
);
351 *iter
= GUINT_TO_POINTER (iteration
);
355 MonoDlFallbackHandler
*
356 mono_dl_fallback_register (MonoDlFallbackLoad load_func
, MonoDlFallbackSymbol symbol_func
, MonoDlFallbackClose close_func
, void *user_data
)
358 MonoDlFallbackHandler
*handler
= NULL
;
359 if (load_func
== NULL
|| symbol_func
== NULL
)
362 handler
= g_new (MonoDlFallbackHandler
, 1);
363 handler
->load_func
= load_func
;
364 handler
->symbol_func
= symbol_func
;
365 handler
->close_func
= close_func
;
366 handler
->user_data
= user_data
;
368 fallback_handlers
= g_slist_prepend (fallback_handlers
, handler
);
375 mono_dl_fallback_unregister (MonoDlFallbackHandler
*handler
)
379 found
= g_slist_find (fallback_handlers
, handler
);
383 g_slist_remove (fallback_handlers
, handler
);
388 try_load (const char *lib_name
, char *dir
, int flags
, char **err
)
395 while ((path
= mono_dl_build_path (dir
, lib_name
, &iter
))) {
397 runtime_lib
= mono_dl_open (path
, flags
, err
);
406 mono_dl_open_runtime_lib (const char* lib_name
, int flags
, char **error_msg
)
408 MonoDl
*runtime_lib
= NULL
;
413 binl
= mono_dl_get_executable_path (buf
, sizeof (buf
));
417 char *resolvedname
, *name
;
418 char *baseparent
= NULL
;
420 resolvedname
= mono_path_resolve_symlinks (buf
);
421 base
= g_path_get_dirname (resolvedname
);
422 name
= g_strdup_printf ("%s/.libs", base
);
423 runtime_lib
= try_load (lib_name
, name
, flags
, error_msg
);
426 baseparent
= g_path_get_dirname (base
);
428 name
= g_strdup_printf ("%s/lib", baseparent
);
429 runtime_lib
= try_load (lib_name
, name
, flags
, error_msg
);
434 name
= g_strdup_printf ("%s/Libraries", baseparent
);
435 runtime_lib
= try_load (lib_name
, name
, flags
, error_msg
);
440 name
= g_strdup_printf ("%s/profiler/.libs", baseparent
);
441 runtime_lib
= try_load (lib_name
, name
, flags
, error_msg
);
445 g_free (resolvedname
);
449 runtime_lib
= try_load (lib_name
, NULL
, flags
, error_msg
);