1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13: #include "ruby/ruby.h"
14: #include "dln.h"
15:
16: #ifdef HAVE_STDLIB_H
17: # include <stdlib.h>
18: #endif
19:
20: #ifdef __CHECKER__
21: #undef HAVE_DLOPEN
22: #undef USE_DLN_A_OUT
23: #undef USE_DLN_DLOPEN
24: #endif
25:
26: #ifdef USE_DLN_A_OUT
27: char *dln_argv0;
28: #endif
29:
30: #if defined(HAVE_ALLOCA_H)
31: #include <alloca.h>
32: #endif
33:
34: #ifdef HAVE_STRING_H
35: # include <string.h>
36: #else
37: # include <strings.h>
38: #endif
39:
40: #ifndef xmalloc
41: void *xmalloc();
42: void *xcalloc();
43: void *xrealloc();
44: #endif
45:
46: #include <stdio.h>
47: #if defined(_WIN32) || defined(__VMS)
48: #include "missing/file.h"
49: #endif
50: #include <sys/types.h>
51: #include <sys/stat.h>
52:
53: #ifndef S_ISDIR
54: # define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
55: #endif
56:
57: #ifdef HAVE_SYS_PARAM_H
58: # include <sys/param.h>
59: #endif
60: #ifndef MAXPATHLEN
61: # define MAXPATHLEN 1024
62: #endif
63:
64: #ifdef HAVE_UNISTD_H
65: # include <unistd.h>
66: #endif
67:
68: #ifndef _WIN32
69: char *getenv();
70: #endif
71:
72: #if defined(__VMS)
73: #pragma builtins
74: #include <dlfcn.h>
75: #endif
76:
77: #ifdef __MACOS__
78: # include <TextUtils.h>
79: # include <CodeFragments.h>
80: # include <Aliases.h>
81: # include "macruby_private.h"
82: #endif
83:
84: #if defined(__APPLE__) && defined(__MACH__)
85: # if defined(HAVE_DLOPEN)
86:
87: # define MACOSX_DLOPEN
88: # else
89: # define MACOSX_DYLD
90: # endif
91: #endif
92:
93: #ifdef __BEOS__
94: # include <image.h>
95: #endif
96:
97: #ifndef NO_DLN_LOAD
98:
99: #if defined(HAVE_DLOPEN) && !defined(USE_DLN_A_OUT) && !defined(_AIX) && !defined(MACOSX_DYLD) && !defined(_UNICOSMP)
100:
101: # define USE_DLN_DLOPEN
102: #endif
103:
104: #ifndef FUNCNAME_PATTERN
105: # if defined(__hp9000s300) || (defined(__NetBSD__) && !defined(__ELF__)) || defined(__BORLANDC__) || (defined(__FreeBSD__) && !defined(__ELF__)) || (defined(__OpenBSD__) && !defined(__ELF__)) || defined(NeXT) || defined(__WATCOMC__) || defined(MACOSX_DYLD)
106: # define FUNCNAME_PATTERN "_Init_%s"
107: # else
108: # define FUNCNAME_PATTERN "Init_%s"
109: # endif
110: #endif
111:
112: static int
113: init_funcname_len(char **buf, const char *file)
114: {
115: char *p;
116: const char *slash;
117: int len;
118:
119:
120: for (slash = file-1; *file; file++)
121: #ifdef __MACOS__
122: if (*file == ':') slash = file;
123: #else
124: if (*file == '/') slash = file;
125: #endif
126:
127: len = strlen(FUNCNAME_PATTERN) + strlen(slash + 1);
128: *buf = xmalloc(len);
129: snprintf(*buf, len, FUNCNAME_PATTERN, slash + 1);
130: for (p = *buf; *p; p++) {
131: if (*p == '.') {
132: *p = '\0'; break;
133: }
134: }
135: return p - *buf;
136: }
137:
138: #define init_funcname(buf, file) do {\
139: int len = init_funcname_len(buf, file);\
140: char *tmp = ALLOCA_N(char, len+1);\
141: if (!tmp) {\
142: free(*buf);\
143: rb_memerror();\
144: }\
145: strcpy(tmp, *buf);\
146: free(*buf);\
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:
162: static int dln_errno;
163:
164: #define DLN_ENOEXEC ENOEXEC
165: #define DLN_ECONFL 1201
166: #define DLN_ENOINIT 1202
167: #define DLN_EUNDEF 1203
168: #define DLN_ENOTLIB 1204
169: #define DLN_EBADLIB 1205
170: #define DLN_EINIT 1206
171:
172: static 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:
188: static st_table *sym_tbl;
189: static st_table *undef_tbl;
190:
191: static int load_lib();
192:
193: static int
194: load_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:
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:
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])
235: static int reloc_r_rightshift[] = {
236: 0, 0, 0, 0, 0, 0, 2, 2, 10, 0, 0, 0, 0, 0, 0,
237: };
238: static int reloc_r_bitsize[] = {
239: 8, 16, 32, 8, 16, 32, 30, 22, 22, 22, 13, 10, 32, 32, 16,
240: };
241: static 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:
263: static struct relocation_info *
264: load_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:
286: static struct nlist *
287: load_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:
327: static st_table *
328: sym_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:
347: static int
348: dln_init(const char *prog)
349: {
350: char *file;
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(prog, NULL);
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) {
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:
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:
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:
421: static long
422: load_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:
455: static int
456: undef_print(char *key, char *value)
457: {
458: fprintf(stderr, " %s\n", key);
459: return ST_CONTINUE;
460: }
461:
462: static void
463: dln_print_undef()
464: {
465: fprintf(stderr, " Undefined symbols:\n");
466: st_foreach(undef_tbl, undef_print, NULL);
467: }
468:
469: static void
470: dln_undefined()
471: {
472: if (undef_tbl->num_entries > 0) {
473: fprintf(stderr, "dln: Calling undefined function\n");
474: dln_print_undef();
475: rb_exit(1);
476: }
477: }
478:
479: struct 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:
491: static st_table *reloc_tbl = NULL;
492: static void
493: link_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:
505: obj->u.c = *addr;
506: break;
507: case 1:
508: obj->u.s = *(short*)addr;
509: break;
510: case 2:
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:
520: struct reloc_arg {
521: const char *name;
522: long value;
523: };
524:
525: static int
526: reloc_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