1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
|
/* dl_dlopen.xs
*
* Platform: SunOS/Solaris, possibly others which use dlopen.
* Author: Paul Marquess (Paul.Marquess@btinternet.com)
* Created: 10th July 1994
*
* Modified:
* 15th July 1994 - Added code to explicitly save any error messages.
* 3rd August 1994 - Upgraded to v3 spec.
* 9th August 1994 - Changed to use IV
* 10th August 1994 - Tim Bunce: Added RTLD_LAZY, switchable debugging,
* basic FreeBSD support, removed ClearError
* 29th February 2000 - Alan Burlison: Added functionality to close dlopen'd
* files when the interpreter exits
* 2015-03-12 - rurban: Added optional 3rd dl_find_symbol argument
*
*/
/* Porting notes:
Definition of Sunos dynamic Linking functions
=============================================
In order to make this implementation easier to understand here is a
quick definition of the SunOS Dynamic Linking functions which are
used here.
dlopen
------
void *
dlopen(path, mode)
char * path;
int mode;
This function takes the name of a dynamic object file and returns
a descriptor which can be used by dlsym later. It returns NULL on
error.
The mode parameter must be set to 1 for Solaris 1 and to
RTLD_LAZY (==2) on Solaris 2.
dlclose
-------
int
dlclose(handle)
void * handle;
This function takes the handle returned by a previous invocation of
dlopen and closes the associated dynamic object file. It returns zero
on success, and non-zero on failure.
dlsym
------
void *
dlsym(handle, symbol)
void * handle;
char * symbol;
Takes the handle returned from dlopen and the name of a symbol to
get the address of. If the symbol was found a pointer is
returned. It returns NULL on error. If DL_PREPEND_UNDERSCORE is
defined an underscore will be added to the start of symbol. This
is required on some platforms (freebsd).
dlerror
------
char * dlerror()
Returns a null-terminated string which describes the last error
that occurred with either dlopen or dlsym. After each call to
dlerror the error message will be reset to a null pointer. The
SaveError function is used to save the error as soon as it happens.
Note that the POSIX standard does not require a per-thread buffer for
the error message, and so on multi-threaded builds, it can be overwritten
by another thread before SaveError accomplishes its task. Some systems do
have a per-thread buffer. The man page on your system should tell you.
If your code might be run on a system where this function is not thread
safe, you should protect your calls with mutexes. See "Dealing with Error
Messages" below.
Return Types
============
In this implementation the two functions, dl_load_file &
dl_find_symbol, return void *. This is because the underlying SunOS
dynamic linker calls also return void *. This is not necessarily
the case for all architectures. For example, some implementation
will want to return a char * for dl_load_file.
If void * is not appropriate for your architecture, you will have to
change the void * to whatever you require. If you are not certain of
how Perl handles C data types, I suggest you start by consulting
Dean Roerich's Perl 5 API document. Also, have a look in the typemap
file (in the ext directory) for a fairly comprehensive list of types
that are already supported. If you are completely stuck, I suggest you
post a message to perl5-porters.
Remember when you are making any changes that the return value from
dl_load_file is used as a parameter in the dl_find_symbol
function. Also the return value from find_symbol is used as a parameter
to install_xsub.
Dealing with Error Messages
============================
In order to make the handling of dynamic linking errors as generic as
possible you should store any error messages associated with your
implementation with the SaveError function.
In the case of SunOS the function dlerror returns the error message
associated with the last dynamic link error. As the SunOS dynamic
linker functions dlopen & dlsym both return NULL on error every call
to a SunOS dynamic link routine is coded like this
RETVAL = dlopen(filename, 1) ;
if (RETVAL == NULL)
SaveError("%s",dlerror()) ;
Note that SaveError() takes a printf format string. Use a "%s" as
the first parameter if the error may contain any % characters.
dlerror() may not be thread-safe on some systems; if this code is run on
any of those, a mutex should be added. khw (who added this comment) has no
idea which systems aren't thread-safe, but consider this possibility when
debugging.
*/
#define PERL_NO_GET_CONTEXT
#define PERL_EXT
#include "EXTERN.h"
#define PERL_IN_DL_DLOPEN_XS
#include "perl.h"
#include "XSUB.h"
#ifdef I_DLFCN
#include <dlfcn.h> /* the dynamic linker include file for Sunos/Solaris */
#else
#include <nlist.h>
#include <link.h>
#endif
#ifndef RTLD_LAZY
# define RTLD_LAZY 1 /* Solaris 1 */
#endif
#ifndef HAS_DLERROR
# ifdef __NetBSD__
# define dlerror() strerror(errno)
# else
# define dlerror() "Unknown error - dlerror() not implemented"
# endif
#endif
#include "dlutils.c" /* SaveError() etc */
static void
dl_private_init(pTHX)
{
(void)dl_generic_private_init(aTHX);
}
MODULE = DynaLoader PACKAGE = DynaLoader
BOOT:
(void)dl_private_init(aTHX);
SV *
dl_load_file(filename, flags=0)
char * filename
int flags
PREINIT:
int mode = RTLD_LAZY;
void *handle;
CODE:
{
#if defined(DLOPEN_WONT_DO_RELATIVE_PATHS)
char pathbuf[PATH_MAX + 2];
if (*filename != '/' && strchr(filename, '/')) {
const size_t filename_len = strlen(filename);
if (getcwd(pathbuf, PATH_MAX - filename_len)) {
const size_t path_len = strlen(pathbuf);
pathbuf[path_len] = '/';
filename = (char *) memcpy(pathbuf + path_len + 1, filename, filename_len + 1);
}
}
#endif
#ifdef RTLD_NOW
{
dMY_CXT;
if (dl_nonlazy)
mode = RTLD_NOW;
}
#endif
if (flags & 0x01)
#ifdef RTLD_GLOBAL
mode |= RTLD_GLOBAL;
#else
Perl_warn(aTHX_ "Can't make loaded symbols global on this platform while loading %s",filename);
#endif
DLDEBUG(1,PerlIO_printf(Perl_debug_log, "dl_load_file(%s,%x):\n", filename,flags));
handle = dlopen(filename, mode) ;
DLDEBUG(2,PerlIO_printf(Perl_debug_log, " libref=%lx\n", (unsigned long) handle));
RETVAL = newSV_type(SVt_IV);
if (handle == NULL)
SaveError(aTHX_ "%s",dlerror()) ;
else
sv_setiv(RETVAL, PTR2IV(handle));
}
OUTPUT:
RETVAL
int
dl_unload_file(libref)
void * libref
CODE:
DLDEBUG(1,PerlIO_printf(Perl_debug_log, "dl_unload_file(%lx):\n", PTR2ul(libref)));
RETVAL = (dlclose(libref) == 0 ? 1 : 0);
if (!RETVAL)
SaveError(aTHX_ "%s", dlerror()) ;
DLDEBUG(2,PerlIO_printf(Perl_debug_log, " retval = %d\n", RETVAL));
OUTPUT:
RETVAL
SV *
dl_find_symbol(libhandle, symbolname, ign_err=0)
void * libhandle
char * symbolname
int ign_err
PREINIT:
void *sym;
CODE:
#ifdef DLSYM_NEEDS_UNDERSCORE
symbolname = Perl_form_nocontext("_%s", symbolname);
#endif
DLDEBUG(2, PerlIO_printf(Perl_debug_log,
"dl_find_symbol(handle=%lx, symbol=%s)\n",
(unsigned long) libhandle, symbolname));
sym = dlsym(libhandle, symbolname);
DLDEBUG(2, PerlIO_printf(Perl_debug_log,
" symbolref = %lx\n", (unsigned long) sym));
RETVAL = newSV_type(SVt_IV);
if (sym == NULL) {
if (!ign_err)
SaveError(aTHX_ "%s", dlerror());
} else
sv_setiv(RETVAL, PTR2IV(sym));
OUTPUT:
RETVAL
void
dl_undef_symbols()
CODE:
# These functions should not need changing on any platform:
SV *
dl_install_xsub(perl_name, symref, filename="$Package")
char * perl_name
void * symref
const char * filename
CODE:
DLDEBUG(2,PerlIO_printf(Perl_debug_log, "dl_install_xsub(name=%s, symref=%" UVxf ")\n",
perl_name, PTR2UV(symref)));
RETVAL = newRV((SV*)newXS_flags(perl_name,
DPTR2FPTR(XSUBADDR_t, symref),
filename, NULL,
XS_DYNAMIC_FILENAME));
OUTPUT:
RETVAL
SV *
dl_error()
CODE:
dMY_CXT;
RETVAL = newSVsv(MY_CXT.x_dl_last_error);
OUTPUT:
RETVAL
#if defined(USE_ITHREADS)
void
CLONE(...)
CODE:
MY_CXT_CLONE;
PERL_UNUSED_VAR(items);
/* MY_CXT_CLONE just does a memcpy on the whole structure, so to avoid
* using Perl variables that belong to another thread, we create our
* own for this thread.
*/
MY_CXT.x_dl_last_error = newSVpvs("");
#endif
# end.
|