mirror of
https://github.com/SDL-Hercules-390/hyperion.git
synced 2026-04-13 15:35:41 +02:00
This corrects the problem of: HHC01462E 0:0009 devtype 3215-C not recognized HHC01462E 0:000C devtype 3505 not recognized HHC01462E 0:000D devtype 3525 not recognized HHC01462E 0:000E devtype 1403 not recognized HHC01462E 0:001F devtype 3270 not recognized caused by previous "ltdl/dlopen" commits:d288c249dffefc687c416db2297e5e
1157 lines
27 KiB
C
1157 lines
27 KiB
C
/* HDL.C (c) Copyright Jan Jaeger, 2003-2012 */
|
|
/* Hercules Dynamic Loader */
|
|
|
|
#include "hstdinc.h"
|
|
|
|
#define _HDL_C_
|
|
#define _HUTIL_DLL_
|
|
|
|
#include "hercules.h"
|
|
#include "opcode.h"
|
|
|
|
/*
|
|
extern HDLPRE hdl_preload[];
|
|
*/
|
|
|
|
#if defined(OPTION_DYNAMIC_LOAD)
|
|
HDLPRE hdl_preload[] = {
|
|
{ "hdteq", HDL_LOAD_NOMSG },
|
|
{ "dyncrypt", HDL_LOAD_NOMSG },
|
|
#if 0
|
|
{ "dyn_test1", HDL_LOAD_DEFAULT },
|
|
{ "dyn_test2", HDL_LOAD_NOMSG },
|
|
{ "dyn_test3", HDL_LOAD_NOMSG | HDL_LOAD_NOUNLOAD },
|
|
#endif
|
|
{ NULL, 0 } };
|
|
|
|
#if 0
|
|
/* Forward definitions from hdlmain.c stuff */
|
|
/* needed because we cannot depend on dlopen(self) */
|
|
extern void *HDL_DEPC;
|
|
extern void *HDL_INIT;
|
|
extern void *HDL_RESO;
|
|
extern void *HDL_DDEV;
|
|
extern void *HDL_DINS;
|
|
extern void *HDL_FINI;
|
|
#endif
|
|
|
|
|
|
static DLLENT *hdl_dll; /* dll chain */
|
|
static LOCK hdl_lock; /* loader lock */
|
|
static DLLENT *hdl_cdll; /* current dll (hdl_lock) */
|
|
|
|
static HDLDEP *hdl_depend; /* Version codes in hdlmain */
|
|
|
|
static char *hdl_modpath = NULL;
|
|
static int hdl_arg_p = FALSE;
|
|
|
|
static void hdl_didf (int, int, char *, void *);
|
|
static void hdl_modify_opcode(int, HDLINS *);
|
|
|
|
#endif
|
|
|
|
static HDLSHD *hdl_shdlist; /* Shutdown call list */
|
|
static int hdl_sdip = FALSE; /* hdl shutdown in progesss */
|
|
|
|
/* Global hdl_device_type_equates */
|
|
|
|
DLL_EXPORT char *(*hdl_device_type_equates)(const char *);
|
|
|
|
/* hdl_adsc - add shutdown call
|
|
*/
|
|
DLL_EXPORT void hdl_adsc (char* shdname, void * shdcall, void * shdarg)
|
|
{
|
|
HDLSHD *newcall;
|
|
HDLSHD **tmpcall;
|
|
|
|
if(hdl_sdip)
|
|
return;
|
|
|
|
/* avoid duplicates - keep the first one */
|
|
for(tmpcall = &(hdl_shdlist); *tmpcall; tmpcall = &((*tmpcall)->next) )
|
|
if( (*tmpcall)->shdcall == shdcall
|
|
&& (*tmpcall)->shdarg == shdarg )
|
|
return;
|
|
|
|
newcall = malloc(sizeof(HDLSHD));
|
|
newcall->shdname = shdname;
|
|
newcall->shdcall = shdcall;
|
|
newcall->shdarg = shdarg;
|
|
newcall->next = hdl_shdlist;
|
|
hdl_shdlist = newcall;
|
|
|
|
}
|
|
|
|
/* hdl_rmsc - remove shutdown call
|
|
*/
|
|
DLL_EXPORT int hdl_rmsc (void *shdcall, void *shdarg)
|
|
{
|
|
HDLSHD **tmpcall;
|
|
int rc = -1;
|
|
|
|
if(hdl_sdip)
|
|
return rc;
|
|
|
|
for(tmpcall = &(hdl_shdlist); *tmpcall; tmpcall = &((*tmpcall)->next) )
|
|
{
|
|
if( (*tmpcall)->shdcall == shdcall
|
|
&& (*tmpcall)->shdarg == shdarg )
|
|
{
|
|
HDLSHD *frecall;
|
|
frecall = *tmpcall;
|
|
*tmpcall = (*tmpcall)->next;
|
|
free(frecall);
|
|
rc = 0;
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
|
|
/* hdl_shut - call all shutdown call entries in LIFO order
|
|
*/
|
|
DLL_EXPORT void hdl_shut (void)
|
|
{
|
|
HDLSHD *shdent;
|
|
|
|
if(MLVL(DEBUG))
|
|
logmsg(MSG(HHC01500, "I"));
|
|
|
|
hdl_sdip = TRUE;
|
|
|
|
for(shdent = hdl_shdlist; shdent; shdent = hdl_shdlist)
|
|
{
|
|
/* Remove shutdown call entry to ensure it is called once */
|
|
hdl_shdlist = shdent->next;
|
|
|
|
{
|
|
if(MLVL(DEBUG))
|
|
logmsg(MSG(HHC01501, "I", shdent->shdname));
|
|
|
|
(shdent->shdcall) (shdent->shdarg);
|
|
|
|
if(MLVL(DEBUG))
|
|
logmsg(MSG(HHC01502, "I", shdent->shdname));
|
|
}
|
|
free(shdent);
|
|
}
|
|
|
|
if(MLVL(DEBUG))
|
|
logmsg(MSG(HHC01504, "I"));
|
|
}
|
|
|
|
#if defined(OPTION_DYNAMIC_LOAD)
|
|
|
|
|
|
/* hdl_setpath - set path for module load
|
|
* If path is NULL, then return the current path
|
|
* If path length is greater than MAX_PATH, send message and return NULL
|
|
* indicating an error has occurred.
|
|
* If flag is TRUE, then only set new path if not already defined
|
|
* If flag is FALSE, then always set the new path.
|
|
*/
|
|
DLL_EXPORT char *hdl_setpath(char *path, int flag)
|
|
{
|
|
char pathname[MAX_PATH]; /* pathname conversion */
|
|
|
|
if (path == NULL)
|
|
return hdl_modpath; /* return module path to caller */
|
|
|
|
if ( strlen(path) > MAX_PATH )
|
|
{
|
|
logmsg(MSG(HHC01505, "E", (int)strlen(path), MAX_PATH));
|
|
return NULL;
|
|
}
|
|
|
|
hostpath(pathname, path, sizeof(pathname));
|
|
|
|
if (flag)
|
|
{
|
|
if (hdl_modpath)
|
|
{
|
|
if (!hdl_arg_p)
|
|
{
|
|
free(hdl_modpath);
|
|
}
|
|
else
|
|
{
|
|
logmsg(MSG(HHC01506, "W", pathname));
|
|
logmsg(MSG(HHC01507, "W", hdl_modpath));
|
|
return hdl_modpath;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hdl_arg_p = TRUE;
|
|
if(hdl_modpath)
|
|
free(hdl_modpath);
|
|
}
|
|
|
|
hdl_modpath = strdup(pathname);
|
|
|
|
if (MLVL(VERBOSE))
|
|
logmsg(MSG(HHC01508, "I", hdl_modpath));
|
|
|
|
return hdl_modpath;
|
|
}
|
|
|
|
/*
|
|
* Check in this order:
|
|
* 1) filename as passed
|
|
* 2) filename with extension if needed
|
|
* 3) modpath added if basename(filename)
|
|
* 4) extension added to #3
|
|
*/
|
|
static void * hdl_dlopen(char *filename, int flag _HDL_UNUSED)
|
|
{
|
|
char *fullname;
|
|
void *ret;
|
|
size_t fulllen = 0;
|
|
|
|
if ( (ret = dlopen(filename,flag)) ) /* try filename as is first */
|
|
return ret;
|
|
|
|
fulllen = strlen(filename) + strlen(hdl_modpath) + 2 + HDL_SUFFIX_LENGTH;
|
|
fullname = (char *)calloc(1,fulllen);
|
|
|
|
if ( fullname == NULL )
|
|
return NULL;
|
|
|
|
#if defined(HDL_MODULE_SUFFIX)
|
|
strlcpy(fullname,filename,fulllen);
|
|
strlcat(fullname,HDL_MODULE_SUFFIX,fulllen);
|
|
|
|
if ( (ret = dlopen(fullname,flag)) ) /* try filename with suffix next */
|
|
{
|
|
free(fullname);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
if( hdl_modpath && *hdl_modpath)
|
|
{
|
|
strlcpy(fullname,hdl_modpath,fulllen);
|
|
strlcat(fullname,PATHSEPS,fulllen);
|
|
strlcat(fullname,basename(filename),fulllen);
|
|
}
|
|
else
|
|
strlcpy(fullname,filename,fulllen);
|
|
|
|
if ( (ret = dlopen(fullname,flag)) )
|
|
{
|
|
free(fullname);
|
|
return ret;
|
|
}
|
|
|
|
#if defined(HDL_MODULE_SUFFIX)
|
|
strlcat(fullname,HDL_MODULE_SUFFIX,fulllen);
|
|
|
|
if((ret = dlopen(fullname,flag)))
|
|
{
|
|
free(fullname);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* hdl_dvad - register device type
|
|
*/
|
|
DLL_EXPORT void hdl_dvad (char *devname, DEVHND *devhnd)
|
|
{
|
|
HDLDEV *newhnd;
|
|
|
|
newhnd = malloc(sizeof(HDLDEV));
|
|
newhnd->name = strdup(devname);
|
|
newhnd->hnd = devhnd;
|
|
newhnd->next = hdl_cdll->hndent;
|
|
hdl_cdll->hndent = newhnd;
|
|
}
|
|
|
|
|
|
/* hdl_fhnd - find registered device handler
|
|
*/
|
|
static DEVHND * hdl_fhnd (const char *devname)
|
|
{
|
|
DLLENT *dllent;
|
|
HDLDEV *hndent;
|
|
|
|
for(dllent = hdl_dll; dllent; dllent = dllent->dllnext)
|
|
{
|
|
for(hndent = dllent->hndent; hndent; hndent = hndent->next)
|
|
{
|
|
if(!strcasecmp(devname,hndent->name))
|
|
{
|
|
return hndent->hnd;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* hdl_bdnm - build device module name
|
|
*/
|
|
static char * hdl_bdnm (const char *ltype)
|
|
{
|
|
char *dtname;
|
|
unsigned int n;
|
|
size_t m;
|
|
|
|
m = strlen(ltype) + sizeof(HDL_HDTP_Q);
|
|
dtname = malloc(m);
|
|
strlcpy(dtname,HDL_HDTP_Q,m);
|
|
strlcat(dtname,ltype,m);
|
|
|
|
for(n = 0; n < strlen(dtname); n++)
|
|
if(isupper(dtname[n]))
|
|
dtname[n] = tolower(dtname[n]);
|
|
|
|
return dtname;
|
|
}
|
|
|
|
|
|
/* hdl_ghnd - obtain device handler
|
|
*/
|
|
DLL_EXPORT DEVHND * hdl_ghnd (const char *devtype)
|
|
{
|
|
DEVHND *hnd;
|
|
char *hdtname;
|
|
char *ltype;
|
|
|
|
if((hnd = hdl_fhnd(devtype)))
|
|
return hnd;
|
|
|
|
hdtname = hdl_bdnm(devtype);
|
|
|
|
if(hdl_load(hdtname,HDL_LOAD_NOMSG) || !hdl_fhnd(devtype))
|
|
{
|
|
if(hdl_device_type_equates)
|
|
{
|
|
if((ltype = hdl_device_type_equates(devtype)))
|
|
{
|
|
free(hdtname);
|
|
|
|
hdtname = hdl_bdnm(ltype);
|
|
|
|
hdl_load(hdtname,HDL_LOAD_NOMSG);
|
|
}
|
|
}
|
|
}
|
|
|
|
free(hdtname);
|
|
|
|
return hdl_fhnd(devtype);
|
|
}
|
|
|
|
|
|
/* hdl_list - list all entry points
|
|
*/
|
|
DLL_EXPORT void hdl_list (int flags)
|
|
{
|
|
DLLENT *dllent;
|
|
MODENT *modent;
|
|
char buf[256];
|
|
int len;
|
|
|
|
for(dllent = hdl_dll; dllent; dllent = dllent->dllnext)
|
|
{
|
|
logmsg(MSG(HHC01531, "I"
|
|
,(dllent->flags & HDL_LOAD_MAIN) ? "main" : "load"
|
|
,dllent->name
|
|
,(dllent->flags & HDL_LOAD_NOUNLOAD) ? "not unloadable" : "unloadable"
|
|
,(dllent->flags & HDL_LOAD_WAS_FORCED) ? "forced" : "not forced"));
|
|
|
|
for(modent = dllent->modent; modent; modent = modent->modnext)
|
|
if((flags & HDL_LIST_ALL)
|
|
|| !((dllent->flags & HDL_LOAD_MAIN) && !modent->fep))
|
|
{
|
|
logmsg(MSG(HHC01532, "I"
|
|
,modent->name
|
|
,modent->count
|
|
,modent->fep ? "" : ", unresolved"
|
|
,dllent->name));
|
|
}
|
|
|
|
if(dllent->hndent)
|
|
{
|
|
HDLDEV *hndent;
|
|
len = 0;
|
|
for(hndent = dllent->hndent; hndent; hndent = hndent->next)
|
|
len += snprintf(buf + len, sizeof(buf) - len - 1, " %s",hndent->name);
|
|
logmsg(MSG(HHC01533, "I", buf));
|
|
|
|
}
|
|
|
|
if(dllent->insent)
|
|
{
|
|
HDLINS *insent;
|
|
for(insent = dllent->insent; insent; insent = insent->next)
|
|
{
|
|
len = 0;
|
|
#if defined(_370)
|
|
if(insent->archflags & HDL_INSTARCH_370)
|
|
len += snprintf(buf + len, sizeof(buf) - len - 1, ", archmode = " _ARCH_370_NAME);
|
|
#endif
|
|
#if defined(_390)
|
|
if(insent->archflags & HDL_INSTARCH_390)
|
|
len += snprintf(buf + len, sizeof(buf) - len - 1, ", archmode = " _ARCH_390_NAME);
|
|
#endif
|
|
#if defined(_900)
|
|
if(insent->archflags & HDL_INSTARCH_900)
|
|
len += snprintf(buf + len, sizeof(buf) - len - 1, ", archmode = " _ARCH_900_NAME);
|
|
#endif
|
|
logmsg(MSG(HHC01534, "I"
|
|
,insent->instname
|
|
,insent->opcode
|
|
,buf));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* hdl_dlst - list all dependencies
|
|
*/
|
|
DLL_EXPORT void hdl_dlst (void)
|
|
{
|
|
HDLDEP *depent;
|
|
|
|
for(depent = hdl_depend;
|
|
depent;
|
|
depent = depent->next)
|
|
logmsg(MSG(HHC01535,"I",depent->name,depent->version,depent->size));
|
|
}
|
|
|
|
|
|
/* hdl_dadd - add dependency
|
|
*/
|
|
static int hdl_dadd (char *name, char *version, int size)
|
|
{
|
|
HDLDEP **newdep;
|
|
|
|
for (newdep = &(hdl_depend);
|
|
*newdep;
|
|
newdep = &((*newdep)->next));
|
|
|
|
(*newdep) = malloc(sizeof(HDLDEP));
|
|
(*newdep)->next = NULL;
|
|
(*newdep)->name = strdup(name);
|
|
(*newdep)->version = strdup(version);
|
|
(*newdep)->size = size;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* hdl_dchk - dependency check
|
|
*/
|
|
static int hdl_dchk (char *name, char *version, int size)
|
|
{
|
|
HDLDEP *depent;
|
|
|
|
for(depent = hdl_depend;
|
|
depent && strcmp(name,depent->name);
|
|
depent = depent->next);
|
|
|
|
if(depent)
|
|
{
|
|
if(strcmp(version,depent->version))
|
|
{
|
|
logmsg(MSG(HHC01509, "I",name, version, depent->version));
|
|
return -1;
|
|
}
|
|
|
|
if(size != depent->size)
|
|
{
|
|
logmsg(MSG(HHC01510, "I", name, size, depent->size));
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hdl_dadd(name,version,size);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* hdl_fent - find entry point
|
|
*/
|
|
DLL_EXPORT void * hdl_fent (char *name)
|
|
{
|
|
DLLENT *dllent;
|
|
MODENT *modent;
|
|
void *fep;
|
|
|
|
/* Find entry point and increase loadcount */
|
|
for(dllent = hdl_dll; dllent; dllent = dllent->dllnext)
|
|
{
|
|
for(modent = dllent->modent; modent; modent = modent->modnext)
|
|
{
|
|
if(!strcmp(name,modent->name))
|
|
{
|
|
modent->count++;
|
|
return modent->fep;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* If not found then lookup as regular symbol */
|
|
for(dllent = hdl_dll; dllent; dllent = dllent->dllnext)
|
|
{
|
|
if((fep = dlsym(dllent->dll,name)))
|
|
{
|
|
if(!(modent = malloc(sizeof(MODENT))))
|
|
{
|
|
logmsg(MSG(HHC01511, "E", "malloc()", strerror(errno)));
|
|
return NULL;
|
|
}
|
|
|
|
modent->fep = fep;
|
|
modent->name = strdup(name);
|
|
modent->count = 1;
|
|
|
|
/* Insert current entry as first in chain */
|
|
modent->modnext = dllent->modent;
|
|
dllent->modent = modent;
|
|
|
|
return fep;
|
|
}
|
|
}
|
|
|
|
/* No entry point found */
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* hdl_nent - find next entry point in chain
|
|
*/
|
|
DLL_EXPORT void * hdl_nent (void *fep)
|
|
{
|
|
DLLENT *dllent;
|
|
MODENT *modent = NULL;
|
|
char *name;
|
|
|
|
for(dllent = hdl_dll; dllent; dllent = dllent->dllnext)
|
|
{
|
|
for(modent = dllent->modent; modent; modent = modent->modnext)
|
|
{
|
|
if(modent->fep == fep)
|
|
break;
|
|
}
|
|
|
|
if(modent && modent->fep == fep)
|
|
break;
|
|
}
|
|
|
|
if(!modent)
|
|
return NULL;
|
|
|
|
name = modent->name;
|
|
|
|
if(!(modent = modent->modnext))
|
|
{
|
|
if((dllent = dllent->dllnext))
|
|
modent = dllent->modent;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
/* Find entry point */
|
|
for(; dllent; dllent = dllent->dllnext, modent = dllent->modent)
|
|
{
|
|
for(; modent; modent = modent->modnext)
|
|
{
|
|
if(!strcmp(name,modent->name))
|
|
{
|
|
return modent->fep;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* hdl_regi - register entry point
|
|
*/
|
|
static void hdl_regi (char *name, void *fep)
|
|
{
|
|
MODENT *modent;
|
|
|
|
modent = malloc(sizeof(MODENT));
|
|
|
|
modent->fep = fep;
|
|
modent->name = strdup(name);
|
|
modent->count = 0;
|
|
|
|
modent->modnext = hdl_cdll->modent;
|
|
hdl_cdll->modent = modent;
|
|
|
|
}
|
|
|
|
|
|
/* hdl_term - process all "HDL_FINAL_SECTION"s
|
|
*/
|
|
static void hdl_term (void *unused _HDL_UNUSED)
|
|
{
|
|
DLLENT *dllent;
|
|
|
|
if(MLVL(DEBUG))
|
|
logmsg(MSG(HHC01512, "I"));
|
|
|
|
/* Call all final routines, in reverse load order */
|
|
for(dllent = hdl_dll; dllent; dllent = dllent->dllnext)
|
|
{
|
|
if(dllent->hdlfini)
|
|
{
|
|
if(MLVL(DEBUG))
|
|
logmsg(MSG(HHC01513, "I", dllent->name));
|
|
|
|
(dllent->hdlfini)();
|
|
|
|
if(MLVL(DEBUG))
|
|
logmsg(MSG(HHC01514, "I", dllent->name));
|
|
}
|
|
}
|
|
|
|
if(MLVL(DEBUG))
|
|
logmsg(MSG(HHC01515, "I"));
|
|
}
|
|
|
|
|
|
#if defined(_MSVC_)
|
|
/* hdl_lexe - load exe
|
|
*/
|
|
static int hdl_lexe ()
|
|
{
|
|
DLLENT *dllent;
|
|
MODENT *modent;
|
|
|
|
for(dllent = hdl_dll; dllent; dllent = dllent->dllnext);
|
|
|
|
dllent->name = strdup("*Main");
|
|
|
|
if(!(dllent->dll = (void*)GetModuleHandle( NULL ) ));
|
|
{
|
|
logmsg(MSG(HHC01516, "E", dllent->name, dlerror()));
|
|
free(dllent);
|
|
return -1;
|
|
}
|
|
|
|
dllent->flags = HDL_LOAD_MAIN;
|
|
|
|
if(!(dllent->hdldepc = dlsym(dllent->dll,HDL_DEPC_Q)))
|
|
{
|
|
logmsg(MSG(HHC01517, "E", dllent->name, dlerror()));
|
|
free(dllent);
|
|
return -1;
|
|
}
|
|
|
|
dllent->hdlinit = dlsym(dllent->dll,HDL_INIT_Q);
|
|
|
|
dllent->hdlreso = dlsym(dllent->dll,HDL_RESO_Q);
|
|
|
|
dllent->hdlddev = dlsym(dllent->dll,HDL_DDEV_Q);
|
|
|
|
dllent->hdldins = dlsym(dllent->dll,HDL_DINS_Q);
|
|
|
|
dllent->hdlfini = dlsym(dllent->dll,HDL_FINI_Q);
|
|
|
|
/* No modules or device types registered yet */
|
|
dllent->modent = NULL;
|
|
dllent->hndent = NULL;
|
|
dllent->insent = NULL;
|
|
|
|
obtain_lock(&hdl_lock);
|
|
|
|
if(dllent->hdldepc)
|
|
{
|
|
if((dllent->hdldepc)(&hdl_dchk))
|
|
{
|
|
logmsg(MSG(HHC01518, "E", dllent->name));
|
|
}
|
|
}
|
|
|
|
hdl_cdll = dllent;
|
|
|
|
/* Call initializer */
|
|
if(hdl_cdll->hdlinit)
|
|
(dllent->hdlinit)(&hdl_regi);
|
|
|
|
/* Insert current entry as first in chain */
|
|
dllent->dllnext = hdl_dll;
|
|
hdl_dll = dllent;
|
|
|
|
/* Reset the loadcounts */
|
|
for(dllent = hdl_dll; dllent; dllent = dllent->dllnext)
|
|
for(modent = dllent->modent; modent; modent = modent->modnext)
|
|
modent->count = 0;
|
|
|
|
/* Call all resolvers */
|
|
for(dllent = hdl_dll; dllent; dllent = dllent->dllnext)
|
|
{
|
|
if(dllent->hdlreso)
|
|
(dllent->hdlreso)(&hdl_fent);
|
|
}
|
|
|
|
/* register any device types */
|
|
if(hdl_cdll->hdlddev)
|
|
(hdl_cdll->hdlddev)(&hdl_dvad);
|
|
|
|
/* register any new instructions */
|
|
if(hdl_cdll->hdldins)
|
|
(hdl_cdll->hdldins)(&hdl_didf);
|
|
|
|
hdl_cdll = NULL;
|
|
|
|
release_lock(&hdl_lock);
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
/* hdl_main - initialize hercules dynamic loader
|
|
*/
|
|
DLL_EXPORT void hdl_main (void)
|
|
{
|
|
HDLPRE *preload;
|
|
|
|
initialize_lock(&hdl_lock);
|
|
|
|
hdl_sdip = FALSE;
|
|
|
|
if ( hdl_modpath == NULL )
|
|
{
|
|
char *def;
|
|
char pathname[MAX_PATH];
|
|
|
|
if (!(def = getenv("HERCULES_LIB")))
|
|
{
|
|
if ( sysblk.hercules_pgmpath == NULL || strlen( sysblk.hercules_pgmpath ) == 0 )
|
|
{
|
|
hostpath(pathname, HDL_DEFAULT_PATH, sizeof(pathname));
|
|
hdl_setpath(pathname, TRUE);
|
|
}
|
|
else
|
|
{
|
|
#if !defined (MODULESDIR)
|
|
hdl_setpath(sysblk.hercules_pgmpath, TRUE);
|
|
#else
|
|
hostpath(pathname, HDL_DEFAULT_PATH, sizeof(pathname));
|
|
hdl_setpath(pathname, TRUE);
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hostpath(pathname, def, sizeof(pathname));
|
|
hdl_setpath(pathname, TRUE);
|
|
}
|
|
}
|
|
|
|
dlinit();
|
|
|
|
if(!(hdl_cdll = hdl_dll = malloc(sizeof(DLLENT))))
|
|
{
|
|
char buf[64];
|
|
MSGBUF( buf, "malloc(%d)", (int)sizeof(DLLENT));
|
|
fprintf(stderr, MSG(HHC01511, "E", buf, strerror(errno)));
|
|
exit(1);
|
|
}
|
|
|
|
hdl_cdll->name = strdup("*Hercules");
|
|
|
|
/* This was a nice trick. Unfortunately, on some platforms */
|
|
/* it becomes impossible. Some platforms need fully defined */
|
|
/* DLLs, some other platforms do not allow dlopen(self) */
|
|
|
|
#if 1
|
|
|
|
if(!(hdl_cdll->dll = hdl_dlopen(NULL, RTLD_NOW )))
|
|
{
|
|
fprintf(stderr, MSG(HHC01516, "E", "hercules", dlerror()));
|
|
exit(1);
|
|
}
|
|
|
|
hdl_cdll->flags = HDL_LOAD_MAIN | HDL_LOAD_NOUNLOAD;
|
|
|
|
if(!(hdl_cdll->hdldepc = dlsym(hdl_cdll->dll,HDL_DEPC_Q)))
|
|
{
|
|
fprintf(stderr, MSG(HHC01517, "E", hdl_cdll->name, dlerror()));
|
|
exit(1);
|
|
}
|
|
|
|
hdl_cdll->hdlinit = dlsym(hdl_cdll->dll,HDL_INIT_Q);
|
|
|
|
hdl_cdll->hdlreso = dlsym(hdl_cdll->dll,HDL_RESO_Q);
|
|
|
|
hdl_cdll->hdlddev = dlsym(hdl_cdll->dll,HDL_DDEV_Q);
|
|
|
|
hdl_cdll->hdldins = dlsym(hdl_cdll->dll,HDL_DINS_Q);
|
|
|
|
hdl_cdll->hdlfini = dlsym(hdl_cdll->dll,HDL_FINI_Q);
|
|
#else
|
|
|
|
hdl_cdll->flags = HDL_LOAD_MAIN | HDL_LOAD_NOUNLOAD;
|
|
|
|
hdl_cdll->hdldepc = &HDL_DEPC;
|
|
|
|
hdl_cdll->hdlinit = &HDL_INIT;
|
|
|
|
hdl_cdll->hdlreso = &HDL_RESO;
|
|
|
|
hdl_cdll->hdlddev = &HDL_DDEV;
|
|
|
|
hdl_cdll->hdldins = &HDL_DINS;
|
|
|
|
hdl_cdll->hdlfini = &HDL_FINI;
|
|
#endif
|
|
|
|
/* No modules or device types registered yet */
|
|
hdl_cdll->modent = NULL;
|
|
hdl_cdll->hndent = NULL;
|
|
hdl_cdll->insent = NULL;
|
|
|
|
/* No dll's loaded yet */
|
|
hdl_cdll->dllnext = NULL;
|
|
|
|
obtain_lock(&hdl_lock);
|
|
|
|
if(hdl_cdll->hdldepc)
|
|
(hdl_cdll->hdldepc)(&hdl_dadd);
|
|
|
|
if(hdl_cdll->hdlinit)
|
|
(hdl_cdll->hdlinit)(&hdl_regi);
|
|
|
|
if(hdl_cdll->hdlreso)
|
|
(hdl_cdll->hdlreso)(&hdl_fent);
|
|
|
|
if(hdl_cdll->hdlddev)
|
|
(hdl_cdll->hdlddev)(&hdl_dvad);
|
|
|
|
if(hdl_cdll->hdldins)
|
|
(hdl_cdll->hdldins)(&hdl_didf);
|
|
|
|
release_lock(&hdl_lock);
|
|
|
|
/* Register termination exit */
|
|
hdl_adsc( "hdl_term", hdl_term, NULL);
|
|
|
|
for(preload = hdl_preload; preload->name; preload++)
|
|
hdl_load(preload->name, preload->flag);
|
|
|
|
#if defined(_MSVC_) && 0
|
|
hdl_lexe();
|
|
#endif
|
|
}
|
|
|
|
|
|
/* hdl_load - load a dll
|
|
*/
|
|
DLL_EXPORT int hdl_load (char *name,int flags)
|
|
{
|
|
DLLENT *dllent, *tmpdll;
|
|
MODENT *modent;
|
|
char *modname;
|
|
|
|
modname = (modname = strrchr(name,'/')) ? modname+1 : name;
|
|
|
|
for(dllent = hdl_dll; dllent; dllent = dllent->dllnext)
|
|
{
|
|
if(strfilenamecmp(modname,dllent->name) == 0)
|
|
{
|
|
logmsg(MSG(HHC01519, "E", dllent->name));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if(!(dllent = malloc(sizeof(DLLENT))))
|
|
{
|
|
logmsg(MSG(HHC01511, "E", "malloc()", strerror(errno)));
|
|
return -1;
|
|
}
|
|
|
|
dllent->name = strdup(modname);
|
|
|
|
if(!(dllent->dll = hdl_dlopen(name, RTLD_NOW)))
|
|
{
|
|
if(!(flags & HDL_LOAD_NOMSG))
|
|
logmsg(MSG(HHC01516, "E", name, dlerror()));
|
|
free(dllent);
|
|
return -1;
|
|
}
|
|
|
|
dllent->flags = (flags & (~HDL_LOAD_WAS_FORCED));
|
|
|
|
if(!(dllent->hdldepc = dlsym(dllent->dll,HDL_DEPC_Q)))
|
|
{
|
|
logmsg(MSG(HHC01517, "E", dllent->name, dlerror()));
|
|
dlclose(dllent->dll);
|
|
free(dllent);
|
|
return -1;
|
|
}
|
|
|
|
for(tmpdll = hdl_dll; tmpdll; tmpdll = tmpdll->dllnext)
|
|
{
|
|
if(tmpdll->hdldepc == dllent->hdldepc)
|
|
{
|
|
logmsg(MSG(HHC01520, "E", dllent->name, tmpdll->name));
|
|
dlclose(dllent->dll);
|
|
free(dllent);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
dllent->hdlinit = dlsym(dllent->dll,HDL_INIT_Q);
|
|
|
|
dllent->hdlreso = dlsym(dllent->dll,HDL_RESO_Q);
|
|
|
|
dllent->hdlddev = dlsym(dllent->dll,HDL_DDEV_Q);
|
|
|
|
dllent->hdldins = dlsym(dllent->dll,HDL_DINS_Q);
|
|
|
|
dllent->hdlfini = dlsym(dllent->dll,HDL_FINI_Q);
|
|
|
|
/* No modules or device types registered yet */
|
|
dllent->modent = NULL;
|
|
dllent->hndent = NULL;
|
|
dllent->insent = NULL;
|
|
|
|
obtain_lock(&hdl_lock);
|
|
|
|
if(dllent->hdldepc)
|
|
{
|
|
if((dllent->hdldepc)(&hdl_dchk))
|
|
{
|
|
logmsg(MSG(HHC01518, "E", dllent->name));
|
|
if(!(flags & HDL_LOAD_FORCE))
|
|
{
|
|
dlclose(dllent->dll);
|
|
free(dllent);
|
|
release_lock(&hdl_lock);
|
|
return -1;
|
|
}
|
|
dllent->flags |= HDL_LOAD_WAS_FORCED;
|
|
}
|
|
}
|
|
|
|
hdl_cdll = dllent;
|
|
|
|
/* Call initializer */
|
|
if(hdl_cdll->hdlinit)
|
|
(dllent->hdlinit)(&hdl_regi);
|
|
|
|
/* Insert current entry as first in chain */
|
|
dllent->dllnext = hdl_dll;
|
|
hdl_dll = dllent;
|
|
|
|
/* Reset the loadcounts */
|
|
for(dllent = hdl_dll; dllent; dllent = dllent->dllnext)
|
|
for(modent = dllent->modent; modent; modent = modent->modnext)
|
|
modent->count = 0;
|
|
|
|
/* Call all resolvers */
|
|
for(dllent = hdl_dll; dllent; dllent = dllent->dllnext)
|
|
{
|
|
if(dllent->hdlreso)
|
|
(dllent->hdlreso)(&hdl_fent);
|
|
}
|
|
|
|
/* register any device types */
|
|
if(hdl_cdll->hdlddev)
|
|
(hdl_cdll->hdlddev)(&hdl_dvad);
|
|
|
|
/* register any new instructions */
|
|
if(hdl_cdll->hdldins)
|
|
(hdl_cdll->hdldins)(&hdl_didf);
|
|
|
|
hdl_cdll = NULL;
|
|
|
|
release_lock(&hdl_lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* hdl_dele - unload a dll
|
|
*/
|
|
DLL_EXPORT int hdl_dele (char *name)
|
|
{
|
|
DLLENT **dllent, *tmpdll;
|
|
MODENT *modent, *tmpmod;
|
|
DEVBLK *dev;
|
|
HDLDEV *hnd;
|
|
HDLINS *ins;
|
|
char *modname;
|
|
|
|
modname = (modname = strrchr(name,'/')) ? modname+1 : name;
|
|
|
|
obtain_lock(&hdl_lock);
|
|
|
|
for(dllent = &(hdl_dll); *dllent; dllent = &((*dllent)->dllnext))
|
|
{
|
|
if(strfilenamecmp(modname,(*dllent)->name) == 0)
|
|
{
|
|
if((*dllent)->flags & (HDL_LOAD_MAIN | HDL_LOAD_NOUNLOAD))
|
|
{
|
|
release_lock(&hdl_lock);
|
|
logmsg(MSG(HHC01521, "E", (*dllent)->name));
|
|
return -1;
|
|
}
|
|
|
|
for(dev = sysblk.firstdev; dev; dev = dev->nextdev)
|
|
if (IS_DEV( dev ))
|
|
for(hnd = (*dllent)->hndent; hnd; hnd = hnd->next)
|
|
if(hnd->hnd == dev->hnd)
|
|
{
|
|
release_lock(&hdl_lock);
|
|
logmsg(MSG(HHC01522, "E",(*dllent)->name, SSID_TO_LCSS(dev->ssid), dev->devnum));
|
|
return -1;
|
|
}
|
|
|
|
/* Call dll close routine */
|
|
if((*dllent)->hdlfini)
|
|
{
|
|
int rc;
|
|
|
|
if((rc = ((*dllent)->hdlfini)()))
|
|
{
|
|
release_lock(&hdl_lock);
|
|
logmsg(MSG(HHC01523, "E", (*dllent)->name));
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
modent = (*dllent)->modent;
|
|
while(modent)
|
|
{
|
|
tmpmod = modent;
|
|
|
|
/* remove current entry from chain */
|
|
modent = modent->modnext;
|
|
|
|
/* free module resources */
|
|
free(tmpmod->name);
|
|
free(tmpmod);
|
|
}
|
|
|
|
tmpdll = *dllent;
|
|
|
|
/* remove current entry from chain */
|
|
*dllent = (*dllent)->dllnext;
|
|
|
|
for(hnd = tmpdll->hndent; hnd;)
|
|
{
|
|
HDLDEV *nexthnd;
|
|
free(hnd->name);
|
|
nexthnd = hnd->next;
|
|
free(hnd);
|
|
hnd = nexthnd;
|
|
}
|
|
|
|
for(ins = tmpdll->insent; ins;)
|
|
{
|
|
HDLINS *nextins;
|
|
|
|
hdl_modify_opcode(FALSE, ins);
|
|
free(ins->instname);
|
|
nextins = ins->next;
|
|
free(ins);
|
|
ins = nextins;
|
|
}
|
|
|
|
// dlclose(tmpdll->dll);
|
|
|
|
/* free dll resources */
|
|
free(tmpdll->name);
|
|
free(tmpdll);
|
|
|
|
/* Reset the loadcounts */
|
|
for(tmpdll = hdl_dll; tmpdll; tmpdll = tmpdll->dllnext)
|
|
for(tmpmod = tmpdll->modent; tmpmod; tmpmod = tmpmod->modnext)
|
|
tmpmod->count = 0;
|
|
|
|
/* Call all resolvers */
|
|
for(tmpdll = hdl_dll; tmpdll; tmpdll = tmpdll->dllnext)
|
|
{
|
|
if(tmpdll->hdlreso)
|
|
(tmpdll->hdlreso)(&hdl_fent);
|
|
}
|
|
|
|
release_lock(&hdl_lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
|
|
release_lock(&hdl_lock);
|
|
|
|
logmsg(MSG(HHC01524, "E", modname));
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
static void hdl_modify_opcode(int insert, HDLINS *instr)
|
|
{
|
|
if(insert)
|
|
{
|
|
#ifdef _370
|
|
if(instr->archflags & HDL_INSTARCH_370)
|
|
instr->original = replace_opcode(ARCH_370, instr->instruction, instr->opcode >> 8, instr->opcode & 0x00ff);
|
|
#endif
|
|
#ifdef _390
|
|
if(instr->archflags & HDL_INSTARCH_390)
|
|
instr->original = replace_opcode(ARCH_390, instr->instruction, instr->opcode >> 8, instr->opcode & 0x00ff);
|
|
#endif
|
|
#ifdef _900
|
|
if(instr->archflags & HDL_INSTARCH_900)
|
|
instr->original = replace_opcode(ARCH_900, instr->instruction, instr->opcode >> 8, instr->opcode & 0x00ff);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef _370
|
|
if(instr->archflags & HDL_INSTARCH_370)
|
|
replace_opcode(ARCH_370, instr->original, instr->opcode >> 8, instr->opcode & 0x00ff);
|
|
#endif
|
|
#ifdef _390
|
|
if(instr->archflags & HDL_INSTARCH_390)
|
|
replace_opcode(ARCH_390, instr->original, instr->opcode >> 8, instr->opcode & 0x00ff);
|
|
#endif
|
|
#ifdef _900
|
|
if(instr->archflags & HDL_INSTARCH_900)
|
|
replace_opcode(ARCH_900, instr->original, instr->opcode >> 8, instr->opcode & 0x00ff);
|
|
#endif
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/* hdl_didf - Define instruction call */
|
|
static void hdl_didf (int archflags, int opcode, char *name, void *routine)
|
|
{
|
|
HDLINS *newins;
|
|
|
|
newins = malloc(sizeof(HDLINS));
|
|
newins->opcode = opcode > 0xff ? opcode : (opcode << 8) ;
|
|
newins->archflags = archflags;
|
|
newins->instname = strdup(name);
|
|
newins->instruction = routine;
|
|
newins->next = hdl_cdll->insent;
|
|
hdl_cdll->insent = newins;
|
|
hdl_modify_opcode(TRUE, newins);
|
|
}
|
|
|
|
#endif /*defined(OPTION_DYNAMIC_LOAD)*/
|