summaryrefslogtreecommitdiff
path: root/src/lib/libdll/dlfcn.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2012-06-24 22:28:35 +0000
committerIgor Pashev <pashev.igor@gmail.com>2012-06-24 22:28:35 +0000
commit3950ffe2a485479f6561c27364d3d7df5a21d124 (patch)
tree468c6e14449d1b1e279222ec32f676b0311917d2 /src/lib/libdll/dlfcn.c
downloadksh-upstream.tar.gz
Imported Upstream version 93u+upstream
Diffstat (limited to 'src/lib/libdll/dlfcn.c')
-rw-r--r--src/lib/libdll/dlfcn.c536
1 files changed, 536 insertions, 0 deletions
diff --git a/src/lib/libdll/dlfcn.c b/src/lib/libdll/dlfcn.c
new file mode 100644
index 0000000..810be1b
--- /dev/null
+++ b/src/lib/libdll/dlfcn.c
@@ -0,0 +1,536 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1997-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* Glenn Fowler <gsf@research.att.com> *
+* *
+***********************************************************************/
+#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) 2010-10-20 $\0\n";
+
+#include <ast.h>
+#include <dlldefs.h>
+#include <error.h>
+
+#define T(x) ERROR_dictionary(x)
+
+#if _BLD_dll && defined(__EXPORT__)
+#define extern __EXPORT__
+#endif
+
+#if _hdr_dlfcn && _lib_dlopen
+
+ /*
+ * standard
+ */
+
+# include <dlfcn.h>
+
+#else
+#if _hdr_dl
+
+ /*
+ * HP-UX
+ */
+
+# include <dl.h>
+# 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 <sys/ldr.h>
+# include <xcoff.h>
+
+ /* 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 <dll.h>
+
+ 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 <mach-o/dyld.h>
+
+ 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