1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        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 // standard shared libraries extensions for different Unix versions 
  70     const wxString 
wxDynamicLibrary::ms_dllext(".sl"); 
  71 #elif defined(__DARWIN__) 
  72     const wxString 
wxDynamicLibrary::ms_dllext(".bundle"); 
  74     const wxString 
wxDynamicLibrary::ms_dllext(".so"); 
  77 // ============================================================================ 
  78 // wxDynamicLibrary implementation 
  79 // ============================================================================ 
  81 // ---------------------------------------------------------------------------- 
  82 // dlxxx() emulation for Darwin 
  83 // Only useful if the OS X version could be < 10.3 at runtime 
  84 // ---------------------------------------------------------------------------- 
  86 #if defined(__DARWIN__) && (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3) 
  87 // --------------------------------------------------------------------------- 
  88 // For Darwin/Mac OS X 
  89 //   supply the sun style dlopen functions in terms of Darwin NS* 
  90 // --------------------------------------------------------------------------- 
  93  *   The dlopen port is a port from dl_next.xs by Anno Siegel. 
  94  *   dl_next.xs is itself a port from dl_dlopen.xs by Paul Marquess. 
  95  *   The method used here is just to supply the sun style dlopen etc. 
  96  *   functions in terms of Darwin NS*. 
 100 #include <mach-o/dyld.h> 
 102 static char dl_last_error
[1024]; 
 104 static const char *wx_darwin_dlerror() 
 106     return dl_last_error
; 
 109 static void *wx_darwin_dlopen(const char *path
, int WXUNUSED(mode
) /* mode is ignored */) 
 111     NSObjectFileImage ofile
; 
 112     NSModule handle 
= NULL
; 
 114     unsigned dyld_result 
= NSCreateObjectFileImageFromFile(path
, &ofile
); 
 115     if ( dyld_result 
!= NSObjectFileImageSuccess 
) 
 119         static const char *errorStrings
[] = 
 121             "%d: Object Image Load Failure", 
 122             "%d: Object Image Load Success", 
 123             "%d: Not an recognisable object file", 
 124             "%d: No valid architecture", 
 125             "%d: Object image has an invalid format", 
 126             "%d: Invalid access (permissions?)", 
 127             "%d: Unknown error code from NSCreateObjectFileImageFromFile" 
 130         const int index 
= dyld_result 
< WXSIZEOF(errorStrings
) 
 132                             : WXSIZEOF(errorStrings
) - 1; 
 134         // this call to sprintf() is safe as strings above are fixed at 
 135         // compile-time and are shorter than WXSIZEOF(dl_last_error) 
 136         sprintf(dl_last_error
, errorStrings
[index
], dyld_result
); 
 140         handle 
= NSLinkModule
 
 144                     NSLINKMODULE_OPTION_BINDNOW 
| 
 145                     NSLINKMODULE_OPTION_RETURN_ON_ERROR
 
 150             NSLinkEditErrors err
; 
 152             const char *filename
; 
 155             NSLinkEditError(&err
, &code
, &filename
, &errmsg
); 
 156             strncpy(dl_last_error
, errmsg
, WXSIZEOF(dl_last_error
)-1); 
 157             dl_last_error
[WXSIZEOF(dl_last_error
)-1] = '\0'; 
 165 static int wx_darwin_dlclose(void *handle
) 
 167     NSUnLinkModule((NSModule
)handle
, NSUNLINKMODULE_OPTION_NONE
); 
 171 static void *wx_darwin_dlsym(void *handle
, const char *symbol
) 
 173     // as on many other systems, C symbols have prepended underscores under 
 174     // Darwin but unlike the normal dlopen(), NSLookupSymbolInModule() is not 
 176     wxCharBuffer 
buf(strlen(symbol
) + 1); 
 177     char *p 
= buf
.data(); 
 179     strcpy(p 
+ 1, symbol
); 
 181     NSSymbol nsSymbol 
= NSLookupSymbolInModule((NSModule
)handle
, p 
); 
 182     return nsSymbol 
? NSAddressOfSymbol(nsSymbol
) : NULL
; 
 185 // Add the weak linking attribute to dlopen's declaration 
 186 extern void * dlopen(const char * __path
, int __mode
) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
; 
 188 // For all of these methods we test dlopen since all of the dl functions we use were added 
 189 // to OS X at the same time.  This also ensures we don't dlopen with the real function then 
 190 // dlclose with the internal implementation. 
 192 static inline void *wx_dlopen(const char *__path
, int __mode
) 
 196         return dlopen(__path
, __mode
); 
 199         return wx_darwin_dlopen(__path
, __mode
); 
 202 static inline int wx_dlclose(void *__handle
) 
 206         return dlclose(__handle
); 
 209         return wx_darwin_dlclose(__handle
); 
 212 static inline const char *wx_dlerror() 
 219         return wx_darwin_dlerror(); 
 222 static inline void *wx_dlsym(void *__handle
, const char *__symbol
) 
 226         return dlsym(__handle
, __symbol
); 
 229         return wx_darwin_dlsym(__handle
, __symbol
); 
 232 #else // __DARWIN__/!__DARWIN__ 
 234 // Use preprocessor definitions for non-Darwin or OS X >= 10.3 
 235 #define wx_dlopen(__path,__mode) dlopen(__path,__mode) 
 236 #define wx_dlclose(__handle) dlclose(__handle) 
 237 #define wx_dlerror() dlerror() 
 238 #define wx_dlsym(__handle,__symbol) dlsym(__handle,__symbol) 
 240 #endif // defined(__DARWIN__) 
 242 // ---------------------------------------------------------------------------- 
 243 // loading/unloading DLLs 
 244 // ---------------------------------------------------------------------------- 
 246 wxDllType 
wxDynamicLibrary::GetProgramHandle() 
 248 #ifdef USE_POSIX_DL_FUNCS 
 249    return wx_dlopen(0, RTLD_LAZY
); 
 256 wxDllType 
wxDynamicLibrary::RawLoad(const wxString
& libname
, int flags
) 
 258     wxASSERT_MSG( !(flags 
& wxDL_NOW
) || !(flags 
& wxDL_LAZY
), 
 259                   _T("wxDL_LAZY and wxDL_NOW are mutually exclusive.") ); 
 261 #ifdef USE_POSIX_DL_FUNCS 
 262     // we need to use either RTLD_NOW or RTLD_LAZY because if we call dlopen() 
 263     // with flags == 0 recent versions of glibc just fail the call, so use 
 264     // RTLD_NOW even if wxDL_NOW was not specified 
 265     int rtldFlags 
= flags 
& wxDL_LAZY 
? RTLD_LAZY 
: RTLD_NOW
; 
 267     if ( flags 
& wxDL_GLOBAL 
) 
 268         rtldFlags 
|= RTLD_GLOBAL
; 
 270     return wx_dlopen(libname
.fn_str(), rtldFlags
); 
 271 #else // !USE_POSIX_DL_FUNCS 
 274     if ( flags 
& wxDL_LAZY 
) 
 276         shlFlags 
|= BIND_DEFERRED
; 
 278     else if ( flags 
& wxDL_NOW 
) 
 280         shlFlags 
|= BIND_IMMEDIATE
; 
 283     return shl_load(libname
.fn_str(), shlFlags
, 0); 
 284 #endif // USE_POSIX_DL_FUNCS/!USE_POSIX_DL_FUNCS 
 288 void wxDynamicLibrary::Unload(wxDllType handle
) 
 290 #ifdef wxHAVE_DYNLIB_ERROR 
 294 #ifdef USE_POSIX_DL_FUNCS 
 296 #else // !USE_POSIX_DL_FUNCS 
 298 #endif // USE_POSIX_DL_FUNCS/!USE_POSIX_DL_FUNCS 
 300 #if defined(USE_POSIX_DL_FUNCS) && defined(wxHAVE_DYNLIB_ERROR) 
 307 void *wxDynamicLibrary::RawGetSymbol(wxDllType handle
, const wxString
& name
) 
 311 #ifdef USE_POSIX_DL_FUNCS 
 312     symbol 
= wx_dlsym(handle
, name
.fn_str()); 
 313 #else // !USE_POSIX_DL_FUNCS 
 314     // note that shl_findsym modifies the handle argument to indicate where the 
 315     // symbol was found, but it's ok to modify the local handle copy here 
 316     if ( shl_findsym(&handle
, name
.fn_str(), TYPE_UNDEFINED
, &symbol
) != 0 ) 
 318 #endif // USE_POSIX_DL_FUNCS/!USE_POSIX_DL_FUNCS 
 323 // ---------------------------------------------------------------------------- 
 325 // ---------------------------------------------------------------------------- 
 327 #ifdef wxHAVE_DYNLIB_ERROR 
 330 void wxDynamicLibrary::Error() 
 332     wxString 
err(wx_dlerror()); 
 335         err 
= _("Unknown dynamic library error"); 
 337     wxLogError(wxT("%s"), err
); 
 340 #endif // wxHAVE_DYNLIB_ERROR 
 342 // ---------------------------------------------------------------------------- 
 343 // listing loaded modules 
 344 // ---------------------------------------------------------------------------- 
 346 // wxDynamicLibraryDetails declares this class as its friend, so put the code 
 347 // initializing new details objects here 
 348 class wxDynamicLibraryDetailsCreator
 
 351     // create a new wxDynamicLibraryDetails from the given data 
 352     static wxDynamicLibraryDetails 
* 
 353     New(void *start
, void *end
, const wxString
& path
) 
 355         wxDynamicLibraryDetails 
*details 
= new wxDynamicLibraryDetails
; 
 356         details
->m_path 
= path
; 
 357         details
->m_name 
= path
.AfterLast(_T('/')); 
 358         details
->m_address 
= start
; 
 359         details
->m_length 
= (char *)end 
- (char *)start
; 
 361         // try to extract the library version from its name 
 362         const size_t posExt 
= path
.rfind(_T(".so")); 
 363         if ( posExt 
!= wxString::npos 
) 
 365             if ( path
.c_str()[posExt 
+ 3] == _T('.') ) 
 367                 // assume "libfoo.so.x.y.z" case 
 368                 details
->m_version
.assign(path
, posExt 
+ 4, wxString::npos
); 
 372                 size_t posDash 
= path
.find_last_of(_T('-'), posExt
); 
 373                 if ( posDash 
!= wxString::npos 
) 
 375                     // assume "libbar-x.y.z.so" case 
 377                     details
->m_version
.assign(path
, posDash
, posExt 
- posDash
); 
 387 wxDynamicLibraryDetailsArray 
wxDynamicLibrary::ListLoaded() 
 389     wxDynamicLibraryDetailsArray dlls
; 
 392     // examine /proc/self/maps to find out what is loaded in our address space 
 393     wxFFile 
file(_T("/proc/self/maps")); 
 394     if ( file
.IsOpened() ) 
 396         // details of the module currently being parsed 
 398         void *startCur 
= NULL
, 
 403         while ( fgets(buf
, WXSIZEOF(buf
), file
.fp()) ) 
 405             // format is: "start-end perm offset maj:min inode path", see proc(5) 
 408             switch ( sscanf(buf
, "%p-%p %*4s %*p %*02x:%*02x %*d %1024s\n", 
 409                             &start
, &end
, path
) ) 
 412                     // there may be no path column 
 417                     // nothing to do, read everything we wanted 
 422                     buf
[strlen(buf
) - 1] = '\0'; 
 423                     wxLogDebug(_T("Failed to parse line \"%s\" in /proc/self/maps."), 
 428             wxASSERT_MSG( start 
>= endCur
, 
 429                           _T("overlapping regions in /proc/self/maps?") ); 
 431             wxString pathNew 
= wxString::FromAscii(path
); 
 432             if ( pathCur
.empty() ) 
 439             else if ( pathCur 
== pathNew 
&& endCur 
== end 
) 
 441                 // continuation of the same module in the address space 
 444             else // end of the current module 
 446                 dlls
.Add(wxDynamicLibraryDetailsCreator::New(startCur
, 
 458 #endif // wxUSE_DYNLIB_CLASS