home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 April / PCO0499.ISO / filesbbs / os2 / apach134.arj / APACH134.ZIP / src / os / unix / os-aix-dso.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-01-01  |  17.8 KB  |  669 lines

  1. /* ====================================================================
  2.  * Copyright (c) 1998-1999 The Apache Group.  All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  *
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer. 
  10.  *
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in
  13.  *    the documentation and/or other materials provided with the
  14.  *    distribution.
  15.  *
  16.  * 3. All advertising materials mentioning features or use of this
  17.  *    software must display the following acknowledgment:
  18.  *    "This product includes software developed by the Apache Group
  19.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  20.  *
  21.  * 4. The names "Apache Server" and "Apache Group" must not be used to
  22.  *    endorse or promote products derived from this software without
  23.  *    prior written permission. For written permission, please contact
  24.  *    apache@apache.org.
  25.  *
  26.  * 5. Products derived from this software may not be called "Apache"
  27.  *    nor may "Apache" appear in their names without prior written
  28.  *    permission of the Apache Group.
  29.  *
  30.  * 6. Redistributions of any form whatsoever must retain the following
  31.  *    acknowledgment:
  32.  *    "This product includes software developed by the Apache Group
  33.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  36.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  37.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  38.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  41.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  42.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  43.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  44.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  45.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  46.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Group and was originally based
  51.  * on public domain software written at the National Center for
  52.  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
  53.  * For more information on the Apache Group and the Apache HTTP server
  54.  * project, please see <http://www.apache.org/>.
  55.  *
  56.  */
  57.  
  58. /*
  59. **  os-aix-dso.c -- DSO system function emulation for AIX
  60.  */
  61.  
  62. /*
  63. **  Based on libdl (dlfcn.c/dlfcn.h) which is
  64. **  Copyright (c) 1992,1993,1995,1996,1997,1988
  65. **  Jens-Uwe Mager, Helios Software GmbH, Hannover, Germany.
  66. **
  67. **  Not derived from licensed software.
  68. **
  69. **  Permission is granted to freely use, copy, modify, and redistribute
  70. **  this software, provided that the author is not construed to be liable
  71. **  for any results of using the software, alterations are clearly marked
  72. **  as such, and this notice is not modified.
  73. **
  74. **  Changes marked with `--jwe' were made on April 7 1996 by
  75. **  John W. Eaton <jwe@bevo.che.wisc.edu> to support g++ 
  76. **
  77. **  Bundled, stripped and adjusted on April 1998 as one single source file 
  78. **  for inclusion into the Apache HTTP server by 
  79. **  Ralf S. Engelschall <rse@apache.org>
  80. */
  81.  
  82. #include <stdio.h>
  83. #include <errno.h>
  84. #include <string.h>
  85. #include <stdlib.h>
  86. #include <sys/types.h>
  87. #include <sys/ldr.h>
  88. #include <a.out.h>
  89.  
  90. #undef FREAD
  91. #undef FWRITE
  92. #include <ldfcn.h>
  93.  
  94. /*
  95.  * AIX 4.3 does remove some useful definitions from ldfcn.h. Define
  96.  * these here to compensate for that lossage.
  97.  */
  98. #ifndef BEGINNING
  99. #define BEGINNING SEEK_SET
  100. #endif
  101. #ifndef FSEEK
  102. #define FSEEK(ldptr,o,p)   fseek(IOPTR(ldptr),(p==BEGINNING)?(OFFSET(ldptr) +o):o,p)
  103. #endif
  104. #ifndef FREAD
  105. #define FREAD(p,s,n,ldptr) fread(p,s,n,IOPTR(ldptr))
  106. #endif
  107.  
  108. /*
  109.  * Mode flags for the dlopen routine.
  110.  */
  111. #undef  RTLD_LAZY
  112. #define RTLD_LAZY    1    /* lazy function call binding */
  113. #undef  RTLD_NOW
  114. #define RTLD_NOW    2    /* immediate function call binding */
  115. #undef  RTLD_GLOBAL
  116. #define RTLD_GLOBAL    0x100    /* allow symbols to be global */
  117.  
  118. /*
  119.  * To be able to intialize, a library may provide a dl_info structure
  120.  * that contains functions to be called to initialize and terminate.
  121.  */
  122. struct dl_info {
  123.     void (*init) (void);
  124.     void (*fini) (void);
  125. };
  126.  
  127.  
  128. /*
  129.  *  Forward declarations
  130.  */
  131. void *dlopen(const char *path, int mode);
  132. void *dlsym(void *handle, const char *symbol);
  133. const char *dlerror(void);
  134. int dlclose(void *handle);
  135.  
  136. /*
  137.  * We simulate dlopen() et al. through a call to load. Because AIX has
  138.  * no call to find an exported symbol we read the loader section of the
  139.  * loaded module and build a list of exported symbols and their virtual
  140.  * address.
  141.  */
  142.  
  143. typedef struct {
  144.     char *name;            /* the symbols's name */
  145.     void *addr;            /* its relocated virtual address */
  146. } Export, *ExportPtr;
  147.  
  148. /*
  149.  * xlC uses the following structure to list its constructors and
  150.  * destructors. This is gleaned from the output of munch.
  151.  */
  152. typedef struct {
  153.     void (*init) (void);    /* call static constructors */
  154.     void (*term) (void);    /* call static destructors */
  155. } Cdtor, *CdtorPtr;
  156.  
  157. typedef void (*GccCDtorPtr) (void);
  158.  
  159. /*
  160.  * The void * handle returned from dlopen is actually a ModulePtr.
  161.  */
  162. typedef struct Module {
  163.     struct Module *next;
  164.     char *name;            /* module name for refcounting */
  165.     int refCnt;            /* the number of references */
  166.     void *entry;        /* entry point from load */
  167.     struct dl_info *info;    /* optional init/terminate functions */
  168.     CdtorPtr cdtors;        /* optional C++ constructors */
  169.     GccCDtorPtr gcc_ctor;    /* g++ constructors  --jwe */
  170.     GccCDtorPtr gcc_dtor;    /* g++ destructors  --jwe */
  171.     int nExports;        /* the number of exports found */
  172.     ExportPtr exports;        /* the array of exports */
  173. } Module, *ModulePtr;
  174.  
  175. /*
  176.  * We keep a list of all loaded modules to be able to call the fini
  177.  * handlers and destructors at atexit() time.
  178.  */
  179. static ModulePtr modList;
  180.  
  181. /*
  182.  * The last error from one of the dl* routines is kept in static
  183.  * variables here. Each error is returned only once to the caller.
  184.  */
  185. static char errbuf[BUFSIZ];
  186. static int errvalid;
  187.  
  188. /*
  189.  * The `fixed' gcc header files on AIX 3.2.5 provide a prototype for
  190.  * strdup().  --jwe
  191.  */
  192. extern char *strdup(const char *);
  193. static void caterr(char *);
  194. static int readExports(ModulePtr);
  195. static void terminate(void);
  196. static void *findMain(void);
  197.  
  198. void *dlopen(const char *path, int mode)
  199. {
  200.     register ModulePtr mp;
  201.     static void *mainModule;
  202.  
  203.     /*
  204.      * Upon the first call register a terminate handler that will
  205.      * close all libraries. Also get a reference to the main module
  206.      * for use with loadbind.
  207.      */
  208.     if (!mainModule) {
  209.     if ((mainModule = findMain()) == NULL)
  210.         return NULL;
  211.     atexit(terminate);
  212.     }
  213.     /*
  214.      * Scan the list of modules if we have the module already loaded.
  215.      */
  216.     for (mp = modList; mp; mp = mp->next)
  217.     if (strcmp(mp->name, path) == 0) {
  218.         mp->refCnt++;
  219.         return mp;
  220.     }
  221.     if ((mp = (ModulePtr) calloc(1, sizeof(*mp))) == NULL) {
  222.     errvalid++;
  223.     strcpy(errbuf, "calloc: ");
  224.     strcat(errbuf, strerror(errno));
  225.     return NULL;
  226.     }
  227.     if ((mp->name = strdup(path)) == NULL) {
  228.     errvalid++;
  229.     strcpy(errbuf, "strdup: ");
  230.     strcat(errbuf, strerror(errno));
  231.     free(mp);
  232.     return NULL;
  233.     }
  234.     /*
  235.      * load should be declared load(const char *...). Thus we
  236.      * cast the path to a normal char *. Ugly.
  237.      */
  238.     if ((mp->entry = (void *) load((char *) path, L_NOAUTODEFER, NULL)) == NULL) {
  239.     free(mp->name);
  240.     free(mp);
  241.     errvalid++;
  242.     strcpy(errbuf, "dlopen: ");
  243.     strcat(errbuf, path);
  244.     strcat(errbuf, ": ");
  245.     /*
  246.      * If AIX says the file is not executable, the error
  247.      * can be further described by querying the loader about
  248.      * the last error.
  249.      */
  250.     if (errno == ENOEXEC) {
  251.         char *tmp[BUFSIZ / sizeof(char *)];
  252.         if (loadquery(L_GETMESSAGES, tmp, sizeof(tmp)) == -1)
  253.         strcpy(errbuf, strerror(errno));
  254.         else {
  255.         char **p;
  256.         for (p = tmp; *p; p++)
  257.             caterr(*p);
  258.         }
  259.     }
  260.     else
  261.         strcat(errbuf, strerror(errno));
  262.     return NULL;
  263.     }
  264.     mp->refCnt = 1;
  265.     mp->next = modList;
  266.     modList = mp;
  267.     if (loadbind(0, mainModule, mp->entry) == -1) {
  268.     dlclose(mp);
  269.     errvalid++;
  270.     strcpy(errbuf, "loadbind: ");
  271.     strcat(errbuf, strerror(errno));
  272.     return NULL;
  273.     }
  274.     /*
  275.      * If the user wants global binding, loadbind against all other
  276.      * loaded modules.
  277.      */
  278.     if (mode & RTLD_GLOBAL) {
  279.     register ModulePtr mp1;
  280.     for (mp1 = mp->next; mp1; mp1 = mp1->next)
  281.         if (loadbind(0, mp1->entry, mp->entry) == -1) {
  282.         dlclose(mp);
  283.         errvalid++;
  284.         strcpy(errbuf, "loadbind: ");
  285.         strcat(errbuf, strerror(errno));
  286.         return NULL;
  287.         }
  288.     }
  289.     if (readExports(mp) == -1) {
  290.     dlclose(mp);
  291.     return NULL;
  292.     }
  293.     /*
  294.      * If there is a dl_info structure, call the init function.
  295.      */
  296.     if (mp->info = (struct dl_info *) dlsym(mp, "dl_info")) {
  297.     if (mp->info->init)
  298.         (*mp->info->init) ();
  299.     }
  300.     else
  301.     errvalid = 0;
  302.     /*
  303.      * If the shared object was compiled using xlC we will need
  304.      * to call static constructors (and later on dlclose destructors).
  305.      */
  306.     if (mp->cdtors = (CdtorPtr) dlsym(mp, "__cdtors")) {
  307.     CdtorPtr cp = mp->cdtors;
  308.     while (cp->init || cp->term) {
  309.         if (cp->init && cp->init != (void (*)(void)) 0xffffffff)
  310.         (*cp->init) ();
  311.         cp++;
  312.     }
  313.     /*
  314.      * If the shared object was compiled using g++, we will need
  315.      * to call global constructors using the _GLOBAL__DI function,
  316.      * and later, global destructors using the _GLOBAL_DD
  317.      * funciton.  --jwe
  318.      */
  319.     }
  320.     else if (mp->gcc_ctor = (GccCDtorPtr) dlsym(mp, "_GLOBAL__DI")) {
  321.     (*mp->gcc_ctor) ();
  322.     mp->gcc_dtor = (GccCDtorPtr) dlsym(mp, "_GLOBAL__DD");
  323.     }
  324.     else
  325.     errvalid = 0;
  326.     return mp;
  327. }
  328.  
  329. /*
  330.  * Attempt to decipher an AIX loader error message and append it
  331.  * to our static error message buffer.
  332.  */
  333. static void caterr(char *s)
  334. {
  335.     register char *p = s;
  336.  
  337.     while (*p >= '0' && *p <= '9')
  338.     p++;
  339.     switch (atoi(s)) {
  340.     case L_ERROR_TOOMANY:
  341.     strcat(errbuf, "to many errors");
  342.     break;
  343.     case L_ERROR_NOLIB:
  344.     strcat(errbuf, "can't load library");
  345.     strcat(errbuf, p);
  346.     break;
  347.     case L_ERROR_UNDEF:
  348.     strcat(errbuf, "can't find symbol");
  349.     strcat(errbuf, p);
  350.     break;
  351.     case L_ERROR_RLDBAD:
  352.     strcat(errbuf, "bad RLD");
  353.     strcat(errbuf, p);
  354.     break;
  355.     case L_ERROR_FORMAT:
  356.     strcat(errbuf, "bad exec format in");
  357.     strcat(errbuf, p);
  358.     break;
  359.     case L_ERROR_ERRNO:
  360.     strcat(errbuf, strerror(atoi(++p)));
  361.     break;
  362.     default:
  363.     strcat(errbuf, s);
  364.     break;
  365.     }
  366. }
  367.  
  368. void *dlsym(void *handle, const char *symbol)
  369. {
  370.     register ModulePtr mp = (ModulePtr) handle;
  371.     register ExportPtr ep;
  372.     register int i;
  373.  
  374.     /*
  375.      * Could speed up the search, but I assume that one assigns
  376.      * the result to function pointers anyways.
  377.      */
  378.     for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
  379.     if (strcmp(ep->name, symbol) == 0)
  380.         return ep->addr;
  381.     errvalid++;
  382.     strcpy(errbuf, "dlsym: undefined symbol ");
  383.     strcat(errbuf, symbol);
  384.     return NULL;
  385. }
  386.  
  387. const char *dlerror(void)
  388. {
  389.     if (errvalid) {
  390.     errvalid = 0;
  391.     return errbuf;
  392.     }
  393.     return NULL;
  394. }
  395.  
  396. int dlclose(void *handle)
  397. {
  398.     register ModulePtr mp = (ModulePtr) handle;
  399.     int result;
  400.     register ModulePtr mp1;
  401.  
  402.     if (--mp->refCnt > 0)
  403.     return 0;
  404.     if (mp->info && mp->info->fini)
  405.     (*mp->info->fini) ();
  406.     if (mp->cdtors) {
  407.     CdtorPtr cp = mp->cdtors;
  408.     while (cp->init || cp->term) {
  409.         if (cp->term && cp->init != (void (*)(void)) 0xffffffff)
  410.         (*cp->term) ();
  411.         cp++;
  412.     }
  413.     /*
  414.      * If the function to handle global destructors for g++
  415.      * exists, call it.  --jwe
  416.      */
  417.     }
  418.     else if (mp->gcc_dtor) {
  419.     (*mp->gcc_dtor) ();
  420.     }
  421.     result = unload(mp->entry);
  422.     if (result == -1) {
  423.     errvalid++;
  424.     strcpy(errbuf, strerror(errno));
  425.     }
  426.     if (mp->exports) {
  427.     register ExportPtr ep;
  428.     register int i;
  429.     for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
  430.         if (ep->name)
  431.         free(ep->name);
  432.     free(mp->exports);
  433.     }
  434.     if (mp == modList)
  435.     modList = mp->next;
  436.     else {
  437.     for (mp1 = modList; mp1; mp1 = mp1->next)
  438.         if (mp1->next == mp) {
  439.         mp1->next = mp->next;
  440.         break;
  441.         }
  442.     }
  443.     free(mp->name);
  444.     free(mp);
  445.     return result;
  446. }
  447.  
  448. static void terminate(void)
  449. {
  450.     while (modList)
  451.     dlclose(modList);
  452. }
  453.  
  454. /*
  455.  * Build the export table from the XCOFF .loader section.
  456.  */
  457. static int readExports(ModulePtr mp)
  458. {
  459.     LDFILE *ldp = NULL;
  460.     SCNHDR sh, shdata;
  461.     LDHDR *lhp;
  462.     char *ldbuf;
  463.     LDSYM *ls;
  464.     int i;
  465.     ExportPtr ep;
  466.     struct ld_info *lp;
  467.     char *buf;
  468.     int size = 4 * 1024;
  469.     void *dataorg;
  470.  
  471.     /*
  472.      * The module might be loaded due to the LIBPATH
  473.      * environment variable. Search for the loaded
  474.      * module using L_GETINFO.
  475.      */
  476.     if ((buf = malloc(size)) == NULL) {
  477.     errvalid++;
  478.     strcpy(errbuf, "readExports: ");
  479.     strcat(errbuf, strerror(errno));
  480.     return -1;
  481.     }
  482.     while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
  483.     free(buf);
  484.     size += 4 * 1024;
  485.     if ((buf = malloc(size)) == NULL) {
  486.         errvalid++;
  487.         strcpy(errbuf, "readExports: ");
  488.         strcat(errbuf, strerror(errno));
  489.         return -1;
  490.     }
  491.     }
  492.     if (i == -1) {
  493.     errvalid++;
  494.     strcpy(errbuf, "readExports: ");
  495.     strcat(errbuf, strerror(errno));
  496.     free(buf);
  497.     return -1;
  498.     }
  499.     /*
  500.      * Traverse the list of loaded modules. The entry point
  501.      * returned by load() does actually point to the TOC
  502.      * entry contained in the data segment.
  503.      */
  504.     lp = (struct ld_info *) buf;
  505.     while (lp) {
  506.     if ((unsigned long) mp->entry >= (unsigned long) lp->ldinfo_dataorg &&
  507.         (unsigned long) mp->entry < (unsigned long) lp->ldinfo_dataorg +
  508.         lp->ldinfo_datasize) {
  509.         dataorg = lp->ldinfo_dataorg;
  510.         ldp = ldopen(lp->ldinfo_filename, ldp);
  511.         break;
  512.     }
  513.     if (lp->ldinfo_next == 0)
  514.         lp = NULL;
  515.     else
  516.         lp = (struct ld_info *) ((char *) lp + lp->ldinfo_next);
  517.     }
  518.     free(buf);
  519.     if (!ldp) {
  520.     errvalid++;
  521.     strcpy(errbuf, "readExports: ");
  522.     strcat(errbuf, strerror(errno));
  523.     return -1;
  524.     }
  525.     if (TYPE(ldp) != U802TOCMAGIC) {
  526.     errvalid++;
  527.     strcpy(errbuf, "readExports: bad magic");
  528.     while (ldclose(ldp) == FAILURE);
  529.     return -1;
  530.     }
  531.     /*
  532.      * Get the padding for the data section. This is needed for
  533.      * AIX 4.1 compilers. This is used when building the final
  534.      * function pointer to the exported symbol.
  535.      */
  536.     if (ldnshread(ldp, _DATA, &shdata) != SUCCESS) {
  537.     errvalid++;
  538.     strcpy(errbuf, "readExports: cannot read data section header");
  539.     while (ldclose(ldp) == FAILURE);
  540.     return -1;
  541.     }
  542.     if (ldnshread(ldp, _LOADER, &sh) != SUCCESS) {
  543.     errvalid++;
  544.     strcpy(errbuf, "readExports: cannot read loader section header");
  545.     while (ldclose(ldp) == FAILURE);
  546.     return -1;
  547.     }
  548.     /*
  549.      * We read the complete loader section in one chunk, this makes
  550.      * finding long symbol names residing in the string table easier.
  551.      */
  552.     if ((ldbuf = (char *) malloc(sh.s_size)) == NULL) {
  553.     errvalid++;
  554.     strcpy(errbuf, "readExports: ");
  555.     strcat(errbuf, strerror(errno));
  556.     while (ldclose(ldp) == FAILURE);
  557.     return -1;
  558.     }
  559.     if (FSEEK(ldp, sh.s_scnptr, BEGINNING) != OKFSEEK) {
  560.     errvalid++;
  561.     strcpy(errbuf, "readExports: cannot seek to loader section");
  562.     free(ldbuf);
  563.     while (ldclose(ldp) == FAILURE);
  564.     return -1;
  565.     }
  566.     if (FREAD(ldbuf, sh.s_size, 1, ldp) != 1) {
  567.     errvalid++;
  568.     strcpy(errbuf, "readExports: cannot read loader section");
  569.     free(ldbuf);
  570.     while (ldclose(ldp) == FAILURE);
  571.     return -1;
  572.     }
  573.     lhp = (LDHDR *) ldbuf;
  574.     ls = (LDSYM *) (ldbuf + LDHDRSZ);
  575.     /*
  576.      * Count the number of exports to include in our export table.
  577.      */
  578.     for (i = lhp->l_nsyms; i; i--, ls++) {
  579.     if (!LDR_EXPORT(*ls))
  580.         continue;
  581.     mp->nExports++;
  582.     }
  583.     if ((mp->exports = (ExportPtr) calloc(mp->nExports, sizeof(*mp->exports))) == NULL) {
  584.     errvalid++;
  585.     strcpy(errbuf, "readExports: ");
  586.     strcat(errbuf, strerror(errno));
  587.     free(ldbuf);
  588.     while (ldclose(ldp) == FAILURE);
  589.     return -1;
  590.     }
  591.     /*
  592.      * Fill in the export table. All entries are relative to
  593.      * the beginning of the data origin.
  594.      */
  595.     ep = mp->exports;
  596.     ls = (LDSYM *) (ldbuf + LDHDRSZ);
  597.     for (i = lhp->l_nsyms; i; i--, ls++) {
  598.     char *symname;
  599.     char tmpsym[SYMNMLEN + 1];
  600.     if (!LDR_EXPORT(*ls))
  601.         continue;
  602.     if (ls->l_zeroes == 0)
  603.         symname = ls->l_offset + lhp->l_stoff + ldbuf;
  604.     else {
  605.         /*
  606.          * The l_name member is not zero terminated, we
  607.          * must copy the first SYMNMLEN chars and make
  608.          * sure we have a zero byte at the end.
  609.          */
  610.         strncpy(tmpsym, ls->l_name, SYMNMLEN);
  611.         tmpsym[SYMNMLEN] = '\0';
  612.         symname = tmpsym;
  613.     }
  614.     ep->name = strdup(symname);
  615.     ep->addr = (void *) ((unsigned long) dataorg +
  616.                  ls->l_value - shdata.s_vaddr);
  617.     ep++;
  618.     }
  619.     free(ldbuf);
  620.     while (ldclose(ldp) == FAILURE);
  621.     return 0;
  622. }
  623.  
  624. /*
  625.  * Find the main modules data origin. This is used as export pointer
  626.  * for loadbind() to be able to resolve references to the main part.
  627.  */
  628. static void *findMain(void)
  629. {
  630.     struct ld_info *lp;
  631.     char *buf;
  632.     int size = 4 * 1024;
  633.     int i;
  634.     void *ret;
  635.  
  636.     if ((buf = malloc(size)) == NULL) {
  637.     errvalid++;
  638.     strcpy(errbuf, "findMain: ");
  639.     strcat(errbuf, strerror(errno));
  640.     return NULL;
  641.     }
  642.     while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
  643.     free(buf);
  644.     size += 4 * 1024;
  645.     if ((buf = malloc(size)) == NULL) {
  646.         errvalid++;
  647.         strcpy(errbuf, "findMain: ");
  648.         strcat(errbuf, strerror(errno));
  649.         return NULL;
  650.     }
  651.     }
  652.     if (i == -1) {
  653.     errvalid++;
  654.     strcpy(errbuf, "findMain: ");
  655.     strcat(errbuf, strerror(errno));
  656.     free(buf);
  657.     return NULL;
  658.     }
  659.     /*
  660.      * The first entry is the main module. The data segment
  661.      * starts with the TOC entries for all exports, so the
  662.      * data segment origin works as argument for loadbind.
  663.      */
  664.     lp = (struct ld_info *) buf;
  665.     ret = lp->ldinfo_dataorg;
  666.     free(buf);
  667.     return ret;
  668. }
  669.