]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygwin/dlfcn.cc
Throughout, update copyrights to reflect dates which correspond to main-branch
[newlib-cygwin.git] / winsup / cygwin / dlfcn.cc
CommitLineData
1fd5e000
CF
1/* dlfcn.cc
2
bc837d22
CF
3 Copyright 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
4 2010, 2011 Red Hat, Inc.
1fd5e000
CF
5
6This file is part of Cygwin.
7
8This software is a copyrighted work licensed under the terms of the
9Cygwin license. Please consult the file "CYGWIN_LICENSE" for
10details. */
11
4c8d72de 12#include "winsup.h"
599b41c4 13#include <psapi.h>
1fd5e000 14#include <stdlib.h>
1fd5e000 15#include <ctype.h>
7ac61736 16#include "path.h"
95a8465b 17#include "perprocess.h"
f0338f54 18#include "dlfcn.h"
29d52c8a 19#include "cygtls.h"
0c4cb560 20#include "tls_pbuf.h"
31ddf45d 21#include "ntdll.h"
1fd5e000
CF
22
23static void __stdcall
24set_dl_error (const char *str)
25{
ac5e21b0 26 strcpy (_my_tls.locals.dl_buffer, strerror (get_errno ()));
29d52c8a 27 _my_tls.locals.dl_error = 1;
1fd5e000
CF
28}
29
01e6597b
CF
30/* Look for an executable file given the name and the environment
31 variable to use for searching (eg., PATH); returns the full
32 pathname (static buffer) if found or NULL if not. */
aa73152e
CF
33inline const char * __stdcall
34check_path_access (const char *mywinenv, const char *name, path_conv& buf)
1fd5e000 35{
4b84e3dc 36 return find_exec (name, buf, mywinenv, FE_NNF | FE_NATIVE | FE_CWD | FE_DLL);
1fd5e000
CF
37}
38
e2d88014
CV
39/* Search LD_LIBRARY_PATH for dll, if it exists. Search /usr/bin and /usr/lib
40 by default. Return valid full path in path_conv real_filename. */
41static inline bool
42gfpod_helper (const char *name, path_conv &real_filename)
43{
44 if (isabspath (name))
45 real_filename.check (name, PC_SYM_FOLLOW | PC_NULLEMPTY);
46 else if (!check_path_access ("LD_LIBRARY_PATH=", name, real_filename))
47 check_path_access ("/usr/bin:/usr/lib", name, real_filename);
48 if (!real_filename.exists ())
49 real_filename.error = ENOENT;
50 return !real_filename.error;
51}
52
54155bc3
CV
53static bool __stdcall
54get_full_path_of_dll (const char* str, path_conv &real_filename)
1fd5e000 55{
aa73152e 56 int len = strlen (str);
1fd5e000 57
54155bc3
CV
58 /* empty string? */
59 if (len == 0)
60 {
61 set_errno (EINVAL);
62 return false; /* Yes. Let caller deal with it. */
63 }
1fd5e000 64
54155bc3
CV
65 tmp_pathbuf tp;
66 char *name = tp.c_get ();
1fd5e000 67
aa73152e 68 strcpy (name, str); /* Put it somewhere where we can manipulate it. */
1fd5e000 69
e2d88014
CV
70 char *basename = strrchr (name, '/');
71 basename = basename ? basename + 1 : name;
72 char *suffix = strrchr (name, '.');
73 if (suffix && suffix < basename)
74 suffix = NULL;
75
76 /* Is suffix ".so"? */
77 if (suffix && !strcmp (suffix, ".so"))
78 {
79 /* Does the file exist? */
80 if (gfpod_helper (name, real_filename))
81 return true;
82 /* No, replace ".so" with ".dll". */
83 strcpy (suffix, ".dll");
84 }
85 /* Does the filename start with "lib"? */
86 if (!strncmp (basename, "lib", 3))
87 {
88 /* Yes, replace "lib" with "cyg". */
89 strncpy (basename, "cyg", 3);
90 /* Does the file exist? */
91 if (gfpod_helper (name, real_filename))
92 return true;
93 /* No, revert back to "lib". */
94 strncpy (basename, "lib", 3);
95 }
96 if (gfpod_helper (name, real_filename))
97 return true;
1fd5e000 98
e2d88014
CV
99 /* If nothing worked, create a relative path from the original incoming
100 filename and let LoadLibrary search for it using the system default
101 DLL search path. */
102 real_filename.check (str, PC_SYM_FOLLOW | PC_NOFULL | PC_NULLEMPTY);
aec297d5 103 if (!real_filename.error)
54155bc3 104 return true;
1fd5e000 105
aec297d5 106 set_errno (real_filename.error);
54155bc3 107 return false;
1fd5e000
CF
108}
109
6bc64eac
CV
110extern "C" void *
111dlopen (const char *name, int flags)
1fd5e000 112{
6bc64eac 113 void *ret = NULL;
1fd5e000 114
aa73152e 115 if (name == NULL)
31ddf45d
CV
116 {
117 ret = (void *) GetModuleHandle (NULL); /* handle for the current module */
118 if (!ret)
b86f999a 119 __seterrno ();
31ddf45d 120 }
1fd5e000
CF
121 else
122 {
01e6597b 123 /* handle for the named library */
54155bc3 124 path_conv pc;
6bc64eac 125 if (get_full_path_of_dll (name, pc))
aa73152e 126 {
54155bc3
CV
127 tmp_pathbuf tp;
128 wchar_t *path = tp.w_get ();
129
130 pc.get_wide_win32_path (path);
df958670 131 /* Check if the last path component contains a dot. If so,
6bc64eac 132 leave the filename alone. Otherwise add a trailing dot
df958670
CV
133 to override LoadLibrary's automatic adding of a ".dll" suffix. */
134 wchar_t *last_bs = wcsrchr (path, L'\\');
135 if (last_bs && !wcschr (last_bs, L'.'))
136 wcscat (last_bs, L".");
ce5eb135
CV
137
138 /* Workaround for broken DLLs built against Cygwin versions 1.7.0-49
139 up to 1.7.0-57. They override the cxx_malloc pointer in their
140 DLL initialization code even if loaded dynamically. This is a
141 no-no since a later dlclose lets cxx_malloc point into nirvana.
142 The below kludge "fixes" that by reverting the original cxx_malloc
143 pointer after LoadLibrary. This implies that their overrides
144 won't be applied; that's OK. All overrides should be present at
145 final link time, as Windows doesn't allow undefined references;
146 it would actually be wrong for a dlopen'd DLL to opportunistically
147 override functions in a way that wasn't known then. We're not
148 going to try and reproduce the full ELF dynamic loader here! */
149
150 /* Store original cxx_malloc pointer. */
151 struct per_process_cxx_malloc *tmp_malloc;
152 tmp_malloc = __cygwin_user_data.cxx_malloc;
153
6bc64eac
CV
154 if (!(flags & RTLD_NOLOAD)
155 || (ret = GetModuleHandleW (path)) != NULL)
156 {
157 ret = (void *) LoadLibraryW (path);
158 if (ret && (flags & RTLD_NODELETE)
159 && !GetModuleHandleExW (GET_MODULE_HANDLE_EX_FLAG_PIN, path,
160 (HMODULE *) &ret))
161 {
162 /* Windows 2000 is missing the GetModuleHandleEx call, so we
833db548
CV
163 use a non-documented way to set the DLL to "don't free".
164 This is how it works: Fetch the Windows Loader data from
165 the PEB. Iterate backwards through the list of loaded
166 DLLs and compare the DllBase address with the address
167 returned by LoadLibrary. If they are equal we found the
168 right entry. Now set the LoadCount to -1, which is the
169 marker for a DLL which should never be free'd. */
170 PPEB_LDR_DATA ldr = NtCurrentTeb ()->Peb->Ldr;
171
172 for (PLDR_DATA_TABLE_ENTRY entry = (PLDR_DATA_TABLE_ENTRY)
173 ldr->InLoadOrderModuleList.Blink;
174 entry && entry->DllBase;
175 entry = (PLDR_DATA_TABLE_ENTRY)
176 entry->InLoadOrderLinks.Blink)
177 {
178 if (entry->DllBase == ret)
179 {
180 entry->LoadCount = (WORD) -1;
181 break;
182 }
183 }
6bc64eac
CV
184 }
185 }
ce5eb135
CV
186
187 /* Restore original cxx_malloc pointer. */
188 __cygwin_user_data.cxx_malloc = tmp_malloc;
189
31ddf45d 190 if (!ret)
aa73152e
CF
191 __seterrno ();
192 }
1fd5e000
CF
193 }
194
195 if (!ret)
196 set_dl_error ("dlopen");
197 debug_printf ("ret %p", ret);
198
1fd5e000
CF
199 return ret;
200}
201
6bc64eac 202extern "C" void *
1fd5e000
CF
203dlsym (void *handle, const char *name)
204{
599b41c4 205 void *ret = NULL;
31ddf45d 206
599b41c4
CV
207 if (handle == RTLD_DEFAULT)
208 { /* search all modules */
31ddf45d
CV
209 PDEBUG_BUFFER buf;
210 NTSTATUS status;
211
212 buf = RtlCreateQueryDebugBuffer (0, FALSE);
213 if (!buf)
05726ddd 214 {
31ddf45d 215 set_errno (ENOMEM);
05726ddd
CF
216 set_dl_error ("dlsym");
217 return NULL;
218 }
31ddf45d
CV
219 status = RtlQueryProcessDebugInformation (GetCurrentProcessId (),
220 PDI_MODULES, buf);
221 if (!NT_SUCCESS (status))
222 __seterrno_from_nt_status (status);
223 else
224 {
225 PDEBUG_MODULE_ARRAY mods = (PDEBUG_MODULE_ARRAY)
226 buf->ModuleInformation;
227 for (ULONG i = 0; i < mods->Count; ++i)
228 if ((ret = (void *)
229 GetProcAddress ((HMODULE) mods->Modules[i].Base, name)))
230 break;
231 if (!ret)
232 set_errno (ENOENT);
233 }
234 RtlDestroyQueryDebugBuffer (buf);
599b41c4
CV
235 }
236 else
31ddf45d
CV
237 {
238 ret = (void *) GetProcAddress ((HMODULE) handle, name);
239 if (!ret)
240 __seterrno ();
241 }
1fd5e000
CF
242 if (!ret)
243 set_dl_error ("dlsym");
244 debug_printf ("ret %p", ret);
245 return ret;
246}
247
6bc64eac 248extern "C" int
1fd5e000
CF
249dlclose (void *handle)
250{
d5d5bf4d
CF
251 int ret;
252 if (handle == GetModuleHandle (NULL))
1fd5e000 253 ret = 0;
98a97ac6
CF
254 else if (FreeLibrary ((HMODULE) handle))
255 ret = 0;
d5d5bf4d 256 else
98a97ac6 257 ret = -1;
1fd5e000
CF
258 if (ret)
259 set_dl_error ("dlclose");
1fd5e000
CF
260 return ret;
261}
262
6bc64eac 263extern "C" char *
1fd5e000
CF
264dlerror ()
265{
a5a93a62 266 char *res;
29d52c8a 267 if (!_my_tls.locals.dl_error)
a5a93a62
CF
268 res = NULL;
269 else
270 {
29d52c8a
CF
271 _my_tls.locals.dl_error = 0;
272 res = _my_tls.locals.dl_buffer;
a5a93a62
CF
273 }
274 return res;
1fd5e000 275}
This page took 0.37661 seconds and 5 git commands to generate.