From 1e760c0be3ed35874204114e7454509f740c0fe2 Mon Sep 17 00:00:00 2001 From: shyouhei Date: Wed, 22 Aug 2007 01:53:51 +0000 Subject: add tag v1_8_6_71 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/tags/v1_8_5_71@13189 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ruby_1_8_6/dln.c | 1889 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1889 insertions(+) create mode 100644 ruby_1_8_6/dln.c (limited to 'ruby_1_8_6/dln.c') diff --git a/ruby_1_8_6/dln.c b/ruby_1_8_6/dln.c new file mode 100644 index 0000000000..b405da6bff --- /dev/null +++ b/ruby_1_8_6/dln.c @@ -0,0 +1,1889 @@ +/********************************************************************** + + dln.c - + + $Author$ + $Date$ + created at: Tue Jan 18 17:05:06 JST 1994 + + Copyright (C) 1993-2003 Yukihiro Matsumoto + +**********************************************************************/ + +#include "ruby.h" +#include "dln.h" + +#ifdef HAVE_STDLIB_H +# include +#endif + +#ifdef __CHECKER__ +#undef HAVE_DLOPEN +#undef USE_DLN_A_OUT +#undef USE_DLN_DLOPEN +#endif + +#ifdef USE_DLN_A_OUT +char *dln_argv0; +#endif + +#if defined(HAVE_ALLOCA_H) +#include +#endif + +#ifdef HAVE_STRING_H +# include +#else +# include +#endif + +#ifndef xmalloc +void *xmalloc(); +void *xcalloc(); +void *xrealloc(); +#endif + +#include +#if defined(_WIN32) || defined(__VMS) +#include "missing/file.h" +#endif +#include +#include + +#ifndef S_ISDIR +# define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR) +#endif + +#ifdef HAVE_SYS_PARAM_H +# include +#endif +#ifndef MAXPATHLEN +# define MAXPATHLEN 1024 +#endif + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifndef _WIN32 +char *getenv(); +#endif + +#if defined(__VMS) +#pragma builtins +#include +#endif + +#ifdef __MACOS__ +# include +# include +# include +# include "macruby_private.h" +#endif + +#ifdef __BEOS__ +# include +#endif + +#ifndef NO_DLN_LOAD + +#if defined(HAVE_DLOPEN) && !defined(USE_DLN_A_OUT) && !defined(_AIX) && !defined(__APPLE__) && !defined(_UNICOSMP) +/* dynamic load with dlopen() */ +# define USE_DLN_DLOPEN +#endif + +#ifndef FUNCNAME_PATTERN +# if defined(__hp9000s300) || (defined(__NetBSD__) && !defined(__ELF__)) || defined(__BORLANDC__) || (defined(__FreeBSD__) && !defined(__ELF__)) || (defined(__OpenBSD__) && !defined(__ELF__)) || defined(NeXT) || defined(__WATCOMC__) || defined(__APPLE__) +# define FUNCNAME_PATTERN "_Init_%s" +# else +# define FUNCNAME_PATTERN "Init_%s" +# endif +#endif + +static int +init_funcname_len(buf, file) + char **buf; + const char *file; +{ + char *p; + const char *slash; + int len; + + /* Load the file as an object one */ + for (slash = file-1; *file; file++) /* Find position of last '/' */ +#ifdef __MACOS__ + if (*file == ':') slash = file; +#else + if (*file == '/') slash = file; +#endif + + len = strlen(FUNCNAME_PATTERN) + strlen(slash + 1); + *buf = xmalloc(len); + snprintf(*buf, len, FUNCNAME_PATTERN, slash + 1); + for (p = *buf; *p; p++) { /* Delete suffix if it exists */ + if (*p == '.') { + *p = '\0'; break; + } + } + return p - *buf; +} + +#define init_funcname(buf, file) do {\ + int len = init_funcname_len(buf, file);\ + char *tmp = ALLOCA_N(char, len+1);\ + if (!tmp) {\ + free(*buf);\ + rb_memerror();\ + }\ + strcpy(tmp, *buf);\ + free(*buf);\ + *buf = tmp;\ +} while (0) + +#ifdef USE_DLN_A_OUT + +#ifndef LIBC_NAME +# define LIBC_NAME "libc.a" +#endif + +#ifndef DLN_DEFAULT_LIB_PATH +# define DLN_DEFAULT_LIB_PATH "/lib:/usr/lib:/usr/local/lib:." +#endif + +#include + +static int dln_errno; + +#define DLN_ENOEXEC ENOEXEC /* Exec format error */ +#define DLN_ECONFL 1201 /* Symbol name conflict */ +#define DLN_ENOINIT 1202 /* No initializer given */ +#define DLN_EUNDEF 1203 /* Undefine symbol remains */ +#define DLN_ENOTLIB 1204 /* Not a library file */ +#define DLN_EBADLIB 1205 /* Malformed library file */ +#define DLN_EINIT 1206 /* Not initialized */ + +static int dln_init_p = 0; + +#include +#include +#ifndef N_COMM +# define N_COMM 0x12 +#endif +#ifndef N_MAGIC +# define N_MAGIC(x) (x).a_magic +#endif + +#define INVALID_OBJECT(h) (N_MAGIC(h) != OMAGIC) + +#include "util.h" +#include "st.h" + +static st_table *sym_tbl; +static st_table *undef_tbl; + +static int load_lib(); + +static int +load_header(fd, hdrp, disp) + int fd; + struct exec *hdrp; + long disp; +{ + int size; + + lseek(fd, disp, 0); + size = read(fd, hdrp, sizeof(struct exec)); + if (size == -1) { + dln_errno = errno; + return -1; + } + if (size != sizeof(struct exec) || N_BADMAG(*hdrp)) { + dln_errno = DLN_ENOEXEC; + return -1; + } + return 0; +} + +#if defined(sequent) +#define RELOC_SYMBOL(r) ((r)->r_symbolnum) +#define RELOC_MEMORY_SUB_P(r) ((r)->r_bsr) +#define RELOC_PCREL_P(r) ((r)->r_pcrel || (r)->r_bsr) +#define RELOC_TARGET_SIZE(r) ((r)->r_length) +#endif + +/* Default macros */ +#ifndef RELOC_ADDRESS +#define RELOC_ADDRESS(r) ((r)->r_address) +#define RELOC_EXTERN_P(r) ((r)->r_extern) +#define RELOC_SYMBOL(r) ((r)->r_symbolnum) +#define RELOC_MEMORY_SUB_P(r) 0 +#define RELOC_PCREL_P(r) ((r)->r_pcrel) +#define RELOC_TARGET_SIZE(r) ((r)->r_length) +#endif + +#if defined(sun) && defined(sparc) +/* Sparc (Sun 4) macros */ +# undef relocation_info +# define relocation_info reloc_info_sparc +# define R_RIGHTSHIFT(r) (reloc_r_rightshift[(r)->r_type]) +# define R_BITSIZE(r) (reloc_r_bitsize[(r)->r_type]) +# define R_LENGTH(r) (reloc_r_length[(r)->r_type]) +static int reloc_r_rightshift[] = { + 0, 0, 0, 0, 0, 0, 2, 2, 10, 0, 0, 0, 0, 0, 0, +}; +static int reloc_r_bitsize[] = { + 8, 16, 32, 8, 16, 32, 30, 22, 22, 22, 13, 10, 32, 32, 16, +}; +static int reloc_r_length[] = { + 0, 1, 2, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +}; +# define R_PCREL(r) \ + ((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22) +# define R_SYMBOL(r) ((r)->r_index) +#endif + +#if defined(sequent) +#define R_SYMBOL(r) ((r)->r_symbolnum) +#define R_MEMORY_SUB(r) ((r)->r_bsr) +#define R_PCREL(r) ((r)->r_pcrel || (r)->r_bsr) +#define R_LENGTH(r) ((r)->r_length) +#endif + +#ifndef R_SYMBOL +# define R_SYMBOL(r) ((r)->r_symbolnum) +# define R_MEMORY_SUB(r) 0 +# define R_PCREL(r) ((r)->r_pcrel) +# define R_LENGTH(r) ((r)->r_length) +#endif + +static struct relocation_info * +load_reloc(fd, hdrp, disp) + int fd; + struct exec *hdrp; + long disp; +{ + struct relocation_info *reloc; + int size; + + lseek(fd, disp + N_TXTOFF(*hdrp) + hdrp->a_text + hdrp->a_data, 0); + size = hdrp->a_trsize + hdrp->a_drsize; + reloc = (struct relocation_info*)xmalloc(size); + if (reloc == NULL) { + dln_errno = errno; + return NULL; + } + + if (read(fd, reloc, size) != size) { + dln_errno = errno; + free(reloc); + return NULL; + } + + return reloc; +} + +static struct nlist * +load_sym(fd, hdrp, disp) + int fd; + struct exec *hdrp; + long disp; +{ + struct nlist * buffer; + struct nlist * sym; + struct nlist * end; + long displ; + int size; + + lseek(fd, N_SYMOFF(*hdrp) + hdrp->a_syms + disp, 0); + if (read(fd, &size, sizeof(int)) != sizeof(int)) { + goto err_noexec; + } + + buffer = (struct nlist*)xmalloc(hdrp->a_syms + size); + if (buffer == NULL) { + dln_errno = errno; + return NULL; + } + + lseek(fd, disp + N_SYMOFF(*hdrp), 0); + if (read(fd, buffer, hdrp->a_syms + size) != hdrp->a_syms + size) { + free(buffer); + goto err_noexec; + } + + sym = buffer; + end = sym + hdrp->a_syms / sizeof(struct nlist); + displ = (long)buffer + (long)(hdrp->a_syms); + + while (sym < end) { + sym->n_un.n_name = (char*)sym->n_un.n_strx + displ; + sym++; + } + return buffer; + + err_noexec: + dln_errno = DLN_ENOEXEC; + return NULL; +} + +static st_table * +sym_hash(hdrp, syms) + struct exec *hdrp; + struct nlist *syms; +{ + st_table *tbl; + struct nlist *sym = syms; + struct nlist *end = syms + (hdrp->a_syms / sizeof(struct nlist)); + + tbl = st_init_strtable(); + if (tbl == NULL) { + dln_errno = errno; + return NULL; + } + + while (sym < end) { + st_insert(tbl, sym->n_un.n_name, sym); + sym++; + } + return tbl; +} + +static int +dln_init(prog) + const char *prog; +{ + char *file; + int fd; + struct exec hdr; + struct nlist *syms; + + if (dln_init_p == 1) return 0; + + file = dln_find_exe(prog, NULL); + if (file == NULL || (fd = open(file, O_RDONLY)) < 0) { + dln_errno = errno; + return -1; + } + + if (load_header(fd, &hdr, 0) == -1) return -1; + syms = load_sym(fd, &hdr, 0); + if (syms == NULL) { + close(fd); + return -1; + } + sym_tbl = sym_hash(&hdr, syms); + if (sym_tbl == NULL) { /* file may be start with #! */ + char c = '\0'; + char buf[MAXPATHLEN]; + char *p; + + free(syms); + lseek(fd, 0L, 0); + if (read(fd, &c, 1) == -1) { + dln_errno = errno; + return -1; + } + if (c != '#') goto err_noexec; + if (read(fd, &c, 1) == -1) { + dln_errno = errno; + return -1; + } + if (c != '!') goto err_noexec; + + p = buf; + /* skip forwarding spaces */ + while (read(fd, &c, 1) == 1) { + if (c == '\n') goto err_noexec; + if (c != '\t' && c != ' ') { + *p++ = c; + break; + } + } + /* read in command name */ + while (read(fd, p, 1) == 1) { + if (*p == '\n' || *p == '\t' || *p == ' ') break; + p++; + if (p-buf >= MAXPATHLEN) { + dln_errno = ENAMETOOLONG; + return -1; + } + } + *p = '\0'; + + return dln_init(buf); + } + dln_init_p = 1; + undef_tbl = st_init_strtable(); + close(fd); + return 0; + + err_noexec: + close(fd); + dln_errno = DLN_ENOEXEC; + return -1; +} + +static long +load_text_data(fd, hdrp, bss, disp) + int fd; + struct exec *hdrp; + int bss; + long disp; +{ + int size; + unsigned char* addr; + + lseek(fd, disp + N_TXTOFF(*hdrp), 0); + size = hdrp->a_text + hdrp->a_data; + + if (bss == -1) size += hdrp->a_bss; + else if (bss > 1) size += bss; + + addr = (unsigned char*)xmalloc(size); + if (addr == NULL) { + dln_errno = errno; + return 0; + } + + if (read(fd, addr, size) != size) { + dln_errno = errno; + free(addr); + return 0; + } + + if (bss == -1) { + memset(addr + hdrp->a_text + hdrp->a_data, 0, hdrp->a_bss); + } + else if (bss > 0) { + memset(addr + hdrp->a_text + hdrp->a_data, 0, bss); + } + + return (long)addr; +} + +static int +undef_print(key, value) + char *key, *value; +{ + fprintf(stderr, " %s\n", key); + return ST_CONTINUE; +} + +static void +dln_print_undef() +{ + fprintf(stderr, " Undefined symbols:\n"); + st_foreach(undef_tbl, undef_print, NULL); +} + +static void +dln_undefined() +{ + if (undef_tbl->num_entries > 0) { + fprintf(stderr, "dln: Calling undefined function\n"); + dln_print_undef(); + rb_exit(1); + } +} + +struct undef { + char *name; + struct relocation_info reloc; + long base; + char *addr; + union { + char c; + short s; + long l; + } u; +}; + +static st_table *reloc_tbl = NULL; +static void +link_undef(name, base, reloc) + const char *name; + long base; + struct relocation_info *reloc; +{ + static int u_no = 0; + struct undef *obj; + char *addr = (char*)(reloc->r_address + base); + + obj = (struct undef*)xmalloc(sizeof(struct undef)); + obj->name = strdup(name); + obj->reloc = *reloc; + obj->base = base; + switch (R_LENGTH(reloc)) { + case 0: /* byte */ + obj->u.c = *addr; + break; + case 1: /* word */ + obj->u.s = *(short*)addr; + break; + case 2: /* long */ + obj->u.l = *(long*)addr; + break; + } + if (reloc_tbl == NULL) { + reloc_tbl = st_init_numtable(); + } + st_insert(reloc_tbl, u_no++, obj); +} + +struct reloc_arg { + const char *name; + long value; +}; + +static int +reloc_undef(no, undef, arg) + int no; + struct undef *undef; + struct reloc_arg *arg; +{ + int datum; + char *address; +#if defined(sun) && defined(sparc) + unsigned int mask = 0; +#endif + + if (strcmp(arg->name, undef->name) != 0) return ST_CONTINUE; + address = (char*)(undef->base + undef->reloc.r_address); + datum = arg->value; + + if (R_PCREL(&(undef->reloc))) datum -= undef->base; +#if defined(sun) && defined(sparc) + datum += undef->reloc.r_addend; + datum >>= R_RIGHTSHIFT(&(undef->reloc)); + mask = (1 << R_BITSIZE(&(undef->reloc))) - 1; + mask |= mask -1; + datum &= mask; + switch (R_LENGTH(&(undef->reloc))) { + case 0: + *address = undef->u.c; + *address &= ~mask; + *address |= datum; + break; + case 1: + *(short *)address = undef->u.s; + *(short *)address &= ~mask; + *(short *)address |= datum; + break; + case 2: + *(long *)address = undef->u.l; + *(long *)address &= ~mask; + *(long *)address |= datum; + break; + } +#else + switch (R_LENGTH(&(undef->reloc))) { + case 0: /* byte */ + if (R_MEMORY_SUB(&(undef->reloc))) + *address = datum - *address; + else *address = undef->u.c + datum; + break; + case 1: /* word */ + if (R_MEMORY_SUB(&(undef->reloc))) + *(short*)address = datum - *(short*)address; + else *(short*)address = undef->u.s + datum; + break; + case 2: /* long */ + if (R_MEMORY_SUB(&(undef->reloc))) + *(long*)address = datum - *(long*)address; + else *(long*)address = undef->u.l + datum; + break; + } +#endif + free(undef->name); + free(undef); + return ST_DELETE; +} + +static void +unlink_undef(name, value) + const char *name; + long value; +{ + struct reloc_arg arg; + + arg.name = name; + arg.value = value; + st_foreach(reloc_tbl, reloc_undef, &arg); +} + +#ifdef N_INDR +struct indr_data { + char *name0, *name1; +}; + +static int +reloc_repl(no, undef, data) + int no; + struct undef *undef; + struct indr_data *data; +{ + if (strcmp(data->name0, undef->name) == 0) { + free(undef->name); + undef->name = strdup(data->name1); + } + return ST_CONTINUE; +} +#endif + +static int +load_1(fd, disp, need_init) + int fd; + long disp; + const char *need_init; +{ + static char *libc = LIBC_NAME; + struct exec hdr; + struct relocation_info *reloc = NULL; + long block = 0; + long new_common = 0; /* Length of new common */ + struct nlist *syms = NULL; + struct nlist *sym; + struct nlist *end; + int init_p = 0; + + if (load_header(fd, &hdr, disp) == -1) return -1; + if (INVALID_OBJECT(hdr)) { + dln_errno = DLN_ENOEXEC; + return -1; + } + reloc = load_reloc(fd, &hdr, disp); + if (reloc == NULL) return -1; + + syms = load_sym(fd, &hdr, disp); + if (syms == NULL) { + free(reloc); + return -1; + } + + sym = syms; + end = syms + (hdr.a_syms / sizeof(struct nlist)); + while (sym < end) { + struct nlist *old_sym; + int value = sym->n_value; + +#ifdef N_INDR + if (sym->n_type == (N_INDR | N_EXT)) { + char *key = sym->n_un.n_name; + + if (st_lookup(sym_tbl, sym[1].n_un.n_name, &old_sym)) { + if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) { + unlink_undef(key, old_sym->n_value); + free(key); + } + } + else { + struct indr_data data; + + data.name0 = sym->n_un.n_name; + data.name1 = sym[1].n_un.n_name; + st_foreach(reloc_tbl, reloc_repl, &data); + + st_insert(undef_tbl, strdup(sym[1].n_un.n_name), NULL); + if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) { + free(key); + } + } + sym += 2; + continue; + } +#endif + if (sym->n_type == (N_UNDF | N_EXT)) { + if (st_lookup(sym_tbl, sym->n_un.n_name, &old_sym) == 0) { + old_sym = NULL; + } + + if (value) { + if (old_sym) { + sym->n_type = N_EXT | N_COMM; + sym->n_value = old_sym->n_value; + } + else { + int rnd = + value >= sizeof(double) ? sizeof(double) - 1 + : value >= sizeof(long) ? sizeof(long) - 1 + : sizeof(short) - 1; + + sym->n_type = N_COMM; + new_common += rnd; + new_common &= ~(long)rnd; + sym->n_value = new_common; + new_common += value; + } + } + else { + if (old_sym) { + sym->n_type = N_EXT | N_COMM; + sym->n_value = old_sym->n_value; + } + else { + sym->n_value = (long)dln_undefined; + st_insert(undef_tbl, strdup(sym->n_un.n_name), NULL); + } + } + } + sym++; + } + + block = load_text_data(fd, &hdr, hdr.a_bss + new_common, disp); + if (block == 0) goto err_exit; + + sym = syms; + while (sym < end) { + struct nlist *new_sym; + char *key; + + switch (sym->n_type) { + case N_COMM: + sym->n_value += hdr.a_text + hdr.a_data; + case N_TEXT|N_EXT: + case N_DATA|N_EXT: + + sym->n_value += block; + + if (st_lookup(sym_tbl, sym->n_un.n_name, &new_sym) != 0 + && new_sym->n_value != (long)dln_undefined) { + dln_errno = DLN_ECONFL; + goto err_exit; + } + + key = sym->n_un.n_name; + if (st_delete(undef_tbl, (st_data_t*)&key, NULL) != 0) { + unlink_undef(key, sym->n_value); + free(key); + } + + new_sym = (struct nlist*)xmalloc(sizeof(struct nlist)); + *new_sym = *sym; + new_sym->n_un.n_name = strdup(sym->n_un.n_name); + st_insert(sym_tbl, new_sym->n_un.n_name, new_sym); + break; + + case N_TEXT: + case N_DATA: + sym->n_value += block; + break; + } + sym++; + } + + /* + * First comes the text-relocation + */ + { + struct relocation_info * rel = reloc; + struct relocation_info * rel_beg = reloc + + (hdr.a_trsize/sizeof(struct relocation_info)); + struct relocation_info * rel_end = reloc + + (hdr.a_trsize+hdr.a_drsize)/sizeof(struct relocation_info); + + while (rel < rel_end) { + char *address = (char*)(rel->r_address + block); + long datum = 0; +#if defined(sun) && defined(sparc) + unsigned int mask = 0; +#endif + + if(rel >= rel_beg) + address += hdr.a_text; + + if (rel->r_extern) { /* Look it up in symbol-table */ + sym = &(syms[R_SYMBOL(rel)]); + switch (sym->n_type) { + case N_EXT|N_UNDF: + link_undef(sym->n_un.n_name, block, rel); + case N_EXT|N_COMM: + case N_COMM: + datum = sym->n_value; + break; + default: + goto err_exit; + } + } /* end.. look it up */ + else { /* is static */ + switch (R_SYMBOL(rel)) { + case N_TEXT: + case N_DATA: + datum = block; + break; + case N_BSS: + datum = block + new_common; + break; + case N_ABS: + break; + } + } /* end .. is static */ + if (R_PCREL(rel)) datum -= block; + +#if defined(sun) && defined(sparc) + datum += rel->r_addend; + datum >>= R_RIGHTSHIFT(rel); + mask = (1 << R_BITSIZE(rel)) - 1; + mask |= mask -1; + datum &= mask; + + switch (R_LENGTH(rel)) { + case 0: + *address &= ~mask; + *address |= datum; + break; + case 1: + *(short *)address &= ~mask; + *(short *)address |= datum; + break; + case 2: + *(long *)address &= ~mask; + *(long *)address |= datum; + break; + } +#else + switch (R_LENGTH(rel)) { + case 0: /* byte */ + if (datum < -128 || datum > 127) goto err_exit; + *address += datum; + break; + case 1: /* word */ + *(short *)address += datum; + break; + case 2: /* long */ + *(long *)address += datum; + break; + } +#endif + rel++; + } + } + + if (need_init) { + int len; + char **libs_to_be_linked = 0; + char *buf; + + if (undef_tbl->num_entries > 0) { + if (load_lib(libc) == -1) goto err_exit; + } + + init_funcname(&buf, need_init); + len = strlen(buf); + + for (sym = syms; symn_un.n_name; + if (name[0] == '_' && sym->n_value >= block) { + if (strcmp(name+1, "dln_libs_to_be_linked") == 0) { + libs_to_be_linked = (char**)sym->n_value; + } + else if (strcmp(name+1, buf) == 0) { + init_p = 1; + ((int (*)())sym->n_value)(); + } + } + } + if (libs_to_be_linked && undef_tbl->num_entries > 0) { + while (*libs_to_be_linked) { + load_lib(*libs_to_be_linked); + libs_to_be_linked++; + } + } + } + free(reloc); + free(syms); + if (need_init) { + if (init_p == 0) { + dln_errno = DLN_ENOINIT; + return -1; + } + if (undef_tbl->num_entries > 0) { + if (load_lib(libc) == -1) goto err_exit; + if (undef_tbl->num_entries > 0) { + dln_errno = DLN_EUNDEF; + return -1; + } + } + } + return 0; + + err_exit: + if (syms) free(syms); + if (reloc) free(reloc); + if (block) free((char*)block); + return -1; +} + +static int target_offset; +static int +search_undef(key, value, lib_tbl) + const char *key; + int value; + st_table *lib_tbl; +{ + long offset; + + if (st_lookup(lib_tbl, key, &offset) == 0) return ST_CONTINUE; + target_offset = offset; + return ST_STOP; +} + +struct symdef { + int rb_str_index; + int lib_offset; +}; + +char *dln_librrb_ary_path = DLN_DEFAULT_LIB_PATH; + +static int +load_lib(lib) + const char *lib; +{ + char *path, *file; + char armagic[SARMAG]; + int fd, size; + struct ar_hdr ahdr; + st_table *lib_tbl = NULL; + int *data, nsym; + struct symdef *base; + char *name_base; + + if (dln_init_p == 0) { + dln_errno = DLN_ENOINIT; + return -1; + } + + if (undef_tbl->num_entries == 0) return 0; + dln_errno = DLN_EBADLIB; + + if (lib[0] == '-' && lib[1] == 'l') { + long len = strlen(lib) + 4; + char *p = alloca(len); + snprintf(p, len, "lib%s.a", lib+2); + lib = p; + } + + /* library search path: */ + /* look for environment variable DLN_LIBRARY_PATH first. */ + /* then variable dln_librrb_ary_path. */ + /* if path is still NULL, use "." for path. */ + path = getenv("DLN_LIBRARY_PATH"); + if (path == NULL) path = dln_librrb_ary_path; + + file = dln_find_file(lib, path); + fd = open(file, O_RDONLY); + if (fd == -1) goto syserr; + size = read(fd, armagic, SARMAG); + if (size == -1) goto syserr; + + if (size != SARMAG) { + dln_errno = DLN_ENOTLIB; + goto badlib; + } + size = read(fd, &ahdr, sizeof(ahdr)); + if (size == -1) goto syserr; + if (size != sizeof(ahdr) || sscanf(ahdr.ar_size, "%d", &size) != 1) { + goto badlib; + } + + if (strncmp(ahdr.ar_name, "__.SYMDEF", 9) == 0) { + /* make hash table from __.SYMDEF */ + + lib_tbl = st_init_strtable(); + data = (int*)xmalloc(size); + if (data == NULL) goto syserr; + size = read(fd, data, size); + nsym = *data / sizeof(struct symdef); + base = (struct symdef*)(data + 1); + name_base = (char*)(base + nsym) + sizeof(int); + while (nsym > 0) { + char *name = name_base + base->rb_str_index; + + st_insert(lib_tbl, name, base->lib_offset + sizeof(ahdr)); + nsym--; + base++; + } + for (;;) { + target_offset = -1; + st_foreach(undef_tbl, search_undef, lib_tbl); + if (target_offset == -1) break; + if (load_1(fd, target_offset, 0) == -1) { + st_free_table(lib_tbl); + free(data); + goto badlib; + } + if (undef_tbl->num_entries == 0) break; + } + free(data); + st_free_table(lib_tbl); + } + else { + /* linear library, need to scan (FUTURE) */ + + for (;;) { + int offset = SARMAG; + int found = 0; + struct exec hdr; + struct nlist *syms, *sym, *end; + + while (undef_tbl->num_entries > 0) { + found = 0; + lseek(fd, offset, 0); + size = read(fd, &ahdr, sizeof(ahdr)); + if (size == -1) goto syserr; + if (size == 0) break; + if (size != sizeof(ahdr) + || sscanf(ahdr.ar_size, "%d", &size) != 1) { + goto badlib; + } + offset += sizeof(ahdr); + if (load_header(fd, &hdr, offset) == -1) + goto badlib; + syms = load_sym(fd, &hdr, offset); + if (syms == NULL) goto badlib; + sym = syms; + end = syms + (hdr.a_syms / sizeof(struct nlist)); + while (sym < end) { + if (sym->n_type == N_EXT|N_TEXT + && st_lookup(undef_tbl, sym->n_un.n_name, NULL)) { + break; + } + sym++; + } + if (sym < end) { + found++; + free(syms); + if (load_1(fd, offset, 0) == -1) { + goto badlib; + } + } + offset += size; + if (offset & 1) offset++; + } + if (found) break; + } + } + close(fd); + return 0; + + syserr: + dln_errno = errno; + badlib: + if (fd >= 0) close(fd); + return -1; +} + +static int +load(file) + const char *file; +{ + int fd; + int result; + + if (dln_init_p == 0) { + if (dln_init(dln_argv0) == -1) return -1; + } + result = strlen(file); + if (file[result-1] == 'a') { + return load_lib(file); + } + + fd = open(file, O_RDONLY); + if (fd == -1) { + dln_errno = errno; + return -1; + } + result = load_1(fd, 0, file); + close(fd); + + return result; +} + +void* +dln_sym(name) + const char *name; +{ + struct nlist *sym; + + if (st_lookup(sym_tbl, name, &sym)) + return (void*)sym->n_value; + return NULL; +} + +#endif /* USE_DLN_A_OUT */ + +#ifdef USE_DLN_DLOPEN +# if defined(__NetBSD__) && defined(__NetBSD_Version__) && __NetBSD_Version__ < 105000000 +# include +# include +# else +# include +# endif +#endif + +#ifdef __hpux +#include +#include "dl.h" +#endif + +#if defined(_AIX) +#include /* for isdigit() */ +#include /* for global errno */ +#include +#endif + +#ifdef NeXT +#if NS_TARGET_MAJOR < 4 +#include +#else +#include +#ifndef NSLINKMODULE_OPTION_BINDNOW +#define NSLINKMODULE_OPTION_BINDNOW 1 +#endif +#endif +#else +#ifdef __APPLE__ +#include +#endif +#endif + +#if defined _WIN32 && !defined __CYGWIN__ +#include +#endif + +#ifdef _WIN32_WCE +#undef FormatMessage +#define FormatMessage FormatMessageA +#undef LoadLibrary +#define LoadLibrary LoadLibraryA +#undef GetProcAddress +#define GetProcAddress GetProcAddressA +#endif + +static const char * +dln_strerror() +{ +#ifdef USE_DLN_A_OUT + char *strerror(); + + switch (dln_errno) { + case DLN_ECONFL: + return "Symbol name conflict"; + case DLN_ENOINIT: + return "No initializer given"; + case DLN_EUNDEF: + return "Unresolved symbols"; + case DLN_ENOTLIB: + return "Not a library file"; + case DLN_EBADLIB: + return "Malformed library file"; + case DLN_EINIT: + return "Not initialized"; + default: + return strerror(dln_errno); + } +#endif + +#ifdef USE_DLN_DLOPEN + return (char*)dlerror(); +#endif + +#if defined _WIN32 && !defined __CYGWIN__ + static char message[1024]; + int error = GetLastError(); + char *p = message; + p += sprintf(message, "%d: ", error); + FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + p, + sizeof message - strlen(message), + NULL); + + for (p = message; *p; p++) { + if (*p == '\n' || *p == '\r') + *p = ' '; + } + return message; +#endif +} + + +#if defined(_AIX) && ! defined(_IA64) +static void +aix_loaderror(const char *pathname) +{ + char *message[8], errbuf[1024]; + int i,j; + + struct errtab { + int errnum; + char *errstr; + } load_errtab[] = { + {L_ERROR_TOOMANY, "too many errors, rest skipped."}, + {L_ERROR_NOLIB, "can't load library:"}, + {L_ERROR_UNDEF, "can't find symbol in library:"}, + {L_ERROR_RLDBAD, + "RLD index out of range or bad relocation type:"}, + {L_ERROR_FORMAT, "not a valid, executable xcoff file:"}, + {L_ERROR_MEMBER, + "file not an archive or does not contain requested member:"}, + {L_ERROR_TYPE, "symbol table mismatch:"}, + {L_ERROR_ALIGN, "text alignment in file is wrong."}, + {L_ERROR_SYSTEM, "System error:"}, + {L_ERROR_ERRNO, NULL} + }; + +#define LOAD_ERRTAB_LEN (sizeof(load_errtab)/sizeof(load_errtab[0])) +#define ERRBUF_APPEND(s) strncat(errbuf, s, sizeof(errbuf)-strlen(errbuf)-1) + + snprintf(errbuf, 1024, "load failed - %s ", pathname); + + if (!loadquery(1, &message[0], sizeof(message))) + ERRBUF_APPEND(strerror(errno)); + for(i = 0; message[i] && *message[i]; i++) { + int nerr = atoi(message[i]); + for (j=0; j +#include +#include +#include +#include +#include + +static char *vms_filespec; +static int vms_fileact(char *filespec, int type); +static long vms_fisexh(long *sigarr, long *mecarr); +#endif + +#endif /* NO_DLN_LOAD */ + +void* +dln_load(file) + const char *file; +{ +#ifdef NO_DLN_LOAD + rb_raise(rb_eLoadError, "this executable file can't load extension libraries"); +#else + +#if !defined(_AIX) && !defined(NeXT) + const char *error = 0; +#define DLN_ERROR() (error = dln_strerror(), strcpy(ALLOCA_N(char, strlen(error) + 1), error)) +#endif + +#if defined _WIN32 && !defined __CYGWIN__ + HINSTANCE handle; + char winfile[MAXPATHLEN]; + void (*init_fct)(); + char *buf; + + if (strlen(file) >= MAXPATHLEN) rb_loaderror("filename too long"); + + /* Load the file as an object one */ + init_funcname(&buf, file); + + strcpy(winfile, file); + + /* Load file */ + if ((handle = LoadLibrary(winfile)) == NULL) { + error = dln_strerror(); + goto failed; + } + + if ((init_fct = (void(*)())GetProcAddress(handle, buf)) == NULL) { + rb_loaderror("%s - %s\n%s", dln_strerror(), buf, file); + } + + /* Call the init code */ + (*init_fct)(); + return handle; +#else +#ifdef USE_DLN_A_OUT + if (load(file) == -1) { + error = dln_strerror(); + goto failed; + } + return 0; +#else + + char *buf; + /* Load the file as an object one */ + init_funcname(&buf, file); + +#ifdef USE_DLN_DLOPEN +#define DLN_DEFINED + { + void *handle; + void (*init_fct)(); + +#ifndef RTLD_LAZY +# define RTLD_LAZY 1 +#endif +#ifdef __INTERIX +# undef RTLD_GLOBAL +#endif +#ifndef RTLD_GLOBAL +# define RTLD_GLOBAL 0 +#endif + + /* Load file */ + if ((handle = (void*)dlopen(file, RTLD_LAZY|RTLD_GLOBAL)) == NULL) { + error = dln_strerror(); + goto failed; + } + + init_fct = (void(*)())dlsym(handle, buf); + if (init_fct == NULL) { + error = DLN_ERROR(); + dlclose(handle); + goto failed; + } + /* Call the init code */ + (*init_fct)(); + + return handle; + } +#endif /* USE_DLN_DLOPEN */ + +#ifdef __hpux +#define DLN_DEFINED + { + shl_t lib = NULL; + int flags; + void (*init_fct)(); + + flags = BIND_DEFERRED; + lib = shl_load(file, flags, 0); + if (lib == NULL) { + extern int errno; + rb_loaderror("%s - %s", strerror(errno), file); + } + shl_findsym(&lib, buf, TYPE_PROCEDURE, (void*)&init_fct); + if (init_fct == NULL) { + shl_findsym(&lib, buf, TYPE_UNDEFINED, (void*)&init_fct); + if (init_fct == NULL) { + errno = ENOSYM; + rb_loaderror("%s - %s", strerror(ENOSYM), file); + } + } + (*init_fct)(); + return (void*)lib; + } +#endif /* hpux */ + +#if defined(_AIX) && ! defined(_IA64) +#define DLN_DEFINED + { + void (*init_fct)(); + + init_fct = (void(*)())load((char*)file, 1, 0); + if (init_fct == NULL) { + aix_loaderror(file); + } + if (loadbind(0, (void*)dln_load, (void*)init_fct) == -1) { + aix_loaderror(file); + } + (*init_fct)(); + return (void*)init_fct; + } +#endif /* _AIX */ + +#if defined(NeXT) || defined(__APPLE__) +#define DLN_DEFINED +/*---------------------------------------------------- + By SHIROYAMA Takayuki Psi@fortune.nest.or.jp + + Special Thanks... + Yu tomoak-i@is.aist-nara.ac.jp, + Mi hisho@tasihara.nest.or.jp, + sunshine@sunshineco.com, + and... Miss ARAI Akino(^^;) + ----------------------------------------------------*/ +#if defined(NeXT) && (NS_TARGET_MAJOR < 4)/* NeXTSTEP rld functions */ + + { + NXStream* s; + unsigned long init_address; + char *object_files[2] = {NULL, NULL}; + + void (*init_fct)(); + + object_files[0] = (char*)file; + + s = NXOpenFile(2,NX_WRITEONLY); + + /* Load object file, if return value ==0 , load failed*/ + if(rld_load(s, NULL, object_files, NULL) == 0) { + NXFlush(s); + NXClose(s); + rb_loaderror("Failed to load %.200s", file); + } + + /* lookup the initial function */ + if(rld_lookup(s, buf, &init_address) == 0) { + NXFlush(s); + NXClose(s); + rb_loaderror("Failed to lookup Init function %.200s", file); + } + + NXFlush(s); + NXClose(s); + + /* Cannot call *init_address directory, so copy this value to + funtion pointer */ + init_fct = (void(*)())init_address; + (*init_fct)(); + return (void*)init_address; + } +#else/* OPENSTEP dyld functions */ + { + int dyld_result; + NSObjectFileImage obj_file; /* handle, but not use it */ + /* "file" is module file name . + "buf" is pointer to initial function name with "_" . */ + + void (*init_fct)(); + + + dyld_result = NSCreateObjectFileImageFromFile(file, &obj_file); + + if (dyld_result != NSObjectFileImageSuccess) { + rb_loaderror("Failed to load %.200s", file); + } + + NSLinkModule(obj_file, file, NSLINKMODULE_OPTION_BINDNOW); + + /* lookup the initial function */ + if(!NSIsSymbolNameDefined(buf)) { + rb_loaderror("Failed to lookup Init function %.200s",file); + } + init_fct = NSAddressOfSymbol(NSLookupAndBindSymbol(buf)); + (*init_fct)(); + + return (void*)init_fct; + } +#endif /* rld or dyld */ +#endif + +#ifdef __BEOS__ +# define DLN_DEFINED + { + status_t err_stat; /* BeOS error status code */ + image_id img_id; /* extention module unique id */ + void (*init_fct)(); /* initialize function for extention module */ + + /* load extention module */ + img_id = load_add_on(file); + if (img_id <= 0) { + rb_loaderror("Failed to load %.200s", file); + } + + /* find symbol for module initialize function. */ + /* The Be Book KernelKit Images section described to use + B_SYMBOL_TYPE_TEXT for symbol of function, not + B_SYMBOL_TYPE_CODE. Why ? */ + /* strcat(init_fct_symname, "__Fv"); */ /* parameter nothing. */ + /* "__Fv" dont need! The Be Book Bug ? */ + err_stat = get_image_symbol(img_id, buf, + B_SYMBOL_TYPE_TEXT, (void **)&init_fct); + + if (err_stat != B_NO_ERROR) { + char real_name[MAXPATHLEN]; + + strcpy(real_name, buf); + strcat(real_name, "__Fv"); + err_stat = get_image_symbol(img_id, real_name, + B_SYMBOL_TYPE_TEXT, (void **)&init_fct); + } + + if ((B_BAD_IMAGE_ID == err_stat) || (B_BAD_INDEX == err_stat)) { + unload_add_on(img_id); + rb_loaderror("Failed to lookup Init function %.200s", file); + } + else if (B_NO_ERROR != err_stat) { + char errmsg[] = "Internal of BeOS version. %.200s (symbol_name = %s)"; + unload_add_on(img_id); + rb_loaderror(errmsg, strerror(err_stat), buf); + } + + /* call module initialize function. */ + (*init_fct)(); + return (void*)img_id; + } +#endif /* __BEOS__*/ + +#ifdef __MACOS__ +# define DLN_DEFINED + { + OSErr err; + FSSpec libspec; + CFragConnectionID connID; + Ptr mainAddr; + char errMessage[1024]; + Boolean isfolder, didsomething; + Str63 fragname; + Ptr symAddr; + CFragSymbolClass class; + void (*init_fct)(); + char fullpath[MAXPATHLEN]; + + strcpy(fullpath, file); + + /* resolve any aliases to find the real file */ + c2pstr(fullpath); + (void)FSMakeFSSpec(0, 0, fullpath, &libspec); + err = ResolveAliasFile(&libspec, 1, &isfolder, &didsomething); + if (err) { + rb_loaderror("Unresolved Alias - %s", file); + } + + /* Load the fragment (or return the connID if it is already loaded */ + fragname[0] = 0; + err = GetDiskFragment(&libspec, 0, 0, fragname, + kLoadCFrag, &connID, &mainAddr, + errMessage); + if (err) { + p2cstr(errMessage); + rb_loaderror("%s - %s",errMessage , file); + } + + /* Locate the address of the correct init function */ + c2pstr(buf); + err = FindSymbol(connID, buf, &symAddr, &class); + if (err) { + rb_loaderror("Unresolved symbols - %s" , file); + } + init_fct = (void (*)())symAddr; + (*init_fct)(); + return (void*)init_fct; + } +#endif /* __MACOS__ */ + +#if defined(__VMS) +#define DLN_DEFINED + { + long status; + void (*init_fct)(); + char *fname, *p1, *p2; + + $DESCRIPTOR(fname_d, ""); + $DESCRIPTOR(image_d, ""); + $DESCRIPTOR(buf_d, ""); + + decc$to_vms(file, vms_fileact, 0, 0); + + fname = (char *)__alloca(strlen(file)+1); + strcpy(fname,file); + if (p1 = strrchr(fname,'/')) + fname = p1 + 1; + if (p2 = strrchr(fname,'.')) + *p2 = '\0'; + + fname_d.dsc$w_length = strlen(fname); + fname_d.dsc$a_pointer = fname; + image_d.dsc$w_length = strlen(vms_filespec); + image_d.dsc$a_pointer = vms_filespec; + buf_d.dsc$w_length = strlen(buf); + buf_d.dsc$a_pointer = buf; + + lib$establish(vms_fisexh); + + status = lib$find_image_symbol ( + &fname_d, + &buf_d, + &init_fct, + &image_d); + + lib$establish(0); + + if (status == RMS$_FNF) { + error = dln_strerror(); + goto failed; + } else if (!$VMS_STATUS_SUCCESS(status)) { + error = DLN_ERROR(); + goto failed; + } + + /* Call the init code */ + (*init_fct)(); + + return 1; + } +#endif /* __VMS */ + +#ifndef DLN_DEFINED + rb_notimplement(); +#endif + +#endif /* USE_DLN_A_OUT */ +#endif +#if !defined(_AIX) && !defined(NeXT) + failed: + rb_loaderror("%s - %s", error, file); +#endif + +#endif /* NO_DLN_LOAD */ + return 0; /* dummy return */ +} + +static char *dln_find_1(); + +char * +dln_find_exe(fname, path) + const char *fname; + const char *path; +{ + if (!path) { + path = getenv(PATH_ENV); + } + + if (!path) { +#if defined(MSDOS) || defined(_WIN32) || defined(__human68k__) || defined(__MACOS__) + path = "/usr/local/bin;/usr/ucb;/usr/bin;/bin;."; +#else + path = "/usr/local/bin:/usr/ucb:/usr/bin:/bin:."; +#endif + } + return dln_find_1(fname, path, 1); +} + +char * +dln_find_file(fname, path) + const char *fname; + const char *path; +{ +#ifndef __MACOS__ + if (!path) path = "."; + return dln_find_1(fname, path, 0); +#else + if (!path) path = "."; + return _macruby_path_conv_posix_to_macos(dln_find_1(fname, path, 0)); +#endif +} + +#if defined(__CYGWIN32__) +const char * +conv_to_posix_path(win32, posix, len) + char *win32; + char *posix; + int len; +{ + char *first = win32; + char *p = win32; + char *dst = posix; + + posix[0] = '\0'; + for (p = win32; *p; p++) + if (*p == ';') { + *p = 0; + cygwin32_conv_to_posix_path(first, posix); + posix += strlen(posix); + *posix++ = ':'; + first = p + 1; + *p = ';'; + } + if (len < strlen(first)) + fprintf(stderr, "PATH length too long: %s\n", first); + else + cygwin32_conv_to_posix_path(first, posix); + return dst; +} +#endif + +static char fbuf[MAXPATHLEN]; + +static char * +dln_find_1(fname, path, exe_flag) + char *fname; + char *path; + int exe_flag; /* non 0 if looking for executable. */ +{ + register char *dp; + register char *ep; + register char *bp; + struct stat st; +#ifdef __MACOS__ + const char* mac_fullpath; +#endif + + if (!fname) return fname; + if (fname[0] == '/') return fname; + if (strncmp("./", fname, 2) == 0 || strncmp("../", fname, 3) == 0) + return fname; + if (exe_flag && strchr(fname, '/')) return fname; +#ifdef DOSISH + if (fname[0] == '\\') return fname; +# ifdef DOSISH_DRIVE_LETTER + if (strlen(fname) > 2 && fname[1] == ':') return fname; +# endif + if (strncmp(".\\", fname, 2) == 0 || strncmp("..\\", fname, 3) == 0) + return fname; + if (exe_flag && strchr(fname, '\\')) return fname; +#endif + + for (dp = path;; dp = ++ep) { + register int l; + int i; + int fspace; + + /* extract a component */ + ep = strchr(dp, PATH_SEP[0]); + if (ep == NULL) + ep = dp+strlen(dp); + + /* find the length of that component */ + l = ep - dp; + bp = fbuf; + fspace = sizeof fbuf - 2; + if (l > 0) { + /* + ** If the length of the component is zero length, + ** start from the current directory. If the + ** component begins with "~", start from the + ** user's $HOME environment variable. Otherwise + ** take the path literally. + */ + + if (*dp == '~' && (l == 1 || +#if defined(DOSISH) + dp[1] == '\\' || +#endif + dp[1] == '/')) { + char *home; + + home = getenv("HOME"); + if (home != NULL) { + i = strlen(home); + if ((fspace -= i) < 0) + goto toolong; + memcpy(bp, home, i); + bp += i; + } + dp++; + l--; + } + if (l > 0) { + if ((fspace -= l) < 0) + goto toolong; + memcpy(bp, dp, l); + bp += l; + } + + /* add a "/" between directory and filename */ + if (ep[-1] != '/') + *bp++ = '/'; + } + + /* now append the file name */ + i = strlen(fname); + if ((fspace -= i) < 0) { + toolong: + fprintf(stderr, "openpath: pathname too long (ignored)\n"); + *bp = '\0'; + fprintf(stderr, "\tDirectory \"%s\"\n", fbuf); + fprintf(stderr, "\tFile \"%s\"\n", fname); + goto next; + } + memcpy(bp, fname, i + 1); + +#ifndef __MACOS__ + if (stat(fbuf, &st) == 0) { + if (exe_flag == 0) return fbuf; + /* looking for executable */ + if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0) + return fbuf; + } +#else + if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf)) { + if (exe_flag == 0) return mac_fullpath; + /* looking for executable */ + if (stat(mac_fullpath, &st) == 0) { + if (!S_ISDIR(st.st_mode) && eaccess(mac_fullpath, X_OK) == 0) + return mac_fullpath; + } + } +#endif +#if defined(DOSISH) + if (exe_flag) { + static const char *extension[] = { +#if defined(MSDOS) + ".com", ".exe", ".bat", +#if defined(DJGPP) + ".btm", ".sh", ".ksh", ".pl", ".sed", +#endif +#elif defined(__EMX__) || defined(_WIN32) + ".exe", ".com", ".cmd", ".bat", +/* end of __EMX__ or _WIN32 */ +#else + ".r", ".R", ".x", ".X", ".bat", ".BAT", +/* __human68k__ */ +#endif + (char *) NULL + }; + int j; + + for (j = 0; extension[j]; j++) { + if (fspace < strlen(extension[j])) { + fprintf(stderr, "openpath: pathname too long (ignored)\n"); + fprintf(stderr, "\tDirectory \"%.*s\"\n", (int) (bp - fbuf), fbuf); + fprintf(stderr, "\tFile \"%s%s\"\n", fname, extension[j]); + continue; + } + strcpy(bp + i, extension[j]); +#ifndef __MACOS__ + if (stat(fbuf, &st) == 0) + return fbuf; +#else + if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf)) + return mac_fullpath; + +#endif + } + } +#endif /* MSDOS or _WIN32 or __human68k__ or __EMX__ */ + + next: + /* if not, and no other alternatives, life is bleak */ + if (*ep == '\0') { + return NULL; + } + + /* otherwise try the next component in the search path */ + } +} + +#if defined(__VMS) + +/* action routine for decc$to_vms */ +static int vms_fileact(char *filespec, int type) +{ + if (vms_filespec) + free(vms_filespec); + vms_filespec = malloc(strlen(filespec)+1); + strcpy(vms_filespec, filespec); + return 1; +} + +/* exception handler for LIB$FIND_IMAGE_SYMBOL */ +static long vms_fisexh(long *sigarr, long *mecarr) +{ + sys$unwind(1, 0); + return 1; +} + +#endif /* __VMS */ -- cgit v1.2.3