1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/unix/dlunix.cpp
3 // Purpose: Unix-specific part of wxDynamicLibrary and related classes
4 // Author: Vadim Zeitlin
6 // Created: 2005-01-16 (extracted from common/dynlib.cpp)
8 // Copyright: (c) 2000-2005 Vadim Zeitlin <vadim@wxwindows.org>
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #include "wx/wxprec.h"
26 #if wxUSE_DYNLIB_CLASS
28 #include "wx/dynlib.h"
41 #include <AvailabilityMacros.h>
44 // if some flags are not supported, just ignore them
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!"
64 // ----------------------------------------------------------------------------
66 // ----------------------------------------------------------------------------
68 // ============================================================================
69 // wxDynamicLibrary implementation
70 // ============================================================================
72 // ----------------------------------------------------------------------------
73 // dlxxx() emulation for Darwin
74 // Only useful if the OS X version could be < 10.3 at runtime
75 // ----------------------------------------------------------------------------
77 #if defined(__DARWIN__) && (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3)
78 // ---------------------------------------------------------------------------
79 // For Darwin/Mac OS X
80 // supply the sun style dlopen functions in terms of Darwin NS*
81 // ---------------------------------------------------------------------------
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*.
91 #include <mach-o/dyld.h>
93 static char dl_last_error
[1024];
95 static const char *wx_darwin_dlerror()
100 static void *wx_darwin_dlopen(const char *path
, int WXUNUSED(mode
) /* mode is ignored */)
102 NSObjectFileImage ofile
;
103 NSModule handle
= NULL
;
105 unsigned dyld_result
= NSCreateObjectFileImageFromFile(path
, &ofile
);
106 if ( dyld_result
!= NSObjectFileImageSuccess
)
110 static const char *const errorStrings
[] =
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"
121 const int index
= dyld_result
< WXSIZEOF(errorStrings
)
123 : WXSIZEOF(errorStrings
) - 1;
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
);
131 handle
= NSLinkModule
135 NSLINKMODULE_OPTION_BINDNOW
|
136 NSLINKMODULE_OPTION_RETURN_ON_ERROR
141 NSLinkEditErrors err
;
143 const char *filename
;
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';
156 static int wx_darwin_dlclose(void *handle
)
158 NSUnLinkModule((NSModule
)handle
, NSUNLINKMODULE_OPTION_NONE
);
162 static void *wx_darwin_dlsym(void *handle
, const char *symbol
)
164 // as on many other systems, C symbols have prepended underscores under
165 // Darwin but unlike the normal dlopen(), NSLookupSymbolInModule() is not
167 wxCharBuffer
buf(strlen(symbol
) + 1);
168 char *p
= buf
.data();
170 strcpy(p
+ 1, symbol
);
172 NSSymbol nsSymbol
= NSLookupSymbolInModule((NSModule
)handle
, p
);
173 return nsSymbol
? NSAddressOfSymbol(nsSymbol
) : NULL
;
176 // Add the weak linking attribute to dlopen's declaration
177 extern void * dlopen(const char * __path
, int __mode
) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
;
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.
183 static inline void *wx_dlopen(const char *__path
, int __mode
)
187 return dlopen(__path
, __mode
);
190 return wx_darwin_dlopen(__path
, __mode
);
193 static inline int wx_dlclose(void *__handle
)
197 return dlclose(__handle
);
200 return wx_darwin_dlclose(__handle
);
203 static inline const char *wx_dlerror()
210 return wx_darwin_dlerror();
213 static inline void *wx_dlsym(void *__handle
, const char *__symbol
)
217 return dlsym(__handle
, __symbol
);
220 return wx_darwin_dlsym(__handle
, __symbol
);
223 #else // __DARWIN__/!__DARWIN__
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)
231 #endif // defined(__DARWIN__)
233 // ----------------------------------------------------------------------------
234 // loading/unloading DLLs
235 // ----------------------------------------------------------------------------
237 wxDllType
wxDynamicLibrary::GetProgramHandle()
239 #ifdef USE_POSIX_DL_FUNCS
240 return wx_dlopen(0, RTLD_LAZY
);
247 wxDllType
wxDynamicLibrary::RawLoad(const wxString
& libname
, int flags
)
249 wxASSERT_MSG( !(flags
& wxDL_NOW
) || !(flags
& wxDL_LAZY
),
250 wxT("wxDL_LAZY and wxDL_NOW are mutually exclusive.") );
252 #ifdef USE_POSIX_DL_FUNCS
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
;
258 if ( flags
& wxDL_GLOBAL
)
259 rtldFlags
|= RTLD_GLOBAL
;
261 return wx_dlopen(libname
.fn_str(), rtldFlags
);
262 #else // !USE_POSIX_DL_FUNCS
265 if ( flags
& wxDL_LAZY
)
267 shlFlags
|= BIND_DEFERRED
;
269 else if ( flags
& wxDL_NOW
)
271 shlFlags
|= BIND_IMMEDIATE
;
274 return shl_load(libname
.fn_str(), shlFlags
, 0);
275 #endif // USE_POSIX_DL_FUNCS/!USE_POSIX_DL_FUNCS
279 void wxDynamicLibrary::Unload(wxDllType handle
)
281 #ifdef wxHAVE_DYNLIB_ERROR
285 #ifdef USE_POSIX_DL_FUNCS
287 #else // !USE_POSIX_DL_FUNCS
289 #endif // USE_POSIX_DL_FUNCS/!USE_POSIX_DL_FUNCS
291 #if defined(USE_POSIX_DL_FUNCS) && defined(wxHAVE_DYNLIB_ERROR)
298 void *wxDynamicLibrary::RawGetSymbol(wxDllType handle
, const wxString
& name
)
302 #ifdef USE_POSIX_DL_FUNCS
303 symbol
= wx_dlsym(handle
, name
.fn_str());
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 )
309 #endif // USE_POSIX_DL_FUNCS/!USE_POSIX_DL_FUNCS
314 // ----------------------------------------------------------------------------
316 // ----------------------------------------------------------------------------
318 #ifdef wxHAVE_DYNLIB_ERROR
321 void wxDynamicLibrary::Error()
323 wxString
err(wx_dlerror());
326 err
= _("Unknown dynamic library error");
328 wxLogError(wxT("%s"), err
);
331 #endif // wxHAVE_DYNLIB_ERROR
333 // ----------------------------------------------------------------------------
334 // listing loaded modules
335 // ----------------------------------------------------------------------------
337 // wxDynamicLibraryDetails declares this class as its friend, so put the code
338 // initializing new details objects here
339 class wxDynamicLibraryDetailsCreator
342 // create a new wxDynamicLibraryDetails from the given data
343 static wxDynamicLibraryDetails
*
344 New(void *start
, void *end
, const wxString
& path
)
346 wxDynamicLibraryDetails
*details
= new wxDynamicLibraryDetails
;
347 details
->m_path
= path
;
348 details
->m_name
= path
.AfterLast(wxT('/'));
349 details
->m_address
= start
;
350 details
->m_length
= (char *)end
- (char *)start
;
352 // try to extract the library version from its name
353 const size_t posExt
= path
.rfind(wxT(".so"));
354 if ( posExt
!= wxString::npos
)
356 if ( path
.c_str()[posExt
+ 3] == wxT('.') )
358 // assume "libfoo.so.x.y.z" case
359 details
->m_version
.assign(path
, posExt
+ 4, wxString::npos
);
363 size_t posDash
= path
.find_last_of(wxT('-'), posExt
);
364 if ( posDash
!= wxString::npos
)
366 // assume "libbar-x.y.z.so" case
368 details
->m_version
.assign(path
, posDash
, posExt
- posDash
);
378 wxDynamicLibraryDetailsArray
wxDynamicLibrary::ListLoaded()
380 wxDynamicLibraryDetailsArray dlls
;
383 // examine /proc/self/maps to find out what is loaded in our address space
384 wxFFile
file(wxT("/proc/self/maps"));
385 if ( file
.IsOpened() )
387 // details of the module currently being parsed
389 void *startCur
= NULL
,
394 while ( fgets(buf
, WXSIZEOF(buf
), file
.fp()) )
396 // format is: "start-end perm offset maj:min inode path", see proc(5)
399 switch ( sscanf(buf
, "%p-%p %*4s %*p %*02x:%*02x %*d %1024s\n",
400 &start
, &end
, path
) )
403 // there may be no path column
408 // nothing to do, read everything we wanted
413 buf
[strlen(buf
) - 1] = '\0';
414 wxLogDebug(wxT("Failed to parse line \"%s\" in /proc/self/maps."),
419 wxASSERT_MSG( start
>= endCur
,
420 wxT("overlapping regions in /proc/self/maps?") );
422 wxString pathNew
= wxString::FromAscii(path
);
423 if ( pathCur
.empty() )
430 else if ( pathCur
== pathNew
&& endCur
== end
)
432 // continuation of the same module in the address space
435 else // end of the current module
437 dlls
.Add(wxDynamicLibraryDetailsCreator::New(startCur
,
449 #endif // wxUSE_DYNLIB_CLASS