[ruby/etc] bump up to 1.3.1
[ruby-80x24.org.git] / dln.c
blob44e8c06d04bda56efb4320003b2ac26dfd1b324f
1 /**********************************************************************
3 dln.c -
5 $Author$
6 created at: Tue Jan 18 17:05:06 JST 1994
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
10 **********************************************************************/
12 #ifdef RUBY_EXPORT
13 #include "ruby/ruby.h"
14 #define dln_notimplement rb_notimplement
15 #define dln_memerror rb_memerror
16 #define dln_exit rb_exit
17 #define dln_loaderror rb_loaderror
18 #else
19 #define dln_notimplement --->>> dln not implemented <<<---
20 #define dln_memerror abort
21 #define dln_exit exit
22 static void dln_loaderror(const char *format, ...);
23 #endif
24 #include "dln.h"
25 #include "internal.h"
26 #include "internal/compilers.h"
28 #ifdef HAVE_STDLIB_H
29 # include <stdlib.h>
30 #endif
32 #if defined(HAVE_ALLOCA_H)
33 #include <alloca.h>
34 #endif
36 #ifdef HAVE_STRING_H
37 # include <string.h>
38 #else
39 # include <strings.h>
40 #endif
42 #ifndef xmalloc
43 void *xmalloc();
44 void *xcalloc();
45 void *xrealloc();
46 #endif
48 #undef free
49 #define free(x) xfree(x)
51 #include <stdio.h>
52 #if defined(_WIN32)
53 #include "missing/file.h"
54 #endif
55 #include <sys/types.h>
56 #include <sys/stat.h>
58 #ifndef S_ISDIR
59 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
60 #endif
62 #ifdef HAVE_SYS_PARAM_H
63 # include <sys/param.h>
64 #endif
65 #ifndef MAXPATHLEN
66 # define MAXPATHLEN 1024
67 #endif
69 #ifdef HAVE_UNISTD_H
70 # include <unistd.h>
71 #endif
73 #ifndef _WIN32
74 char *getenv();
75 #endif
77 #ifdef __APPLE__
78 # if defined(HAVE_DLOPEN)
79 /* Mac OS X with dlopen (10.3 or later) */
80 # define MACOSX_DLOPEN
81 # else
82 # define MACOSX_DYLD
83 # endif
84 #endif
86 #ifndef dln_loaderror
87 static void
88 dln_loaderror(const char *format, ...)
90 va_list ap;
91 va_start(ap, format);
92 vfprintf(stderr, format, ap);
93 va_end(ap);
94 abort();
96 #endif
98 #if defined(HAVE_DLOPEN) && !defined(_AIX) && !defined(MACOSX_DYLD) && !defined(_UNICOSMP)
99 /* dynamic load with dlopen() */
100 # define USE_DLN_DLOPEN
101 #endif
103 #if defined(__hp9000s300) || ((defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)) && !defined(__ELF__)) || defined(NeXT) || defined(MACOSX_DYLD)
104 # define EXTERNAL_PREFIX "_"
105 #else
106 # define EXTERNAL_PREFIX ""
107 #endif
108 #define FUNCNAME_PREFIX EXTERNAL_PREFIX"Init_"
110 #if defined __CYGWIN__ || defined DOSISH
111 #define isdirsep(x) ((x) == '/' || (x) == '\\')
112 #else
113 #define isdirsep(x) ((x) == '/')
114 #endif
116 static size_t
117 init_funcname_len(const char **file)
119 const char *p = *file, *base, *dot = NULL;
121 /* Load the file as an object one */
122 for (base = p; *p; p++) { /* Find position of last '/' */
123 if (*p == '.' && !dot) dot = p;
124 if (isdirsep(*p)) base = p+1, dot = NULL;
126 *file = base;
127 /* Delete suffix if it exists */
128 return (dot ? dot : p) - base;
131 static const char funcname_prefix[sizeof(FUNCNAME_PREFIX) - 1] = FUNCNAME_PREFIX;
133 #define init_funcname(buf, file) do {\
134 const char *base = (file);\
135 const size_t flen = init_funcname_len(&base);\
136 const size_t plen = sizeof(funcname_prefix);\
137 char *const tmp = ALLOCA_N(char, plen+flen+1);\
138 if (!tmp) {\
139 dln_memerror();\
141 memcpy(tmp, funcname_prefix, plen);\
142 memcpy(tmp+plen, base, flen);\
143 tmp[plen+flen] = '\0';\
144 *(buf) = tmp;\
145 } while (0)
147 #ifdef USE_DLN_DLOPEN
148 # include <dlfcn.h>
149 #endif
151 #ifdef __hpux
152 #include <errno.h>
153 #include "dl.h"
154 #endif
156 #if defined(_AIX)
157 #include <ctype.h> /* for isdigit() */
158 #include <errno.h> /* for global errno */
159 #include <sys/ldr.h>
160 #endif
162 #ifdef NeXT
163 #if NS_TARGET_MAJOR < 4
164 #include <mach-o/rld.h>
165 #else
166 #include <mach-o/dyld.h>
167 #ifndef NSLINKMODULE_OPTION_BINDNOW
168 #define NSLINKMODULE_OPTION_BINDNOW 1
169 #endif
170 #endif
171 #else
172 #ifdef MACOSX_DYLD
173 #include <mach-o/dyld.h>
174 #endif
175 #endif
177 #ifdef _WIN32
178 #include <windows.h>
179 #include <imagehlp.h>
180 #endif
182 #ifdef _WIN32
183 static const char *
184 dln_strerror(char *message, size_t size)
186 int error = GetLastError();
187 char *p = message;
188 size_t len = snprintf(message, size, "%d: ", error);
190 #define format_message(sublang) FormatMessage(\
191 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \
192 NULL, error, MAKELANGID(LANG_NEUTRAL, (sublang)), \
193 message + len, size - len, NULL)
194 if (format_message(SUBLANG_ENGLISH_US) == 0)
195 format_message(SUBLANG_DEFAULT);
196 for (p = message + len; *p; p++) {
197 if (*p == '\n' || *p == '\r')
198 *p = ' ';
200 return message;
202 #define dln_strerror() dln_strerror(message, sizeof message)
203 #elif defined USE_DLN_DLOPEN
204 static const char *
205 dln_strerror(void)
207 return (char*)dlerror();
209 #endif
211 #if defined(_AIX)
212 static void
213 aix_loaderror(const char *pathname)
215 char *message[1024], errbuf[1024];
216 int i;
217 #define ERRBUF_APPEND(s) strlcat(errbuf, (s), sizeof(errbuf))
218 snprintf(errbuf, sizeof(errbuf), "load failed - %s. ", pathname);
220 if (loadquery(L_GETMESSAGES, &message[0], sizeof(message)) != -1) {
221 ERRBUF_APPEND("Please issue below command for detailed reasons:\n\t");
222 ERRBUF_APPEND("/usr/sbin/execerror ruby ");
223 for (i=0; message[i]; i++) {
224 ERRBUF_APPEND("\"");
225 ERRBUF_APPEND(message[i]);
226 ERRBUF_APPEND("\" ");
228 ERRBUF_APPEND("\n");
230 else {
231 ERRBUF_APPEND(strerror(errno));
232 ERRBUF_APPEND("[loadquery failed]");
234 dln_loaderror("%s", errbuf);
236 #endif
238 #if defined _WIN32 && defined RUBY_EXPORT
239 HANDLE rb_libruby_handle(void);
241 static int
242 rb_w32_check_imported(HMODULE ext, HMODULE mine)
244 ULONG size;
245 const IMAGE_IMPORT_DESCRIPTOR *desc;
247 desc = ImageDirectoryEntryToData(ext, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size);
248 if (!desc) return 0;
249 while (desc->Name) {
250 PIMAGE_THUNK_DATA pint = (PIMAGE_THUNK_DATA)((char *)ext + desc->Characteristics);
251 PIMAGE_THUNK_DATA piat = (PIMAGE_THUNK_DATA)((char *)ext + desc->FirstThunk);
252 for (; piat->u1.Function; piat++, pint++) {
253 static const char prefix[] = "rb_";
254 PIMAGE_IMPORT_BY_NAME pii;
255 const char *name;
257 if (IMAGE_SNAP_BY_ORDINAL(pint->u1.Ordinal)) continue;
258 pii = (PIMAGE_IMPORT_BY_NAME)((char *)ext + (size_t)pint->u1.AddressOfData);
259 name = (const char *)pii->Name;
260 if (strncmp(name, prefix, sizeof(prefix) - 1) == 0) {
261 FARPROC addr = GetProcAddress(mine, name);
262 if (addr) return (FARPROC)piat->u1.Function == addr;
265 desc++;
267 return 1;
269 #endif
271 #if defined(DLN_NEEDS_ALT_SEPARATOR) && DLN_NEEDS_ALT_SEPARATOR
272 #define translit_separator(src) do { \
273 char *tmp = ALLOCA_N(char, strlen(src) + 1), *p = tmp, c; \
274 do { \
275 *p++ = ((c = *file++) == '/') ? DLN_NEEDS_ALT_SEPARATOR : c; \
276 } while (c); \
277 (src) = tmp; \
278 } while (0)
279 #else
280 #define translit_separator(str) (void)(str)
281 #endif
283 #ifdef USE_DLN_DLOPEN
284 # include "ruby/internal/stdbool.h"
285 # include "internal/warnings.h"
286 COMPILER_WARNING_PUSH
287 #if defined(__clang__) || GCC_VERSION_SINCE(4, 2, 0)
288 COMPILER_WARNING_IGNORED(-Wpedantic)
289 #endif
290 static bool
291 dln_incompatible_library_p(void *handle)
293 void *ex = dlsym(handle, EXTERNAL_PREFIX"ruby_xmalloc");
294 void *const fp = (void *)ruby_xmalloc;
295 return ex && ex != fp;
297 COMPILER_WARNING_POP
298 #endif
300 void*
301 dln_load(const char *file)
303 #if (defined _WIN32 || defined USE_DLN_DLOPEN) && defined RUBY_EXPORT
304 static const char incompatible[] = "incompatible library version";
305 #endif
306 #if defined _WIN32 || defined USE_DLN_DLOPEN
307 const char *error = 0;
308 #endif
310 #if defined _WIN32
311 HINSTANCE handle;
312 WCHAR *winfile;
313 char message[1024];
314 void (*init_fct)(void);
315 char *buf;
317 /* Load the file as an object one */
318 init_funcname(&buf, file);
320 /* Convert the file path to wide char */
321 winfile = rb_w32_mbstr_to_wstr(CP_UTF8, file, -1, NULL);
322 if (!winfile) {
323 dln_memerror();
326 /* Load file */
327 handle = LoadLibraryW(winfile);
328 free(winfile);
330 if (!handle) {
331 error = dln_strerror();
332 goto failed;
335 #if defined _WIN32 && defined RUBY_EXPORT
336 if (!rb_w32_check_imported(handle, rb_libruby_handle())) {
337 FreeLibrary(handle);
338 error = incompatible;
339 goto failed;
341 #endif
343 if ((init_fct = (void(*)(void))GetProcAddress(handle, buf)) == NULL) {
344 dln_loaderror("%s - %s\n%s", dln_strerror(), buf, file);
347 /* Call the init code */
348 (*init_fct)();
349 return handle;
350 #else
351 char *buf;
352 /* Load the file as an object one */
353 init_funcname(&buf, file);
354 translit_separator(file);
356 #ifdef USE_DLN_DLOPEN
357 #define DLN_DEFINED
359 void *handle;
360 void (*init_fct)(void);
362 #ifndef RTLD_LAZY
363 # define RTLD_LAZY 1
364 #endif
365 #ifdef __INTERIX
366 # undef RTLD_GLOBAL
367 #endif
368 #ifndef RTLD_GLOBAL
369 # define RTLD_GLOBAL 0
370 #endif
372 /* Load file */
373 if ((handle = (void*)dlopen(file, RTLD_LAZY|RTLD_GLOBAL)) == NULL) {
374 error = dln_strerror();
375 goto failed;
377 # if defined RUBY_EXPORT
379 if (dln_incompatible_library_p(handle)) {
381 # if defined __APPLE__ && \
382 defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
383 (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11)
384 /* dlclose() segfaults */
385 rb_fatal("%s - %s", incompatible, file);
386 # else
387 dlclose(handle);
388 error = incompatible;
389 goto failed;
390 # endif
393 # endif
395 init_fct = (void(*)(void))(VALUE)dlsym(handle, buf);
396 if (init_fct == NULL) {
397 const size_t errlen = strlen(error = dln_strerror()) + 1;
398 error = memcpy(ALLOCA_N(char, errlen), error, errlen);
399 dlclose(handle);
400 goto failed;
402 /* Call the init code */
403 (*init_fct)();
405 return handle;
407 #endif /* USE_DLN_DLOPEN */
409 #ifdef __hpux
410 #define DLN_DEFINED
412 shl_t lib = NULL;
413 int flags;
414 void (*init_fct)(void);
416 flags = BIND_DEFERRED;
417 lib = shl_load(file, flags, 0);
418 if (lib == NULL) {
419 extern int errno;
420 dln_loaderror("%s - %s", strerror(errno), file);
422 shl_findsym(&lib, buf, TYPE_PROCEDURE, (void*)&init_fct);
423 if (init_fct == NULL) {
424 shl_findsym(&lib, buf, TYPE_UNDEFINED, (void*)&init_fct);
425 if (init_fct == NULL) {
426 errno = ENOSYM;
427 dln_loaderror("%s - %s", strerror(ENOSYM), file);
430 (*init_fct)();
431 return (void*)lib;
433 #endif /* hpux */
435 #if defined(_AIX)
436 #define DLN_DEFINED
438 void (*init_fct)(void);
440 init_fct = (void(*)(void))load((char*)file, 1, 0);
441 if (init_fct == NULL) {
442 aix_loaderror(file);
444 if (loadbind(0, (void*)dln_load, (void*)init_fct) == -1) {
445 aix_loaderror(file);
447 (*init_fct)();
448 return (void*)init_fct;
450 #endif /* _AIX */
452 #if defined(MACOSX_DYLD)
453 #define DLN_DEFINED
454 /*----------------------------------------------------
455 By SHIROYAMA Takayuki Psi@fortune.nest.or.jp
457 Special Thanks...
458 Yu tomoak-i@is.aist-nara.ac.jp,
459 Mi hisho@tasihara.nest.or.jp,
460 sunshine@sunshineco.com,
461 and... Miss ARAI Akino(^^;)
462 ----------------------------------------------------*/
464 int dyld_result;
465 NSObjectFileImage obj_file; /* handle, but not use it */
466 /* "file" is module file name .
467 "buf" is pointer to initial function name with "_" . */
469 void (*init_fct)(void);
472 dyld_result = NSCreateObjectFileImageFromFile(file, &obj_file);
474 if (dyld_result != NSObjectFileImageSuccess) {
475 dln_loaderror("Failed to load %.200s", file);
478 NSLinkModule(obj_file, file, NSLINKMODULE_OPTION_BINDNOW);
480 /* lookup the initial function */
481 if (!NSIsSymbolNameDefined(buf)) {
482 dln_loaderror("Failed to lookup Init function %.200s",file);
484 init_fct = NSAddressOfSymbol(NSLookupAndBindSymbol(buf));
485 (*init_fct)();
487 return (void*)init_fct;
489 #endif
491 #ifndef DLN_DEFINED
492 dln_notimplement();
493 #endif
495 #endif
496 #if defined(_WIN32) || defined(USE_DLN_DLOPEN)
497 failed:
498 dln_loaderror("%s - %s", error, file);
499 #endif
501 return 0; /* dummy return */