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