]> git.saurik.com Git - wxWidgets.git/blame - src/unix/dlunix.cpp
Correctly restore the originally used C locale in wxLocale dtor.
[wxWidgets.git] / src / unix / dlunix.cpp
CommitLineData
da55d064 1/////////////////////////////////////////////////////////////////////////////
80fdcdb9 2// Name: src/unix/dlunix.cpp
da55d064
VZ
3// Purpose: Unix-specific part of wxDynamicLibrary and related classes
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 2005-01-16 (extracted from common/dynlib.cpp)
7// RCS-ID: $Id$
8// Copyright: (c) 2000-2005 Vadim Zeitlin <vadim@wxwindows.org>
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
23 #pragma hdrstop
24#endif
25
26#if wxUSE_DYNLIB_CLASS
27
28#include "wx/dynlib.h"
297ebe6b 29#include "wx/ffile.h"
da55d064 30
ac6b7b3c
VZ
31#ifndef WX_PRECOMP
32 #include "wx/intl.h"
33 #include "wx/log.h"
34#endif
35
96b35b25 36#ifdef HAVE_DLOPEN
d8e342b7
DE
37 #include <dlfcn.h>
38#endif
39
96b35b25
DE
40#ifdef __DARWIN__
41 #include <AvailabilityMacros.h>
42#endif
43
bc5f4d98
VZ
44// if some flags are not supported, just ignore them
45#ifndef RTLD_LAZY
46 #define RTLD_LAZY 0
47#endif
48
49#ifndef RTLD_NOW
50 #define RTLD_NOW 0
51#endif
52
53#ifndef RTLD_GLOBAL
bcd1ec33 54 #define RTLD_GLOBAL 0
bc5f4d98
VZ
55#endif
56
57
da55d064
VZ
58#if defined(HAVE_DLOPEN) || defined(__DARWIN__)
59 #define USE_POSIX_DL_FUNCS
60#elif !defined(HAVE_SHL_LOAD)
61 #error "Don't know how to load dynamic libraries on this platform!"
62#endif
63
64// ----------------------------------------------------------------------------
65// constants
66// ----------------------------------------------------------------------------
67
da55d064
VZ
68// ============================================================================
69// wxDynamicLibrary implementation
70// ============================================================================
71
72// ----------------------------------------------------------------------------
73// dlxxx() emulation for Darwin
96b35b25 74// Only useful if the OS X version could be < 10.3 at runtime
da55d064
VZ
75// ----------------------------------------------------------------------------
76
96b35b25 77#if defined(__DARWIN__) && (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3)
da55d064
VZ
78// ---------------------------------------------------------------------------
79// For Darwin/Mac OS X
80// supply the sun style dlopen functions in terms of Darwin NS*
81// ---------------------------------------------------------------------------
82
83/* Porting notes:
84 * The dlopen port is a port from dl_next.xs by Anno Siegel.
85 * dl_next.xs is itself a port from dl_dlopen.xs by Paul Marquess.
86 * The method used here is just to supply the sun style dlopen etc.
87 * functions in terms of Darwin NS*.
88 */
89
90#include <stdio.h>
91#include <mach-o/dyld.h>
92
93static char dl_last_error[1024];
94
96b35b25 95static const char *wx_darwin_dlerror()
da55d064
VZ
96{
97 return dl_last_error;
98}
99
96b35b25 100static void *wx_darwin_dlopen(const char *path, int WXUNUSED(mode) /* mode is ignored */)
da55d064
VZ
101{
102 NSObjectFileImage ofile;
103 NSModule handle = NULL;
104
84ac8772 105 unsigned dyld_result = NSCreateObjectFileImageFromFile(path, &ofile);
da55d064
VZ
106 if ( dyld_result != NSObjectFileImageSuccess )
107 {
108 handle = NULL;
84ac8772 109
a243da29 110 static const char *const errorStrings[] =
84ac8772
VZ
111 {
112 "%d: Object Image Load Failure",
113 "%d: Object Image Load Success",
114 "%d: Not an recognisable object file",
115 "%d: No valid architecture",
116 "%d: Object image has an invalid format",
117 "%d: Invalid access (permissions?)",
118 "%d: Unknown error code from NSCreateObjectFileImageFromFile"
119 };
120
121 const int index = dyld_result < WXSIZEOF(errorStrings)
122 ? dyld_result
123 : WXSIZEOF(errorStrings) - 1;
124
125 // this call to sprintf() is safe as strings above are fixed at
126 // compile-time and are shorter than WXSIZEOF(dl_last_error)
127 sprintf(dl_last_error, errorStrings[index], dyld_result);
da55d064
VZ
128 }
129 else
130 {
131 handle = NSLinkModule
132 (
133 ofile,
134 path,
135 NSLINKMODULE_OPTION_BINDNOW |
136 NSLINKMODULE_OPTION_RETURN_ON_ERROR
137 );
84ac8772
VZ
138
139 if ( !handle )
140 {
141 NSLinkEditErrors err;
142 int code;
143 const char *filename;
144 const char *errmsg;
145
146 NSLinkEditError(&err, &code, &filename, &errmsg);
147 strncpy(dl_last_error, errmsg, WXSIZEOF(dl_last_error)-1);
148 dl_last_error[WXSIZEOF(dl_last_error)-1] = '\0';
149 }
da55d064
VZ
150 }
151
da55d064
VZ
152
153 return handle;
154}
155
96b35b25 156static int wx_darwin_dlclose(void *handle)
da55d064 157{
5b74902d 158 NSUnLinkModule((NSModule)handle, NSUNLINKMODULE_OPTION_NONE);
da55d064
VZ
159 return 0;
160}
161
96b35b25 162static void *wx_darwin_dlsym(void *handle, const char *symbol)
da55d064
VZ
163{
164 // as on many other systems, C symbols have prepended underscores under
165 // Darwin but unlike the normal dlopen(), NSLookupSymbolInModule() is not
166 // aware of this
167 wxCharBuffer buf(strlen(symbol) + 1);
168 char *p = buf.data();
169 p[0] = '_';
170 strcpy(p + 1, symbol);
171
5b74902d 172 NSSymbol nsSymbol = NSLookupSymbolInModule((NSModule)handle, p );
da55d064
VZ
173 return nsSymbol ? NSAddressOfSymbol(nsSymbol) : NULL;
174}
175
96b35b25
DE
176// Add the weak linking attribute to dlopen's declaration
177extern void * dlopen(const char * __path, int __mode) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER;
178
179// For all of these methods we test dlopen since all of the dl functions we use were added
180// to OS X at the same time. This also ensures we don't dlopen with the real function then
181// dlclose with the internal implementation.
182
183static inline void *wx_dlopen(const char *__path, int __mode)
184{
185#ifdef HAVE_DLOPEN
186 if(&dlopen != NULL)
187 return dlopen(__path, __mode);
188 else
189#endif
190 return wx_darwin_dlopen(__path, __mode);
191}
192
193static inline int wx_dlclose(void *__handle)
194{
195#ifdef HAVE_DLOPEN
196 if(&dlopen != NULL)
197 return dlclose(__handle);
198 else
199#endif
200 return wx_darwin_dlclose(__handle);
201}
202
203static inline const char *wx_dlerror()
204{
205#ifdef HAVE_DLOPEN
206 if(&dlopen != NULL)
207 return dlerror();
208 else
209#endif
210 return wx_darwin_dlerror();
211}
212
213static inline void *wx_dlsym(void *__handle, const char *__symbol)
214{
215#ifdef HAVE_DLOPEN
216 if(&dlopen != NULL)
217 return dlsym(__handle, __symbol);
218 else
219#endif
220 return wx_darwin_dlsym(__handle, __symbol);
221}
222
223#else // __DARWIN__/!__DARWIN__
224
225// Use preprocessor definitions for non-Darwin or OS X >= 10.3
226#define wx_dlopen(__path,__mode) dlopen(__path,__mode)
227#define wx_dlclose(__handle) dlclose(__handle)
228#define wx_dlerror() dlerror()
229#define wx_dlsym(__handle,__symbol) dlsym(__handle,__symbol)
230
da55d064
VZ
231#endif // defined(__DARWIN__)
232
233// ----------------------------------------------------------------------------
234// loading/unloading DLLs
235// ----------------------------------------------------------------------------
236
237wxDllType wxDynamicLibrary::GetProgramHandle()
238{
239#ifdef USE_POSIX_DL_FUNCS
96b35b25 240 return wx_dlopen(0, RTLD_LAZY);
da55d064
VZ
241#else
242 return PROG_HANDLE;
243#endif
244}
245
246/* static */
247wxDllType wxDynamicLibrary::RawLoad(const wxString& libname, int flags)
248{
cf72919c 249 wxASSERT_MSG( !(flags & wxDL_NOW) || !(flags & wxDL_LAZY),
9a83f860 250 wxT("wxDL_LAZY and wxDL_NOW are mutually exclusive.") );
da55d064
VZ
251
252#ifdef USE_POSIX_DL_FUNCS
cf72919c
VZ
253 // we need to use either RTLD_NOW or RTLD_LAZY because if we call dlopen()
254 // with flags == 0 recent versions of glibc just fail the call, so use
255 // RTLD_NOW even if wxDL_NOW was not specified
256 int rtldFlags = flags & wxDL_LAZY ? RTLD_LAZY : RTLD_NOW;
da55d064 257
da55d064 258 if ( flags & wxDL_GLOBAL )
da55d064 259 rtldFlags |= RTLD_GLOBAL;
da55d064 260
96b35b25 261 return wx_dlopen(libname.fn_str(), rtldFlags);
da55d064
VZ
262#else // !USE_POSIX_DL_FUNCS
263 int shlFlags = 0;
264
265 if ( flags & wxDL_LAZY )
266 {
267 shlFlags |= BIND_DEFERRED;
268 }
269 else if ( flags & wxDL_NOW )
270 {
271 shlFlags |= BIND_IMMEDIATE;
272 }
273
274 return shl_load(libname.fn_str(), shlFlags, 0);
275#endif // USE_POSIX_DL_FUNCS/!USE_POSIX_DL_FUNCS
276}
277
278/* static */
279void wxDynamicLibrary::Unload(wxDllType handle)
280{
281#ifdef wxHAVE_DYNLIB_ERROR
282 int rc =
283#endif
284
285#ifdef USE_POSIX_DL_FUNCS
96b35b25 286 wx_dlclose(handle);
da55d064
VZ
287#else // !USE_POSIX_DL_FUNCS
288 shl_unload(handle);
289#endif // USE_POSIX_DL_FUNCS/!USE_POSIX_DL_FUNCS
290
d8e342b7 291#if defined(USE_POSIX_DL_FUNCS) && defined(wxHAVE_DYNLIB_ERROR)
da55d064
VZ
292 if ( rc != 0 )
293 Error();
294#endif
295}
296
297/* static */
298void *wxDynamicLibrary::RawGetSymbol(wxDllType handle, const wxString& name)
299{
300 void *symbol;
301
302#ifdef USE_POSIX_DL_FUNCS
96b35b25 303 symbol = wx_dlsym(handle, name.fn_str());
da55d064
VZ
304#else // !USE_POSIX_DL_FUNCS
305 // note that shl_findsym modifies the handle argument to indicate where the
306 // symbol was found, but it's ok to modify the local handle copy here
307 if ( shl_findsym(&handle, name.fn_str(), TYPE_UNDEFINED, &symbol) != 0 )
308 symbol = 0;
309#endif // USE_POSIX_DL_FUNCS/!USE_POSIX_DL_FUNCS
310
311 return symbol;
312}
313
297ebe6b
VZ
314// ----------------------------------------------------------------------------
315// error handling
316// ----------------------------------------------------------------------------
317
da55d064
VZ
318#ifdef wxHAVE_DYNLIB_ERROR
319
320/* static */
321void wxDynamicLibrary::Error()
322{
96b35b25 323 wxString err(wx_dlerror());
c9f78968
VS
324
325 if ( err.empty() )
326 err = _("Unknown dynamic library error");
da55d064 327
c9f78968 328 wxLogError(wxT("%s"), err);
da55d064
VZ
329}
330
331#endif // wxHAVE_DYNLIB_ERROR
332
297ebe6b
VZ
333// ----------------------------------------------------------------------------
334// listing loaded modules
335// ----------------------------------------------------------------------------
336
337// wxDynamicLibraryDetails declares this class as its friend, so put the code
338// initializing new details objects here
339class wxDynamicLibraryDetailsCreator
340{
341public:
342 // create a new wxDynamicLibraryDetails from the given data
343 static wxDynamicLibraryDetails *
ad41e209 344 New(void *start, void *end, const wxString& path)
297ebe6b
VZ
345 {
346 wxDynamicLibraryDetails *details = new wxDynamicLibraryDetails;
347 details->m_path = path;
9a83f860 348 details->m_name = path.AfterLast(wxT('/'));
ad41e209
VZ
349 details->m_address = start;
350 details->m_length = (char *)end - (char *)start;
297ebe6b
VZ
351
352 // try to extract the library version from its name
9a83f860 353 const size_t posExt = path.rfind(wxT(".so"));
297ebe6b
VZ
354 if ( posExt != wxString::npos )
355 {
9a83f860 356 if ( path.c_str()[posExt + 3] == wxT('.') )
297ebe6b
VZ
357 {
358 // assume "libfoo.so.x.y.z" case
359 details->m_version.assign(path, posExt + 4, wxString::npos);
360 }
361 else
362 {
9a83f860 363 size_t posDash = path.find_last_of(wxT('-'), posExt);
297ebe6b
VZ
364 if ( posDash != wxString::npos )
365 {
366 // assume "libbar-x.y.z.so" case
367 posDash++;
368 details->m_version.assign(path, posDash, posExt - posDash);
369 }
370 }
371 }
372
373 return details;
374 }
375};
376
377/* static */
378wxDynamicLibraryDetailsArray wxDynamicLibrary::ListLoaded()
379{
380 wxDynamicLibraryDetailsArray dlls;
381
382#ifdef __LINUX__
383 // examine /proc/self/maps to find out what is loaded in our address space
9a83f860 384 wxFFile file(wxT("/proc/self/maps"));
297ebe6b
VZ
385 if ( file.IsOpened() )
386 {
387 // details of the module currently being parsed
388 wxString pathCur;
ad41e209
VZ
389 void *startCur = NULL,
390 *endCur = NULL;
297ebe6b
VZ
391
392 char path[1024];
393 char buf[1024];
394 while ( fgets(buf, WXSIZEOF(buf), file.fp()) )
395 {
ad41e209
VZ
396 // format is: "start-end perm offset maj:min inode path", see proc(5)
397 void *start,
398 *end;
399 switch ( sscanf(buf, "%p-%p %*4s %*p %*02x:%*02x %*d %1024s\n",
297ebe6b
VZ
400 &start, &end, path) )
401 {
402 case 2:
403 // there may be no path column
404 path[0] = '\0';
405 break;
406
407 case 3:
408 // nothing to do, read everything we wanted
409 break;
410
411 default:
412 // chop '\n'
413 buf[strlen(buf) - 1] = '\0';
9a83f860 414 wxLogDebug(wxT("Failed to parse line \"%s\" in /proc/self/maps."),
297ebe6b
VZ
415 buf);
416 continue;
417 }
418
ad41e209 419 wxASSERT_MSG( start >= endCur,
9a83f860 420 wxT("overlapping regions in /proc/self/maps?") );
ad41e209 421
297ebe6b
VZ
422 wxString pathNew = wxString::FromAscii(path);
423 if ( pathCur.empty() )
424 {
425 // new module start
426 pathCur = pathNew;
427 startCur = start;
428 endCur = end;
429 }
ad41e209 430 else if ( pathCur == pathNew && endCur == end )
297ebe6b 431 {
ad41e209 432 // continuation of the same module in the address space
297ebe6b
VZ
433 endCur = end;
434 }
435 else // end of the current module
436 {
437 dlls.Add(wxDynamicLibraryDetailsCreator::New(startCur,
438 endCur,
439 pathCur));
440 pathCur.clear();
441 }
442 }
443 }
444#endif // __LINUX__
445
446 return dlls;
447}
448
da55d064
VZ
449#endif // wxUSE_DYNLIB_CLASS
450