Fixed DevStudio 2003 build with memory check code.
[pwlib.git] / src / ptlib / unix / udll.cxx
blobe297bad1d9ac1ae063959b38c867cc83e3bd30ee
1 /*
2 * udll.cxx
4 * Dynamic Link Library implementation.
6 * Portable Windows Library
8 * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
25 * All Rights Reserved.
27 * Contributor(s): ______________________________________.
29 * $Log$
30 * Revision 1.24 2007/07/06 02:12:14 csoutheren
31 * Add extra memory leak debugging on Linux
32 * Remove compile warnings
34 * Revision 1.23 2006/08/20 00:32:00 csoutheren
35 * Fixed error reporting on DLL load error
37 * Revision 1.22 2006/07/18 05:15:58 csoutheren
38 * Removed pre-emptive call to dlerror as this crashes RedHat 9
40 * Revision 1.21 2006/06/20 13:26:19 csoutheren
41 * Only call dlerror if error occurs
43 * Revision 1.20 2006/06/20 05:36:38 csoutheren
44 * Patch 1471705 rewritten to make threadsafe
45 * Display error from dlopen if available
46 * Thanks to Joerg Pulz
48 * Revision 1.19 2005/11/30 12:47:42 csoutheren
49 * Removed tabs, reformatted some code, and changed tags for Doxygen
51 * Revision 1.18 2005/08/04 20:10:24 csoutheren
52 * Apply patch #1217596
53 * Fixed problems with MacOSX Tiger
54 * Thanks to Hannes Friederich
56 * Revision 1.17 2004/05/11 01:15:53 csoutheren
57 * Included name into Unix PDynaLink implementation
59 * Revision 1.16 2003/09/11 00:52:13 dereksmithies
60 * Full dependancy check on dynamically loading a library.
61 * Thanks to Snark on #gnomemeeting for pointing this out...
63 * Revision 1.15 2003/07/09 11:37:13 rjongbloed
64 * Fixed corrct closing of DLL (setting handle to NULL) thanks Fabrizio Ammollo
66 * Revision 1.14 2003/05/14 10:50:30 dereksmithies
67 * Quick hack to add the function: PDynaLink::GetName(). Fix me.
69 * Revision 1.13 2003/05/06 06:59:12 robertj
70 * Dynamic library support for MacOSX, thanks Hugo Santos
72 * Revision 1.12 2003/04/16 07:17:35 craigs
73 * CHanged to use new #define
75 * Revision 1.11 2001/06/30 06:59:07 yurik
76 * Jac Goudsmit from Be submit these changes 6/28. Implemented by Yuri Kiryanov
78 * Revision 1.10 2001/03/07 06:57:52 yurik
79 * Changed email to current one
81 * Revision 1.9 2000/03/10 08:21:17 rogerh
82 * Add correct OpenBSD support
84 * Revision 1.8 2000/03/09 18:41:53 rogerh
85 * Workaround for OpenBSD. This breaks the functionality on OpenBSD but
86 * gains us a clean compilation. We can return to this problem later.
88 * Revision 1.7 1999/02/22 13:26:54 robertj
89 * BeOS port changes.
91 * Revision 1.6 1999/02/06 05:49:44 robertj
92 * BeOS port effort by Yuri Kiryanov <openh323@kiryanov.com>
94 * Revision 1.5 1998/11/30 21:52:03 robertj
95 * New directory structure.
97 * Revision 1.4 1998/09/24 04:12:26 robertj
98 * Added open software license.
100 * Revision 1.3 1998/01/04 08:11:41 craigs
101 * Remove Solarisism and made platform independent
103 * Revision 1.2 1997/10/30 12:41:22 craigs
104 * Added GetExtension command
106 * Revision 1.1 1997/04/22 10:58:17 craigs
107 * Initial revision
112 #pragma implementation "dynalink.h"
114 #include <ptlib.h>
116 #ifdef P_MACOSX
117 #if P_MACOSX < 700
120 Copyright (c) 2002 Peter O'Gorman <ogorman@users.sourceforge.net>
122 Permission is hereby granted, free of charge, to any person obtaining
123 a copy of this software and associated documentation files (the
124 "Software"), to deal in the Software without restriction, including
125 without limitation the rights to use, copy, modify, merge, publish,
126 distribute, sublicense, and/or sell copies of the Software, and to
127 permit persons to whom the Software is furnished to do so, subject to
128 the following conditions:
130 The above copyright notice and this permission notice shall be
131 included in all copies or substantial portions of the Software.
133 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
134 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
135 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
136 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
137 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
138 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
139 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
143 /* Just to prove that it isn't that hard to add Mac calls to your code :)
144 This works with pretty much everything, including kde3 xemacs and the gimp,
145 I'd guess that it'd work in at least 95% of cases, use this as your starting
146 point, rather than the mess that is dlfcn.c, assuming that your code does not
147 require ref counting or symbol lookups in dependent libraries
150 #include <stdio.h>
151 #include <stdlib.h>
152 #include <string.h>
153 #include <sys/types.h>
154 #include <sys/stat.h>
155 #include <stdarg.h>
156 #include <limits.h>
157 #include <mach-o/dyld.h>
159 #define RTLD_LAZY 0x1
160 #define RTLD_NOW 0x2
161 #define RTLD_LOCAL 0x4
162 #define RTLD_GLOBAL 0x8
163 #define RTLD_NOLOAD 0x10
164 #define RTLD_NODELETE 0x80
166 #define ERR_STR_LEN 256
168 static void *dlsymIntern(void *handle, const char *symbol);
170 static const char *error(int setget, const char *str, ...);
172 /* Set and get the error string for use by dlerror */
173 static const char *error(int setget, const char *str, ...)
175 static char errstr[ERR_STR_LEN];
176 static int err_filled = 0;
177 const char *retval;
178 va_list arg;
179 if (setget == 0)
181 va_start(arg, str);
182 strncpy(errstr, "dlsimple: ", ERR_STR_LEN);
183 vsnprintf(errstr + 10, ERR_STR_LEN - 10, str, arg);
184 va_end(arg);
185 err_filled = 1;
186 retval = NULL;
188 else
190 if (!err_filled)
191 retval = NULL;
192 else
193 retval = errstr;
194 err_filled = 0;
196 return retval;
199 /* dlopen */
200 static void *dlopen(const char *path, int mode)
202 void *module = 0;
203 NSObjectFileImage ofi = 0;
204 NSObjectFileImageReturnCode ofirc;
205 static int (*make_private_module_public) (NSModule module) = 0;
206 unsigned int flags = NSLINKMODULE_OPTION_RETURN_ON_ERROR | NSLINKMODULE_OPTION_PRIVATE;
208 /* If we got no path, the app wants the global namespace, use -1 as the marker
209 in this case */
210 if (!path)
211 return (void *)-1;
213 /* Create the object file image, works for things linked with the -bundle arg to ld */
214 ofirc = NSCreateObjectFileImageFromFile(path, &ofi);
215 switch (ofirc)
217 case NSObjectFileImageSuccess:
218 /* It was okay, so use NSLinkModule to link in the image */
219 if (!(mode & RTLD_LAZY)) flags += NSLINKMODULE_OPTION_BINDNOW;
220 module = NSLinkModule(ofi, path,flags);
221 /* Don't forget to destroy the object file image, unless you like leaks */
222 NSDestroyObjectFileImage(ofi);
223 /* If the mode was global, then change the module, this avoids
224 multiply defined symbol errors to first load private then make
225 global. Silly, isn't it. */
226 if ((mode & RTLD_GLOBAL))
228 if (!make_private_module_public)
230 _dyld_func_lookup("__dyld_NSMakePrivateModulePublic",
231 (unsigned long *)&make_private_module_public);
233 make_private_module_public(module);
235 break;
236 case NSObjectFileImageInappropriateFile:
237 /* It may have been a dynamic library rather than a bundle, try to load it */
238 module = (void *)NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR);
239 break;
240 case NSObjectFileImageFailure:
241 error(0,"Object file setup failure : \"%s\"", path);
242 return 0;
243 case NSObjectFileImageArch:
244 error(0,"No object for this architecture : \"%s\"", path);
245 return 0;
246 case NSObjectFileImageFormat:
247 error(0,"Bad object file format : \"%s\"", path);
248 return 0;
249 case NSObjectFileImageAccess:
250 error(0,"Can't read object file : \"%s\"", path);
251 return 0;
253 if (!module)
254 error(0, "Can not open \"%s\"", path);
255 return module;
258 /* dlsymIntern is used by dlsym to find the symbol */
259 static void *dlsymIntern(void *handle, const char *symbol)
261 NSSymbol *nssym = 0;
262 /* If the handle is -1, if is the app global context */
263 if (handle == (void *)-1)
265 /* Global context, use NSLookupAndBindSymbol */
266 if (NSIsSymbolNameDefined(symbol))
268 nssym = NSLookupAndBindSymbol(symbol);
272 /* Now see if the handle is a struch mach_header* or not, use NSLookupSymbol in image
273 for libraries, and NSLookupSymbolInModule for bundles */
274 else
276 /* Check for both possible magic numbers depending on x86/ppc byte order */
277 if ((((struct mach_header *)handle)->magic == MH_MAGIC) ||
278 (((struct mach_header *)handle)->magic == MH_CIGAM))
280 if (NSIsSymbolNameDefinedInImage((struct mach_header *)handle, symbol))
282 nssym = NSLookupSymbolInImage((struct mach_header *)handle,
283 symbol,
284 NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
285 | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
289 else
291 nssym = NSLookupSymbolInModule(handle, symbol);
294 if (!nssym)
296 error(0, "Symbol \"%s\" Not found", symbol);
297 return NULL;
299 return NSAddressOfSymbol(nssym);
302 static const char *dlerror(void)
304 return error(1, (char *)NULL);
307 static int dlclose(void *handle)
309 if ((((struct mach_header *)handle)->magic == MH_MAGIC) ||
310 (((struct mach_header *)handle)->magic == MH_CIGAM))
312 error(0, "Can't remove dynamic libraries on darwin");
313 return 0;
315 if (!NSUnLinkModule(handle, 0))
317 error(0, "unable to unlink module %s", NSNameOfModule(handle));
318 return 1;
320 return 0;
324 /* dlsym, prepend the underscore and call dlsymIntern */
325 static void *dlsym(void *handle, const char *symbol)
327 static char undersym[257]; /* Saves calls to malloc(3) */
328 int sym_len = strlen(symbol);
329 void *value = NULL;
330 char *malloc_sym = NULL;
332 if (sym_len < 256)
334 snprintf(undersym, 256, "_%s", symbol);
335 value = dlsymIntern(handle, undersym);
337 else
339 malloc_sym = malloc(sym_len + 2);
340 if (malloc_sym)
342 sprintf(malloc_sym, "_%s", symbol);
343 value = dlsymIntern(handle, malloc_sym);
344 free(malloc_sym);
346 else
348 error(0, "Unable to allocate memory");
351 return value;
354 #else
356 // The functionality implemented above ships directly with MacOSX 10.3 and later
357 #include <dlfcn.h>
359 #endif // P_MACOSX < 700
361 #endif // P_MACOSX
363 static PMutex & GetDLLMutex()
365 static PMutex mutex;
366 return mutex;
369 #ifndef P_DYNALINK
371 #warning "No implementation for dynamic library functions"
373 #else
375 PDynaLink::PDynaLink()
377 dllHandle = NULL;
380 PDynaLink::PDynaLink(const PString & _name)
381 : name(_name)
383 dllHandle = NULL;
384 Open(_name);
387 PDynaLink::~PDynaLink()
389 Close();
392 PString PDynaLink::GetExtension()
394 return PString(".so");
397 BOOL PDynaLink::Open(const PString & _name)
399 Close();
401 name = _name;
404 PWaitAndSignal m(GetDLLMutex());
406 const char *err; //= dlerror();
408 #if defined(P_OPENBSD)
409 dllHandle = dlopen((char *)(const char *)name, RTLD_NOW);
410 #else
411 dllHandle = dlopen((const char *)name, RTLD_NOW);
412 #endif
414 if (dllHandle == NULL) {
415 err = dlerror();
416 PTRACE_IF(1, err != NULL, "DLL\tError loading DLL - " << err);
420 return IsLoaded();
423 void PDynaLink::Close()
425 if (dllHandle != NULL) {
426 dlclose(dllHandle);
427 dllHandle = NULL;
429 name.MakeEmpty();
432 BOOL PDynaLink::IsLoaded() const
434 return dllHandle != NULL;
437 PString PDynaLink::GetName(BOOL full) const
439 if (!IsLoaded())
440 return "";
442 PString str = name;
443 PINDEX pos = str.FindLast('/');
444 if (pos != P_MAX_INDEX)
445 str = str.Mid(pos+1);
446 pos = str.FindLast(".so");
447 if (pos != P_MAX_INDEX)
448 str = str.Left(pos);
450 return str;
454 BOOL PDynaLink::GetFunction(PINDEX, Function &)
456 return FALSE;
459 BOOL PDynaLink::GetFunction(const PString & fn, Function & func)
461 if (dllHandle == NULL)
462 return FALSE;
464 #if defined(P_OPENBSD)
465 void * p = dlsym(dllHandle, (char *)(const char *)fn);
466 #else
467 void * p = dlsym(dllHandle, (const char *)fn);
468 #endif
470 if (p == NULL)
471 return FALSE;
473 func = (Function)p;
474 return TRUE;
477 #endif
479 // End of file