2 #include "mono/utils/mono-dl.h"
12 static const char suffixes [][5] = {
15 #elif defined(__APPLE__)
16 #define SOPREFIX "lib"
17 static const char suffixes [][8] = {
23 #define SOPREFIX "lib"
24 static const char suffixes [][4] = {
34 #define SO_HANDLE_TYPE HMODULE
35 #define LL_SO_OPEN(file,flags) w32_load_module ((file), (flags))
36 #define LL_SO_CLOSE(module) do { if (!(module)->main_module) FreeLibrary ((module)->handle); } while (0)
37 #define LL_SO_SYMBOL(module, name) w32_find_symbol ((module), (name))
38 #define LL_SO_TRFLAGS(flags) 0
39 #define LL_SO_ERROR() w32_dlerror ()
41 #elif defined (HAVE_DL_LOADER)
47 #endif /* RTLD_LAZY */
49 #define SO_HANDLE_TYPE void*
50 #define LL_SO_OPEN(file,flags) dlopen ((file), (flags))
51 #define LL_SO_CLOSE(module) dlclose ((module)->handle)
52 #define LL_SO_SYMBOL(module, name) dlsym ((module)->handle, (name))
53 #define LL_SO_TRFLAGS(flags) convert_flags ((flags))
54 #define LL_SO_ERROR() g_strdup (dlerror ())
57 convert_flags (int flags)
59 int lflags = flags & MONO_DL_LOCAL? 0: RTLD_GLOBAL;
61 if (flags & MONO_DL_LAZY)
69 /* no dynamic loader supported */
70 #define SO_HANDLE_TYPE void*
71 #define LL_SO_OPEN(file,flags) NULL
72 #define LL_SO_CLOSE(module)
73 #define LL_SO_SYMBOL(module, name) NULL
74 #define LL_SO_TRFLAGS(flags) (flags)
75 #define LL_SO_ERROR() g_strdup ("No support for dynamic loader")
80 SO_HANDLE_TYPE handle;
91 DWORD code = GetLastError ();
93 if (FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL,
94 code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 0, NULL))
96 ret = g_utf16_to_utf8 (buf, wcslen(buf), NULL, NULL, NULL);
103 w32_find_symbol (MonoDl *module, const gchar *symbol_name)
106 DWORD buffer_size = sizeof (HMODULE) * 1024;
108 gpointer proc = NULL;
110 /* get the symbol directly from the specified module */
111 if (!module->main_module)
112 return GetProcAddress (module->handle, symbol_name);
114 /* get the symbol from the main module */
115 proc = GetProcAddress (module->handle, symbol_name);
119 /* get the symbol from the loaded DLLs */
120 modules = (HMODULE *) g_malloc (buffer_size);
124 if (!EnumProcessModules (GetCurrentProcess (), modules,
125 buffer_size, &needed)) {
130 /* check whether the supplied buffer was too small, realloc, retry */
131 if (needed > buffer_size) {
134 buffer_size = needed;
135 modules = (HMODULE *) g_malloc (buffer_size);
140 if (!EnumProcessModules (GetCurrentProcess (), modules,
141 buffer_size, &needed)) {
147 for (i = 0; i < needed / sizeof (HANDLE); i++) {
148 proc = GetProcAddress (modules [i], symbol_name);
161 w32_load_module (const char* file, int flags)
163 gpointer hModule = NULL;
166 gunichar2* file_utf16 = g_utf8_to_utf16 (file, strlen (file), NULL, NULL, NULL);
167 hModule = LoadLibrary (file_utf16);
172 hModule = GetModuleHandle (NULL);
179 * read a value string from line with any of the following formats:
182 * \s*=\s*non_white_space_string
185 read_string (char *p, FILE *file)
189 while (*p && isspace (*p))
195 while (*p && isspace (*p))
197 if (*p == '\'' || *p == '"') {
201 endp = strchr (p, t);
202 /* FIXME: may need to read more from file... */
206 return g_memdup (startp, (endp - startp) + 1);
211 while (*p && !isspace (*p))
214 return g_memdup (startp, (p - startp) + 1);
218 * parse a libtool .la file and return the path of the file to dlopen ()
219 * handling both the installed and uninstalled cases
222 get_dl_name_from_libtool (const char *libtool_file)
226 char *line, *dlname = NULL, *libdir = NULL, *installed = NULL;
227 if (!(file = fopen (libtool_file, "r")))
229 while ((line = fgets (buf, 512, file))) {
230 while (*line && isspace (*line))
232 if (*line == '#' || *line == 0)
234 if (strncmp ("dlname", line, 6) == 0) {
236 dlname = read_string (line + 6, file);
237 } else if (strncmp ("libdir", line, 6) == 0) {
239 libdir = read_string (line + 6, file);
240 } else if (strncmp ("installed", line, 9) == 0) {
242 installed = read_string (line + 9, file);
247 if (installed && strcmp (installed, "no") == 0) {
248 char *dir = g_path_get_dirname (libtool_file);
250 line = g_strconcat (dir, G_DIR_SEPARATOR_S ".libs" G_DIR_SEPARATOR_S, dlname, NULL);
253 if (libdir && dlname)
254 line = g_strconcat (libdir, G_DIR_SEPARATOR_S, dlname, NULL);
264 * @name: name of file containing shared module
266 * @error_msg: pointer for error message on failure
268 * Load the given file @name as a shared library or dynamically loadable
269 * module. @name can be NULL to indicate loading the currently executing
271 * @flags can have the MONO_DL_LOCAL bit set to avoid exporting symbols
272 * from the module to the shared namespace. The MONO_DL_LAZY bit can be set
273 * to lazily load the symbols instead of resolving everithing at load time.
274 * @error_msg points to a string where an error message will be stored in
277 * Returns: a MonoDl pointer on success, NULL on failure.
280 mono_dl_open (const char *name, int flags, char **error_msg)
284 int lflags = LL_SO_TRFLAGS (flags);
289 module = malloc (sizeof (MonoDl));
292 *error_msg = g_strdup ("Out of memory");
295 module->main_module = name == NULL? TRUE: FALSE;
296 lib = LL_SO_OPEN (name, lflags);
300 const char *suff = ".la";
301 const char *ext = strrchr (name, '.');
302 if (ext && strcmp (ext, ".la") == 0)
304 lname = g_strconcat (name, suff, NULL);
305 llname = get_dl_name_from_libtool (lname);
308 lib = LL_SO_OPEN (llname, lflags);
313 *error_msg = LL_SO_ERROR ();
319 module->handle = lib;
325 * @module: a MonoDl pointer
327 * @symbol: pointer for the result value
329 * Load the address of symbol @name from the given @module.
330 * The address is stored in the pointer pointed to by @symbol.
332 * Returns: NULL on success, an error message on failure
335 mono_dl_symbol (MonoDl *module, const char *name, void **symbol)
339 #if MONO_DL_NEED_USCORE
341 char *usname = malloc (strlen (name) + 2);
343 strcpy (usname + 1, name);
344 sym = LL_SO_SYMBOL (module, usname);
348 sym = LL_SO_SYMBOL (module, name);
357 return LL_SO_ERROR ();
362 * @module: a MonoDl pointer
364 * Unload the given module and free the module memory.
366 * Returns: 0 on success.
369 mono_dl_close (MonoDl *module)
371 LL_SO_CLOSE (module);
376 * mono_dl_build_path:
377 * @directory: optional directory
378 * @name: base name of the library
379 * @iter: iterator token
381 * Given a directory name and the base name of a library, iterate
382 * over the possible file names of the library, taking into account
383 * the possible different suffixes and prefixes on the host platform.
385 * The returned file name must be freed by the caller.
386 * @iter must point to a NULL pointer the first time the function is called
387 * and then passed unchanged to the following calls.
388 * Returns: the filename or NULL at the end of the iteration
391 mono_dl_build_path (const char *directory, const char *name, void **iter)
400 idx = GPOINTER_TO_UINT (*iter);
401 if (idx >= G_N_ELEMENTS (suffixes))
404 prlen = strlen (SOPREFIX);
405 if (prlen && strncmp (name, SOPREFIX, prlen) != 0)
409 /* if the platform prefix is already provided, we suppose the caller knows the full name already */
410 if (prlen && strncmp (name, SOPREFIX, prlen) == 0)
413 suffix = suffixes [idx];
414 if (directory && *directory)
415 res = g_strconcat (directory, G_DIR_SEPARATOR_S, prefix, name, suffixes [idx], NULL);
417 res = g_strconcat (prefix, name, suffixes [idx], NULL);
419 *iter = GUINT_TO_POINTER (idx);