/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1997-2007 AT&T Knowledge Ventures * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Knowledge Ventures * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * * * * Information and Software Systems Research * * AT&T Research * * Florham Park NJ * * * * Glenn Fowler * * * ***********************************************************************/ #pragma prototyped /* * provide dlopen/dlsym/dlerror interface * * David Korn * Glenn Fowler * AT&T Research */ static const char id[] = "\n@(#)$Id: dll library (AT&T Research) 2005-02-14 $\0\n"; #include #include #include #define T(x) ERROR_dictionary(x) #if _BLD_dll && defined(__EXPORT__) #define extern __EXPORT__ #endif #if _hdr_dlfcn && _lib_dlopen /* * standard */ # include #else #if _hdr_dl /* * HP-UX */ # include # ifndef BIND_FIRST # define BIND_FIRST 0x4 # endif # ifndef BIND_NOSTART # define BIND_NOSTART 0x10 # endif static shl_t all; static int err; extern void* dlopen(const char* path, int mode) { void* dll; if (!path) return (void*)&all; if (mode) mode = (BIND_IMMEDIATE|BIND_FIRST|BIND_NOSTART); if (!(dll = (void*)shl_load(path, mode, 0L))) err = errno; return dll; } extern int dlclose(void* dll) { return 0; } extern void* dlsym(void* dll, const char* name) { shl_t handle; long addr; handle = dll == (void*)&all ? (shl_t)0 : (shl_t)dll; if (shl_findsym(&handle, name, TYPE_UNDEFINED, &addr)) { err = errno; return 0; } return (void*)addr; } extern char* dlerror(void) { char* msg; if (!err) return 0; msg = fmterror(err); err = 0; return msg; } #else #if _sys_ldr && _lib_loadbind /* * rs6000 */ # include # include /* xcoff module header */ struct hdr { struct filehdr f; struct aouthdr a; struct scnhdr s[1]; }; static struct ld_info* ld_info; static unsigned int ld_info_size = 1024; static void* last_module; static int err; extern void* dlopen(const char* path, int mode) { void* dll; if (!(dll = (void*)load((char*)path, mode, getenv("LIBPATH")))) err = errno; return dll; } extern int dlclose(void* dll) { return 0; } static int getquery(void) { if (!ld_info) ld_info = malloc(ld_info_size); for (;;) { if (!ld_info) return 1; if (!loadquery(L_GETINFO, ld_info, ld_info_size)) return 0; if (errno != ENOMEM) return 1; ld_info = realloc(ld_info, ld_info_size *= 2); } } /* find the loaded module whose data area contains the * address passed in. Remember that procedure pointers * are implemented as pointers to descriptors in the * data area of the module defining the procedure */ static struct ld_info* getinfo(void* module) { struct ld_info* info = ld_info; register int n = 1; if (!ld_info || module != last_module) { last_module = module; if (getquery()) return 0; info = ld_info; } while (n) { if ((char*)(info->ldinfo_dataorg) <= (char*)module && (char*)module <= ((char*)(info->ldinfo_dataorg) + (unsigned)(info->ldinfo_datasize))) return info; if (n=info->ldinfo_next) info = (void*)((char*)info + n); } return 0; } static char* getloc(struct hdr* hdr, char* data, char* name) { struct ldhdr* ldhdr; struct ldsym* ldsym; ulong datareloc; ulong textreloc; int i; /* data is relocated by the difference between * its virtual origin and where it was * actually placed */ /*N.B. o_sndata etc. are one based */ datareloc = (ulong)data - hdr->s[hdr->a.o_sndata-1].s_vaddr; /*hdr is address of header, not text, so add text s_scnptr */ textreloc = (ulong)hdr + hdr->s[hdr->a.o_sntext-1].s_scnptr - hdr->s[hdr->a.o_sntext-1].s_vaddr; ldhdr = (void*)((char*)hdr+ hdr->s[hdr->a.o_snloader-1].s_scnptr); ldsym = (void*) (ldhdr+1); /* search the exports symbols */ for(i=0; i < ldhdr->l_nsyms;ldsym++,i++) { char *symname,symbuf[9]; char *loc; /* the symbol name representation is a nuisance since * 8 character names appear in l_name but may * not be null terminated. This code works around * that by brute force */ if (ldsym->l_zeroes) { symname = symbuf; memcpy(symbuf,ldsym->l_name,8); symbuf[8] = 0; } else symname = (void*)(ldsym->l_offset + (ulong)ldhdr + ldhdr->l_stoff); if (strcmp(symname,name)) continue; loc = (char*)ldsym->l_value; if ((ldsym->l_scnum==hdr->a.o_sndata) || (ldsym->l_scnum==hdr->a.o_snbss)) loc += datareloc; else if (ldsym->l_scnum==hdr->a.o_sntext) loc += textreloc; return loc; } return 0; } extern void* dlsym(void* handle, const char* name) { void* addr; struct ld_info* info; if (!(info = getinfo(handle)) || !(addr = getloc(info->ldinfo_textorg,info->ldinfo_dataorg,(char*)name))) { err = errno; return 0; } return addr; } extern char* dlerror(void) { char* msg; if (!err) return 0; msg = fmterror(err); err = 0; return msg; } #else #if _hdr_dll && _lib_dllload /* * MVS */ # include static int err; extern void* dlopen(const char* path, int mode) { void* dll; NoP(mode); if (!(dll = (void*)dllload(path))) err = errno; return dll; } extern int dlclose(void* dll) { return 0; } extern void* dlsym(void* handle, const char* name) { void* addr; if (!(addr = (void*)dllqueryfn(handle, (char*)name))) err = errno; return addr; } extern char* dlerror(void) { char* msg; if (!err) return 0; msg = fmterror(err); err = 0; return msg; } #else #if _hdr_mach_o_dyld /* * mac[h] */ # include typedef const struct mach_header* NSImage; typedef struct Dll_s { unsigned long magic; NSImage image; NSModule module; char path[1]; } Dll_t; #define DL_MAGIC 0x04190c04 #define DL_NEXT ((Dll_t*)RTLD_NEXT) static const char* dlmessage = "no error"; static const char e_cover[] = T("cannot access covered library"); static const char e_handle[] = T("invalid handle"); static const char e_space[] = T("out of space"); static const char e_static[] = T("image statically linked"); static const char e_undefined[] = T("undefined symbol"); static Dll_t global = { DL_MAGIC }; static void undefined(const char* name) { } static NSModule multiple(NSSymbol sym, NSModule om, NSModule nm) { return om; } static void linkedit(NSLinkEditErrors c, int n, const char* f, const char* m) { dlmessage = m; } static NSLinkEditErrorHandlers handlers = { undefined, multiple, linkedit }; extern void* dlopen(const char* path, int mode) { Dll_t* dll; int i; NSObjectFileImage image; static int init = 0; if (!_dyld_present()) { dlmessage = e_static; return 0; } if (!init) { init = 1; NSInstallLinkEditErrorHandlers(&handlers); } if (!path) dll = &global; else if (!(dll = newof(0, Dll_t, 1, strlen(path)))) { dlmessage = e_space; return 0; } else { switch (NSCreateObjectFileImageFromFile(path, &image)) { case NSObjectFileImageSuccess: dll->module = NSLinkModule(image, path, (mode & RTLD_LAZY) ? 0 : NSLINKMODULE_OPTION_BINDNOW); NSDestroyObjectFileImage(image); if (!dll->module) { free(dll); return 0; } break; case NSObjectFileImageInappropriateFile: dll->image = NSAddImage(path, 0); if (!dll->image) { free(dll); return 0; } break; default: free(dll); return 0; } strcpy(dll->path, path); dll->magic = DL_MAGIC; } return (void*)dll; } extern int dlclose(void* handle) { Dll_t* dll = (Dll_t*)handle; if (!dll || dll == DL_NEXT || dll->magic != DL_MAGIC) { dlmessage = e_handle; return -1; } if (dll->module) NSUnLinkModule(dll->module, 0); free(dll); return 0; } static NSSymbol lookup(Dll_t* dll, const char* name) { unsigned long pun; void* address; if (dll == DL_NEXT) { if (!_dyld_func_lookup(name, &pun)) return 0; address = (NSSymbol)pun; } else if (dll->module) address = NSLookupSymbolInModule(dll->module, name); else if (dll->image) { if (!NSIsSymbolNameDefinedInImage(dll->image, name)) return 0; address = NSLookupSymbolInImage(dll->image, name, 0); } else { if (!NSIsSymbolNameDefined(name)) return 0; address = NSLookupAndBindSymbol(name); } if (address) address = NSAddressOfSymbol(address); return address; } extern void* dlsym(void* handle, const char* name) { Dll_t* dll = (Dll_t*)handle; NSSymbol address; char buf[1024]; if (!dll || dll != DL_NEXT && (dll->magic != DL_MAGIC || !dll->image && !dll->module)) { dlmessage = e_handle; return 0; } if (!(address = lookup(dll, name)) && name[0] != '_' && strlen(name) < (sizeof(buf) - 1)) { buf[0] = '_'; strcpy(buf + 1, name); address = lookup(dll, buf); } if (!address) { dlmessage = dll == DL_NEXT ? e_cover : e_undefined; return 0; } return (void*)address; } extern char* dlerror(void) { char* msg; msg = (char*)dlmessage; dlmessage = 0; return msg; } #else /* * punt */ static int err; extern void* dlopen(const char* path, int mode) { err = 1; return 0; } extern int dlclose(void* dll) { err = 1; return 0; } extern void* dlsym(void* handle, const char* name) { err = 1; return 0; } extern char* dlerror(void) { if (!err) return 0; err = 0; return "dynamic linking not supported"; } #endif #endif #endif #endif #endif