[eglib] In AIX/generic POSIX, handle null addresses better (#17892)
[mono-project.git] / mono / eglib / gmodule-unix.c
blob24b3a3023b114a7413a41a2c193b92236a0768ae
1 /*
2 * gmodule.c: dl* functions, glib style
4 * Author:
5 * Gonzalo Paniagua Javier (gonzalo@novell.com)
6 * Jonathan Chambers (joncham@gmail.com)
7 * Robert Jordan (robertj@gmx.net)
9 * (C) 2006 Novell, Inc.
10 * (C) 2006 Jonathan Chambers
12 * Permission is hereby granted, free of charge, to any person obtaining
13 * a copy of this software and associated documentation files (the
14 * "Software"), to deal in the Software without restriction, including
15 * without limitation the rights to use, copy, modify, merge, publish,
16 * distribute, sublicense, and/or sell copies of the Software, and to
17 * permit persons to whom the Software is furnished to do so, subject to
18 * the following conditions:
20 * The above copyright notice and this permission notice shall be
21 * included in all copies or substantial portions of the Software.
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 #include <config.h>
33 #include <glib.h>
34 #include <gmodule.h>
36 #if defined(G_OS_UNIX) && defined(HAVE_DLFCN_H)
37 #include <dlfcn.h>
39 /* For Linux and Solaris, need to add others as we port this */
40 #define LIBPREFIX "lib"
41 #define LIBSUFFIX ".so"
43 struct _GModule {
44 void *handle;
47 GModule *
48 g_module_open (const gchar *file, GModuleFlags flags)
50 int f = 0;
51 GModule *module;
52 void *handle;
54 flags &= G_MODULE_BIND_MASK;
55 if ((flags & G_MODULE_BIND_LAZY) != 0)
56 f |= RTLD_LAZY;
57 if ((flags & G_MODULE_BIND_LOCAL) != 0)
58 f |= RTLD_LOCAL;
60 handle = dlopen (file, f);
61 if (handle == NULL)
62 return NULL;
64 module = g_new (GModule,1);
65 module->handle = handle;
67 return module;
70 gboolean
71 g_module_symbol (GModule *module, const gchar *symbol_name, gpointer *symbol)
73 if (symbol_name == NULL || symbol == NULL)
74 return FALSE;
76 if (module == NULL || module->handle == NULL)
77 return FALSE;
79 *symbol = dlsym (module->handle, symbol_name);
80 return (*symbol != NULL);
83 #if defined(HAVE_DLADDR)
84 gboolean
85 g_module_address (void *addr, char *file_name, size_t file_name_len,
86 void **file_base, char *sym_name, size_t sym_name_len,
87 void **sym_addr)
89 Dl_info dli;
90 int ret = dladdr(addr, &dli);
91 /* This zero-on-failure is unlike other Unix APIs. */
92 if (ret == 0)
93 return FALSE;
95 * AIX/Win32 return non-const, so we use caller-allocated bufs instead
97 if (file_name != NULL && file_name_len >= 1) {
98 if (dli.dli_fname)
99 g_strlcpy(file_name, dli.dli_fname, file_name_len);
100 else
101 file_name [0] = '\0';
103 if (file_base != NULL)
104 *file_base = dli.dli_fbase;
105 if (sym_name != NULL && sym_name_len >= 1) {
106 if (dli.dli_sname)
107 g_strlcpy (sym_name, dli.dli_sname, sym_name_len);
108 else
109 sym_name [0] = '\0';
111 if (sym_addr != NULL)
112 *sym_addr = dli.dli_saddr;
113 return TRUE;
115 #elif !defined(_AIX)
116 /* AIX has its own implementation that is long enough to be its own file. */
117 gboolean
118 g_module_address (void *addr, char *file_name, size_t file_name_len,
119 void **file_base, char *sym_name, size_t sym_name_len,
120 void **sym_addr)
122 return FALSE;
124 #endif
126 const gchar *
127 g_module_error (void)
129 return dlerror ();
132 gboolean
133 g_module_close (GModule *module)
135 void *handle;
136 if (module == NULL || module->handle == NULL)
137 return FALSE;
139 handle = module->handle;
140 module->handle = NULL;
141 g_free (module);
142 return (0 == dlclose (handle));
145 #elif defined (G_OS_WIN32)
146 #ifndef PSAPI_VERSION
147 #define PSAPI_VERSION 2 // Use the Windows 7 or newer version more directly.
148 #endif
149 #include <windows.h>
150 #include <psapi.h>
152 #define LIBSUFFIX ".dll"
153 #define LIBPREFIX ""
155 struct _GModule {
156 HMODULE handle;
157 int main_module;
160 GModule *
161 g_module_open (const gchar *file, GModuleFlags flags)
163 GModule *module;
164 module = g_malloc (sizeof (GModule));
165 if (module == NULL)
166 return NULL;
168 if (file != NULL) {
169 gunichar2 *file16;
170 file16 = u8to16(file);
171 module->main_module = FALSE;
172 module->handle = LoadLibrary (file16);
173 g_free(file16);
174 if (!module->handle) {
175 g_free (module);
176 return NULL;
179 } else {
180 module->main_module = TRUE;
181 module->handle = GetModuleHandle (NULL);
184 return module;
187 static gpointer
188 w32_find_symbol (const gchar *symbol_name)
190 HMODULE *modules;
191 DWORD buffer_size = sizeof (HMODULE) * 1024;
192 DWORD needed, i;
194 modules = (HMODULE *) g_malloc (buffer_size);
196 if (modules == NULL)
197 return NULL;
199 if (!EnumProcessModules (GetCurrentProcess (), modules,
200 buffer_size, &needed)) {
201 g_free (modules);
202 return NULL;
205 /* check whether the supplied buffer was too small, realloc, retry */
206 if (needed > buffer_size) {
207 g_free (modules);
209 buffer_size = needed;
210 modules = (HMODULE *) g_malloc (buffer_size);
212 if (modules == NULL)
213 return NULL;
215 if (!EnumProcessModules (GetCurrentProcess (), modules,
216 buffer_size, &needed)) {
217 g_free (modules);
218 return NULL;
222 for (i = 0; i < needed / sizeof (HANDLE); i++) {
223 gpointer proc = (gpointer)(intptr_t)GetProcAddress (modules [i], symbol_name);
224 if (proc != NULL) {
225 g_free (modules);
226 return proc;
230 g_free (modules);
231 return NULL;
234 gboolean
235 g_module_symbol (GModule *module, const gchar *symbol_name, gpointer *symbol)
237 if (module == NULL || symbol_name == NULL || symbol == NULL)
238 return FALSE;
240 if (module->main_module) {
241 *symbol = (gpointer)(intptr_t)GetProcAddress (module->handle, symbol_name);
242 if (*symbol != NULL)
243 return TRUE;
245 *symbol = w32_find_symbol (symbol_name);
246 return *symbol != NULL;
247 } else {
248 *symbol = (gpointer)(intptr_t)GetProcAddress (module->handle, symbol_name);
249 return *symbol != NULL;
253 const gchar *
254 g_module_error (void)
256 gchar* ret = NULL;
257 TCHAR* buf = NULL;
258 DWORD code = GetLastError ();
260 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL,
261 code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 0, NULL);
263 ret = u16to8 (buf);
264 LocalFree(buf);
266 return ret;
269 gboolean
270 g_module_close (GModule *module)
272 HMODULE handle;
273 int main_module;
275 if (module == NULL || module->handle == NULL)
276 return FALSE;
278 handle = module->handle;
279 main_module = module->main_module;
280 module->handle = NULL;
281 g_free (module);
282 return (main_module ? 1 : (0 == FreeLibrary (handle)));
285 #else
287 #define LIBSUFFIX ""
288 #define LIBPREFIX ""
290 GModule *
291 g_module_open (const gchar *file, GModuleFlags flags)
293 g_error ("%s", "g_module_open not implemented on this platform");
294 return NULL;
297 gboolean
298 g_module_symbol (GModule *module, const gchar *symbol_name, gpointer *symbol)
300 g_error ("%s", "g_module_open not implemented on this platform");
301 return FALSE;
304 const gchar *
305 g_module_error (void)
307 g_error ("%s", "g_module_open not implemented on this platform");
308 return NULL;
311 gboolean
312 g_module_close (GModule *module)
314 g_error ("%s", "g_module_open not implemented on this platform");
315 return FALSE;
317 #endif
319 gchar *
320 g_module_build_path (const gchar *directory, const gchar *module_name)
322 const char *lib_prefix = "";
324 if (module_name == NULL)
325 return NULL;
327 if (strncmp (module_name, "lib", 3) != 0)
328 lib_prefix = LIBPREFIX;
330 if (directory && *directory)
331 return g_strdup_printf ("%s/%s%s" LIBSUFFIX, directory, lib_prefix, module_name);
332 return g_strdup_printf ("%s%s" LIBSUFFIX, lib_prefix, module_name);