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" 
  36 // only Mac OS X 10.3+ has dlfcn.h, and it is simpler to always provide our own 
  37 // wrappers using the native functions instead of doing checks for OS version 
  42 // if some flags are not supported, just ignore them 
  56 #if defined(HAVE_DLOPEN) || defined(__DARWIN__) 
  57     #define USE_POSIX_DL_FUNCS 
  58 #elif !defined(HAVE_SHL_LOAD) 
  59     #error "Don't know how to load dynamic libraries on this platform!" 
  62 // ---------------------------------------------------------------------------- 
  64 // ---------------------------------------------------------------------------- 
  66 // standard shared libraries extensions for different Unix versions 
  68     const wxChar 
*wxDynamicLibrary::ms_dllext 
= _T(".sl"); 
  69 #elif defined(__DARWIN__) 
  70     const wxChar 
*wxDynamicLibrary::ms_dllext 
= _T(".bundle"); 
  72     const wxChar 
*wxDynamicLibrary::ms_dllext 
= _T(".so"); 
  75 // ============================================================================ 
  76 // wxDynamicLibrary implementation 
  77 // ============================================================================ 
  79 // ---------------------------------------------------------------------------- 
  80 // dlxxx() emulation for Darwin 
  81 // ---------------------------------------------------------------------------- 
  83 #if defined(__DARWIN__) 
  84 // --------------------------------------------------------------------------- 
  85 // For Darwin/Mac OS X 
  86 //   supply the sun style dlopen functions in terms of Darwin NS* 
  87 // --------------------------------------------------------------------------- 
  90  *   The dlopen port is a port from dl_next.xs by Anno Siegel. 
  91  *   dl_next.xs is itself a port from dl_dlopen.xs by Paul Marquess. 
  92  *   The method used here is just to supply the sun style dlopen etc. 
  93  *   functions in terms of Darwin NS*. 
  97 #include <mach-o/dyld.h> 
  99 static char dl_last_error
[1024]; 
 101 const char *dlerror() 
 103     return dl_last_error
; 
 106 void *dlopen(const char *path
, int WXUNUSED(mode
) /* mode is ignored */) 
 108     NSObjectFileImage ofile
; 
 109     NSModule handle 
= NULL
; 
 111     unsigned dyld_result 
= NSCreateObjectFileImageFromFile(path
, &ofile
); 
 112     if ( dyld_result 
!= NSObjectFileImageSuccess 
) 
 116         static const char *errorStrings
[] = 
 118             "%d: Object Image Load Failure", 
 119             "%d: Object Image Load Success", 
 120             "%d: Not an recognisable object file", 
 121             "%d: No valid architecture", 
 122             "%d: Object image has an invalid format", 
 123             "%d: Invalid access (permissions?)", 
 124             "%d: Unknown error code from NSCreateObjectFileImageFromFile" 
 127         const int index 
= dyld_result 
< WXSIZEOF(errorStrings
) 
 129                             : WXSIZEOF(errorStrings
) - 1; 
 131         // this call to sprintf() is safe as strings above are fixed at 
 132         // compile-time and are shorter than WXSIZEOF(dl_last_error) 
 133         sprintf(dl_last_error
, errorStrings
[index
], dyld_result
); 
 137         handle 
= NSLinkModule
 
 141                     NSLINKMODULE_OPTION_BINDNOW 
| 
 142                     NSLINKMODULE_OPTION_RETURN_ON_ERROR
 
 147             NSLinkEditErrors err
; 
 149             const char *filename
; 
 152             NSLinkEditError(&err
, &code
, &filename
, &errmsg
); 
 153             strncpy(dl_last_error
, errmsg
, WXSIZEOF(dl_last_error
)-1); 
 154             dl_last_error
[WXSIZEOF(dl_last_error
)-1] = '\0'; 
 162 int dlclose(void *handle
) 
 164     NSUnLinkModule((NSModule
)handle
, NSUNLINKMODULE_OPTION_NONE
); 
 168 void *dlsym(void *handle
, const char *symbol
) 
 170     // as on many other systems, C symbols have prepended underscores under 
 171     // Darwin but unlike the normal dlopen(), NSLookupSymbolInModule() is not 
 173     wxCharBuffer 
buf(strlen(symbol
) + 1); 
 174     char *p 
= buf
.data(); 
 176     strcpy(p 
+ 1, symbol
); 
 178     NSSymbol nsSymbol 
= NSLookupSymbolInModule((NSModule
)handle
, p 
); 
 179     return nsSymbol 
? NSAddressOfSymbol(nsSymbol
) : NULL
; 
 182 #endif // defined(__DARWIN__) 
 184 // ---------------------------------------------------------------------------- 
 185 // loading/unloading DLLs 
 186 // ---------------------------------------------------------------------------- 
 188 wxDllType 
wxDynamicLibrary::GetProgramHandle() 
 190 #ifdef USE_POSIX_DL_FUNCS 
 191    return dlopen(0, RTLD_LAZY
); 
 198 wxDllType 
wxDynamicLibrary::RawLoad(const wxString
& libname
, int flags
) 
 200     wxASSERT_MSG( !(flags 
& wxDL_NOW
) || !(flags 
& wxDL_LAZY
), 
 201                   _T("wxDL_LAZY and wxDL_NOW are mutually exclusive.") ); 
 203 #ifdef USE_POSIX_DL_FUNCS 
 204     // we need to use either RTLD_NOW or RTLD_LAZY because if we call dlopen() 
 205     // with flags == 0 recent versions of glibc just fail the call, so use 
 206     // RTLD_NOW even if wxDL_NOW was not specified 
 207     int rtldFlags 
= flags 
& wxDL_LAZY 
? RTLD_LAZY 
: RTLD_NOW
; 
 209     if ( flags 
& wxDL_GLOBAL 
) 
 210         rtldFlags 
|= RTLD_GLOBAL
; 
 212     return dlopen(libname
.fn_str(), rtldFlags
); 
 213 #else // !USE_POSIX_DL_FUNCS 
 216     if ( flags 
& wxDL_LAZY 
) 
 218         shlFlags 
|= BIND_DEFERRED
; 
 220     else if ( flags 
& wxDL_NOW 
) 
 222         shlFlags 
|= BIND_IMMEDIATE
; 
 225     return shl_load(libname
.fn_str(), shlFlags
, 0); 
 226 #endif // USE_POSIX_DL_FUNCS/!USE_POSIX_DL_FUNCS 
 230 void wxDynamicLibrary::Unload(wxDllType handle
) 
 232 #ifdef wxHAVE_DYNLIB_ERROR 
 236 #ifdef USE_POSIX_DL_FUNCS 
 238 #else // !USE_POSIX_DL_FUNCS 
 240 #endif // USE_POSIX_DL_FUNCS/!USE_POSIX_DL_FUNCS 
 242 #if defined(USE_POSIX_DL_FUNCS) && defined(wxHAVE_DYNLIB_ERROR) 
 249 void *wxDynamicLibrary::RawGetSymbol(wxDllType handle
, const wxString
& name
) 
 253 #ifdef USE_POSIX_DL_FUNCS 
 254     symbol 
= dlsym(handle
, name
.fn_str()); 
 255 #else // !USE_POSIX_DL_FUNCS 
 256     // note that shl_findsym modifies the handle argument to indicate where the 
 257     // symbol was found, but it's ok to modify the local handle copy here 
 258     if ( shl_findsym(&handle
, name
.fn_str(), TYPE_UNDEFINED
, &symbol
) != 0 ) 
 260 #endif // USE_POSIX_DL_FUNCS/!USE_POSIX_DL_FUNCS 
 265 // ---------------------------------------------------------------------------- 
 267 // ---------------------------------------------------------------------------- 
 269 #ifdef wxHAVE_DYNLIB_ERROR 
 272 void wxDynamicLibrary::Error() 
 275     wxWCharBuffer buffer 
= wxConvLocal
.cMB2WC( dlerror() ); 
 276     const wxChar 
*err 
= buffer
; 
 278     const wxChar 
*err 
= dlerror(); 
 281     wxLogError(wxT("%s"), err 
? err 
: _("Unknown dynamic library error")); 
 284 #endif // wxHAVE_DYNLIB_ERROR 
 286 // ---------------------------------------------------------------------------- 
 287 // listing loaded modules 
 288 // ---------------------------------------------------------------------------- 
 290 // wxDynamicLibraryDetails declares this class as its friend, so put the code 
 291 // initializing new details objects here 
 292 class wxDynamicLibraryDetailsCreator
 
 295     // create a new wxDynamicLibraryDetails from the given data 
 296     static wxDynamicLibraryDetails 
* 
 297     New(void *start
, void *end
, const wxString
& path
) 
 299         wxDynamicLibraryDetails 
*details 
= new wxDynamicLibraryDetails
; 
 300         details
->m_path 
= path
; 
 301         details
->m_name 
= path
.AfterLast(_T('/')); 
 302         details
->m_address 
= start
; 
 303         details
->m_length 
= (char *)end 
- (char *)start
; 
 305         // try to extract the library version from its name 
 306         const size_t posExt 
= path
.rfind(_T(".so")); 
 307         if ( posExt 
!= wxString::npos 
) 
 309             if ( path
.c_str()[posExt 
+ 3] == _T('.') ) 
 311                 // assume "libfoo.so.x.y.z" case 
 312                 details
->m_version
.assign(path
, posExt 
+ 4, wxString::npos
); 
 316                 size_t posDash 
= path
.find_last_of(_T('-'), posExt
); 
 317                 if ( posDash 
!= wxString::npos 
) 
 319                     // assume "libbar-x.y.z.so" case 
 321                     details
->m_version
.assign(path
, posDash
, posExt 
- posDash
); 
 331 wxDynamicLibraryDetailsArray 
wxDynamicLibrary::ListLoaded() 
 333     wxDynamicLibraryDetailsArray dlls
; 
 336     // examine /proc/self/maps to find out what is loaded in our address space 
 337     wxFFile 
file(_T("/proc/self/maps")); 
 338     if ( file
.IsOpened() ) 
 340         // details of the module currently being parsed 
 342         void *startCur 
= NULL
, 
 347         while ( fgets(buf
, WXSIZEOF(buf
), file
.fp()) ) 
 349             // format is: "start-end perm offset maj:min inode path", see proc(5) 
 352             switch ( sscanf(buf
, "%p-%p %*4s %*p %*02x:%*02x %*d %1024s\n", 
 353                             &start
, &end
, path
) ) 
 356                     // there may be no path column 
 361                     // nothing to do, read everything we wanted 
 366                     buf
[strlen(buf
) - 1] = '\0'; 
 367                     wxLogDebug(_T("Failed to parse line \"%s\" in /proc/self/maps."), 
 372             wxASSERT_MSG( start 
>= endCur
, 
 373                           _T("overlapping regions in /proc/self/maps?") ); 
 375             wxString pathNew 
= wxString::FromAscii(path
); 
 376             if ( pathCur
.empty() ) 
 383             else if ( pathCur 
== pathNew 
&& endCur 
== end 
) 
 385                 // continuation of the same module in the address space 
 388             else // end of the current module 
 390                 dlls
.Add(wxDynamicLibraryDetailsCreator::New(startCur
, 
 402 #endif // wxUSE_DYNLIB_CLASS