(linenum→info "unix/slp.c:2238")

ruby/1.9.0/dln.c

    1: /**********************************************************************
    2: 
    3:   dln.c -
    4: 
    5:   $Author: matz $
    6:   $Date: 2007-08-25 12:29:39 +0900 (Sat, 25 Aug 2007) $
    7:   created at: Tue Jan 18 17:05:06 JST 1994
    8: 
    9:   Copyright (C) 1993-2007 Yukihiro Matsumoto
   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__)   /* Mac OS X */
   85: # if defined(HAVE_DLOPEN)
   86:    /* Mac OS X with dlopen (10.3 or later) */
   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: /* dynamic load with dlopen() */
  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:     /* Load the file as an object one */
  120:     for (slash = file-1; *file; file++) /* Find position of last '/' */
  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++) {         /* Delete suffix if it exists */
  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     /* 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: 
  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: /* 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])
  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) {      /* 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: 
  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:           /* 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: 
  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