Index: ltdl.c =================================================================== RCS file: /home/cvs/libtool/libltdl/ltdl.c,v retrieving revision 1.64.2.19 diff -u -r1.64.2.19 ltdl.c --- ltdl.c 2000/09/04 01:53:05 1.64.2.19 +++ ltdl.c 2000/10/13 13:39:37 @@ -206,7 +206,7 @@ #endif -#if HAVE_LIBDL +#if defined(HAVE_LIBDL) && !defined(_AIX) /* dynamic linking with dlopen/dlsym */ @@ -458,6 +458,7 @@ if (dld_link(filename) != 0) { last_error = cannot_open_error; lt_dlfree(handle->handle); + handle->handle = NULL; return 1; } return 0; @@ -472,6 +473,8 @@ return 1; } lt_dlfree(handle->filename); + handle->handle = NULL; + handle->filename = NULL; return 0; } @@ -497,6 +500,431 @@ #endif +#ifdef _AIX + +/* dynamic linking for AIX */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * AIX 4.3 removes some useful definitions from ldfcn.h. Define + * these here to compensate for that lossage. + */ +#ifndef BEGINNING +# define BEGINNING SEEK_SET +#endif +#ifndef FSEEK +# define FSEEK(ldptr,o,p) fseek(IOPTR(ldptr),(p==BEGINNING)?(OFFSET(ldptr) +o):o,p) +#endif +#ifndef FREAD +# define FREAD(p,s,n,ldptr) fread(p,s,n,IOPTR(ldptr)) +#endif + +/* + * We simulate dlopen() et al. through a call to load. Because AIX has + * no call to find an exported symbol we read the loader section of the + * loaded module and build a list of exported symbols and their virtual + * address. + */ + +typedef struct { + char *name; /* the symbols's name */ + lt_ptr_t *addr; /* its relocated virtual address */ +} Export, *ExportPtr; + +/* + * The void * handle returned from dlopen is actually a ModulePtr. + */ +typedef struct Module { + void *entry; /* entry point from load */ + int nExports; /* the number of exports found */ + ExportPtr exports; /* the array of exports */ +} Module, *ModulePtr; + +static void *mainModule; +static char errbuf[BUFSIZ]; + +static int readExports(ModulePtr); + +static void caterr(char *s) +{ + register char *p = s; + + while (isdigit(*p)) p++; + + last_error = errbuf; + + switch(atoi(s)) { + case L_ERROR_TOOMANY: + last_error = "too many errors"; + break; + case L_ERROR_NOLIB: + strcpy(errbuf, "can't load library"); + strcat(errbuf, p); + break; + case L_ERROR_UNDEF: + strcpy(errbuf, symbol_error); + strcat(errbuf, p); + break; + case L_ERROR_RLDBAD: + strcpy(errbuf, "bad RLD"); + strcat(errbuf, p); + break; + case L_ERROR_FORMAT: + strcpy(errbuf, "bad exec format in"); + strcat(errbuf, p); + break; + case L_ERROR_ERRNO: + last_error = strerror(atoi(++p)); + break; + case L_ERROR_MEMBER: + strcpy(errbuf, "member not found"); + strcat(errbuf, p); + break; + case L_ERROR_TYPE: + strcpy(errbuf, "symbol type mismatch"); + strcat(errbuf, p); + break; + case L_ERROR_ALIGN: + last_error = "bad text alignment"; + break; + case L_ERROR_DOMCREAT: + last_error = "cannot create loader domain"; + break; + case L_ERROR_DOMADD: + last_error = "cannot add to loader domain"; + break; + case L_ERROR_SYSTEM: + strcpy(errbuf, "system error"); + strcat(errbuf, p); + break; + default: + strcpy(errbuf, s); + break; + } +} + +/* + * Find the main module's entry point. This is used as export pointer + * for loadbind() to be able to resolve references to the main part. + */ +static int +sys_aix_init LTDL_PARAMS((void)) +{ + struct ld_info *lp; + char *buf; + int size = 4*1024; + int i; + void *ret; + + if ((buf = lt_dlmalloc(size)) == NULL) { + last_error = memory_error; + return -1; + } + while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) { + lt_dlfree(buf); + size += 4*1024; + if ((buf = lt_dlmalloc(size)) == NULL) { + last_error = memory_error; + return -1; + } + } + if (i == -1) { + last_error = strerror(errno); + lt_dlfree(buf); + return -1; + } + /* + * The first entry is the main module. The entry point + * returned by load() actually points to the data + * segment origin. + */ + lp = (struct ld_info *)buf; + mainModule = lp->ldinfo_dataorg; + lt_dlfree(buf); + return 0; +} + +static int +sys_aix_exit LTDL_PARAMS((void)) +{ + return 0; +} + +/* Forward declaration... */ +static lt_dlhandle handles; + +static int sys_aix_doclose(ModulePtr mp); + +static int +sys_aix_open (handle, filename) + lt_dlhandle handle; + const char *filename; +{ + register ModulePtr mp = lt_dlmalloc(sizeof(Module)); + lt_dlhandle cur; + + handle->handle = NULL; + if (!mp) { + last_error = memory_error; + return 1; + } + mp->nExports = 0; + mp->exports = NULL; + if (!filename) { + mp->entry = mainModule; + } else { + if (!(mp->entry = (lt_ptr_t)load((char *)filename, 0, NULL))) { + char *tmp[BUFSIZ/sizeof(char *)]; + lt_dlfree(mp); + if (loadquery(L_GETMESSAGES, tmp, sizeof(tmp)) == -1) + last_error = strerror(errno); + else + caterr(tmp[0]); + + return 1; + } + if (loadbind(0, mainModule, mp->entry) == -1) { + sys_aix_doclose(mp); + last_error = strerror(errno); + return 1; + } + for (cur=handles; cur; cur=cur->next) { + ModulePtr m2 = (ModulePtr)cur->handle; + if (m2 && loadbind(0, m2->entry, mp->entry) == -1) { + sys_aix_doclose(mp); + last_error = strerror(errno); + return 1; + } + } + } + if (readExports(mp) == -1) { + sys_aix_doclose(mp); + return 1; + } + handle->handle = mp; + return 0; +} + +static int sys_aix_doclose(ModulePtr mp) +{ + int result; + + result = unload(mp->entry); + if (result == -1) { + last_error = strerror(errno); + } + if (mp->exports) { + register ExportPtr ep; + register int i; + for (ep = mp->exports, i = mp->nExports; i; i--, ep++) + if (ep->name) + lt_dlfree(ep->name); + lt_dlfree(mp->exports); + } + lt_dlfree(mp); + return result; +} + +static int +sys_aix_close(handle) + lt_dlhandle handle; +{ + register ModulePtr mp = (ModulePtr)handle->handle; + int res = sys_aix_doclose(mp); + handle->handle = NULL; + return res; +} + +static lt_ptr_t +sys_aix_sym (handle, symbol) + lt_dlhandle handle; + const char *symbol; +{ + register ModulePtr mp = (ModulePtr)handle->handle; + register ExportPtr ep; + register int i; + + /* + * Could speed up search, but I assume that one assigns + * the result to function pointers anyways. + */ + for (ep = mp->exports, i = mp->nExports; i; i--, ep++) + if (strcmp(ep->name, symbol) == 0) + return ep->addr; + last_error = symbol_error; + return NULL; +} +/* + * Build the export table from the XCOFF .loader section. + */ +static int +readExports(mp) + ModulePtr mp; +{ + LDFILE *ldp = NULL; + SCNHDR sh, shdata; + LDHDR *lhp; + char *ldbuf; + LDSYM *ls; + int i; + ExportPtr ep; + struct ld_info *lp; + char *buf; + int size = 4*1024; + void *dataorg; + + if (mp->entry == mainModule) { + char ***args = (char ***)ARGS_loc; + dataorg = mainModule; + ldp = ldopen(*args[0], ldp); + } else { + + /* + * The module might be loaded due to the LIBPATH + * environment variable. Search for the loaded + * module using L_GETINFO. + */ + if ((buf = lt_dlmalloc(size)) == NULL) { + last_error = memory_error; + return -1; + } + while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) { + lt_dlfree(buf); + size += 4*1024; + if ((buf = lt_dlmalloc(size)) == NULL) { + last_error = memory_error; + return -1; + } + } + if (i == -1) { + last_error = strerror(errno); + lt_dlfree(buf); + return -1; + } + /* + * Traverse the list of loaded modules. The entry point + * returned by load() does actually point to the data + * segment origin. + */ + lp = (struct ld_info *)buf; + while (lp) { + if ((unsigned long)mp->entry >= (unsigned long)lp->ldinfo_dataorg && + (unsigned long)mp->entry < (unsigned long)lp->ldinfo_dataorg + + lp->ldinfo_datasize) { + dataorg = lp->ldinfo_dataorg; + ldp = ldopen(lp->ldinfo_filename, ldp); + break; + } + if (lp->ldinfo_next == 0) + lp = NULL; + else + lp = (struct ld_info *)((char *)lp + lp->ldinfo_next); + } + lt_dlfree(buf); + } + if (!ldp) { + last_error = strerror(errno); + return -1; + } + if (TYPE(ldp) != U802TOCMAGIC) { + last_error = "bad magic"; + while(ldclose(ldp) == FAILURE) + ; + return -1; + } + if (ldnshread(ldp, _DATA, &shdata) != SUCCESS) { + last_error = "cannot read data section header"; + while(ldclose(ldp) == FAILURE) ; + return -1; + } + if (ldnshread(ldp, _LOADER, &sh) != SUCCESS) { + last_error = "cannot read loader section header"; + while(ldclose(ldp) == FAILURE) ; + return -1; + } + /* + * We read the complete loader section in one chunk, this makes + * finding long symbol names residing in the string table easier. + */ + if ((ldbuf = (char *)lt_dlmalloc(sh.s_size)) == NULL) { + last_error = memory_error; + while(ldclose(ldp) == FAILURE) ; + return -1; + } + if (FSEEK(ldp, sh.s_scnptr, BEGINNING) != OKFSEEK) { + last_error = "cannot seek to loader section"; + lt_dlfree(ldbuf); + while(ldclose(ldp) == FAILURE) ; + return -1; + } + if (FREAD(ldbuf, sh.s_size, 1, ldp) != 1) { + last_error = "cannot read loader section"; + lt_dlfree(ldbuf); + while(ldclose(ldp) == FAILURE) ; + return -1; + } + lhp = (LDHDR *)ldbuf; + ls = (LDSYM *)(ldbuf+LDHDRSZ); + /* + * Count the number of exports to include in our export table. + */ + for (i = lhp->l_nsyms; i; i--, ls++) { + if (!LDR_EXPORT(*ls)) + continue; + mp->nExports++; + } + mp->exports = lt_dlmalloc(sizeof(Export)*mp->nExports); + if (mp->exports == NULL) { + last_error = memory_error; + lt_dlfree(ldbuf); + while(ldclose(ldp) == FAILURE) ; + return -1; + } + /* + * Fill in the export table. All entries are relative to + * the beginning of the data section. + */ + ep = mp->exports; + ls = (LDSYM *)(ldbuf+LDHDRSZ); + for (i = lhp->l_nsyms; i; i--, ls++) { + char *symname; + char tmpsym[SYMNMLEN+1]; + if (!LDR_EXPORT(*ls)) + continue; + if (ls->l_zeroes == 0) + symname = ls->l_offset+lhp->l_stoff+ldbuf; + else { + strncpy(tmpsym, ls->l_name, SYMNMLEN); + tmpsym[SYMNMLEN] = '\0'; + symname = tmpsym; + } + ep->name = strdup(symname); + ep->addr = (void *)((unsigned long)dataorg + ls->l_value - + shdata.s_vaddr); + ep++; + } + lt_dlfree(ldbuf); + while(ldclose(ldp) == FAILURE) ; + return 0; + } + +static +lt_dltype_t +sys_aix = { LTDL_TYPE_TOP, 0, sys_aix_init, sys_aix_exit, + sys_aix_open, sys_aix_close, sys_aix_sym }; + +#undef LTDL_TYPE_TOP +#define LTDL_TYPE_TOP &sys_aix + +#endif /* _AIX */ + #ifdef _WIN32 /* dynamic linking for Win32 */ @@ -524,23 +952,32 @@ const char *filename; { lt_dlhandle cur; - char *searchname = NULL; - char *ext = strrchr(filename, '.'); - if (ext) { - /* FILENAME already has an extension. */ - searchname = strdup(filename); - } else { - /* Append a `.' to stop Windows from adding an - implicit `.dll' extension. */ - searchname = (char*)lt_dlmalloc(2+ strlen(filename)); - strcpy(searchname, filename); - strcat(searchname, "."); - } - - handle->handle = LoadLibrary(searchname); - lt_dlfree(searchname); - + if (filename) + { + char *searchname = NULL; + char *ext = strrchr(filename, '.'); + + if (ext) { + /* FILENAME already has an extension. */ + searchname = strdup(filename); + } else { + /* Append a `.' to stop Windows from adding an + implicit `.dll' extension. */ + searchname = (char*)lt_dlmalloc(2+ strlen(filename)); + strcpy(searchname, filename); + strcat(searchname, "."); + } + + handle->handle = LoadLibrary(searchname); + lt_dlfree(searchname); + } + else + { + handle->handle = GetModuleHandle(NULL); + return 0; + } + /* libltdl expects this function to fail if it is unable to physically load the library. Sadly, LoadLibrary will search the loaded libraries for a match and return @@ -549,6 +986,7 @@ We check whether LoadLibrary is returning a handle to an already loaded module, and simulate failure if we find one. */ + cur = handles; while (cur) { if (!cur->handle) { @@ -586,6 +1024,20 @@ { lt_ptr_t address = GetProcAddress(handle->handle, symbol); + if (!address && !handle->filename) + { + lt_dlhandle cur; + + for (cur = handles; cur; cur=cur->next) + { + if (cur == handle) + continue; + address = GetProcAddress(cur->handle, symbol); + if (address) + break; + } + } + if (!address) last_error = symbol_error; return address; @@ -932,6 +1384,13 @@ cur = *handle; if (filename) { + FILE *f = fopen(filename, "r"); + if (!f) + { + last_error = file_not_found_error; + return 1; + } + fclose(f); cur->filename = strdup(filename); if (!cur->filename) { last_error = memory_error; @@ -946,7 +1405,10 @@ } if (!type) { if (cur->filename) + { lt_dlfree(cur->filename); + cur->filename = NULL; + } return 1; } cur->type = type; @@ -971,6 +1433,7 @@ if (old_name && tryall_dlopen(handle, old_name) == 0) return 0; /* try to open the dynamic library */ + last_error = NULL; if (dlname) { /* try to open the installed module */ if (installed && libdir) { @@ -987,6 +1450,8 @@ lt_dlfree(filename); if (error) return 0; + if (last_error != file_not_found_error) + return 1; } /* try to open the not-installed module */ if (!installed) { @@ -1008,6 +1473,8 @@ lt_dlfree(filename); if (error) return 0; + if (last_error != file_not_found_error) + return 1; } /* hmm, maybe it was moved to another directory */ { @@ -1025,7 +1492,8 @@ return 0; } } - last_error = file_not_found_error; + if (!last_error) + last_error = file_not_found_error; return 1; }