git-svn-id: svn://10.65.10.50/branches/R_10_00@23289 c028cbd2-c16b-5b4b-a496-9718f37d4682
613 lines
12 KiB
C
613 lines
12 KiB
C
/*
|
|
* dlf.c
|
|
*
|
|
* $Id: dlf.c 2613 1999-06-01 15:32:12Z VZ $
|
|
*
|
|
* Dynamic Library Loader (mapping to SVR4)
|
|
*
|
|
* The iODBC driver manager.
|
|
*
|
|
* Copyright (C) 1995 by Ke Jin <kejin@empress.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the Free
|
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#include "dlf.h"
|
|
#include <errno.h>
|
|
|
|
#ifdef DLDAPI_DEFINED
|
|
#undef DLDAPI_DEFINED
|
|
#endif
|
|
|
|
#ifdef DLDAPI_SVR4_DLFCN
|
|
#define DLDAPI_DEFINED
|
|
static char sccsid[] = "@(#)dynamic load interface -- SVR4 dlfcn";
|
|
#endif
|
|
|
|
/*********************************
|
|
*
|
|
* HP/UX
|
|
*
|
|
*********************************/
|
|
|
|
#ifdef DLDAPI_HP_SHL
|
|
#define DLDAPI_DEFINED
|
|
#include <dl.h>
|
|
|
|
static char sccsid[] = "@(#)dynamic load interface -- HP/UX dl(shl)";
|
|
|
|
void *
|
|
dlopen (char *path, int mode)
|
|
{
|
|
return (void *) shl_load ((char *) (path), BIND_DEFERRED, 0L);
|
|
}
|
|
|
|
|
|
void *
|
|
dlsym (void *hdll, char *sym)
|
|
{
|
|
void *symaddr = 0;
|
|
int ret;
|
|
|
|
if (!hdll)
|
|
hdll = (void *) PROG_HANDLE;
|
|
|
|
/* Remember, a driver may export calls as function pointers
|
|
* (i.e. with type TYPE_DATA) rather than as functions
|
|
* (i.e. with type TYPE_PROCEDURE). Thus, to be safe, we
|
|
* uses TYPE_UNDEFINED to cover all of them.
|
|
*/
|
|
ret = shl_findsym ((shl_t *) & hdll, sym, TYPE_UNDEFINED, &symaddr);
|
|
|
|
if (ret == -1)
|
|
return 0;
|
|
|
|
return symaddr;
|
|
}
|
|
|
|
|
|
char *
|
|
dlerror ()
|
|
{
|
|
extern char *strerror ();
|
|
|
|
return strerror (errno);
|
|
}
|
|
|
|
|
|
int
|
|
dlclose (void *hdll)
|
|
{
|
|
return shl_unload ((shl_t) hdll);
|
|
}
|
|
#endif /* end of HP/UX Seection */
|
|
|
|
|
|
/*********************************
|
|
*
|
|
* IBM AIX
|
|
*
|
|
*********************************/
|
|
|
|
#ifdef DLDAPI_AIX_LOAD
|
|
#define DLDAPI_DEFINED
|
|
#include <sys/types.h>
|
|
#include <sys/ldr.h>
|
|
#include <sys/stat.h>
|
|
#include <nlist.h>
|
|
|
|
/*
|
|
* Following id sting is a copyright mark. Removing(i.e. use the
|
|
* source code in this .c file without include it or make it not
|
|
* appear in the final object file of AIX platform) or modifing
|
|
* it without permission from original author(kejin@empress.com)
|
|
* are copyright violation.
|
|
*/
|
|
static char sccsid[]
|
|
= "@(#)dynamic load interface, Copyright(c) 1995 by Ke Jin";
|
|
|
|
#ifndef HTAB_SIZE
|
|
#define HTAB_SIZE 256
|
|
#endif
|
|
|
|
#define FACTOR 0.618039887 /* i.e. (sqrt(5) - 1)/2 */
|
|
|
|
#ifndef ENTRY_SYM
|
|
#define ENTRY_SYM ".__start" /* default entry point for aix */
|
|
#endif
|
|
|
|
typedef struct slot_s
|
|
{
|
|
char *sym;
|
|
long fdesc[3]; /* 12 bytes function descriptor */
|
|
struct slot_s *next;
|
|
}
|
|
slot_t;
|
|
|
|
/* Note: on AIX, a function pointer actually points to a
|
|
* function descriptor, a 12 bytes data. The first 4 bytes
|
|
* is the virtual address of the function. The next 4 bytes
|
|
* is the virtual address of TOC (Table of Contents) of the
|
|
* object module the function belong to. The last 4 bytes
|
|
* are always 0 for C and Fortran functions. Every object
|
|
* module has an entry point (which can be specified at link
|
|
* time by -e ld option). iODBC driver manager requires ODBC
|
|
* driver shared library always use the default entry point
|
|
* (so you shouldn't use -e ld option when creating a driver
|
|
* share library). load() returns the function descriptor of
|
|
* a module's entry point. From which we can calculate function
|
|
* descriptors of other functions in the same module by using
|
|
* the fact that the load() doesn't change the relative
|
|
* offset of functions to their module entry point(i.e the
|
|
* offset in memory loaded by load() will be as same as in
|
|
* the module library file).
|
|
*/
|
|
|
|
typedef slot_t *hent_t;
|
|
typedef struct nlist nlist_t;
|
|
typedef struct stat stat_t;
|
|
|
|
typedef struct obj
|
|
{
|
|
int dev; /* device id */
|
|
int ino; /* inode number */
|
|
char *path; /* file name */
|
|
int (*pentry) (); /* entry point of this share library */
|
|
int refn; /* number of reference */
|
|
hent_t htab[HTAB_SIZE];
|
|
struct obj * next;
|
|
}
|
|
obj_t;
|
|
|
|
static char *errmsg = 0;
|
|
|
|
static void
|
|
init_htab (hent_t * ht)
|
|
/* initate a hashing table */
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < HTAB_SIZE; i++)
|
|
ht[i] = (slot_t *) 0;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
static void
|
|
clean_htab (hent_t * ht)
|
|
/* free all slots */
|
|
{
|
|
int i;
|
|
slot_t *ent;
|
|
slot_t *tent;
|
|
|
|
for (i = 0; i < HTAB_SIZE; i++)
|
|
{
|
|
for (ent = ht[i]; ent;)
|
|
{
|
|
tent = ent->next;
|
|
|
|
free (ent->sym);
|
|
free (ent);
|
|
|
|
ent = tent;
|
|
}
|
|
|
|
ht[i] = 0;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
static int
|
|
hash (char *sym)
|
|
{
|
|
int a, key;
|
|
double f;
|
|
|
|
if (!sym || !*sym)
|
|
return 0;
|
|
|
|
for (key = *sym; *sym; sym++)
|
|
{
|
|
key += *sym;
|
|
a = key;
|
|
|
|
key = (int) ((a << 8) + (key >> 8));
|
|
key = (key > 0) ? key : -key;
|
|
}
|
|
|
|
f = key * FACTOR;
|
|
a = (int) f;
|
|
|
|
return (int) ((HTAB_SIZE - 1) * (f - a));
|
|
}
|
|
|
|
|
|
static hent_t
|
|
search (hent_t * htab, char *sym)
|
|
/* search hashing table to find a matched slot */
|
|
{
|
|
int key;
|
|
slot_t *ent;
|
|
|
|
key = hash (sym);
|
|
|
|
for (ent = htab[key]; ent; ent = ent->next)
|
|
{
|
|
if (!strcmp (ent->sym, sym))
|
|
return ent;
|
|
}
|
|
|
|
return 0; /* no match */
|
|
}
|
|
|
|
|
|
static void
|
|
insert (hent_t * htab, slot_t * ent)
|
|
/* insert a new slot to hashing table */
|
|
{
|
|
int key;
|
|
|
|
key = hash (ent->sym);
|
|
|
|
ent->next = htab[key];
|
|
htab[key] = ent;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
static slot_t *
|
|
slot_alloc (char *sym)
|
|
/* allocate a new slot with symbol */
|
|
{
|
|
slot_t *ent;
|
|
|
|
ent = (slot_t *) malloc (sizeof (slot_t));
|
|
|
|
ent->sym = (char *) malloc (strlen (sym) + 1);
|
|
|
|
if (!ent->sym)
|
|
{
|
|
free (ent);
|
|
return 0;
|
|
}
|
|
|
|
strcpy (ent->sym, sym);
|
|
|
|
return ent;
|
|
}
|
|
|
|
|
|
static obj_t *obj_list = 0;
|
|
|
|
void *
|
|
dlopen (char *file, int mode)
|
|
{
|
|
stat_t st;
|
|
obj_t *pobj;
|
|
char buf[1024];
|
|
|
|
if (!file || !*file)
|
|
{
|
|
errno = EINVAL;
|
|
return 0;
|
|
}
|
|
|
|
errno = 0;
|
|
errmsg = 0;
|
|
|
|
if (stat (file, &st))
|
|
return 0;
|
|
|
|
for (pobj = obj_list; pobj; pobj = pobj->next)
|
|
/* find a match object */
|
|
{
|
|
if (pobj->ino == st.st_ino
|
|
&& pobj->dev == st.st_dev)
|
|
{
|
|
/* found a match. increase its
|
|
* reference count and return
|
|
* its address */
|
|
pobj->refn++;
|
|
return pobj;
|
|
}
|
|
}
|
|
|
|
pobj = (obj_t *) malloc (sizeof (obj_t));
|
|
|
|
if (!pobj)
|
|
return 0;
|
|
|
|
pobj->path = (char *) malloc (strlen (file) + 1);
|
|
|
|
if (!pobj->path)
|
|
{
|
|
free (pobj);
|
|
return 0;
|
|
}
|
|
|
|
strcpy (pobj->path, file);
|
|
|
|
pobj->dev = st.st_dev;
|
|
pobj->ino = st.st_ino;
|
|
pobj->refn = 1;
|
|
|
|
pobj->pentry = (int (*)()) load (file, 0, 0);
|
|
|
|
if (!pobj->pentry)
|
|
{
|
|
free (pobj->path);
|
|
free (pobj);
|
|
return 0;
|
|
}
|
|
|
|
init_htab (pobj->htab);
|
|
|
|
pobj->next = obj_list;
|
|
obj_list = pobj;
|
|
|
|
return pobj;
|
|
}
|
|
|
|
|
|
int
|
|
dlclose (void *hobj)
|
|
{
|
|
obj_t *pobj = (obj_t *) hobj;
|
|
obj_t *tpobj;
|
|
int match = 0;
|
|
|
|
if (!hobj)
|
|
{
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
errno = 0;
|
|
errmsg = 0;
|
|
|
|
if (pobj == obj_list)
|
|
{
|
|
pobj->refn--;
|
|
|
|
if (pobj->refn)
|
|
return 0;
|
|
|
|
match = 1;
|
|
obj_list = pobj->next;
|
|
}
|
|
|
|
for (tpobj = obj_list; !match && tpobj; tpobj = tpobj->next)
|
|
{
|
|
if (tpobj->next == pobj)
|
|
{
|
|
pobj->refn--;
|
|
|
|
if (pobj->refn)
|
|
return 0;
|
|
|
|
match = 1;
|
|
tpobj->next = pobj->next;
|
|
}
|
|
}
|
|
|
|
if (match)
|
|
{
|
|
unload ((void *) (pobj->pentry));
|
|
clean_htab (pobj->htab);
|
|
free (pobj->path);
|
|
free (pobj);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
char *
|
|
dlerror ()
|
|
{
|
|
extern char *sys_errlist[];
|
|
|
|
if (!errmsg || !errmsg[0])
|
|
{
|
|
if (errno >= 0)
|
|
return sys_errlist[errno];
|
|
|
|
return "";
|
|
}
|
|
|
|
return errmsg;
|
|
}
|
|
|
|
|
|
void *
|
|
dlsym (void *hdl, char *sym)
|
|
{
|
|
nlist_t nl[3];
|
|
obj_t *pobj = (obj_t *) hdl;
|
|
slot_t *ent;
|
|
int (*fp) ();
|
|
long lbuf[3];
|
|
|
|
if (!hdl || !(pobj->htab) || !sym || !*sym)
|
|
{
|
|
errno = EINVAL;
|
|
return 0;
|
|
}
|
|
|
|
errno = 0;
|
|
errmsg = 0;
|
|
|
|
ent = search (pobj->htab, sym);
|
|
|
|
if (ent)
|
|
return ent->fdesc;
|
|
|
|
#define n_name _n._n_name
|
|
|
|
nl[0].n_name = ENTRY_SYM;
|
|
nl[1].n_name = sym;
|
|
nl[2].n_name = 0;
|
|
|
|
/* There is a potential problem here. If application
|
|
* did not pass a full path name, and changed the
|
|
* working directory after the load(), then nlist()
|
|
* will be unable to open the original shared library
|
|
* file to resolve the symbols. there are 3 ways to working
|
|
* round this: 1. convert to full pathname in driver
|
|
* manager. 2. applications always pass driver's full
|
|
* path name. 3. if driver itself don't support
|
|
* SQLGetFunctions(), call it with SQL_ALL_FUNCTIONS
|
|
* as flag immidately after SQLConnect(), SQLDriverConnect()
|
|
* and SQLBrowseConnect() to force the driver manager
|
|
* resolving all will be used symbols.
|
|
*/
|
|
if (nlist (pobj->path, nl) == -1)
|
|
return 0;
|
|
|
|
if (!nl[0].n_type && !nl[0].n_value)
|
|
{
|
|
errmsg = "can't locate module entry symbol";
|
|
return 0;
|
|
}
|
|
|
|
/* Note: On AIX 3.x if the object library is not
|
|
* built with -g compiling option, .n_type field
|
|
* is always 0. While on 4.x it will be 32.
|
|
* On AIX 4.x, if the symbol is a entry point,
|
|
* n_value will be 0. However, one thing is for sure
|
|
* that if a symbol is not existance in the file,
|
|
* both .n_type and .n_value would be 0.
|
|
*/
|
|
|
|
if (!nl[1].n_type && !nl[1].n_value)
|
|
{
|
|
errmsg = "symbol not existance in this module";
|
|
return 0;
|
|
}
|
|
|
|
ent = slot_alloc (sym);
|
|
|
|
if (!ent)
|
|
return 0;
|
|
|
|
/* catch it with a slot in the hashing table */
|
|
insert (pobj->htab, ent);
|
|
|
|
memcpy (ent->fdesc, pobj->pentry, sizeof (ent->fdesc));
|
|
|
|
/* now ent->fdesc[0] is the virtual address of entry point
|
|
* and ent->fdesc[1] is the TOC of the module
|
|
*/
|
|
|
|
/* let's calculate the virtual address of the symbol
|
|
* by adding a relative offset getting from the module
|
|
* file symbol table, i.e
|
|
*
|
|
* functin virtual address = entry point virtual address +
|
|
* + ( function offset in file - entry point offset in file )
|
|
*/
|
|
|
|
(ent->fdesc)[0] = (ent->fdesc)[0] +
|
|
(nl[1].n_value - nl[0].n_value);
|
|
|
|
/* return the function descriptor */
|
|
return ent->fdesc;
|
|
}
|
|
#endif /* end of IBM AIX Section */
|
|
|
|
|
|
/*********************************
|
|
*
|
|
* Windows 3.x, 95, NT
|
|
*
|
|
*********************************/
|
|
|
|
#ifdef DLDAPI_WINDOWS
|
|
#define DLDAPI_DEFINED
|
|
#include <windows.h>
|
|
|
|
void FAR *
|
|
dlopen (char FAR * dll, int mode)
|
|
{
|
|
HINSTANCE hint;
|
|
|
|
if (dll == NULL)
|
|
{
|
|
return GetWindowWord (NULL, GWW_HINSTANCE);
|
|
}
|
|
|
|
hint = LoadLibrary (dll);
|
|
|
|
if (hint < HINSTANCE_ERROR)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return (void FAR *) hint;
|
|
}
|
|
|
|
|
|
void FAR *
|
|
dlsym (void FAR * hdll, char FAR * sym)
|
|
{
|
|
return (void FAR *) GetProcAddress (hdll, sym);
|
|
}
|
|
|
|
|
|
char FAR *
|
|
dlerror ()
|
|
{
|
|
return 0L; /* unimplemented yet */
|
|
}
|
|
|
|
|
|
int
|
|
dlclose (void FAR * hdll)
|
|
{
|
|
FreeLibrary ((HINSTANCE) hdll);
|
|
}
|
|
#endif /* end of Windows family */
|
|
|
|
|
|
/***********************************
|
|
*
|
|
* other platforms
|
|
*
|
|
***********************************/
|
|
|
|
#ifdef DLDAPI_OS2
|
|
#define DLDAPI_DEFINED
|
|
/*
|
|
* DosLoadModule(), DosQueryProcAddress(), DosFreeModule(), ...
|
|
*/
|
|
#endif
|
|
|
|
#ifdef DLDAPI_MAC
|
|
#define DLDAPI_DEFINED
|
|
#endif
|
|
|
|
#ifdef DLDAPI_NEXT
|
|
#define DLDAPI_DEFINED
|
|
#endif
|
|
|
|
#ifndef DLDAPI_DEFINED
|
|
#error "dynamic load editor undefined"
|
|
#endif
|