compilation fixes for !USE_PCH
[wxWidgets.git] / src / unix / dlunix.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: unix/dlunix.cpp
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"
29 #include "wx/ffile.h"
30
31 #ifndef WX_PRECOMP
32 #include "wx/intl.h"
33 #include "wx/log.h"
34 #endif
35
36 #if defined(HAVE_DLOPEN) || defined(__DARWIN__)
37 #define USE_POSIX_DL_FUNCS
38 #elif !defined(HAVE_SHL_LOAD)
39 #error "Don't know how to load dynamic libraries on this platform!"
40 #endif
41
42 // ----------------------------------------------------------------------------
43 // constants
44 // ----------------------------------------------------------------------------
45
46 // standard shared libraries extensions for different Unix versions
47 #if defined(__HPUX__)
48 const wxChar *wxDynamicLibrary::ms_dllext = _T(".sl");
49 #elif defined(__DARWIN__)
50 const wxChar *wxDynamicLibrary::ms_dllext = _T(".bundle");
51 #else
52 const wxChar *wxDynamicLibrary::ms_dllext = _T(".so");
53 #endif
54
55 // ============================================================================
56 // wxDynamicLibrary implementation
57 // ============================================================================
58
59 // ----------------------------------------------------------------------------
60 // dlxxx() emulation for Darwin
61 // ----------------------------------------------------------------------------
62
63 #if defined(__DARWIN__)
64 // ---------------------------------------------------------------------------
65 // For Darwin/Mac OS X
66 // supply the sun style dlopen functions in terms of Darwin NS*
67 // ---------------------------------------------------------------------------
68
69 /* Porting notes:
70 * The dlopen port is a port from dl_next.xs by Anno Siegel.
71 * dl_next.xs is itself a port from dl_dlopen.xs by Paul Marquess.
72 * The method used here is just to supply the sun style dlopen etc.
73 * functions in terms of Darwin NS*.
74 */
75
76 #include <stdio.h>
77 #include <mach-o/dyld.h>
78
79 static char dl_last_error[1024];
80
81 static
82 void TranslateError(const char *path, int number)
83 {
84 unsigned int index;
85 static char *OFIErrorStrings[] =
86 {
87 "%s(%d): Object Image Load Failure\n",
88 "%s(%d): Object Image Load Success\n",
89 "%s(%d): Not an recognisable object file\n",
90 "%s(%d): No valid architecture\n",
91 "%s(%d): Object image has an invalid format\n",
92 "%s(%d): Invalid access (permissions?)\n",
93 "%s(%d): Unknown error code from NSCreateObjectFileImageFromFile\n",
94 };
95 #define NUM_OFI_ERRORS (sizeof(OFIErrorStrings) / sizeof(OFIErrorStrings[0]))
96
97 index = number;
98 if (index > NUM_OFI_ERRORS - 1) {
99 index = NUM_OFI_ERRORS - 1;
100 }
101 sprintf(dl_last_error, OFIErrorStrings[index], path, number);
102 }
103
104 const char *dlerror()
105 {
106 return dl_last_error;
107 }
108
109 void *dlopen(const char *path, int WXUNUSED(mode) /* mode is ignored */)
110 {
111 NSObjectFileImage ofile;
112 NSModule handle = NULL;
113
114 int dyld_result = NSCreateObjectFileImageFromFile(path, &ofile);
115 if ( dyld_result != NSObjectFileImageSuccess )
116 {
117 handle = NULL;
118 }
119 else
120 {
121 handle = NSLinkModule
122 (
123 ofile,
124 path,
125 NSLINKMODULE_OPTION_BINDNOW |
126 NSLINKMODULE_OPTION_RETURN_ON_ERROR
127 );
128 }
129
130 if ( !handle )
131 TranslateError(path, dyld_result);
132
133 return handle;
134 }
135
136 int dlclose(void *handle)
137 {
138 NSUnLinkModule( handle, NSUNLINKMODULE_OPTION_NONE);
139 return 0;
140 }
141
142 void *dlsym(void *handle, const char *symbol)
143 {
144 // as on many other systems, C symbols have prepended underscores under
145 // Darwin but unlike the normal dlopen(), NSLookupSymbolInModule() is not
146 // aware of this
147 wxCharBuffer buf(strlen(symbol) + 1);
148 char *p = buf.data();
149 p[0] = '_';
150 strcpy(p + 1, symbol);
151
152 NSSymbol nsSymbol = NSLookupSymbolInModule( handle, p );
153 return nsSymbol ? NSAddressOfSymbol(nsSymbol) : NULL;
154 }
155
156 #endif // defined(__DARWIN__)
157
158 // ----------------------------------------------------------------------------
159 // loading/unloading DLLs
160 // ----------------------------------------------------------------------------
161
162 wxDllType wxDynamicLibrary::GetProgramHandle()
163 {
164 #ifdef USE_POSIX_DL_FUNCS
165 return dlopen(0, RTLD_LAZY);
166 #else
167 return PROG_HANDLE;
168 #endif
169 }
170
171 /* static */
172 wxDllType wxDynamicLibrary::RawLoad(const wxString& libname, int flags)
173 {
174 wxASSERT_MSG( (flags & wxDL_NOW) == 0,
175 _T("wxDL_LAZY and wxDL_NOW are mutually exclusive.") );
176
177 #ifdef USE_POSIX_DL_FUNCS
178 int rtldFlags = 0;
179
180 #ifdef RTLD_LAZY
181 if ( flags & wxDL_LAZY )
182 {
183 rtldFlags |= RTLD_LAZY;
184 }
185 #endif
186 #ifdef RTLD_NOW
187 if ( flags & wxDL_NOW )
188 {
189 rtldFlags |= RTLD_NOW;
190 }
191 #endif
192 #ifdef RTLD_GLOBAL
193 if ( flags & wxDL_GLOBAL )
194 {
195 rtldFlags |= RTLD_GLOBAL;
196 }
197 #endif
198
199 return dlopen(libname.fn_str(), rtldFlags);
200 #else // !USE_POSIX_DL_FUNCS
201 int shlFlags = 0;
202
203 if ( flags & wxDL_LAZY )
204 {
205 shlFlags |= BIND_DEFERRED;
206 }
207 else if ( flags & wxDL_NOW )
208 {
209 shlFlags |= BIND_IMMEDIATE;
210 }
211
212 return shl_load(libname.fn_str(), shlFlags, 0);
213 #endif // USE_POSIX_DL_FUNCS/!USE_POSIX_DL_FUNCS
214 }
215
216 /* static */
217 void wxDynamicLibrary::Unload(wxDllType handle)
218 {
219 #ifdef wxHAVE_DYNLIB_ERROR
220 int rc =
221 #endif
222
223 #ifdef USE_POSIX_DL_FUNCS
224 dlclose(handle);
225 #else // !USE_POSIX_DL_FUNCS
226 shl_unload(handle);
227 #endif // USE_POSIX_DL_FUNCS/!USE_POSIX_DL_FUNCS
228
229 #ifdef USE_POSIX_DL_FUNCS
230 if ( rc != 0 )
231 Error();
232 #endif
233 }
234
235 /* static */
236 void *wxDynamicLibrary::RawGetSymbol(wxDllType handle, const wxString& name)
237 {
238 void *symbol;
239
240 #ifdef USE_POSIX_DL_FUNCS
241 symbol = dlsym(handle, name.fn_str());
242 #else // !USE_POSIX_DL_FUNCS
243 // note that shl_findsym modifies the handle argument to indicate where the
244 // symbol was found, but it's ok to modify the local handle copy here
245 if ( shl_findsym(&handle, name.fn_str(), TYPE_UNDEFINED, &symbol) != 0 )
246 symbol = 0;
247 #endif // USE_POSIX_DL_FUNCS/!USE_POSIX_DL_FUNCS
248
249 return symbol;
250 }
251
252 // ----------------------------------------------------------------------------
253 // error handling
254 // ----------------------------------------------------------------------------
255
256 #ifdef wxHAVE_DYNLIB_ERROR
257
258 /* static */
259 void wxDynamicLibrary::Error()
260 {
261 #if wxUSE_UNICODE
262 wxWCharBuffer buffer = wxConvLocal.cMB2WC( dlerror() );
263 const wxChar *err = buffer;
264 #else
265 const wxChar *err = dlerror();
266 #endif
267
268 wxLogError(wxT("%s"), err ? err : _("Unknown dynamic library error"));
269 }
270
271 #endif // wxHAVE_DYNLIB_ERROR
272
273 // ----------------------------------------------------------------------------
274 // listing loaded modules
275 // ----------------------------------------------------------------------------
276
277 // wxDynamicLibraryDetails declares this class as its friend, so put the code
278 // initializing new details objects here
279 class wxDynamicLibraryDetailsCreator
280 {
281 public:
282 // create a new wxDynamicLibraryDetails from the given data
283 static wxDynamicLibraryDetails *
284 New(unsigned long start, unsigned long end, const wxString& path)
285 {
286 wxDynamicLibraryDetails *details = new wxDynamicLibraryDetails;
287 details->m_path = path;
288 details->m_name = path.AfterLast(_T('/'));
289 details->m_address = wx_reinterpret_cast(void *, start);
290 details->m_length = end - start;
291
292 // try to extract the library version from its name
293 const size_t posExt = path.rfind(_T(".so"));
294 if ( posExt != wxString::npos )
295 {
296 if ( path.c_str()[posExt + 3] == _T('.') )
297 {
298 // assume "libfoo.so.x.y.z" case
299 details->m_version.assign(path, posExt + 4, wxString::npos);
300 }
301 else
302 {
303 size_t posDash = path.find_last_of(_T('-'), posExt);
304 if ( posDash != wxString::npos )
305 {
306 // assume "libbar-x.y.z.so" case
307 posDash++;
308 details->m_version.assign(path, posDash, posExt - posDash);
309 }
310 }
311 }
312
313 return details;
314 }
315 };
316
317 /* static */
318 wxDynamicLibraryDetailsArray wxDynamicLibrary::ListLoaded()
319 {
320 wxDynamicLibraryDetailsArray dlls;
321
322 #ifdef __LINUX__
323 // examine /proc/self/maps to find out what is loaded in our address space
324 wxFFile file("/proc/self/maps");
325 if ( file.IsOpened() )
326 {
327 // details of the module currently being parsed
328 wxString pathCur;
329 unsigned long startCur,
330 endCur;
331
332 char path[1024];
333 char buf[1024];
334 while ( fgets(buf, WXSIZEOF(buf), file.fp()) )
335 {
336 // format is: start-end perm something? maj:min inode path
337 unsigned long start, end;
338 switch ( sscanf(buf, "%08lx-%08lx %*4s %*08x %*02d:%*02d %*d %1024s\n",
339 &start, &end, path) )
340 {
341 case 2:
342 // there may be no path column
343 path[0] = '\0';
344 break;
345
346 case 3:
347 // nothing to do, read everything we wanted
348 break;
349
350 default:
351 // chop '\n'
352 buf[strlen(buf) - 1] = '\0';
353 wxLogDebug(_T("Failed to parse line \"%s\" in /proc/self/maps."),
354 buf);
355 continue;
356 }
357
358 wxString pathNew = wxString::FromAscii(path);
359 if ( pathCur.empty() )
360 {
361 // new module start
362 pathCur = pathNew;
363 startCur = start;
364 endCur = end;
365 }
366 else if ( pathCur == pathNew )
367 {
368 // continuation of the same module
369 wxASSERT_MSG( start == endCur, _T("hole in /proc/self/maps?") );
370 endCur = end;
371 }
372 else // end of the current module
373 {
374 dlls.Add(wxDynamicLibraryDetailsCreator::New(startCur,
375 endCur,
376 pathCur));
377 pathCur.clear();
378 }
379 }
380 }
381 #endif // __LINUX__
382
383 return dlls;
384 }
385
386 #endif // wxUSE_DYNLIB_CLASS
387