Ruby 2.7.7p221 (2022-11-24 revision 168ec2b1e5ad0e4688e963d9de019557c78feed9)
dln.c
Go to the documentation of this file.
1/**********************************************************************
2
3 dln.c -
4
5 $Author$
6 created at: Tue Jan 18 17:05:06 JST 1994
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9
10**********************************************************************/
11
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
22static void dln_loaderror(const char *format, ...);
23#endif
24#include "dln.h"
25#include "internal.h"
26
27#ifdef HAVE_STDLIB_H
28# include <stdlib.h>
29#endif
30
31#ifdef USE_DLN_A_OUT
32char *dln_argv0;
33#endif
34
35#if defined(HAVE_ALLOCA_H)
36#include <alloca.h>
37#endif
38
39#ifdef HAVE_STRING_H
40# include <string.h>
41#else
42# include <strings.h>
43#endif
44
45#ifndef xmalloc
46void *xmalloc();
47void *xcalloc();
48void *xrealloc();
49#endif
50
51#undef free
52#define free(x) xfree(x)
53
54#include <stdio.h>
55#if defined(_WIN32)
56#include "missing/file.h"
57#endif
58#include <sys/types.h>
59#include <sys/stat.h>
60
61#ifndef S_ISDIR
62# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
63#endif
64
65#ifdef HAVE_SYS_PARAM_H
66# include <sys/param.h>
67#endif
68#ifndef MAXPATHLEN
69# define MAXPATHLEN 1024
70#endif
71
72#ifdef HAVE_UNISTD_H
73# include <unistd.h>
74#endif
75
76#ifndef _WIN32
77char *getenv();
78#endif
79
80#ifdef __APPLE__
81# if defined(HAVE_DLOPEN)
82 /* Mac OS X with dlopen (10.3 or later) */
83# define MACOSX_DLOPEN
84# else
85# define MACOSX_DYLD
86# endif
87#endif
88
89#ifndef dln_loaderror
90static void
91dln_loaderror(const char *format, ...)
92{
93 va_list ap;
94 va_start(ap, format);
95 vfprintf(stderr, format, ap);
96 va_end(ap);
97 abort();
98}
99#endif
100
101#if defined(HAVE_DLOPEN) && !defined(USE_DLN_A_OUT) && !defined(_AIX) && !defined(MACOSX_DYLD) && !defined(_UNICOSMP)
102/* dynamic load with dlopen() */
103# define USE_DLN_DLOPEN
104#endif
105
106#if defined(__hp9000s300) || ((defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)) && !defined(__ELF__)) || defined(NeXT) || defined(MACOSX_DYLD)
107# define EXTERNAL_PREFIX "_"
108#else
109# define EXTERNAL_PREFIX ""
110#endif
111#define FUNCNAME_PREFIX EXTERNAL_PREFIX"Init_"
112
113#if defined __CYGWIN__ || defined DOSISH
114#define isdirsep(x) ((x) == '/' || (x) == '\\')
115#else
116#define isdirsep(x) ((x) == '/')
117#endif
118
119static size_t
120init_funcname_len(const char **file)
121{
122 const char *p = *file, *base, *dot = NULL;
123
124 /* Load the file as an object one */
125 for (base = p; *p; p++) { /* Find position of last '/' */
126 if (*p == '.' && !dot) dot = p;
127 if (isdirsep(*p)) base = p+1, dot = NULL;
128 }
129 *file = base;
130 /* Delete suffix if it exists */
131 return (dot ? dot : p) - base;
132}
133
134static const char funcname_prefix[sizeof(FUNCNAME_PREFIX) - 1] = FUNCNAME_PREFIX;
135
136#define init_funcname(buf, file) do {\
137 const char *base = (file);\
138 const size_t flen = init_funcname_len(&base);\
139 const size_t plen = sizeof(funcname_prefix);\
140 char *const tmp = ALLOCA_N(char, plen+flen+1);\
141 if (!tmp) {\
142 dln_memerror();\
143 }\
144 memcpy(tmp, funcname_prefix, plen);\
145 memcpy(tmp+plen, base, flen);\
146 tmp[plen+flen] = '\0';\
147 *(buf) = tmp;\
148} while (0)
149
150#ifdef USE_DLN_A_OUT
151
152#ifndef LIBC_NAME
153# define LIBC_NAME "libc.a"
154#endif
155
156#ifndef DLN_DEFAULT_LIB_PATH
157# define DLN_DEFAULT_LIB_PATH "/lib:/usr/lib:/usr/local/lib:."
158#endif
159
160#include <errno.h>
161
162static int dln_errno;
163
164#define DLN_ENOEXEC ENOEXEC /* Exec format error */
165#define DLN_ECONFL 1201 /* Symbol name conflict */
166#define DLN_ENOINIT 1202 /* No initializer given */
167#define DLN_EUNDEF 1203 /* Undefine symbol remains */
168#define DLN_ENOTLIB 1204 /* Not a library file */
169#define DLN_EBADLIB 1205 /* Malformed library file */
170#define DLN_EINIT 1206 /* Not initialized */
171
172static int dln_init_p = 0;
173
174#include <ar.h>
175#include <a.out.h>
176#ifndef N_COMM
177# define N_COMM 0x12
178#endif
179#ifndef N_MAGIC
180# define N_MAGIC(x) (x).a_magic
181#endif
182
183#define INVALID_OBJECT(h) (N_MAGIC(h) != OMAGIC)
184
185#include "ruby/util.h"
186#include "ruby/st.h"
187
188static st_table *sym_tbl;
189static st_table *undef_tbl;
190
191static int load_lib();
192
193static int
194load_header(int fd, struct exec *hdrp, long disp)
195{
196 int size;
197
198 lseek(fd, disp, 0);
199 size = read(fd, hdrp, sizeof(struct exec));
200 if (size == -1) {
201 dln_errno = errno;
202 return -1;
203 }
204 if (size != sizeof(struct exec) || N_BADMAG(*hdrp)) {
205 dln_errno = DLN_ENOEXEC;
206 return -1;
207 }
208 return 0;
209}
210
211#if defined(sequent)
212#define RELOC_SYMBOL(r) ((r)->r_symbolnum)
213#define RELOC_MEMORY_SUB_P(r) ((r)->r_bsr)
214#define RELOC_PCREL_P(r) ((r)->r_pcrel || (r)->r_bsr)
215#define RELOC_TARGET_SIZE(r) ((r)->r_length)
216#endif
217
218/* Default macros */
219#ifndef RELOC_ADDRESS
220#define RELOC_ADDRESS(r) ((r)->r_address)
221#define RELOC_EXTERN_P(r) ((r)->r_extern)
222#define RELOC_SYMBOL(r) ((r)->r_symbolnum)
223#define RELOC_MEMORY_SUB_P(r) 0
224#define RELOC_PCREL_P(r) ((r)->r_pcrel)
225#define RELOC_TARGET_SIZE(r) ((r)->r_length)
226#endif
227
228#if defined(__sun) && defined(__sparc)
229/* Sparc (Sun 4) macros */
230# undef relocation_info
231# define relocation_info reloc_info_sparc
232# define R_RIGHTSHIFT(r) (reloc_r_rightshift[(r)->r_type])
233# define R_BITSIZE(r) (reloc_r_bitsize[(r)->r_type])
234# define R_LENGTH(r) (reloc_r_length[(r)->r_type])
235static const int reloc_r_rightshift[] = {
236 0, 0, 0, 0, 0, 0, 2, 2, 10, 0, 0, 0, 0, 0, 0,
237};
238static const int reloc_r_bitsize[] = {
239 8, 16, 32, 8, 16, 32, 30, 22, 22, 22, 13, 10, 32, 32, 16,
240};
241static const int reloc_r_length[] = {
242 0, 1, 2, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
243};
244# define R_PCREL(r) \
245 ((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22)
246# define R_SYMBOL(r) ((r)->r_index)
247#endif
248
249#if defined(sequent)
250#define R_SYMBOL(r) ((r)->r_symbolnum)
251#define R_MEMORY_SUB(r) ((r)->r_bsr)
252#define R_PCREL(r) ((r)->r_pcrel || (r)->r_bsr)
253#define R_LENGTH(r) ((r)->r_length)
254#endif
255
256#ifndef R_SYMBOL
257# define R_SYMBOL(r) ((r)->r_symbolnum)
258# define R_MEMORY_SUB(r) 0
259# define R_PCREL(r) ((r)->r_pcrel)
260# define R_LENGTH(r) ((r)->r_length)
261#endif
262
263static struct relocation_info *
264load_reloc(int fd, struct exec *hdrp, long disp)
265{
266 struct relocation_info *reloc;
267 int size;
268
269 lseek(fd, disp + N_TXTOFF(*hdrp) + hdrp->a_text + hdrp->a_data, 0);
270 size = hdrp->a_trsize + hdrp->a_drsize;
271 reloc = (struct relocation_info*)xmalloc(size);
272 if (reloc == NULL) {
273 dln_errno = errno;
274 return NULL;
275 }
276
277 if (read(fd, reloc, size) != size) {
278 dln_errno = errno;
279 free(reloc);
280 return NULL;
281 }
282
283 return reloc;
284}
285
286static struct nlist *
287load_sym(int fd, struct exec *hdrp, long disp)
288{
289 struct nlist * buffer;
290 struct nlist * sym;
291 struct nlist * end;
292 long displ;
293 int size;
294
295 lseek(fd, N_SYMOFF(*hdrp) + hdrp->a_syms + disp, 0);
296 if (read(fd, &size, sizeof(int)) != sizeof(int)) {
297 goto err_noexec;
298 }
299
300 buffer = (struct nlist*)xmalloc(hdrp->a_syms + size);
301 if (buffer == NULL) {
302 dln_errno = errno;
303 return NULL;
304 }
305
306 lseek(fd, disp + N_SYMOFF(*hdrp), 0);
307 if (read(fd, buffer, hdrp->a_syms + size) != hdrp->a_syms + size) {
308 free(buffer);
309 goto err_noexec;
310 }
311
312 sym = buffer;
313 end = sym + hdrp->a_syms / sizeof(struct nlist);
314 displ = (long)buffer + (long)(hdrp->a_syms);
315
316 while (sym < end) {
317 sym->n_un.n_name = (char*)sym->n_un.n_strx + displ;
318 sym++;
319 }
320 return buffer;
321
322 err_noexec:
323 dln_errno = DLN_ENOEXEC;
324 return NULL;
325}
326
327static st_table *
328sym_hash(struct exec *hdrp, struct nlist *syms)
329{
330 st_table *tbl;
331 struct nlist *sym = syms;
332 struct nlist *end = syms + (hdrp->a_syms / sizeof(struct nlist));
333
334 tbl = st_init_strtable();
335 if (tbl == NULL) {
336 dln_errno = errno;
337 return NULL;
338 }
339
340 while (sym < end) {
341 st_insert(tbl, sym->n_un.n_name, sym);
342 sym++;
343 }
344 return tbl;
345}
346
347static int
348dln_init(const char *prog)
349{
350 char *file, fbuf[MAXPATHLEN];
351 int fd;
352 struct exec hdr;
353 struct nlist *syms;
354
355 if (dln_init_p == 1) return 0;
356
357 file = dln_find_exe_r(prog, NULL, fbuf, sizeof(fbuf));
358 if (file == NULL || (fd = open(file, O_RDONLY)) < 0) {
359 dln_errno = errno;
360 return -1;
361 }
362
363 if (load_header(fd, &hdr, 0) == -1) return -1;
364 syms = load_sym(fd, &hdr, 0);
365 if (syms == NULL) {
366 close(fd);
367 return -1;
368 }
369 sym_tbl = sym_hash(&hdr, syms);
370 if (sym_tbl == NULL) { /* file may be start with #! */
371 char c = '\0';
372 char buf[MAXPATHLEN];
373 char *p;
374
375 free(syms);
376 lseek(fd, 0L, 0);
377 if (read(fd, &c, 1) == -1) {
378 dln_errno = errno;
379 return -1;
380 }
381 if (c != '#') goto err_noexec;
382 if (read(fd, &c, 1) == -1) {
383 dln_errno = errno;
384 return -1;
385 }
386 if (c != '!') goto err_noexec;
387
388 p = buf;
389 /* skip forwarding spaces */
390 while (read(fd, &c, 1) == 1) {
391 if (c == '\n') goto err_noexec;
392 if (c != '\t' && c != ' ') {
393 *p++ = c;
394 break;
395 }
396 }
397 /* read in command name */
398 while (read(fd, p, 1) == 1) {
399 if (*p == '\n' || *p == '\t' || *p == ' ') break;
400 p++;
401 if (p-buf >= MAXPATHLEN) {
402 dln_errno = ENAMETOOLONG;
403 return -1;
404 }
405 }
406 *p = '\0';
407
408 return dln_init(buf);
409 }
410 dln_init_p = 1;
411 undef_tbl = st_init_strtable();
412 close(fd);
413 return 0;
414
415 err_noexec:
416 close(fd);
417 dln_errno = DLN_ENOEXEC;
418 return -1;
419}
420
421static long
422load_text_data(int fd, struct exec *hdrp, int bss, long disp)
423{
424 int size;
425 unsigned char* addr;
426
427 lseek(fd, disp + N_TXTOFF(*hdrp), 0);
428 size = hdrp->a_text + hdrp->a_data;
429
430 if (bss == -1) size += hdrp->a_bss;
431 else if (bss > 1) size += bss;
432
433 addr = (unsigned char*)xmalloc(size);
434 if (addr == NULL) {
435 dln_errno = errno;
436 return 0;
437 }
438
439 if (read(fd, addr, size) != size) {
440 dln_errno = errno;
441 free(addr);
442 return 0;
443 }
444
445 if (bss == -1) {
446 memset(addr + hdrp->a_text + hdrp->a_data, 0, hdrp->a_bss);
447 }
448 else if (bss > 0) {
449 memset(addr + hdrp->a_text + hdrp->a_data, 0, bss);
450 }
451
452 return (long)addr;
453}
454
455static int
456undef_print(char *key, char *value)
457{
458 fprintf(stderr, " %s\n", key);
459 return ST_CONTINUE;
460}
461
462static void
463dln_print_undef(void)
464{
465 fprintf(stderr, " Undefined symbols:\n");
466 st_foreach(undef_tbl, undef_print, NULL);
467}
468
469static void
470dln_undefined(void)
471{
472 if (undef_tbl->num_entries > 0) {
473 fprintf(stderr, "dln: Calling undefined function\n");
474 dln_print_undef();
475 dln_exit(1);
476 }
477}
478
479struct undef {
480 char *name;
481 struct relocation_info reloc;
482 long base;
483 char *addr;
484 union {
485 char c;
486 short s;
487 long l;
488 } u;
489};
490
491static st_table *reloc_tbl = NULL;
492static void
493link_undef(const char *name, long base, struct relocation_info *reloc)
494{
495 static int u_no = 0;
496 struct undef *obj;
497 char *addr = (char*)(reloc->r_address + base);
498
499 obj = (struct undef*)xmalloc(sizeof(struct undef));
500 obj->name = strdup(name);
501 obj->reloc = *reloc;
502 obj->base = base;
503 switch (R_LENGTH(reloc)) {
504 case 0: /* byte */
505 obj->u.c = *addr;
506 break;
507 case 1: /* word */
508 obj->u.s = *(short*)addr;
509 break;
510 case 2: /* long */
511 obj->u.l = *(long*)addr;
512 break;
513 }
514 if (reloc_tbl == NULL) {
515 reloc_tbl = st_init_numtable();
516 }
517 st_insert(reloc_tbl, u_no++, obj);
518}
519
520struct reloc_arg {
521 const char *name;
522 long value;
523};
524
525static int
526reloc_undef(int no, struct undef *undef, struct reloc_arg *arg)
527{
528 int datum;
529 char *address;
530#if defined(__sun) && defined(__sparc)
531 unsigned int mask = 0;
532#endif
533
534 if (strcmp(arg->name, undef->name) != 0) return ST_CONTINUE;
535 address = (char*)(undef->base + undef->reloc.r_address);
536 datum = arg->value;
537
538 if (R_PCREL(&(undef->reloc))) datum -= undef->base;
539#if defined(__sun) && defined(__sparc)
540 datum += undef->reloc.r_addend;
541 datum >>= R_RIGHTSHIFT(&(undef->reloc));
542 mask = (1 << R_BITSIZE(&(undef->reloc))) - 1;
543 mask |= mask -1;
544 datum &= mask;
545 switch (R_LENGTH(&(undef->reloc))) {
546 case 0:
547 *address = undef->u.c;
548 *address &= ~mask;
549 *address |= datum;
550 break;
551 case 1:
552 *(short *)address = undef->u.s;
553 *(short *)address &= ~mask;
554 *(short *)address |= datum;
555 break;
556 case 2:
557 *(long *)address = undef->u.l;
558 *(long *)address &= ~mask;
559 *(long *)address |= datum;
560 break;
561 }
562#else
563 switch (R_LENGTH(&(undef->reloc))) {
564 case 0: /* byte */
565 if (R_MEMORY_SUB(&(undef->reloc)))
566 *address = datum - *address;
567 else *address = undef->u.c + datum;
568 break;
569 case 1: /* word */
570 if (R_MEMORY_SUB(&(undef->reloc)))
571 *(short*)address = datum - *(short*)address;
572 else *(short*)address = undef->u.s + datum;
573 break;
574 case 2: /* long */
575 if (R_MEMORY_SUB(&(undef->reloc)))
576 *(long*)address = datum - *(long*)address;
577 else *(long*)address = undef->u.l + datum;
578 break;
579 }
580#endif
581 free(undef->name);
582 free(undef);
583 return ST_DELETE;
584}
585
586static void
587unlink_undef(const char *name, long value)
588{
589 struct reloc_arg arg;
590
591 arg.name = name;
592 arg.value = value;
593 st_foreach(reloc_tbl, reloc_undef, &arg);
594}
595
596#ifdef N_INDR
597struct indr_data {
598 char *name0, *name1;
599};
600
601static int
602reloc_repl(int no, struct undef *undef, struct indr_data *data)
603{
604 if (strcmp(data->name0, undef->name) == 0) {
605 free(undef->name);
606 undef->name = strdup(data->name1);
607 }
608 return ST_CONTINUE;
609}
610#endif
611
612static int
613load_1(int fd, long disp, const char *need_init)
614{
615 static const char *libc = LIBC_NAME;
616 struct exec hdr;
617 struct relocation_info *reloc = NULL;
618 long block = 0;
619 long new_common = 0; /* Length of new common */
620 struct nlist *syms = NULL;
621 struct nlist *sym;
622 struct nlist *end;
623 int init_p = 0;
624
625 if (load_header(fd, &hdr, disp) == -1) return -1;
626 if (INVALID_OBJECT(hdr)) {
627 dln_errno = DLN_ENOEXEC;
628 return -1;
629 }
630 reloc = load_reloc(fd, &hdr, disp);
631 if (reloc == NULL) return -1;
632
633 syms = load_sym(fd, &hdr, disp);
634 if (syms == NULL) {
635 free(reloc);
636 return -1;
637 }
638
639 sym = syms;
640 end = syms + (hdr.a_syms / sizeof(struct nlist));
641 while (sym < end) {
642 struct nlist *old_sym;
643 int value = sym->n_value;
644
645#ifdef N_INDR
646 if (sym->n_type == (N_INDR | N_EXT)) {
647 char *key = sym->n_un.n_name;
648
649 if (st_lookup(sym_tbl, sym[1].n_un.n_name, &old_sym)) {
650 if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) {
651 unlink_undef(key, old_sym->n_value);
652 free(key);
653 }
654 }
655 else {
656 struct indr_data data;
657
658 data.name0 = sym->n_un.n_name;
659 data.name1 = sym[1].n_un.n_name;
660 st_foreach(reloc_tbl, reloc_repl, &data);
661
662 st_insert(undef_tbl, strdup(sym[1].n_un.n_name), NULL);
663 if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) {
664 free(key);
665 }
666 }
667 sym += 2;
668 continue;
669 }
670#endif
671 if (sym->n_type == (N_UNDF | N_EXT)) {
672 if (st_lookup(sym_tbl, sym->n_un.n_name, &old_sym) == 0) {
673 old_sym = NULL;
674 }
675
676 if (value) {
677 if (old_sym) {
678 sym->n_type = N_EXT | N_COMM;
679 sym->n_value = old_sym->n_value;
680 }
681 else {
682 int rnd =
683 value >= sizeof(double) ? sizeof(double) - 1
684 : value >= sizeof(long) ? sizeof(long) - 1
685 : sizeof(short) - 1;
686
687 sym->n_type = N_COMM;
688 new_common += rnd;
689 new_common &= ~(long)rnd;
690 sym->n_value = new_common;
691 new_common += value;
692 }
693 }
694 else {
695 if (old_sym) {
696 sym->n_type = N_EXT | N_COMM;
697 sym->n_value = old_sym->n_value;
698 }
699 else {
700 sym->n_value = (long)dln_undefined;
701 st_insert(undef_tbl, strdup(sym->n_un.n_name), NULL);
702 }
703 }
704 }
705 sym++;
706 }
707
708 block = load_text_data(fd, &hdr, hdr.a_bss + new_common, disp);
709 if (block == 0) goto err_exit;
710
711 sym = syms;
712 while (sym < end) {
713 struct nlist *new_sym;
714 char *key;
715
716 switch (sym->n_type) {
717 case N_COMM:
718 sym->n_value += hdr.a_text + hdr.a_data;
719 case N_TEXT|N_EXT:
720 case N_DATA|N_EXT:
721
722 sym->n_value += block;
723
724 if (st_lookup(sym_tbl, sym->n_un.n_name, &new_sym) != 0
725 && new_sym->n_value != (long)dln_undefined) {
726 dln_errno = DLN_ECONFL;
727 goto err_exit;
728 }
729
730 key = sym->n_un.n_name;
731 if (st_delete(undef_tbl, (st_data_t*)&key, NULL) != 0) {
732 unlink_undef(key, sym->n_value);
733 free(key);
734 }
735
736 new_sym = (struct nlist*)xmalloc(sizeof(struct nlist));
737 *new_sym = *sym;
738 new_sym->n_un.n_name = strdup(sym->n_un.n_name);
739 st_insert(sym_tbl, new_sym->n_un.n_name, new_sym);
740 break;
741
742 case N_TEXT:
743 case N_DATA:
744 sym->n_value += block;
745 break;
746 }
747 sym++;
748 }
749
750 /*
751 * First comes the text-relocation
752 */
753 {
754 struct relocation_info * rel = reloc;
755 struct relocation_info * rel_beg = reloc +
756 (hdr.a_trsize/sizeof(struct relocation_info));
757 struct relocation_info * rel_end = reloc +
758 (hdr.a_trsize+hdr.a_drsize)/sizeof(struct relocation_info);
759
760 while (rel < rel_end) {
761 char *address = (char*)(rel->r_address + block);
762 long datum = 0;
763#if defined(__sun) && defined(__sparc)
764 unsigned int mask = 0;
765#endif
766
767 if (rel >= rel_beg)
768 address += hdr.a_text;
769
770 if (rel->r_extern) { /* Look it up in symbol-table */
771 sym = &(syms[R_SYMBOL(rel)]);
772 switch (sym->n_type) {
773 case N_EXT|N_UNDF:
774 link_undef(sym->n_un.n_name, block, rel);
775 case N_EXT|N_COMM:
776 case N_COMM:
777 datum = sym->n_value;
778 break;
779 default:
780 goto err_exit;
781 }
782 } /* end.. look it up */
783 else { /* is static */
784 switch (R_SYMBOL(rel)) {
785 case N_TEXT:
786 case N_DATA:
787 datum = block;
788 break;
789 case N_BSS:
790 datum = block + new_common;
791 break;
792 case N_ABS:
793 break;
794 }
795 } /* end .. is static */
796 if (R_PCREL(rel)) datum -= block;
797
798#if defined(__sun) && defined(__sparc)
799 datum += rel->r_addend;
800 datum >>= R_RIGHTSHIFT(rel);
801 mask = (1 << R_BITSIZE(rel)) - 1;
802 mask |= mask -1;
803 datum &= mask;
804
805 switch (R_LENGTH(rel)) {
806 case 0:
807 *address &= ~mask;
808 *address |= datum;
809 break;
810 case 1:
811 *(short *)address &= ~mask;
812 *(short *)address |= datum;
813 break;
814 case 2:
815 *(long *)address &= ~mask;
816 *(long *)address |= datum;
817 break;
818 }
819#else
820 switch (R_LENGTH(rel)) {
821 case 0: /* byte */
822 if (datum < -128 || datum > 127) goto err_exit;
823 *address += datum;
824 break;
825 case 1: /* word */
826 *(short *)address += datum;
827 break;
828 case 2: /* long */
829 *(long *)address += datum;
830 break;
831 }
832#endif
833 rel++;
834 }
835 }
836
837 if (need_init) {
838 int len;
839 char **libs_to_be_linked = 0;
840 char *buf;
841
842 if (undef_tbl->num_entries > 0) {
843 if (load_lib(libc) == -1) goto err_exit;
844 }
845
846 init_funcname(&buf, need_init);
847 len = strlen(buf);
848
849 for (sym = syms; sym<end; sym++) {
850 char *name = sym->n_un.n_name;
851 if (name[0] == '_' && sym->n_value >= block) {
852 if (strcmp(name+1, "dln_libs_to_be_linked") == 0) {
853 libs_to_be_linked = (char**)sym->n_value;
854 }
855 else if (strcmp(name+1, buf) == 0) {
856 init_p = 1;
857 ((int (*)())sym->n_value)();
858 }
859 }
860 }
861 if (libs_to_be_linked && undef_tbl->num_entries > 0) {
862 while (*libs_to_be_linked) {
863 load_lib(*libs_to_be_linked);
864 libs_to_be_linked++;
865 }
866 }
867 }
868 free(reloc);
869 free(syms);
870 if (need_init) {
871 if (init_p == 0) {
872 dln_errno = DLN_ENOINIT;
873 return -1;
874 }
875 if (undef_tbl->num_entries > 0) {
876 if (load_lib(libc) == -1) goto err_exit;
877 if (undef_tbl->num_entries > 0) {
878 dln_errno = DLN_EUNDEF;
879 return -1;
880 }
881 }
882 }
883 return 0;
884
885 err_exit:
886 if (syms) free(syms);
887 if (reloc) free(reloc);
888 if (block) free((char*)block);
889 return -1;
890}
891
892static int target_offset;
893static int
894search_undef(const char *key, int value, st_table *lib_tbl)
895{
896 long offset;
897
898 if (st_lookup(lib_tbl, key, &offset) == 0) return ST_CONTINUE;
899 target_offset = offset;
900 return ST_STOP;
901}
902
903struct symdef {
904 int rb_str_index;
905 int lib_offset;
906};
907
908const char *dln_librrb_ary_path = DLN_DEFAULT_LIB_PATH;
909
910static int
911load_lib(const char *lib)
912{
913 char *path, *file, fbuf[MAXPATHLEN];
914 char *envpath = 0;
915 char armagic[SARMAG];
916 int fd, size;
917 struct ar_hdr ahdr;
918 st_table *lib_tbl = NULL;
919 int *data, nsym;
920 struct symdef *base;
921 char *name_base;
922
923 if (dln_init_p == 0) {
924 dln_errno = DLN_ENOINIT;
925 return -1;
926 }
927
928 if (undef_tbl->num_entries == 0) return 0;
929 dln_errno = DLN_EBADLIB;
930
931 if (lib[0] == '-' && lib[1] == 'l') {
932 long len = strlen(lib) + 4;
933 char *p = alloca(len);
934 snprintf(p, len, "lib%s.a", lib+2);
935 lib = p;
936 }
937
938 /* library search path: */
939 /* look for environment variable DLN_LIBRARY_PATH first. */
940 /* then variable dln_librrb_ary_path. */
941 /* if path is still NULL, use "." for path. */
942 path = getenv("DLN_LIBRARY_PATH");
943 if (path == NULL) path = dln_librrb_ary_path;
944 else path = envpath = strdup(path);
945
946 file = dln_find_file_r(lib, path, fbuf, sizeof(fbuf));
947 if (envpath) free(envpath);
948 fd = open(file, O_RDONLY);
949 if (fd == -1) goto syserr;
950 size = read(fd, armagic, SARMAG);
951 if (size == -1) goto syserr;
952
953 if (size != SARMAG) {
954 dln_errno = DLN_ENOTLIB;
955 goto badlib;
956 }
957 size = read(fd, &ahdr, sizeof(ahdr));
958 if (size == -1) goto syserr;
959 if (size != sizeof(ahdr) || sscanf(ahdr.ar_size, "%d", &size) != 1) {
960 goto badlib;
961 }
962
963 if (strncmp(ahdr.ar_name, "__.SYMDEF", 9) == 0) {
964 /* make hash table from __.SYMDEF */
965
966 lib_tbl = st_init_strtable();
967 data = (int*)xmalloc(size);
968 if (data == NULL) goto syserr;
969 size = read(fd, data, size);
970 nsym = *data / sizeof(struct symdef);
971 base = (struct symdef*)(data + 1);
972 name_base = (char*)(base + nsym) + sizeof(int);
973 while (nsym > 0) {
974 char *name = name_base + base->rb_str_index;
975
976 st_insert(lib_tbl, name, base->lib_offset + sizeof(ahdr));
977 nsym--;
978 base++;
979 }
980 for (;;) {
981 target_offset = -1;
982 st_foreach(undef_tbl, search_undef, lib_tbl);
983 if (target_offset == -1) break;
984 if (load_1(fd, target_offset, 0) == -1) {
985 st_free_table(lib_tbl);
986 free(data);
987 goto badlib;
988 }
989 if (undef_tbl->num_entries == 0) break;
990 }
991 free(data);
992 st_free_table(lib_tbl);
993 }
994 else {
995 /* linear library, need to scan (FUTURE) */
996
997 for (;;) {
998 int offset = SARMAG;
999 int found = 0;
1000 struct exec hdr;
1001 struct nlist *syms, *sym, *end;
1002
1003 while (undef_tbl->num_entries > 0) {
1004 found = 0;
1005 lseek(fd, offset, 0);
1006 size = read(fd, &ahdr, sizeof(ahdr));
1007 if (size == -1) goto syserr;
1008 if (size == 0) break;
1009 if (size != sizeof(ahdr)
1010 || sscanf(ahdr.ar_size, "%d", &size) != 1) {
1011 goto badlib;
1012 }
1013 offset += sizeof(ahdr);
1014 if (load_header(fd, &hdr, offset) == -1)
1015 goto badlib;
1016 syms = load_sym(fd, &hdr, offset);
1017 if (syms == NULL) goto badlib;
1018 sym = syms;
1019 end = syms + (hdr.a_syms / sizeof(struct nlist));
1020 while (sym < end) {
1021 if (sym->n_type == N_EXT|N_TEXT
1022 && st_lookup(undef_tbl, sym->n_un.n_name, NULL)) {
1023 break;
1024 }
1025 sym++;
1026 }
1027 if (sym < end) {
1028 found++;
1029 free(syms);
1030 if (load_1(fd, offset, 0) == -1) {
1031 goto badlib;
1032 }
1033 }
1034 offset += size;
1035 if (offset & 1) offset++;
1036 }
1037 if (found) break;
1038 }
1039 }
1040 close(fd);
1041 return 0;
1042
1043 syserr:
1044 dln_errno = errno;
1045 badlib:
1046 if (fd >= 0) close(fd);
1047 return -1;
1048}
1049
1050static int
1051load(const char *file)
1052{
1053 int fd;
1054 int result;
1055
1056 if (dln_init_p == 0) {
1057 if (dln_init(dln_argv0) == -1) return -1;
1058 }
1059 result = strlen(file);
1060 if (file[result-1] == 'a') {
1061 return load_lib(file);
1062 }
1063
1064 fd = open(file, O_RDONLY);
1065 if (fd == -1) {
1066 dln_errno = errno;
1067 return -1;
1068 }
1069 result = load_1(fd, 0, file);
1070 close(fd);
1071
1072 return result;
1073}
1074
1075void*
1076dln_sym(const char *name)
1077{
1078 struct nlist *sym;
1079
1080 if (st_lookup(sym_tbl, name, &sym))
1081 return (void*)sym->n_value;
1082 return NULL;
1083}
1084
1085#endif /* USE_DLN_A_OUT */
1086
1087#ifdef USE_DLN_DLOPEN
1088# include <dlfcn.h>
1089#endif
1090
1091#ifdef __hpux
1092#include <errno.h>
1093#include "dl.h"
1094#endif
1095
1096#if defined(_AIX)
1097#include <ctype.h> /* for isdigit() */
1098#include <errno.h> /* for global errno */
1099#include <sys/ldr.h>
1100#endif
1101
1102#ifdef NeXT
1103#if NS_TARGET_MAJOR < 4
1104#include <mach-o/rld.h>
1105#else
1106#include <mach-o/dyld.h>
1107#ifndef NSLINKMODULE_OPTION_BINDNOW
1108#define NSLINKMODULE_OPTION_BINDNOW 1
1109#endif
1110#endif
1111#else
1112#ifdef MACOSX_DYLD
1113#include <mach-o/dyld.h>
1114#endif
1115#endif
1116
1117#ifdef _WIN32
1118#include <windows.h>
1119#include <imagehlp.h>
1120#endif
1121
1122#ifdef _WIN32
1123static const char *
1124dln_strerror(char *message, size_t size)
1125{
1126 int error = GetLastError();
1127 char *p = message;
1128 size_t len = snprintf(message, size, "%d: ", error);
1129
1130#define format_message(sublang) FormatMessage(\
1131 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \
1132 NULL, error, MAKELANGID(LANG_NEUTRAL, (sublang)), \
1133 message + len, size - len, NULL)
1134 if (format_message(SUBLANG_ENGLISH_US) == 0)
1135 format_message(SUBLANG_DEFAULT);
1136 for (p = message + len; *p; p++) {
1137 if (*p == '\n' || *p == '\r')
1138 *p = ' ';
1139 }
1140 return message;
1141}
1142#define dln_strerror() dln_strerror(message, sizeof message)
1143#elif ! defined _AIX
1144static const char *
1145dln_strerror(void)
1146{
1147#ifdef USE_DLN_A_OUT
1148 char *strerror();
1149
1150 switch (dln_errno) {
1151 case DLN_ECONFL:
1152 return "Symbol name conflict";
1153 case DLN_ENOINIT:
1154 return "No initializer given";
1155 case DLN_EUNDEF:
1156 return "Unresolved symbols";
1157 case DLN_ENOTLIB:
1158 return "Not a library file";
1159 case DLN_EBADLIB:
1160 return "Malformed library file";
1161 case DLN_EINIT:
1162 return "Not initialized";
1163 default:
1164 return strerror(dln_errno);
1165 }
1166#endif
1167
1168#ifdef USE_DLN_DLOPEN
1169 return (char*)dlerror();
1170#endif
1171}
1172#endif
1173
1174#if defined(_AIX)
1175static void
1176aix_loaderror(const char *pathname)
1177{
1178 char *message[1024], errbuf[1024];
1179 int i;
1180#define ERRBUF_APPEND(s) strlcat(errbuf, (s), sizeof(errbuf))
1181 snprintf(errbuf, sizeof(errbuf), "load failed - %s. ", pathname);
1182
1183 if (loadquery(L_GETMESSAGES, &message[0], sizeof(message)) != -1) {
1184 ERRBUF_APPEND("Please issue below command for detailed reasons:\n\t");
1185 ERRBUF_APPEND("/usr/sbin/execerror ruby ");
1186 for (i=0; message[i]; i++) {
1187 ERRBUF_APPEND("\"");
1188 ERRBUF_APPEND(message[i]);
1189 ERRBUF_APPEND("\" ");
1190 }
1191 ERRBUF_APPEND("\n");
1192 }
1193 else {
1194 ERRBUF_APPEND(strerror(errno));
1195 ERRBUF_APPEND("[loadquery failed]");
1196 }
1197 dln_loaderror("%s", errbuf);
1198}
1199#endif
1200
1201#if defined _WIN32 && defined RUBY_EXPORT
1202HANDLE rb_libruby_handle(void);
1203
1204static int
1205rb_w32_check_imported(HMODULE ext, HMODULE mine)
1206{
1207 ULONG size;
1208 const IMAGE_IMPORT_DESCRIPTOR *desc;
1209
1210 desc = ImageDirectoryEntryToData(ext, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size);
1211 if (!desc) return 0;
1212 while (desc->Name) {
1213 PIMAGE_THUNK_DATA pint = (PIMAGE_THUNK_DATA)((char *)ext + desc->Characteristics);
1214 PIMAGE_THUNK_DATA piat = (PIMAGE_THUNK_DATA)((char *)ext + desc->FirstThunk);
1215 for (; piat->u1.Function; piat++, pint++) {
1216 static const char prefix[] = "rb_";
1217 PIMAGE_IMPORT_BY_NAME pii;
1218 const char *name;
1219
1220 if (IMAGE_SNAP_BY_ORDINAL(pint->u1.Ordinal)) continue;
1221 pii = (PIMAGE_IMPORT_BY_NAME)((char *)ext + (size_t)pint->u1.AddressOfData);
1222 name = (const char *)pii->Name;
1223 if (strncmp(name, prefix, sizeof(prefix) - 1) == 0) {
1224 FARPROC addr = GetProcAddress(mine, name);
1225 if (addr) return (FARPROC)piat->u1.Function == addr;
1226 }
1227 }
1228 desc++;
1229 }
1230 return 1;
1231}
1232#endif
1233
1234#if defined(DLN_NEEDS_ALT_SEPARATOR) && DLN_NEEDS_ALT_SEPARATOR
1235#define translit_separator(src) do { \
1236 char *tmp = ALLOCA_N(char, strlen(src) + 1), *p = tmp, c; \
1237 do { \
1238 *p++ = ((c = *file++) == '/') ? DLN_NEEDS_ALT_SEPARATOR : c; \
1239 } while (c); \
1240 (src) = tmp; \
1241 } while (0)
1242#else
1243#define translit_separator(str) (void)(str)
1244#endif
1245
1246#ifdef USE_DLN_DLOPEN
1248#if defined(__clang__) || GCC_VERSION_SINCE(4, 2, 0)
1249COMPILER_WARNING_IGNORED(-Wpedantic)
1250#endif
1251static bool
1252dln_incompatible_library_p(void *handle)
1253{
1254 void *ex = dlsym(handle, EXTERNAL_PREFIX"ruby_xmalloc");
1255 return ex && ex != ruby_xmalloc;
1256}
1258#endif
1259
1260void*
1261dln_load(const char *file)
1262{
1263#if (defined _WIN32 || defined USE_DLN_DLOPEN) && defined RUBY_EXPORT
1264 static const char incompatible[] = "incompatible library version";
1265#endif
1266#if !defined(_AIX) && !defined(NeXT)
1267 const char *error = 0;
1268#endif
1269
1270#if defined _WIN32
1271 HINSTANCE handle;
1272 WCHAR *winfile;
1273 char message[1024];
1274 void (*init_fct)();
1275 char *buf;
1276
1277 /* Load the file as an object one */
1278 init_funcname(&buf, file);
1279
1280 /* Convert the file path to wide char */
1281 winfile = rb_w32_mbstr_to_wstr(CP_UTF8, file, -1, NULL);
1282 if (!winfile) {
1283 dln_memerror();
1284 }
1285
1286 /* Load file */
1287 handle = LoadLibraryW(winfile);
1288 free(winfile);
1289
1290 if (!handle) {
1291 error = dln_strerror();
1292 goto failed;
1293 }
1294
1295#if defined _WIN32 && defined RUBY_EXPORT
1296 if (!rb_w32_check_imported(handle, rb_libruby_handle())) {
1297 FreeLibrary(handle);
1298 error = incompatible;
1299 goto failed;
1300 }
1301#endif
1302
1303 if ((init_fct = (void(*)())GetProcAddress(handle, buf)) == NULL) {
1304 dln_loaderror("%s - %s\n%s", dln_strerror(), buf, file);
1305 }
1306
1307 /* Call the init code */
1308 (*init_fct)();
1309 return handle;
1310#else
1311#ifdef USE_DLN_A_OUT
1312 if (load(file) == -1) {
1313 error = dln_strerror();
1314 goto failed;
1315 }
1316 return 0;
1317#else
1318
1319 char *buf;
1320 /* Load the file as an object one */
1321 init_funcname(&buf, file);
1322 translit_separator(file);
1323
1324#ifdef USE_DLN_DLOPEN
1325#define DLN_DEFINED
1326 {
1327 void *handle;
1328 void (*init_fct)();
1329
1330#ifndef RTLD_LAZY
1331# define RTLD_LAZY 1
1332#endif
1333#ifdef __INTERIX
1334# undef RTLD_GLOBAL
1335#endif
1336#ifndef RTLD_GLOBAL
1337# define RTLD_GLOBAL 0
1338#endif
1339
1340 /* Load file */
1341 if ((handle = (void*)dlopen(file, RTLD_LAZY|RTLD_GLOBAL)) == NULL) {
1342 error = dln_strerror();
1343 goto failed;
1344 }
1345# if defined RUBY_EXPORT
1346 {
1347 if (dln_incompatible_library_p(handle)) {
1348
1349# if defined __APPLE__ && \
1350 defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
1351 (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11)
1352 /* dlclose() segfaults */
1353 rb_fatal("%s - %s", incompatible, file);
1354# else
1355 dlclose(handle);
1356 error = incompatible;
1357 goto failed;
1358# endif
1359 }
1360 }
1361# endif
1362
1363 init_fct = (void(*)())(VALUE)dlsym(handle, buf);
1364 if (init_fct == NULL) {
1365 const size_t errlen = strlen(error = dln_strerror()) + 1;
1366 error = memcpy(ALLOCA_N(char, errlen), error, errlen);
1367 dlclose(handle);
1368 goto failed;
1369 }
1370 /* Call the init code */
1371 (*init_fct)();
1372
1373 return handle;
1374 }
1375#endif /* USE_DLN_DLOPEN */
1376
1377#ifdef __hpux
1378#define DLN_DEFINED
1379 {
1380 shl_t lib = NULL;
1381 int flags;
1382 void (*init_fct)();
1383
1384 flags = BIND_DEFERRED;
1385 lib = shl_load(file, flags, 0);
1386 if (lib == NULL) {
1387 extern int errno;
1388 dln_loaderror("%s - %s", strerror(errno), file);
1389 }
1390 shl_findsym(&lib, buf, TYPE_PROCEDURE, (void*)&init_fct);
1391 if (init_fct == NULL) {
1392 shl_findsym(&lib, buf, TYPE_UNDEFINED, (void*)&init_fct);
1393 if (init_fct == NULL) {
1394 errno = ENOSYM;
1395 dln_loaderror("%s - %s", strerror(ENOSYM), file);
1396 }
1397 }
1398 (*init_fct)();
1399 return (void*)lib;
1400 }
1401#endif /* hpux */
1402
1403#if defined(_AIX)
1404#define DLN_DEFINED
1405 {
1406 void (*init_fct)();
1407
1408 init_fct = (void(*)())load((char*)file, 1, 0);
1409 if (init_fct == NULL) {
1410 aix_loaderror(file);
1411 }
1412 if (loadbind(0, (void*)dln_load, (void*)init_fct) == -1) {
1413 aix_loaderror(file);
1414 }
1415 (*init_fct)();
1416 return (void*)init_fct;
1417 }
1418#endif /* _AIX */
1419
1420#if defined(MACOSX_DYLD)
1421#define DLN_DEFINED
1422/*----------------------------------------------------
1423 By SHIROYAMA Takayuki Psi@fortune.nest.or.jp
1424
1425 Special Thanks...
1426 Yu tomoak-i@is.aist-nara.ac.jp,
1427 Mi hisho@tasihara.nest.or.jp,
1428 sunshine@sunshineco.com,
1429 and... Miss ARAI Akino(^^;)
1430 ----------------------------------------------------*/
1431 {
1432 int dyld_result;
1433 NSObjectFileImage obj_file; /* handle, but not use it */
1434 /* "file" is module file name .
1435 "buf" is pointer to initial function name with "_" . */
1436
1437 void (*init_fct)();
1438
1439
1440 dyld_result = NSCreateObjectFileImageFromFile(file, &obj_file);
1441
1442 if (dyld_result != NSObjectFileImageSuccess) {
1443 dln_loaderror("Failed to load %.200s", file);
1444 }
1445
1446 NSLinkModule(obj_file, file, NSLINKMODULE_OPTION_BINDNOW);
1447
1448 /* lookup the initial function */
1449 if (!NSIsSymbolNameDefined(buf)) {
1450 dln_loaderror("Failed to lookup Init function %.200s",file);
1451 }
1452 init_fct = NSAddressOfSymbol(NSLookupAndBindSymbol(buf));
1453 (*init_fct)();
1454
1455 return (void*)init_fct;
1456 }
1457#endif
1458
1459#ifndef DLN_DEFINED
1461#endif
1462
1463#endif /* USE_DLN_A_OUT */
1464#endif
1465#if !defined(_AIX) && !defined(NeXT)
1466 failed:
1467 dln_loaderror("%s - %s", error, file);
1468#endif
1469
1470 return 0; /* dummy return */
1471}
int errno
#define L(x)
Definition: asm.h:125
#define sym(x)
Definition: date_core.c:3717
enum @73::@75::@76 mask
#define dln_memerror
Definition: dln.c:20
#define EXTERNAL_PREFIX
Definition: dln.c:109
#define dln_notimplement
Definition: dln.c:19
void * dln_load(const char *file)
Definition: dln.c:1261
char * getenv()
#define isdirsep(x)
Definition: dln.c:116
#define FUNCNAME_PREFIX
Definition: dln.c:111
#define MAXPATHLEN
Definition: dln.c:69
#define translit_separator(str)
Definition: dln.c:1243
#define dln_exit
Definition: dln.c:21
#define init_funcname(buf, file)
Definition: dln.c:136
#define free(x)
Definition: dln.c:52
void rb_fatal(const char *fmt,...)
Definition: error.c:2722
const char * name
Definition: nkf.c:208
#define alloca(size)
#define NULL
#define ALLOCA_N(type, n)
#define COMPILER_WARNING_PUSH
unsigned long st_data_t
size_t strlen(const char *)
int strcmp(const char *, const char *)
int int int int int sscanf(const char *__restrict__, const char *__restrict__,...) __attribute__((__format__(__scanf__
int close(int __fildes)
int int int int int int vfprintf(FILE *__restrict__, const char *__restrict__, __gnuc_va_list) __attribute__((__format__(__printf__
const VALUE VALUE obj
const rb_iseq_t const char * error
#define xrealloc
char * strerror(int)
Definition: strerror.c:11
#define ENAMETOOLONG
int snprintf(char *__restrict__, size_t, const char *__restrict__,...) __attribute__((__format__(__printf__
#define COMPILER_WARNING_POP
int fprintf(FILE *__restrict__, const char *__restrict__,...) __attribute__((__format__(__printf__
unsigned long VALUE
#define stderr
#define xmalloc
uint32_t i
int strncmp(const char *, const char *, size_t)
__inline__ const void *__restrict__ size_t len
#define va_end(v)
__gnuc_va_list va_list
#define long
void * memset(void *, int, size_t)
#define short
#define va_start(v, l)
#define TRUE
unsigned int size
long unsigned int size_t
char * strdup(const char *) __attribute__((__malloc__)) __attribute__((__warn_unused_result__))
struct rb_call_cache buf
void abort(void) __attribute__((__noreturn__))
void * memcpy(void *__restrict__, const void *__restrict__, size_t)
__inline__ int
if((__builtin_expect(!!(!me), 0)))
#define xcalloc
#define COMPILER_WARNING_IGNORED(flag)
off_t lseek(int __fildes, off_t __offset, int __whence)
_ssize_t read(int __fd, void *__buf, size_t __nbyte)
void * ruby_xmalloc(size_t) __attribute__((__malloc__)) __attribute__((__returns_nonnull__)) __attribute__((alloc_size(1)))
Definition: gc.c:12008
void st_free_table(st_table *tab)
Definition: st.c:709
int st_delete(st_table *tab, st_data_t *key, st_data_t *value)
Definition: st.c:1418
st_table * st_init_numtable(void)
Definition: st.c:653
st_table * st_init_strtable(void)
Definition: st.c:668
int st_insert(st_table *tab, st_data_t key, st_data_t value)
Definition: st.c:1171
int st_lookup(st_table *tab, st_data_t key, st_data_t *value)
Definition: st.c:1101
int st_foreach(st_table *tab, st_foreach_callback_func *func, st_data_t arg)
Definition: st.c:1717
#define rb_str_index(str, sub, offset)
Definition: string.c:3490
Definition: sdbm.h:50
#define dln_find_exe_r
Definition: win32.c:84
#define dln_find_file_r
Definition: win32.c:85
WCHAR * rb_w32_mbstr_to_wstr(UINT, const char *, int, long *)
Definition: win32.c:2179