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
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): ______________________________________.
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
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
112 #pragma implementation "dynalink.h"
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
153 #include <sys/types.h>
154 #include <sys/stat.h>
157 #include <mach-o/dyld.h>
159 #define RTLD_LAZY 0x1
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;
182 strncpy(errstr
, "dlsimple: ", ERR_STR_LEN
);
183 vsnprintf(errstr
+ 10, ERR_STR_LEN
- 10, str
, arg
);
200 static void *dlopen(const char *path
, int mode
)
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
213 /* Create the object file image, works for things linked with the -bundle arg to ld */
214 ofirc
= NSCreateObjectFileImageFromFile(path
, &ofi
);
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
);
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
);
240 case NSObjectFileImageFailure
:
241 error(0,"Object file setup failure : \"%s\"", path
);
243 case NSObjectFileImageArch
:
244 error(0,"No object for this architecture : \"%s\"", path
);
246 case NSObjectFileImageFormat
:
247 error(0,"Bad object file format : \"%s\"", path
);
249 case NSObjectFileImageAccess
:
250 error(0,"Can't read object file : \"%s\"", path
);
254 error(0, "Can not open \"%s\"", path
);
258 /* dlsymIntern is used by dlsym to find the symbol */
259 static void *dlsymIntern(void *handle
, const char *symbol
)
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 */
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
,
284 NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
285 | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
);
291 nssym
= NSLookupSymbolInModule(handle
, symbol
);
296 error(0, "Symbol \"%s\" Not found", symbol
);
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");
315 if (!NSUnLinkModule(handle
, 0))
317 error(0, "unable to unlink module %s", NSNameOfModule(handle
));
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
);
330 char *malloc_sym
= NULL
;
334 snprintf(undersym
, 256, "_%s", symbol
);
335 value
= dlsymIntern(handle
, undersym
);
339 malloc_sym
= malloc(sym_len
+ 2);
342 sprintf(malloc_sym
, "_%s", symbol
);
343 value
= dlsymIntern(handle
, malloc_sym
);
348 error(0, "Unable to allocate memory");
356 // The functionality implemented above ships directly with MacOSX 10.3 and later
359 #endif // P_MACOSX < 700
363 static PMutex
& GetDLLMutex()
371 #warning "No implementation for dynamic library functions"
375 PDynaLink::PDynaLink()
380 PDynaLink::PDynaLink(const PString
& _name
)
387 PDynaLink::~PDynaLink()
392 PString
PDynaLink::GetExtension()
394 return PString(".so");
397 BOOL
PDynaLink::Open(const PString
& _name
)
404 PWaitAndSignal
m(GetDLLMutex());
406 const char *err
; //= dlerror();
408 #if defined(P_OPENBSD)
409 dllHandle
= dlopen((char *)(const char *)name
, RTLD_NOW
);
411 dllHandle
= dlopen((const char *)name
, RTLD_NOW
);
414 if (dllHandle
== NULL
) {
416 PTRACE_IF(1, err
!= NULL
, "DLL\tError loading DLL - " << err
);
423 void PDynaLink::Close()
425 if (dllHandle
!= NULL
) {
432 BOOL
PDynaLink::IsLoaded() const
434 return dllHandle
!= NULL
;
437 PString
PDynaLink::GetName(BOOL full
) const
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
)
454 BOOL
PDynaLink::GetFunction(PINDEX
, Function
&)
459 BOOL
PDynaLink::GetFunction(const PString
& fn
, Function
& func
)
461 if (dllHandle
== NULL
)
464 #if defined(P_OPENBSD)
465 void * p
= dlsym(dllHandle
, (char *)(const char *)fn
);
467 void * p
= dlsym(dllHandle
, (const char *)fn
);