mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4290 lines
144 KiB
4290 lines
144 KiB
|
|
#include "ldrextrn.h"
|
|
#include "ldrdbg.h"
|
|
#ifdef PMNT
|
|
#define INCL_32BIT
|
|
#include "pmnt.h"
|
|
PID PMNTPMShellPid = 0;
|
|
#endif
|
|
|
|
/***EP LDRNewExe - load a new .EXE file format program.
|
|
*
|
|
* This routine is called by the w_execpgm function to
|
|
* load a program module and it's referenced library
|
|
* modules.
|
|
*
|
|
* This procedure performs the following steps:
|
|
*
|
|
* - Compute module name string length and validate it.
|
|
* - Load the program module and referenced library modules.
|
|
* - Copy startup information into the exec_info structure.
|
|
*
|
|
* ENTRY pachModname - pointer to ASCII module name
|
|
* pexec_info - pointer to return buffer
|
|
*
|
|
* EXIT int - return code (NO_ERROR if successful)
|
|
* pexec_info structure set
|
|
*/
|
|
|
|
BOOLEAN
|
|
LDRNewExe(
|
|
IN POS2_THREAD t,
|
|
IN POS2_API_MSG m
|
|
)
|
|
{
|
|
P_LDRNEWEXE_MSG a = &m->u.LdrNewExe;
|
|
ldrmte_t *pmte; /* Pointer to loaded mte */
|
|
ldrmte_t *pmteToChange;
|
|
ldrste_t *psteToChange;
|
|
USHORT Offset;
|
|
PVOID FlatEntryPoint;
|
|
UCHAR c = (UCHAR)0xCC;
|
|
USHORT cb;
|
|
int rc;
|
|
NTSTATUS Status;
|
|
ULONG NEFlags;
|
|
#if PMNT
|
|
BOOLEAN SavedErrInfo=FALSE;
|
|
#endif
|
|
|
|
ldrNewExeInit(t,a,&cb);
|
|
/*
|
|
* Load the program module and referenced library modules.
|
|
*/
|
|
rc = ldrGetModule(a->ProcessName.Buffer,
|
|
cb,
|
|
(char)EXT_PROGRAM,
|
|
(ushort_t) CLASS_PROGRAM,
|
|
&pmte,
|
|
&a->BoundApp,
|
|
&NEFlags);
|
|
#if PMNT
|
|
if ((rc == ERROR_INVALID_ORDINAL || rc == ERROR_PROC_NOT_FOUND) &&
|
|
!(CurrentThread->Process->Flags & OS2_PROCESS_WINDOWAPI) &&
|
|
ldrTgtModNameBufL == 8 && ! strncmp(ldrTgtModNameBuf,"VIOCALLS",8)
|
|
) {
|
|
SavedErrInfo = ldrSaveErrInfo(rc);
|
|
CurrentThread->Process->Flags |= OS2_PROCESS_FORCEDPM;
|
|
//
|
|
// Maybe a PM application with WINDOWAPI flags off; try forced PM
|
|
//
|
|
ldrUnloadTagedModules(t->Process);
|
|
|
|
ldrNewExeInit(t,a,&cb);
|
|
|
|
/*
|
|
* Load the program module and referenced library modules.
|
|
*/
|
|
rc = ldrGetModule(a->ProcessName.Buffer,
|
|
cb,
|
|
(char)EXT_PROGRAM,
|
|
(ushort_t) CLASS_PROGRAM,
|
|
&pmte,
|
|
&a->BoundApp,
|
|
&NEFlags);
|
|
if ((rc != NO_ERROR || ! (CurrentThread->Process->Flags & OS2_PROCESS_PMMSGQUE))
|
|
&& SavedErrInfo) {
|
|
ldrRestoreErrInfo(&rc);
|
|
}
|
|
|
|
}
|
|
else if (rc == ERROR_2ND_PMSHELL) {
|
|
ldrUnloadTagedModules(t->Process);
|
|
m->ReturnedErrorValue = ERROR_2ND_PMSHELL;
|
|
return(TRUE);
|
|
}
|
|
#endif // if PMNT
|
|
|
|
if (rc != NO_ERROR) {
|
|
ldrWriteErrTxt(rc);
|
|
#if PMNT
|
|
if (SavedErrInfo) {
|
|
ldrFreeErrInfo();
|
|
}
|
|
#endif
|
|
ldrUnloadTagedModules(t->Process);
|
|
m->ReturnedErrorValue = rc;
|
|
return(TRUE);
|
|
}
|
|
|
|
#if PMNT
|
|
if (SavedErrInfo) {
|
|
ldrFreeErrInfo();
|
|
}
|
|
#endif
|
|
if (CurrentThread->Process->Flags & OS2_PROCESS_TRACE) {
|
|
/*
|
|
* Replace the initial instruction of the first init
|
|
* routine with int 3. This will be replaced back by
|
|
* Os2DebugEventHandle at init time.
|
|
*/
|
|
|
|
if (*pldrLibiCounter > 0) {
|
|
/*
|
|
* There is an init routine
|
|
*/
|
|
|
|
pmteToChange = ldrFindMTEForHandle(pldrLibiRecord[0].handle);
|
|
}
|
|
else {
|
|
pmteToChange = ldrFindMTEForHandle(((LinkMTE *)CurrentThread->Process->LinkMte)->NextMTE->MTE);
|
|
}
|
|
|
|
CurrentThread->Process->FirstMTE = pmteToChange;
|
|
psteToChange = ldrNumToSte(pmteToChange, pmteToChange->mte_swapmte->smte_startobj);
|
|
Offset = (USHORT)pmteToChange->mte_swapmte->smte_eip;
|
|
FlatEntryPoint = (PVOID)((ULONG)(SELTOFLAT(psteToChange->ste_selector |7)) | (ULONG)(Offset));
|
|
Status = NtWriteVirtualMemory( CurrentThread->Process->ProcessHandle,
|
|
(PVOID) FlatEntryPoint,
|
|
(PVOID) &(c),
|
|
1,
|
|
NULL
|
|
);
|
|
#if DBG
|
|
if (!(NT_SUCCESS(Status))) {
|
|
KdPrint(( "LDRNewExe: PTrace support failed to write entry. Status %lx\n", Status));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Update app type in process structure
|
|
//
|
|
pmte->mte_mflags2 = NEFlags;
|
|
|
|
//
|
|
// set/force bound-app flag
|
|
//
|
|
if (a->BoundApp) {
|
|
pmte->mte_mflags2 |= NEBOUND;
|
|
}
|
|
|
|
#if PMNT
|
|
a->PMProcess = 0;
|
|
|
|
if (CurrentThread->Process->Flags & OS2_PROCESS_IS_PMSHELL)
|
|
{
|
|
pmte->mte_mflags2 |= NEPMSHELL;
|
|
a->PMProcess |= APPTYPE_PMSHELL;
|
|
}
|
|
|
|
if (CurrentThread->Process->Flags & OS2_PROCESS_PMMSGQUE)
|
|
{
|
|
pmte->mte_mflags2 |= NEPMMSGQUE;
|
|
}
|
|
|
|
if (Os2srvProcessIsPMProcess(CurrentThread->Process))
|
|
{
|
|
a->PMProcess |= APPTYPE_PM;
|
|
}
|
|
|
|
if ((CurrentThread->Process->Parent != NULL) &&
|
|
(CurrentThread->Process->Parent->ProcessId != 0) &&
|
|
(CurrentThread->Process->Parent->ProcessId == PMNTPMShellPid))
|
|
{
|
|
a->PMProcess |= APPTYPE_PMSHELL_CHILD;
|
|
}
|
|
|
|
if (a->PMProcess && !PMNTPMShellPid) {
|
|
ldrUnloadTagedModules(t->Process);
|
|
m->ReturnedErrorValue = ERROR_PMSHELL_NOT_UP;
|
|
return(TRUE);
|
|
}
|
|
#endif // PMNT
|
|
|
|
/*
|
|
* get program module startup parameters
|
|
*/
|
|
rc = ldrGetModParams(pmte, (ldrrei_t *)&a->ExecInfo);
|
|
if (rc != NO_ERROR) {
|
|
ldrWriteErrTxt(rc);
|
|
ldrUnloadTagedModules(t->Process);
|
|
m->ReturnedErrorValue = rc;
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// Save the handle of the CLASS_PROGRAM mte in the process
|
|
// data structure
|
|
//
|
|
t->Process->ProcessMTE = (PVOID)pmte;
|
|
|
|
a->DoscallsSel = LDRDoscallsSel;
|
|
m->ReturnedErrorValue = NO_ERROR;
|
|
#if DBG
|
|
IF_OL2_DEBUG ( TRACE ) {
|
|
DbgPrint("OS2LDR: LDRNewExe is returning to the client, rc = %d\n", rc);
|
|
}
|
|
#endif
|
|
//
|
|
// Increment the usecnt of the referenced modules
|
|
//
|
|
pmte = mte_h;
|
|
while (pmte != NULL) {
|
|
if ((pmte->mte_mflags & INGRAPH) != 0) {
|
|
pmte->mte_usecnt++;
|
|
}
|
|
pmte = pmte->mte_link;
|
|
}
|
|
|
|
#if DBG
|
|
IF_OL2_DEBUG ( MTE ) {
|
|
DbgPrint("\nDumping segments after LDRNewExe() processing\n");
|
|
ldrDisplaySegmentTable();
|
|
}
|
|
#endif
|
|
|
|
#if PMNT && DBG
|
|
LDRDumpSegments((POS2_THREAD)NULL,
|
|
(POS2_API_MSG)NULL);
|
|
#endif
|
|
|
|
m->ReturnedErrorValue = NO_ERROR;
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
VOID
|
|
ldrNewExeInit(
|
|
IN POS2_THREAD t,
|
|
IN P_LDRNEWEXE_MSG a,
|
|
OUT PUSHORT cb
|
|
)
|
|
{
|
|
//
|
|
// Set the global variable CurrentThread to the value of
|
|
// the current running Thread. This is used by other routines
|
|
// in the loader to find relevant information regarding the
|
|
// OS/2 process that issued the call.
|
|
//
|
|
CurrentThread = t;
|
|
|
|
//
|
|
// Set the fForceUnmap flag to TRUE so that ldrUnloadTagedModules()
|
|
// does unmap the app's freed segments from the app's address space.
|
|
//
|
|
fForceUnmap = TRUE;
|
|
|
|
//
|
|
// Invalidate the error message buffers
|
|
//
|
|
ldrInvSrcErrTxt();
|
|
ldrInvTgtErrTxt();
|
|
|
|
//
|
|
// Update once the Ol2EntryFlat variable which points to
|
|
// the client's entry flat address
|
|
//
|
|
Ol2EntryFlat = a->EntryFlatAddr;
|
|
|
|
//
|
|
// Init the Library Intialization routines data structure
|
|
//
|
|
pldrLibiRecord = (ldrlibi_t *)a->InitRecords.Buffer;
|
|
pldrLibiCounter = &a->NumOfInitRecords;
|
|
*pldrLibiCounter = 0;
|
|
|
|
//
|
|
// init the pointer to the error string
|
|
//
|
|
pErrText = &a->FailName;
|
|
|
|
ldrClearAllMteFlag(INGRAPH | USED);
|
|
|
|
/*
|
|
* Point to ldrLibPathBuf to contain the environment string
|
|
*/
|
|
strncpy(ldrLibPathBuf, a->LibPathName.Buffer, SizeOfldrLibPathBuf);
|
|
ldrLibPathBuf[SizeOfldrLibPathBuf - 1] = '\0';
|
|
|
|
_strupr(ldrpLibPath);
|
|
|
|
*cb = (USHORT)a->ProcessName.Length;
|
|
|
|
}
|
|
|
|
UCHAR
|
|
ldrGetEntryPoint(
|
|
IN POS2_PROCESS Process
|
|
)
|
|
{
|
|
ldrsmte_t *psmte;
|
|
ldrste_t *pste;
|
|
USHORT offset;
|
|
PVOID FlatEntryPoint;
|
|
NTSTATUS Status;
|
|
UCHAR c;
|
|
ldrmte_t *pMte;
|
|
|
|
if (((LinkMTE *)Process->LinkMte)->NextMTE == NULL) {
|
|
return(0);
|
|
}
|
|
|
|
pMte = Process->FirstMTE;
|
|
psmte = pMte->mte_swapmte;
|
|
pste = ldrNumToSte(pMte, psmte->smte_startobj);
|
|
offset = (USHORT) psmte->smte_eip;
|
|
FlatEntryPoint = (PVOID)((ULONG)(SELTOFLAT(pste->ste_selector | 7)) | (ULONG)(offset));
|
|
Status = NtReadVirtualMemory(Process->ProcessHandle,
|
|
FlatEntryPoint,
|
|
(PVOID) &(c),
|
|
1,
|
|
NULL
|
|
);
|
|
if (!(NT_SUCCESS(Status))) {
|
|
#if DBG
|
|
KdPrint(( "ldrGetEntryPoint failed to read entry. Status %lx\n", Status));
|
|
#endif
|
|
|
|
return(0);
|
|
}
|
|
|
|
return(c);
|
|
}
|
|
|
|
VOID
|
|
ldrRestoreEntryPoint(
|
|
IN POS2_PROCESS Process
|
|
)
|
|
{
|
|
//
|
|
// A process being traced just started, replace the int 3 with the real
|
|
// code
|
|
//
|
|
PVOID FlatEntryPoint;
|
|
UCHAR c;
|
|
NTSTATUS Status;
|
|
ldrste_t *pste;
|
|
USHORT offset;
|
|
ldrsmte_t *psmte;
|
|
ldrmte_t *pMte;
|
|
|
|
if (((LinkMTE *)Process->LinkMte)->NextMTE == NULL) {
|
|
return;
|
|
}
|
|
|
|
pMte = Process->FirstMTE;
|
|
psmte = pMte->mte_swapmte;
|
|
pste = ldrNumToSte(pMte, psmte->smte_startobj);
|
|
offset = (USHORT) psmte->smte_eip;
|
|
FlatEntryPoint = (PVOID)((ULONG)(SELTOFLAT(pste->ste_selector | 7)) | (ULONG)(offset));
|
|
//
|
|
// get the original value from os2srv address space, and stick it into
|
|
// the debuggee process
|
|
//
|
|
c = *(PUCHAR)(FlatEntryPoint);
|
|
Status = NtWriteVirtualMemory(Process->ProcessHandle,
|
|
FlatEntryPoint,
|
|
(PVOID) &(c),
|
|
1,
|
|
NULL
|
|
);
|
|
if (!(NT_SUCCESS(Status))) {
|
|
#if DBG
|
|
KdPrint(( "ldrRestoreEntryPoint failed to write entry. Status %lx\n", Status));
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/***LP ldrGetModule - Get module handle, load if required
|
|
*
|
|
* Get the module table entry handle for this module. If the
|
|
* module is not already loaded, call ldrLoadModule to load it.
|
|
*
|
|
* This procedure performs the following steps:
|
|
*
|
|
* - Allocate loader variables on the stack and initialize.
|
|
* - Get the desired module table entry handle.
|
|
* - Scan the mte list loading objects for modules that
|
|
* are not loaded.
|
|
* - Load the module
|
|
* - Release loader variables on the stack.
|
|
*
|
|
* ENTRY pachModname - pointer to module name
|
|
* cb - length of module name
|
|
* chLdrtype - load type being requested
|
|
* (program,library)
|
|
* class - module class
|
|
* (PROGRAM, GLOBAL or SPECIFIC)
|
|
* ppmte - a pointer to a mte pointer which
|
|
* was loaded
|
|
* pBound - optional pointer to a flag set if BOUND exe
|
|
*
|
|
* pNEFlags - Flags word of the NE header
|
|
*
|
|
* EXIT int - return code (NO_ERROR if successful)
|
|
*
|
|
* COMMENT:
|
|
* ldrGetModule is called from LDRNewExe, LDRLoadVdd and w_loadmodule.
|
|
*/
|
|
|
|
APIRET ldrGetModule(pachModname, cb, chLdrtype, class, ppmte, pBound, pNEFlags)
|
|
PUCHAR pachModname; /* pointer to ASCII module name */
|
|
USHORT cb; /* length of mod name */
|
|
char chLdrtype; /* type of module to load */
|
|
USHORT class; /* module class */
|
|
ldrmte_t **ppmte; /* place to return pointer to mte */
|
|
PBOOLEAN pBound; /* optional pointer to a flag set if BOUND exe */
|
|
PULONG pNEFlags; /* optional pointer to Flags word of the NE header */
|
|
{
|
|
register ldrmte_t *pmte; /* pointer to mte */
|
|
ldrlv_t lv; /* define local variables */
|
|
ldrlv_t *plv = &lv;
|
|
int rc;
|
|
LinkMTE *mteInLinkList;
|
|
|
|
#if DBG
|
|
IF_OL2_DEBUG ( TRACE ) {
|
|
DbgPrint("OS2LDR: ldrGetModule() was called with modname=%.*s, ", cb, pachModname);
|
|
if (chLdrtype == EXT_PROGRAM) {
|
|
DbgPrint("Type=PROGRAM\n");
|
|
}
|
|
else {
|
|
DbgPrint("Type=LIBRARY\n");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (pBound != 0) {
|
|
*pBound = FALSE;
|
|
}
|
|
|
|
try {
|
|
/*
|
|
* Init local variables
|
|
*/
|
|
memset((PCHAR) plv, 0, sizeof(ldrlv_t));
|
|
|
|
lv.lv_type = chLdrtype;
|
|
lv.lv_sfn = 0;
|
|
lv.lv_class = class;
|
|
|
|
/*
|
|
* initialize mte
|
|
*/
|
|
rc = ldrGetMte(pachModname, cb, chLdrtype, class, &plv->lv_pmte, pBound, pNEFlags);
|
|
if (rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
|
|
/*
|
|
* return handle and pointer of loaded mte
|
|
*/
|
|
pmte = *ppmte = lv.lv_pmte;
|
|
|
|
//
|
|
// Scan linked list of mtes and load or attach to objects.
|
|
//
|
|
|
|
for (pmte = mte_h; pmte != NULL; pmte = pmte->mte_link) {
|
|
//
|
|
// If module is not referenced, continue to next module
|
|
//
|
|
if ((pmte->mte_mflags & INGRAPH) == 0) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Module was referenced. Load it into memory
|
|
//
|
|
lv.lv_pmte = pmte; /* save pointer to mte */
|
|
lv.lv_hobmte = pmte->mte_handle;/* save handle to mte */
|
|
lv.lv_sfn = pmte->mte_sfn; /* save SFN of this mte */
|
|
rc = ldrLoadModule(plv); /* load required objects */
|
|
if (rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
if (CurrentThread->Process->Flags & OS2_PROCESS_TRACE) {
|
|
if ((*(PCHAR)pmte->mte_modname != 8) ||
|
|
(strncmp((PCHAR)(pmte->mte_modname)+1, "DOSCALLS", 8))) {
|
|
/*
|
|
* Add the mte to the process link list of mte.
|
|
*/
|
|
mteInLinkList = (LinkMTE *) (CurrentThread->Process->LinkMte);
|
|
mteInLinkList->NeedToTransfer++;
|
|
while (mteInLinkList->NextMTE != NULL) {
|
|
mteInLinkList = mteInLinkList->NextMTE;
|
|
}
|
|
|
|
mteInLinkList->NextMTE = RtlAllocateHeap(Os2Heap, 0, sizeof(LinkMTE));
|
|
if (mteInLinkList->NextMTE) {
|
|
mteInLinkList->NextMTE->MTE = pmte->mte_handle;
|
|
mteInLinkList->NextMTE->NextMTE = NULL;
|
|
mteInLinkList->NextMTE->NeedToTransfer = TRUE;
|
|
}
|
|
else {
|
|
#if DBG
|
|
KdPrint(( "ldrGetModule: Unable to allocate memory for new mte in link list\n"));
|
|
#endif
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
|
return(0xdeadbeef);
|
|
}
|
|
}
|
|
|
|
|
|
/***LP ldrUCaseString - Upper case string
|
|
*/
|
|
void ldrUCaseString(PCHAR pstring, ULONG cb)
|
|
{
|
|
PUCHAR plocal;
|
|
ULONG i;
|
|
|
|
plocal = (PUCHAR)pstring;
|
|
for (i = 0; i < cb; i++) {
|
|
#ifdef DBCS
|
|
// MSKK Apr.09.1993 V-AkihiS
|
|
if (IsDBCSLeadByte(*plocal)) {
|
|
plocal++;
|
|
if (i < cb) {
|
|
i++;
|
|
plocal++;
|
|
}
|
|
} else {
|
|
*plocal = (CHAR) toupper(*plocal);
|
|
plocal++;
|
|
}
|
|
#else
|
|
*plocal = (CHAR) toupper(*plocal);
|
|
plocal++;
|
|
#endif
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/***LP ldrGetMte - Get module handle
|
|
*
|
|
* Get the module table entry (mte) handle for this module. If
|
|
* the module's mte is not in the linked list of mte's, open and
|
|
* read the file EXE header, verify the header is for a segmented
|
|
* or linear EXE file format, create an mte for the module and initialize
|
|
* it. If this is a program module, save the mte handle in the user's
|
|
* PTDA. If the module's mte is found in the linked list of mte's,
|
|
* attach to the module if not already attached and allocate non_shared
|
|
* objects.
|
|
*
|
|
* ENTRY pachModname - pointer to module name
|
|
* cb - length of module name
|
|
* chLdrtype - load type being requested
|
|
* (program,library,device)
|
|
* class - program,global or specific
|
|
* ppmte - pointer to a pmte if exist else 0
|
|
* pBound - optional pointer to a flag set if BOUND exe
|
|
* pNEFlags - Flags word of the NE header
|
|
*
|
|
* EXIT none - return successful or call load_error
|
|
*
|
|
* EFFECTS - pointer of reqested mte placed in
|
|
* ppmte
|
|
*
|
|
* COMMENT - ldrGetMte is called from ldrGetModule
|
|
* and ldrLoadModule
|
|
*/
|
|
|
|
APIRET ldrGetMte(pachModname, cb, chLdrtype, class, ppmte, pBound, pNEFlags)
|
|
PUCHAR pachModname; /* pointer to ASCII module name */
|
|
USHORT cb; /* length of module name */
|
|
UCHAR chLdrtype; /* type of module to load */
|
|
USHORT class; /* class to which module belongs */
|
|
ldrmte_t **ppmte; /* pointer to a mte pointer */
|
|
PBOOLEAN pBound; /* optional pointer to a flag set if BOUND exe */
|
|
PULONG pNEFlags; /* optional pointer to Flags word of the NE header */
|
|
{
|
|
ldrlv_t lv; /* loader variable */
|
|
register ldrlv_t *plv = &lv;
|
|
register ldrmte_t *pmte; /* pointer to mte */
|
|
struct e32_exe *pe32; /* pointer to link exe format image */
|
|
ldrmte_t *ptemp;
|
|
ldrsmte_t *psmte;
|
|
int rc;
|
|
int rc1;
|
|
int ModuleNameSize;
|
|
PCHAR ModuleNameString;
|
|
ULONG i;
|
|
ULONG lindex;
|
|
PCHAR RefModname;
|
|
USHORT Refcb;
|
|
BOOLEAN BoundApp;
|
|
|
|
#if DBG
|
|
IF_OL2_DEBUG ( TRACE ) {
|
|
DbgPrint("OS2LDR: ldrGetMte() was called with modname=%.*s, ", cb, pachModname);
|
|
if (chLdrtype == EXT_PROGRAM) {
|
|
DbgPrint("Type=PROGRAM\n");
|
|
}
|
|
else {
|
|
DbgPrint("Type=LIBRARY\n");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (pBound != 0) {
|
|
*pBound = FALSE;
|
|
}
|
|
|
|
/*
|
|
* Init local variables
|
|
*/
|
|
memset((PCHAR) plv, 0, sizeof(ldrlv_t));
|
|
|
|
/*
|
|
* setup source global error message txt
|
|
*/
|
|
|
|
if ((cb > 14) && !strncmp(pachModname, "\\OS2SS\\DRIVES\\", 14)) {
|
|
ldrSetupSrcErrTxt(pachModname+14, cb-14);
|
|
}
|
|
else {
|
|
ldrSetupSrcErrTxt(pachModname, cb);
|
|
}
|
|
|
|
lv.lv_type = chLdrtype;
|
|
lv.lv_sfn = 0;
|
|
lv.lv_class = class;
|
|
|
|
if ((*ppmte == NULL) && (lv.lv_type != EXT_DEVICE)) {
|
|
/*
|
|
* Upper case module name
|
|
*/
|
|
ldrUCaseString(pachModname, (ulong_t) cb);
|
|
|
|
/*
|
|
* Do not search for device drivers.
|
|
* Search to see if the module is already loaded so that
|
|
* it may be shared. ppmte is set to zero if the module
|
|
* is not found
|
|
*/
|
|
ldrFindModule(pachModname, cb, class, ppmte);
|
|
|
|
/*
|
|
* We can not load VDDs twice, so if FindModule found it
|
|
* return an error.
|
|
* BUGBUG - This error should be changed to:
|
|
* ERROR_VDD_ALREADY_LOADED
|
|
*/
|
|
if (chLdrtype == EXT_VDD && *ppmte != NULL) {
|
|
|
|
if (pBound != 0 &&
|
|
((*ppmte)->mte_mflags2 & NEBOUND)) {
|
|
|
|
*pBound = TRUE;
|
|
}
|
|
|
|
return(ERROR_NOT_SAME_DEVICE);
|
|
}
|
|
}
|
|
|
|
again:
|
|
pmte = lv.lv_pmte = *ppmte;
|
|
|
|
if (pmte != NULL) {
|
|
|
|
if (pBound != 0 &&
|
|
(pmte->mte_mflags2 & NEBOUND)) {
|
|
|
|
*pBound = TRUE;
|
|
}
|
|
|
|
if (class == CLASS_PROGRAM) {
|
|
//
|
|
// process with same name is running
|
|
// initialize the new process Flags (normally done during loading
|
|
//
|
|
|
|
*pNEFlags = pmte->mte_mflags2;
|
|
|
|
if ((pmte->mte_mflags2 & NEAPPTYP) == NENOTWINCOMPAT) {
|
|
CurrentThread->Process->Flags |= OS2_PROCESS_NOTWINDOWCOMPAT;
|
|
}
|
|
else if ((pmte->mte_mflags2 & NEAPPTYP) == NEWINCOMPAT) {
|
|
CurrentThread->Process->Flags |= OS2_PROCESS_WINDOWCOMPAT;
|
|
}
|
|
else if ((pmte->mte_mflags2 & NEAPPTYP) == NEWINAPI) {
|
|
CurrentThread->Process->Flags |= OS2_PROCESS_WINDOWAPI;
|
|
}
|
|
#if PMNT
|
|
if (pmte->mte_mflags2 & NEPMSHELL) {
|
|
return(ERROR_2ND_PMSHELL);
|
|
}
|
|
if (pmte->mte_mflags2 & NEPMMSGQUE) {
|
|
CurrentThread->Process->Flags |= OS2_PROCESS_PMMSGQUE;
|
|
}
|
|
#endif //if PMNT
|
|
}
|
|
|
|
if ((pmte->mte_mflags & INGRAPH) != 0) {
|
|
return(NO_ERROR);
|
|
}
|
|
ldrChkLoadType(pmte->mte_mflags, plv);
|
|
|
|
// ldrInvTgtErrTxt();
|
|
#if 0
|
|
/*
|
|
* Don't load modules that are attached already.
|
|
*/
|
|
if (ldrIsAttached(pmte)) {
|
|
return;
|
|
}
|
|
else {
|
|
/*
|
|
* setup existing SFN to load non-shared objects
|
|
*/
|
|
lv.lv_sfn = pmte->mte_sfn;
|
|
/*
|
|
* Indicate that shared objects should not have the page tables
|
|
* scanned. We will use the USED bit to indicate this
|
|
*/
|
|
pmte->mte_mflags |= USED;
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
/*
|
|
* We come here after ldrFindModule has failed to find this module
|
|
* in the class specified. We can have the following situation:
|
|
*
|
|
* a, We are trying to load a CLASS_SPECIFIC module. In this case
|
|
* we need to check if this module is loaded as a CLASS_GLOBAL
|
|
* module. If it is we use that MTE. The MTE is maintained as
|
|
* CLASS_GLOBAL.
|
|
*
|
|
* b, We are trying to load a CLASS_GLOBAL module. In this case
|
|
* we need to check if this mod is loaded as a CLASS_SPECIFIC
|
|
* module. If it is we use that MTE. The MTE is then promoted
|
|
* to CLASS_GLOBAL.
|
|
*/
|
|
if ((class == CLASS_SPECIFIC) &&
|
|
ldrCheckGlobal(pachModname, cb, ppmte))
|
|
goto again;
|
|
|
|
if ((rc=ldrOpenNewExe(pachModname, cb, plv, 0, &BoundApp, pNEFlags)) != NO_ERROR) {
|
|
|
|
if (rc == ERROR_OPEN_FAILED)
|
|
rc = ERROR_FILE_NOT_FOUND;
|
|
|
|
if (pBound != 0) {
|
|
*pBound = BoundApp;
|
|
}
|
|
|
|
return(rc) ;
|
|
}
|
|
|
|
if (pBound != 0) {
|
|
*pBound = BoundApp;
|
|
}
|
|
|
|
if ((class == CLASS_GLOBAL) && ldrCheckSpecific(ppmte, plv)) {
|
|
NtClose(lv.lv_sfn);
|
|
lv.lv_sfn = (*ppmte)->mte_sfn;
|
|
goto again;
|
|
}
|
|
pe32 = (struct e32_exe *) pheaderbuf;
|
|
ldrChkLoadType(pe32->e32_mflags, plv);
|
|
rc = ldrCreateMte(pe32, plv);
|
|
if (rc != NO_ERROR) {
|
|
NtClose(lv.lv_sfn);
|
|
return(rc);
|
|
}
|
|
pmte = lv.lv_pmte;
|
|
|
|
ModuleNameSize = *(PCHAR)pmte->mte_modname;
|
|
ModuleNameString = ((PCHAR)pmte->mte_modname)+1;
|
|
if ((ModuleNameSize == 8) &&
|
|
(strncmp("DOSCALLS", ModuleNameString, 8) == 0)) {
|
|
pmte->mte_mflags |= DOSLIB;
|
|
pmte->mte_usecnt = 1;
|
|
}
|
|
|
|
// ldrInvTgtErrTxt();
|
|
/*
|
|
* If VMProtectedMem is TRUE, set MTEMODPROT if module is a 16-bit
|
|
* DLL and is in PROTECT16 list.
|
|
* Else clear MTEMODPROT (for both 16 and 32-bit modules).
|
|
*/
|
|
// if (VMProtectedMem) {
|
|
// if (ldrIsNE(pmte) && (pmte->mte_mflags & LIBRARYMOD) &&
|
|
// ldrIsModuleProtected())
|
|
// pmte->mte_mflags |= MTEMODPROT;
|
|
// }
|
|
// else pmte->mte_mflags &= ~MTEMODPROT;
|
|
|
|
}
|
|
|
|
//
|
|
// Set the INGRAPH flag in order to prevent cycles
|
|
//
|
|
pmte->mte_mflags |= INGRAPH;
|
|
|
|
/*
|
|
* allocate object for this module by calling ldrAllocSegments for
|
|
* 16-bit modules or ldrAllocObjects for 32-bit modules
|
|
*/
|
|
if (ldrIsNE(pmte)) {
|
|
//
|
|
// For system dll's other than Doscalls don't allocate
|
|
// segments.
|
|
//
|
|
if ((pmte->mte_mflags & DOSMOD) == 0) {
|
|
//
|
|
// Don't allocate segments for modules that are already
|
|
// allocated for this program
|
|
//
|
|
if ((pmte->mte_mflags & USED) == 0) {
|
|
rc = ldrAllocSegments(plv);
|
|
if (rc != NO_ERROR) {
|
|
if (pmte->mte_usecnt == 0) {
|
|
NtClose(lv.lv_sfn);
|
|
rc1 = Free16BHandle(pmte->mte_handle);
|
|
ASSERT(rc1 == NO_ERROR);
|
|
ldrUnlinkMTE(pmte);
|
|
RtlFreeHeap(LDRNEHeap, 0, pmte->mte_swapmte);
|
|
RtlFreeHeap(LDRNEHeap, 0, pmte);
|
|
}
|
|
return(rc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
*ppmte = pmte; /* return pmte */
|
|
|
|
//
|
|
// Now try to recursively allocate the referenced modules
|
|
//
|
|
|
|
/*
|
|
* For Each module in import module name table attach to or load
|
|
*/
|
|
ppmte = (ldrmte_t **) pmte->mte_modptrs;
|
|
|
|
for (i = 1; i <= pmte->mte_impmodcnt; i++) {
|
|
/*
|
|
* Since it is required for 16-bit modules to load the
|
|
* referneced module in reverse order and not for 32-bit,
|
|
* lindex will be the index for the array of mte pointers
|
|
* for both 16-bit and 32-bit modules
|
|
*/
|
|
lindex = pmte->mte_impmodcnt-i;
|
|
|
|
/*
|
|
* check if module loaded already, if so try to attach to it
|
|
*/
|
|
ptemp = ppmte[lindex];
|
|
|
|
if ((ptemp != NULL) && ((ptemp->mte_mflags & INGRAPH) != 0)) {
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* point to mod name in table for 16-bit modules,
|
|
* load in reverse order
|
|
*/
|
|
psmte = pmte->mte_swapmte;
|
|
RefModname = (uchar_t *) (psmte->smte_impproc +
|
|
((ushort_t *) (psmte->smte_impmod))[lindex]);
|
|
Refcb = (USHORT) (*((uchar_t *) RefModname++));
|
|
|
|
rc = ldrGetMte(RefModname, Refcb, EXT_LIBRARY, CLASS_GLOBAL, &ptemp, NULL, NULL);
|
|
if (rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
ppmte[lindex] = ptemp;
|
|
|
|
/*
|
|
* validate as mte
|
|
*/
|
|
ASSERT(fMTEValid(ptemp));
|
|
|
|
}
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
|
|
/***LP ldrGetModParams - get program module startup parameters
|
|
*
|
|
* The program module startup parameters are obtained
|
|
* from the module's MTE header and are returned to the
|
|
* Exec function through the exec_info structure. This
|
|
* routine gets these parameters from the MTE and validates
|
|
* them and places them into the exec_info structure passed
|
|
* on the stack.
|
|
*
|
|
* This procedure performs the following steps:
|
|
*
|
|
* - Validates the starting code segment number.
|
|
* - Stores the starting CS:IP in the exec_info structure.
|
|
* - Validates the initial stack segment number and
|
|
* checks that it is not a shared segment.
|
|
* - Stores the initial SS in the exec_info structure.
|
|
* - Stores the auto data selector in the exec_info structure.
|
|
* - Calculates the initial SP and stores it in the exec_info
|
|
* structure.
|
|
* - Stores the additional heap size and stack size values in
|
|
* the exec_info structure.
|
|
*
|
|
* ENTRY pmte - pointer to module table entry
|
|
* pei - pointer to exec_info structure
|
|
*
|
|
* EXIT int - return code (NO_ERROR if successful)
|
|
*/
|
|
|
|
int ldrGetModParams(pmte, pei)
|
|
ldrmte_t *pmte; /* pointer to mte */
|
|
register ldrrei_t *pei; /* pointer to return buffer */
|
|
{
|
|
ldrsmte_t *psmte; /* pointer to swappable mte */
|
|
ulong_t lobjnum;
|
|
|
|
#if DBG
|
|
IF_OL2_DEBUG ( TRACE ) {
|
|
DbgPrint("OS2LDR: ldrGetModParams(pmte=%X) was called\n", pmte);
|
|
}
|
|
#endif
|
|
|
|
psmte = pmte->mte_swapmte;
|
|
|
|
/*
|
|
* see what type of module it is
|
|
*/
|
|
if (ldrIsNE(pmte)) {
|
|
register ldrste_t *pste;
|
|
|
|
pei->ei_loadtype = LDR_16bit;
|
|
pei->ei_stacksize = (USHORT) psmte->smte_stacksize;
|
|
pei->ei_hmod = pmte->mte_handle;
|
|
pei->ei_heapsize = (USHORT) psmte->smte_heapsize;
|
|
|
|
/*
|
|
* The start object was checked in ldrCreateMTE
|
|
*/
|
|
pste = ldrNumToSte(pmte, psmte->smte_startobj);
|
|
pei->ei_startaddr.ptr_off = (USHORT) psmte->smte_eip;
|
|
pei->ei_startaddr.ptr_sel = pste->ste_selector | 7;
|
|
|
|
/*
|
|
* compute stack, force word alignment. Stack object checked in
|
|
* ldrCreateMTE.
|
|
*/
|
|
if (psmte->smte_stackobj != 0) {
|
|
pste = ldrNumToSte(pmte, psmte->smte_stackobj);
|
|
pei->ei_stackaddr.ptr_sel = pste->ste_selector | 7;
|
|
pei->ei_stackaddr.ptr_off = (USHORT) (psmte->smte_esp & 0x0fffe);
|
|
}
|
|
else {
|
|
pei->ei_stackaddr.ptr_sel = pste->ste_selector | 7;
|
|
pei->ei_stackaddr.ptr_off = (USHORT) (psmte->smte_esp & 0x0fffe);
|
|
}
|
|
|
|
/*
|
|
* setup autods
|
|
*/
|
|
if (psmte->smte_autods != 0) {
|
|
pste = ldrNumToSte(pmte, psmte->smte_autods);
|
|
pei->ei_ds = pste->ste_selector | 7;
|
|
pei->ei_dgroupsize = pste->ste_minsiz;
|
|
}
|
|
else {
|
|
pei->ei_ds = 0; /* insure that value is ZERO */
|
|
}
|
|
}
|
|
else { /* 32-bit module */
|
|
register ldrote_t *pote;
|
|
ulong_t eip;
|
|
|
|
eip = psmte->smte_eip + psmte->smte_vbase;
|
|
pote = (ldrote_t *) psmte->smte_objtab;
|
|
for (lobjnum = 0; lobjnum < psmte->smte_objcnt; lobjnum++,
|
|
pote++) {
|
|
if ((eip >= pote->ote_base) &&
|
|
(eip < (pote->ote_base + pote->ote_psize)))
|
|
break;
|
|
}
|
|
if (lobjnum == psmte->smte_objcnt) {
|
|
return(ERROR_INVALID_STARTING_CODESEG);
|
|
}
|
|
|
|
/*
|
|
* check to see what type of entry point we have in this
|
|
* 32-bit module.
|
|
*/
|
|
if (pote->ote_flags & OBJ_BIGDEF) { /* 32-bit object */
|
|
pei->ei_loadtype = LDR_32bit;
|
|
pei->ei_startaddr.ptr_flat = eip;
|
|
pei->ei_ds = 0;
|
|
|
|
/*
|
|
* The stack object was checked in ldrCreateMTE
|
|
*/
|
|
pote = ldrNumToOte(pmte, psmte->smte_stackobj);
|
|
pei->ei_stackaddr.ptr_flat = pote->ote_base +
|
|
((pote->ote_flags & OBJ_INVALID) ? pote->ote_psize :
|
|
pote->ote_vsize);
|
|
pei->ei_heapsize = 0;
|
|
}
|
|
else { /* 16-bit object */
|
|
pei->ei_loadtype = LDR_16bit;
|
|
pei->ei_heapsize = (USHORT) psmte->smte_heapsize;
|
|
pei->ei_startaddr.ptr_off = (USHORT) eip;
|
|
// pei->ei_startaddr.ptr_sel = LaToSelTiled(pote->ote_base) |
|
|
// (USHORT) SEL_RPL3;
|
|
pei->ei_startaddr.ptr_sel = FLATTOSEL(pote->ote_base);
|
|
|
|
if ((psmte->smte_autods == 0) ||
|
|
(pote = ldrNumToOte(pmte, psmte->smte_autods)) == NULL)
|
|
pei->ei_ds = 0;
|
|
else
|
|
pei->ei_ds = FLATTOSEL(pote->ote_base);
|
|
// pei->ei_ds = LaToSelTiled(pote->ote_base) |
|
|
// (USHORT) SEL_RPL3;
|
|
/*
|
|
* The stack object was checked in ldrCreateMTE
|
|
*/
|
|
pote = ldrNumToOte(pmte, psmte->smte_stackobj);
|
|
pei->ei_stackaddr.ptr_sel = FLATTOSEL(pote->ote_base +
|
|
psmte->smte_esp);
|
|
|
|
// pei->ei_stackaddr.ptr_sel = LaToSelTiled(pote->ote_base +
|
|
// psmte->smte_esp) | (USHORT) SEL_RPL3;
|
|
pei->ei_stackaddr.ptr_off = (ushort_t) psmte->smte_esp;
|
|
}
|
|
} /* end 32-bit module */
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
#if PMNT
|
|
BOOLEAN
|
|
LDRDumpSegments(
|
|
IN POS2_THREAD t,
|
|
IN POS2_API_MSG m
|
|
)
|
|
{
|
|
UNICODE_STRING name_U;
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE File;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
char Buffer[256]; // = "Hello, world\n";
|
|
ldrmte_t *pmte = mte_h; /* pointer to module table entry */
|
|
ldrsmte_t *psmte; /* pointer to swappable mte */
|
|
ldrste_t *pste;
|
|
ulong_t csegs;
|
|
|
|
RtlInitUnicodeString(&name_U, L"\\OS2SS\\DRIVES\\p:\\tmp\\pmnt.log");
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&name_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL );
|
|
|
|
Status = NtCreateFile(
|
|
&File,
|
|
FILE_GENERIC_WRITE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
NULL, // Allocation size
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ,
|
|
FILE_SUPERSEDE,
|
|
FILE_NON_DIRECTORY_FILE |
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL, // EA buffer
|
|
0 // EA size
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
KdPrint(("ldrDumpSegmentTable: NtOpenFile failed, Status=%x\n", Status));
|
|
return(TRUE);
|
|
}
|
|
|
|
while (pmte != NULL)
|
|
{
|
|
Status = NtWriteFile(
|
|
File,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
Buffer,
|
|
sprintf(Buffer, "\n%.*s\n",
|
|
*(char *)pmte->mte_modname,
|
|
pmte->mte_modname + 1),
|
|
NULL,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
KdPrint(("ldrDumpSegmentTable: NtWriteFile failed, Status=%x\n", Status));
|
|
return(TRUE);
|
|
}
|
|
|
|
psmte = (ldrsmte_t *) pmte->mte_swapmte;
|
|
pste = (ldrste_t *) psmte->smte_objtab;
|
|
for (csegs = 1; csegs <= psmte->smte_objcnt; csegs++,
|
|
pste++)
|
|
{
|
|
Status = NtWriteFile(
|
|
File,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
Buffer,
|
|
sprintf(Buffer, " %2x: %4x %4x %4x %4x %4x %4x %8x\n",
|
|
csegs,
|
|
pste->ste_offset, /* file offset to segment data */
|
|
pste->ste_size, /* file data size */
|
|
pste->ste_flags, /* type and attribute flags */
|
|
pste->ste_minsiz, /* minimum allocation size */
|
|
pste->ste_seghdl, /* segment handle */
|
|
pste->ste_selector,/* segment selector */
|
|
pste->ste_fixups /* fixup record storage */
|
|
),
|
|
NULL,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
KdPrint(("ldrDumpSegmentTable: NtWriteFile failed, Status=%x\n", Status));
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
pmte = pmte->mte_link;
|
|
}
|
|
|
|
NtClose(File);
|
|
|
|
return(TRUE);
|
|
}
|
|
#endif // PMNT
|
|
|
|
#if DBG
|
|
void ldrDisplaySegmentTable()
|
|
{
|
|
ldrmte_t *pmte = mte_h; /* pointer to module table entry */
|
|
ldrsmte_t *psmte; /* pointer to swappable mte */
|
|
ldrste_t *pste;
|
|
ulong_t csegs;
|
|
|
|
while (pmte != NULL)
|
|
{
|
|
DbgPrint("\n%.*s\npmte=%x, usecnt=%d, handle=%d\n",
|
|
*(char *)pmte->mte_modname,
|
|
pmte->mte_modname + 1,
|
|
pmte,
|
|
pmte->mte_usecnt,
|
|
pmte->mte_handle
|
|
);
|
|
|
|
psmte = (ldrsmte_t *) pmte->mte_swapmte;
|
|
pste = (ldrste_t *) psmte->smte_objtab;
|
|
for (csegs = 1; csegs <= psmte->smte_objcnt; csegs++,
|
|
pste++)
|
|
{
|
|
DbgPrint(" %2x: %4x %4x %4x %4x %4x %4x %8x %4x\n",
|
|
csegs,
|
|
pste->ste_offset, /* file offset to segment data */
|
|
pste->ste_size, /* file data size */
|
|
pste->ste_flags, /* type and attribute flags */
|
|
pste->ste_minsiz, /* minimum allocation size */
|
|
pste->ste_seghdl, /* segment handle */
|
|
pste->ste_selector,/* segment selector */
|
|
pste->ste_fixups /* fixup record storage */
|
|
);
|
|
}
|
|
|
|
pmte = pmte->mte_link;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if PMNT
|
|
/*
|
|
* We want PMNT apps to load the original viocalls.dll
|
|
* and OS2 char. apps to load it from doscalls.dll
|
|
* This routine returns FALSE if an app. finds the wrong DLL
|
|
*/
|
|
BOOLEAN
|
|
ldrChkPmntApp(pachModname, cb, pmte)
|
|
PUCHAR pachModname; /* pointer to ASCII module name */
|
|
USHORT cb; /* length of module name */
|
|
ldrmte_t *pmte; /* pointer to mte */
|
|
{
|
|
ULONG pmapp,dosmod;
|
|
|
|
if ((cb != 8) || (strncmp (pachModname,"VIOCALLS",cb))) {
|
|
return(TRUE);
|
|
}
|
|
|
|
// pmapp = CurrentThread->Process->Flags &
|
|
// (OS2_PROCESS_WINDOWAPI | OS2_PROCESS_FORCEDPM | OS2_PROCESS_PMMSGQUE);
|
|
pmapp = Os2srvProcessIsPMProcess(CurrentThread->Process);
|
|
dosmod = pmte->mte_mflags & DOSMOD;
|
|
|
|
return((pmapp && !dosmod) || (!pmapp && dosmod));
|
|
}
|
|
#endif //if PMNT
|
|
|
|
|
|
/***LP ldrFindModule - Check if module is already loaded.
|
|
*
|
|
* Scans the class-list (CLASS_PROGRAM, CLASS_GLOBAL or CLASS_SPECIFIC)
|
|
* searching for a matching pathname. If the request is for a global
|
|
* dynlink library module, the module name, which is the first entry in
|
|
* the resident name table, is used for comparison. Otherwise the pathname
|
|
* is fully expanded and compared with expanded pathname in the mte.
|
|
*
|
|
* The MTE list is organised like this:
|
|
*
|
|
* program_h global_h specific_h
|
|
* | | |
|
|
* mte_h +------+ +-----+ +-----+ +-----+ +-----+ +-----+
|
|
* ----> | | | |--->| | | |--->| | | |---+
|
|
* +------+ .. +-----+ +-----+ .. +-----+ +-----+ .. +-----+ |
|
|
* | | | ___
|
|
* program_l global_l specific_l -
|
|
*
|
|
* mte_h is the head of the linked list. Both program_h and specific_h
|
|
* could be NULL. If program_h is NULL, then mte_h and global_h point to
|
|
* the same MTE. global_l can never be NULL. program_l and specific_l
|
|
* can be.
|
|
*
|
|
* ENTRY pachModname - pointer to module name
|
|
* class - CLASS_GLOBAL, CLASS_SPECIFIC or
|
|
* CLASS_PROGRAM
|
|
* ppmte - pointer to a pmte to return
|
|
*
|
|
* EXIT int - return code (NO_ERROR if successful)
|
|
* - pointer to reqested mte returned in
|
|
* ppmte
|
|
*
|
|
*/
|
|
|
|
int ldrFindModule(pachModname, cb, class, ppmte)
|
|
PUCHAR pachModname; /* pointer to ASCII module name */
|
|
USHORT cb; /* length of module name */
|
|
USHORT class; /* class of module */
|
|
ldrmte_t **ppmte; /* place to return pointer */
|
|
{
|
|
register ldrmte_t *pmte; /* pointer to module table entry */
|
|
ldrsmte_t *psmte; /* pointer to swappable MTE */
|
|
USHORT cchlen; /* length of module name in restab */
|
|
USHORT fpath; /* If TRUE then search by path */
|
|
|
|
fpath = (USHORT) (class & SEARCH_BY_PATH);
|
|
class &= ~SEARCH_BY_PATH;
|
|
|
|
switch (class) {
|
|
case CLASS_ALL:
|
|
pmte = mte_h;
|
|
break;
|
|
case CLASS_GLOBAL:
|
|
pmte = global_h;
|
|
break;
|
|
case CLASS_SPECIFIC:
|
|
pmte = specific_h;
|
|
break;
|
|
case CLASS_PROGRAM:
|
|
pmte = program_h;
|
|
break;
|
|
default:
|
|
#if DBG
|
|
DbgPrint("ldrFindModule: Invalid class");
|
|
#endif
|
|
pmte = mte_h;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Search the mte list for module name in TempBuf
|
|
*/
|
|
while (pmte != NULL) {
|
|
|
|
/*
|
|
* If not searching CLASS_ALL, terminate the scan when the
|
|
* class value in the MTE is not what we want.
|
|
*/
|
|
if ((class != CLASS_ALL) &&
|
|
((USHORT)(pmte->mte_mflags & CLASS_MASK) != class)) {
|
|
pmte = NULL;
|
|
break;
|
|
}
|
|
if ((class == CLASS_GLOBAL) && (fpath != SEARCH_BY_PATH)) {
|
|
/*
|
|
* If we're looking for global library module, first check
|
|
* length of name for match then check name.
|
|
*/
|
|
cchlen = (USHORT) *((PCHAR )pmte->mte_modname);
|
|
if ((cb == cchlen) &&
|
|
(strncmp((PCHAR)(pmte->mte_modname+1),
|
|
pachModname,
|
|
cchlen) == 0)) {
|
|
#if PMNT
|
|
/*
|
|
* check for viocalls
|
|
*
|
|
*/
|
|
if (ldrChkPmntApp(pachModname, cb, pmte))
|
|
#endif //if PMNT
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If either program or specific module, just compare name.
|
|
* First compare length of strings to fix the problem of
|
|
* the string matching the first n characters of the pathname
|
|
* but what if the pathname has n+1 characters in name.
|
|
*/
|
|
else {
|
|
psmte = pmte->mte_swapmte;
|
|
if (psmte->smte_pathlen == cb) {
|
|
if (strncmp((PCHAR) psmte->smte_path,
|
|
pachModname,
|
|
cb) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
pmte = pmte->mte_link;
|
|
}
|
|
*ppmte = pmte; /* Could be NULL, in which case we */
|
|
return(NO_ERROR); /* did not find the module */
|
|
}
|
|
|
|
|
|
/***LP ldrLinkMTE - Link MTE in the list at the appropriate place
|
|
*
|
|
* MTEs are linked according to the class they belong to. The possible
|
|
* classes are CLASS_PROGRAM, CLASS_GLOBAL and CLASS_SPECIFIC. The corres.
|
|
* list heads are program_h, global_h and specific_h. We also have the
|
|
* tail of CLASS_PROGRAM, CLASS_GLOBAL and CLASS_SPECIFIC lists which are
|
|
* program_l, global_l and specific_l. These aid us in linking and
|
|
* unlinking the list and not having to go through the chain every time.
|
|
*
|
|
* To begin with mte_h and global_h point to the same MTE, program_h,
|
|
* program_l, specific_h and specific_l are NULL. global_l is also
|
|
* initialised.
|
|
* See ldrFindModule for organisation of the MTE List.
|
|
*
|
|
* The possible cases are:
|
|
* 1. Link a CLASS_PROGRAM MTE.
|
|
* if (program_h == NULL) {
|
|
* pmte->mte_link = global_h;
|
|
* program_l = pmte;
|
|
* }
|
|
* else pmte->mte_link = program_h;
|
|
* mte_h = program_h = pmte;
|
|
*
|
|
* 2. Link a CLASS_GLOBAL MTE.
|
|
* pmte->mte_link = global_h; // global_h can never be NULL
|
|
* global_h = pmte;
|
|
* if (program_l == NULL) // and hence program_h is NULL
|
|
* mte_h = global_h;
|
|
* else program_l->mte_link = global_h;
|
|
*
|
|
* 3. Link a CLASS_SPECIFIC MTE.
|
|
* if (specific_l == NULL)
|
|
* specific_l = pmte;
|
|
* pmte->mte_link = specific_h;
|
|
* global_l->mte_link = pmte;
|
|
*
|
|
* ENTRY
|
|
* pmte MTE to link in the list
|
|
*
|
|
* EXIT NONE
|
|
* MTE is linked at the right place
|
|
*/
|
|
void ldrLinkMTE(pmte)
|
|
register ldrmte_t *pmte;
|
|
{
|
|
|
|
switch (pmte->mte_mflags & CLASS_MASK) {
|
|
case CLASS_PROGRAM:
|
|
if (program_h == NULL) {
|
|
pmte->mte_link = global_h;
|
|
program_l = pmte;
|
|
}
|
|
else
|
|
pmte->mte_link = program_h;
|
|
mte_h = program_h = pmte;
|
|
break;
|
|
|
|
case CLASS_GLOBAL:
|
|
pmte->mte_link = global_h; /* global_h can never be NULL */
|
|
global_h = pmte;
|
|
if (program_l == NULL) /* and hence program_h is NULL */
|
|
mte_h = pmte;
|
|
else
|
|
program_l->mte_link = pmte;
|
|
break;
|
|
|
|
case CLASS_SPECIFIC:
|
|
if (specific_l == NULL)
|
|
specific_l = pmte;
|
|
pmte->mte_link = specific_h;
|
|
specific_h = pmte;
|
|
global_l->mte_link = pmte; /* global_l can never be NULL */
|
|
break;
|
|
|
|
default:
|
|
#if DBG
|
|
DbgPrint("ldrLinkMTE: Invalid class");
|
|
#endif
|
|
// same as CLASS_GLOBAL
|
|
pmte->mte_link = global_h; /* global_h can never be NULL */
|
|
global_h = pmte;
|
|
if (program_l == NULL) /* and hence program_h is NULL */
|
|
mte_h = pmte;
|
|
else
|
|
program_l->mte_link = pmte;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/***LP ldrUnlinkMTE - Unlink MTE from the list
|
|
*
|
|
* Unlink the given MTE from the list. See ldrFindModule and ldrLinkMTE
|
|
* for details of how the list is organised.
|
|
*
|
|
* ENTRY
|
|
* pmte MTE to unlink from the list
|
|
*
|
|
* EXIT NONE
|
|
* MTE is unlinked
|
|
*/
|
|
void ldrUnlinkMTE(pmte)
|
|
register ldrmte_t *pmte;
|
|
{
|
|
register ldrmte_t *pmtecur; /* Current mte */
|
|
register ldrmte_t **ppmtepred; /* Predecessor mte */
|
|
ldrmte_t **ppmtehead; /* Pointer to class head */
|
|
ldrmte_t **ppmtetail; /* Pointer to class tail */
|
|
USHORT class;
|
|
|
|
switch (class = (USHORT)(pmte->mte_mflags & CLASS_MASK)) {
|
|
case CLASS_PROGRAM:
|
|
pmtecur = program_h;
|
|
ppmtepred = &mte_h;
|
|
ppmtehead = &program_h;
|
|
ppmtetail = &program_l;
|
|
break;
|
|
|
|
case CLASS_GLOBAL:
|
|
pmtecur = global_h;
|
|
ppmtepred = &program_l->mte_link;
|
|
if (program_l == NULL)
|
|
ppmtepred = &mte_h;
|
|
ppmtehead = &global_h;
|
|
ppmtetail = &global_l;
|
|
break;
|
|
|
|
case CLASS_SPECIFIC:
|
|
pmtecur = specific_h;
|
|
ppmtepred = &global_l->mte_link;
|
|
ppmtehead = &specific_h;
|
|
ppmtetail = &specific_l;
|
|
break;
|
|
|
|
default:
|
|
#if DBG
|
|
DbgPrint("ldrUnlinkMTE: Invalid list");
|
|
#endif
|
|
// same as class global
|
|
pmtecur = global_h;
|
|
ppmtepred = &program_l->mte_link;
|
|
if (program_l == NULL)
|
|
ppmtepred = &mte_h;
|
|
ppmtehead = &global_h;
|
|
ppmtetail = &global_l;
|
|
break;
|
|
}
|
|
while (TRUE) {
|
|
|
|
ldrAssert((pmtecur != NULL &&
|
|
(pmtecur->mte_mflags & CLASS_MASK) == class));
|
|
|
|
if (pmtecur == pmte)
|
|
break;
|
|
ppmtepred = &pmtecur->mte_link;
|
|
pmtecur = pmtecur->mte_link;
|
|
}
|
|
|
|
*ppmtepred = pmte->mte_link; /* Unlink MTE */
|
|
|
|
if (pmte == *ppmtehead) { /* If unlinkee is at the head */
|
|
*ppmtehead = pmte->mte_link;
|
|
/* If class disappears, then both head and tail disappear */
|
|
if ((*ppmtehead == NULL) ||
|
|
((USHORT)((*ppmtehead)->mte_mflags & CLASS_MASK) != class)) {
|
|
*ppmtehead = NULL;
|
|
*ppmtetail = NULL;
|
|
}
|
|
}
|
|
/*
|
|
* Since we have a pointer to the mte_link field of the predecessor
|
|
* we need to get back to the mte pointer by subtracting the offset
|
|
* of the link field of MTE from the pointer to predecessor.
|
|
*/
|
|
if (pmte == *ppmtetail) { /* If unlinkee is at the tail */
|
|
*ppmtetail = (ldrmte_t *)((ULONG)ppmtepred -
|
|
FIELDOFFSET(ldrmte_t, mte_link));
|
|
ldrAssert(fMTEValid(*ppmtetail));
|
|
}
|
|
}
|
|
|
|
|
|
/***LP ldrCheckGlobal - Check if specified module is loaded as global
|
|
*
|
|
* Called by ldrGetMte. If a module is being loaded as a specific module
|
|
* and ldrFindModule has not found this in the specific list, we see if
|
|
* this is loaded as a global module. For this to happen, the following
|
|
* has to be satisfied.
|
|
* a, The file has to have a ".DLL" as the last part of its name.
|
|
* b, It should be somewhere in the libpath
|
|
*
|
|
* ENTRY
|
|
* pachModname file name string
|
|
* cb length of module name
|
|
* ppmte pointer to where the MTE pointer, if found,
|
|
* is to be returned
|
|
*
|
|
* EXIT
|
|
* TRUE if module found as loaded global
|
|
* FALSE module not global.
|
|
*/
|
|
int ldrCheckGlobal(pachModname, cb, ppmte)
|
|
PUCHAR pachModname;
|
|
USHORT cb;
|
|
register ldrmte_t **ppmte;
|
|
{
|
|
int rc;
|
|
|
|
if ((cb <= 4) || _strnicmp(&pachModname[cb-4], ".DLL", 4)) {
|
|
return(FALSE);
|
|
}
|
|
|
|
if ((rc = ldrFindModule(pachModname, cb,
|
|
CLASS_GLOBAL|SEARCH_BY_PATH, ppmte)) != NO_ERROR) {
|
|
load_error(rc, NULL);
|
|
}
|
|
return (*ppmte != NULL);
|
|
}
|
|
|
|
|
|
/***LP ldrCheckSpecific - Check if specified module is loaded as specfic
|
|
*
|
|
* Called by ldrGetMte. If a module is being loaded as a global module
|
|
* and ldrFindModule has not found this in the global list, we see if
|
|
* this is loaded as a specific module. If we find this in the specific
|
|
* list, then we promte it to the global list.
|
|
*
|
|
* ENTRY ppmte pointer to where the MTE pointer, if found,
|
|
* is to be returned.
|
|
* plv pointer to loader variables structure
|
|
*
|
|
* EXIT
|
|
* TRUE If module found as loaded global
|
|
* FALSE Otherwise.
|
|
*/
|
|
int ldrCheckSpecific(ppmte, plv)
|
|
ldrmte_t **ppmte;
|
|
ldrlv_t *plv ;
|
|
{
|
|
USHORT cchModname;
|
|
register PCHAR pldrbuf = LdrBuf;
|
|
int rc;
|
|
|
|
cchModname = (USHORT) (strlen(pldrbuf));
|
|
|
|
ldrUCaseString(pldrbuf, cchModname);
|
|
|
|
if ((rc = ldrFindModule(pldrbuf, cchModname, CLASS_SPECIFIC, ppmte)) != NO_ERROR) {
|
|
NtClose(plv->lv_sfn);
|
|
load_error(rc, NULL);
|
|
}
|
|
if (*ppmte == NULL)
|
|
return (FALSE);
|
|
ldrPromoteMTE(*ppmte);
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
/***LP ldrPromoteMTE - Promote MTE from specific class list to global
|
|
*
|
|
* Unlink an MTE from the specific class list and link into global
|
|
* class list.
|
|
*
|
|
* ENTRY pmte MTE to promote
|
|
*
|
|
* EXIT NONE
|
|
*/
|
|
void ldrPromoteMTE(pmte)
|
|
ldrmte_t *pmte;
|
|
{
|
|
#ifdef MISCSTRICT
|
|
if ((pmte->mte_mflags & CLASS_MASK) != CLASS_SPECIFIC)
|
|
panic("ldrPromoteMTE: Invalid class");
|
|
#endif
|
|
ldrUnlinkMTE(pmte);
|
|
pmte->mte_mflags &= ~CLASS_SPECIFIC;
|
|
pmte->mte_mflags |= CLASS_GLOBAL;
|
|
ldrLinkMTE(pmte);
|
|
}
|
|
|
|
|
|
/***LP ldrOpenNewExe - Open module pathname and verify it's a new EXE format
|
|
*
|
|
* The specified file is opened and the old header and
|
|
* New EXE headers are read and verified. If New EXE header is
|
|
* a 16-bit module ("NE"), expand the 16-bit header to a 32-bit
|
|
* header. pheaderbuf is implicitly used.
|
|
*
|
|
* ENTRY pachModname - pointer to module name
|
|
* cb - length of module name
|
|
* plv - pointer to local variables on stack
|
|
* pfl - optional pointer to a flag set if OLD exe
|
|
* pBound - optional pointer to a flag set if BOUND exe
|
|
* pNEFlags - Flags word of the NE header
|
|
*
|
|
* EXIT int - return code (NO_ERROR if successful)
|
|
*/
|
|
|
|
int ldrOpenNewExe(pachModname, cb, plv, pfl, pBound, pNEFlags)
|
|
PUCHAR pachModname; /* pointer to ASCII module name */
|
|
USHORT cb; /* length of module name */
|
|
ldrlv_t *plv; /* pointer to local variables */
|
|
PUSHORT pfl; /* optional pointer to a flag set if OLD exe */
|
|
PBOOLEAN pBound; /* optional pointer to a flag set if BOUND exe */
|
|
PULONG pNEFlags; /* optional pointer to Flags word of the NE header */
|
|
{
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
LARGE_INTEGER ByteOffset;
|
|
ULONG ulNewHdrOff; /* Offset hdr offset */
|
|
ULONG ulCopied; /* Number of bytes copied */
|
|
ULONG ulNeeded; /* Number of bytes needed */
|
|
ULONG usoff; /* Offset to new exe header */
|
|
ULONG *pl; /* pointer to a long */
|
|
USHORT *ps; /* pointer to a short */
|
|
struct e32_exe *pe32;
|
|
struct e32_exe *pe32temp;
|
|
ULONG flmte; /* flags */
|
|
int rc;
|
|
ULONG BoundAppFlag = 0L;
|
|
struct new_exe *ne;
|
|
|
|
#if DBG
|
|
IF_OL2_DEBUG ( TRACE ) {
|
|
DbgPrint("OS2LDR: ldrOpenNewExe() was called\n");
|
|
}
|
|
#endif
|
|
|
|
flmte = 0;
|
|
|
|
if (pfl != 0)
|
|
*pfl = FALSE;
|
|
|
|
if (pBound != 0)
|
|
*pBound = FALSE;
|
|
|
|
if ((rc = ldrOpenPath(pachModname,
|
|
cb,
|
|
plv,
|
|
&flmte)) != NO_ERROR) {
|
|
plv->lv_sfn = NULL;
|
|
return(rc);
|
|
}
|
|
|
|
pe32 = (struct e32_exe *) pheaderbuf;
|
|
ne = (struct new_exe *) pe32;
|
|
|
|
/*
|
|
* Start read at beginning of file
|
|
*/
|
|
ByteOffset.LowPart = 0;
|
|
ByteOffset.HighPart = 0;
|
|
|
|
if ((rc = NtReadFile( plv->lv_sfn,
|
|
0,
|
|
0,
|
|
0,
|
|
&IoStatusBlock,
|
|
pe32,
|
|
512,
|
|
&ByteOffset,
|
|
0 )) != 0) {
|
|
NtClose(plv->lv_sfn);
|
|
rc = Or2MapNtStatusToOs2Error(rc, ERROR_BAD_FORMAT);
|
|
return(rc);
|
|
}
|
|
|
|
/*
|
|
* validate old (MZ) signature in header
|
|
*/
|
|
if (((struct exe_hdr *) pe32)->e_magic != EMAGIC) {
|
|
NtClose(plv->lv_sfn);
|
|
return(ERROR_INVALID_EXE_SIGNATURE) ;
|
|
}
|
|
|
|
usoff = ((struct exe_hdr *) pe32)->e_lfarlc;
|
|
|
|
/*
|
|
* Set flag to say that it's at least a DOS app
|
|
*/
|
|
if (pfl != 0) {
|
|
*pfl = TRUE;
|
|
}
|
|
|
|
/*
|
|
* get pointer to (NE) or (LE) exe header
|
|
*/
|
|
ulNewHdrOff =
|
|
plv->lv_new_exe_off = ((struct exe_hdr *) pe32)->e_lfanew;
|
|
|
|
//
|
|
// Check if the file has the potential of being a bound
|
|
// app, and if so set BoundAppFlag
|
|
//
|
|
|
|
if (pBound != 0 &&
|
|
plv->lv_new_exe_off != 0x40L &&
|
|
((struct exe_hdr *) pe32)->e_minalloc != 0xffff &&
|
|
IoStatusBlock.Information >= 0x52 &&
|
|
strncmp(((char *) pe32) + 0x4e, "This", 4) != 0
|
|
) {
|
|
|
|
BoundAppFlag |= 0x1L;
|
|
}
|
|
|
|
/*
|
|
* check if we read at least up to the (NE) or (LE) header
|
|
*/
|
|
if (ulNewHdrOff < IoStatusBlock.Information) {
|
|
|
|
/*
|
|
* assume we are reading a 32-bit module
|
|
*/
|
|
ulNeeded = sizeof(struct e32_exe);
|
|
pe32temp = (struct e32_exe *) ((ULONG) pe32 + ulNewHdrOff);
|
|
|
|
if ((ulNewHdrOff < (IoStatusBlock.Information -
|
|
sizeof(pe32->e32_magic))) &&
|
|
(*(short *) (pe32temp->e32_magic) == NEMAGIC))
|
|
ulNeeded = sizeof(struct new_exe);
|
|
|
|
ulCopied = min(IoStatusBlock.Information - ulNewHdrOff, ulNeeded);
|
|
|
|
memcpy(pe32, (PVOID) ((ULONG) pe32 + ulNewHdrOff), ulCopied);
|
|
|
|
if (ulNeeded -= ulCopied) {
|
|
if ((rc = NtReadFile( plv->lv_sfn,
|
|
0,
|
|
0,
|
|
0,
|
|
&IoStatusBlock,
|
|
(PCHAR) pe32 + ulCopied,
|
|
ulNeeded,
|
|
&ByteOffset,
|
|
0 )) != 0) {
|
|
NtClose(plv->lv_sfn);
|
|
rc = Or2MapNtStatusToOs2Error(rc, ERROR_BAD_FORMAT);
|
|
return(rc);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
|
|
/*
|
|
* read in new header to size of 32-bit mte plus a ote entry
|
|
*/
|
|
ByteOffset.LowPart = (ULONG)((struct exe_hdr *)pe32)->e_lfanew;
|
|
ByteOffset.HighPart = 0;
|
|
|
|
if ((rc = NtReadFile( plv->lv_sfn,
|
|
0,
|
|
0,
|
|
0,
|
|
&IoStatusBlock,
|
|
(PCHAR) pe32,
|
|
sizeof(struct e32_exe)+sizeof(ldrote_t),
|
|
&ByteOffset,
|
|
0 )) != 0) {
|
|
NtClose(plv->lv_sfn);
|
|
rc = Or2MapNtStatusToOs2Error(rc, ERROR_BAD_FORMAT);
|
|
return(rc);
|
|
}
|
|
}
|
|
|
|
/* Verify that this is a protect-mode exe. (Check this before
|
|
* checking MTE signature for 1.2 error code compatability.)
|
|
*/
|
|
if (usoff != 0x40) {
|
|
NtClose(plv->lv_sfn);
|
|
return(ERROR_BAD_EXE_FORMAT) ;
|
|
}
|
|
|
|
/*
|
|
* validate as 16-bit signature or 32-bit signature
|
|
*/
|
|
if (!(*(short *) (pe32->e32_magic) == LEMAGIC ||
|
|
*(short *) (pe32->e32_magic) == NEMAGIC)) {
|
|
NtClose(plv->lv_sfn);
|
|
return(ERROR_INVALID_EXE_SIGNATURE);
|
|
}
|
|
|
|
/*
|
|
* verify some header fields for LE modules only.
|
|
*/
|
|
if ((*(short *) (pe32->e32_magic) == LEMAGIC) &&
|
|
(!((pe32->e32_bworder == E32LEWO) &&
|
|
(pe32->e32_os == NE_OS2)))) {
|
|
NtClose(plv->lv_sfn);
|
|
return(ERROR_INVALID_EXE_SIGNATURE);
|
|
}
|
|
|
|
/*
|
|
* This is known to be a Protect-mode app at this point.
|
|
*/
|
|
if (pfl != NULL)
|
|
*pfl = FALSE;
|
|
|
|
/*
|
|
* if header in 16-bit format save ne_sssp and move ne_mflags into
|
|
* e32_mflags
|
|
*/
|
|
if (*(short *) (pe32->e32_magic) == NEMAGIC) {
|
|
pl = (ULONG *) ((PCHAR) pe32 +
|
|
FIELDOFFSET(struct e32_exe, e32_res4));
|
|
*pl = ((struct new_exe *) pe32)->ne_sssp;
|
|
ps = (USHORT *) ((PCHAR) pe32 +
|
|
FIELDOFFSET(struct e32_exe, e32_mflags));
|
|
*ps = ((struct new_exe *)pe32)->ne_flags;
|
|
/*
|
|
* mask out those flags that are not used in the 32-bit header
|
|
*/
|
|
pe32->e32_mflags &= (AUTODS_MASK | INSTLIBINIT | LDRINVALID |
|
|
LIBRARYMOD | E32_APPMASK | NEBOUND);
|
|
if (((struct new_exe *)pe32)->ne_flagsothers & NELONGNAMES)
|
|
pe32->e32_mflags |= MTELONGNAMES;
|
|
}
|
|
else {
|
|
pe32->e32_mflags |= MTELONGNAMES;
|
|
}
|
|
|
|
/*
|
|
* check if executable is a valid image
|
|
*/
|
|
if (pe32->e32_mflags & LDRINVALID) {
|
|
NtClose(plv->lv_sfn);
|
|
return(ERROR_EXE_MARKED_INVALID);
|
|
}
|
|
|
|
/* Clear for internal use */
|
|
pe32->e32_mflags &= ~(MTE_MEDIAFIXED|MTE_MEDIACONTIG|MTE_MEDIA16M);
|
|
pe32->e32_mflags |= flmte; /* Set flags set by ldrOpenPath */
|
|
|
|
rc = ldrMungeFlags(pe32);
|
|
if (rc != NO_ERROR) {
|
|
NtClose(plv->lv_sfn);
|
|
return(rc);
|
|
}
|
|
|
|
//
|
|
// Figure out if this is a bound app
|
|
//
|
|
|
|
if (pBound != 0 &&
|
|
*(short *) (pe32->e32_magic) == NEMAGIC) {
|
|
|
|
if ((ne->ne_flags & NENOTP) == 0) {
|
|
|
|
if ((ne->ne_flags & NEBOUND) != 0) {
|
|
|
|
BoundAppFlag |= 0x2;
|
|
|
|
} else if ((BoundAppFlag & 0x1) != 0 &&
|
|
ne->ne_enttab - ne->ne_imptab != 0 &&
|
|
ne->ne_restab - ne->ne_rsrctab == 0) {
|
|
|
|
BoundAppFlag |= 0x2;
|
|
}
|
|
}
|
|
|
|
if ((BoundAppFlag & 0x2) != 0)
|
|
*pBound = TRUE;
|
|
}
|
|
|
|
//
|
|
// Get the NE file Flags word
|
|
//
|
|
if ((pNEFlags != NULL) &&
|
|
*(short *) (pe32->e32_magic) == NEMAGIC) {
|
|
|
|
*pNEFlags = (ULONG)ne->ne_flags;
|
|
if (plv->lv_class == CLASS_PROGRAM) {
|
|
if ((*pNEFlags & NEAPPTYP) == NENOTWINCOMPAT) {
|
|
CurrentThread->Process->Flags |= OS2_PROCESS_NOTWINDOWCOMPAT;
|
|
}
|
|
else if ((*pNEFlags & NEAPPTYP) == NEWINCOMPAT) {
|
|
CurrentThread->Process->Flags |= OS2_PROCESS_WINDOWCOMPAT;
|
|
}
|
|
else if ((*pNEFlags & NEAPPTYP) == NEWINAPI) {
|
|
CurrentThread->Process->Flags |= OS2_PROCESS_WINDOWAPI;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Verify number of segments in the NE header
|
|
//
|
|
if (*(short *) (pe32->e32_magic) == NEMAGIC) {
|
|
if ((USHORT)(ne->ne_cseg * (USHORT)sizeof(struct new_seg)) >
|
|
((USHORT)ne->ne_rsrctab - (USHORT)ne->ne_segtab)) {
|
|
#if DBG
|
|
DbgPrint("ne_cseg 0x%x\n", (USHORT)ne->ne_cseg);
|
|
DbgPrint("ne_cmod 0x%x\n", (USHORT)ne->ne_cmod);
|
|
DbgPrint("ne_cbnrestab 0x%x\n", (USHORT)ne->ne_cbnrestab);
|
|
DbgPrint("ne_segtab 0x%x\n", (USHORT)ne->ne_segtab);
|
|
DbgPrint("ne_rsrctab 0x%x\n", (USHORT)ne->ne_rsrctab);
|
|
DbgPrint("ne_restab 0x%x\n", (USHORT)ne->ne_restab);
|
|
DbgPrint("ne_modtab 0x%x\n", (USHORT)ne->ne_modtab);
|
|
#endif
|
|
NtClose(plv->lv_sfn);
|
|
return(ERROR_BAD_EXE_FORMAT);
|
|
}
|
|
}
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
/***LP ldrOpenPath - Open module file, possibly searching LIBPATH
|
|
*
|
|
* ldrOpenPath opens the file for the module, given the module name.
|
|
*
|
|
* The names passed for CLASS_GLOBAL must not contain a drive,
|
|
* path, or extension. For program modules, the name must contain
|
|
* the desired null terminated relative path. If IsIFS, the LIBPATH
|
|
* name is ignored.
|
|
*
|
|
* ldrOpenPath(pchModname, cchModname, plv, pflmte)
|
|
*
|
|
* ENTRY pachModname - pointer to module name
|
|
* cb - module name length
|
|
* plv - pointer to local variables
|
|
* pflmte - pointer to mte flags to return
|
|
* piostatus - pointer to IO stat buffer
|
|
*
|
|
* EXIT none - return successful or call load_error
|
|
*
|
|
*/
|
|
|
|
int ldrOpenPath(pachModname, cb, plv, pflmte)
|
|
PUCHAR pachModname; /* pointer to ASCII module name */
|
|
USHORT cb; /* length of module name */
|
|
ldrlv_t *plv; /* pointer to local variables */
|
|
PULONG pflmte; /* pointer to return mte flags in */
|
|
|
|
{
|
|
|
|
HANDLE File;
|
|
STRING name;
|
|
UNICODE_STRING name_U;
|
|
NTSTATUS Status;
|
|
PSTRING pname = &name;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
PUCHAR pstring;
|
|
PUCHAR ptmp;
|
|
ULONG cbstring;
|
|
PUCHAR plibpath;
|
|
int rc; /* return code */
|
|
|
|
#if DBG
|
|
IF_OL2_DEBUG ( TRACE ) {
|
|
DbgPrint("OS2LDR: ldrOpenPath() was called with modname=%.*s\n", cb, pachModname);
|
|
}
|
|
#endif
|
|
|
|
if (plv->lv_class == CLASS_GLOBAL) {
|
|
plibpath = ldrpLibPath;
|
|
}
|
|
else {
|
|
LdrBuf[0] = '\0'; // This causes the try_another loop to exit
|
|
plibpath = LdrBuf; // after the first try
|
|
}
|
|
|
|
do {
|
|
if (plv->lv_class == CLASS_GLOBAL) {
|
|
ptmp = (PUCHAR)strchr(plibpath, ';');
|
|
if (ptmp == NULL)
|
|
cbstring = strlen(plibpath);
|
|
else
|
|
cbstring = ptmp - plibpath;
|
|
memcpy(LdrBuf, plibpath, cbstring);
|
|
plibpath += cbstring;
|
|
pstring = &LdrBuf[cbstring];
|
|
if (*(pstring - 1) != '\\') { // prevent double backslash in \OS2SS\DRIVES\C:\ cases
|
|
*pstring++ = '\\';
|
|
}
|
|
memcpy(pstring, pachModname, cb);
|
|
pstring += cb;
|
|
if (pflmte != NULL) {
|
|
memcpy(pstring, ".DLL\0", 5);
|
|
}
|
|
else {
|
|
*pstring = '\0';
|
|
}
|
|
pstring = LdrBuf;
|
|
}
|
|
else {
|
|
pstring = pachModname;
|
|
}
|
|
|
|
RtlInitAnsiString(pname, pstring);
|
|
|
|
//
|
|
// UNICODE conversion -
|
|
//
|
|
Status = RtlOemStringToUnicodeString(
|
|
&name_U,
|
|
pname,
|
|
TRUE);
|
|
ASSERT (NT_SUCCESS(Status));
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&name_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL );
|
|
|
|
Status = NtOpenFile(&File,
|
|
GENERIC_READ | FILE_READ_DATA | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ,
|
|
FILE_NON_DIRECTORY_FILE |
|
|
FILE_SYNCHRONOUS_IO_NONALERT);
|
|
|
|
RtlFreeUnicodeString (&name_U);
|
|
if (NT_SUCCESS(Status) && (plv->lv_class != CLASS_GLOBAL)) {
|
|
strncpy(&LdrBuf[0], name.Buffer, name.Length);
|
|
LdrBuf[name.Length] = '\0';
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) { // Avoid switch in the NO_ERROR case.
|
|
plv->lv_sfn = File;
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
rc = ERROR_FILE_NOT_FOUND; // Assume end of LibPath
|
|
} while (*plibpath++ != '\0');
|
|
|
|
//
|
|
// Test if the error code should be
|
|
// ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND or ERROR_INVALID_DRIVE
|
|
// by trying to open the directory path for SPECIFIC modules
|
|
//
|
|
if (plv->lv_class == CLASS_SPECIFIC) {
|
|
memcpy(LdrBuf, pachModname, cb);
|
|
LdrBuf[cb] = '\0';
|
|
ptmp = strrchr(LdrBuf, '\\');
|
|
if (ptmp == NULL) {
|
|
return(rc);
|
|
}
|
|
*ptmp = '\0';
|
|
|
|
RtlInitAnsiString(pname, LdrBuf);
|
|
|
|
//
|
|
// UNICODE conversion -
|
|
//
|
|
Status = RtlOemStringToUnicodeString(
|
|
&name_U,
|
|
pname,
|
|
TRUE);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return(rc);
|
|
}
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&name_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL );
|
|
|
|
Status = NtOpenFile(&File,
|
|
GENERIC_READ | FILE_READ_DATA | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ,
|
|
FILE_DIRECTORY_FILE |
|
|
FILE_SYNCHRONOUS_IO_NONALERT);
|
|
|
|
RtlFreeUnicodeString (&name_U);
|
|
if (NT_SUCCESS(Status)) {
|
|
NtClose(File);
|
|
return(rc);
|
|
}
|
|
else {
|
|
rc = ERROR_PATH_NOT_FOUND;
|
|
}
|
|
//
|
|
// Now differentiate between
|
|
// ERROR_PATH_NOT_FOUND and ERROR_INVALID_DRIVE
|
|
//
|
|
ptmp = strchr(LdrBuf, ':');
|
|
if (ptmp == NULL) {
|
|
return(rc);
|
|
}
|
|
ptmp++; // point to the \ after the drive name
|
|
if (*ptmp != '\\') {
|
|
return(rc);
|
|
}
|
|
ptmp++;
|
|
*ptmp = '\0';
|
|
|
|
RtlInitAnsiString(pname, LdrBuf);
|
|
|
|
//
|
|
// UNICODE conversion -
|
|
//
|
|
Status = RtlOemStringToUnicodeString(
|
|
&name_U,
|
|
pname,
|
|
TRUE);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return(rc);
|
|
}
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&name_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL );
|
|
|
|
Status = NtOpenFile(&File,
|
|
GENERIC_READ | FILE_READ_DATA | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ,
|
|
FILE_DIRECTORY_FILE |
|
|
FILE_SYNCHRONOUS_IO_NONALERT);
|
|
|
|
RtlFreeUnicodeString (&name_U);
|
|
if (NT_SUCCESS(Status)) {
|
|
NtClose(File);
|
|
return(rc);
|
|
}
|
|
else {
|
|
rc = ERROR_INVALID_DRIVE;
|
|
}
|
|
}
|
|
return(rc);
|
|
}
|
|
|
|
#pragma optimize("", off)
|
|
/***LP ldrMungeFlags - Translate Module flags to internal flags
|
|
*
|
|
* Translate the module info in the EXE header to the internal
|
|
* format.
|
|
*
|
|
* ENTRY pe32 Pointer to the linker EXE image
|
|
*
|
|
* EXIT NO_ERROR
|
|
* ERROR_BAD_EXE_FORMAT, if the module type is garbage
|
|
*/
|
|
int ldrMungeFlags(pe32)
|
|
register struct e32_exe *pe32;
|
|
{
|
|
register int modtype;
|
|
|
|
modtype = pe32->e32_mflags & E32_MODMASK;
|
|
pe32->e32_mflags &= ~E32_MODMASK;
|
|
|
|
switch (modtype) {
|
|
|
|
case E32_MODEXE:
|
|
break;
|
|
|
|
case E32_MODDLL:
|
|
pe32->e32_mflags |= LIBRARYMOD;
|
|
break;
|
|
|
|
case E32_MODPDEV:
|
|
pe32->e32_mflags |= DEVDRVMOD | LIBRARYMOD;
|
|
break;
|
|
|
|
/* BUGBUG: JH - The following case is to overcome a LINK386 bug
|
|
which turns on the PROTMOD bit if loaddses is used */
|
|
case E32_MODVDEV:
|
|
pe32->e32_mflags |= VDDMOD | LIBRARYMOD;
|
|
break;
|
|
|
|
default:
|
|
return (ERROR_BAD_EXE_FORMAT);
|
|
}
|
|
return (NO_ERROR);
|
|
}
|
|
#pragma optimize("", on)
|
|
|
|
|
|
/***LP ldrCreateMte - allocate and load module table entry
|
|
*
|
|
* This routine loads and initializes a module table entry. Memory
|
|
* is allocated for the file module data with additional
|
|
* space for module handles and the module
|
|
* pathname. Segment handle and selector fields are added to the
|
|
* end of each segment table entry for 16-bit modules. The module
|
|
* reference strings are checked to make sure there are no wild pointers
|
|
* that would cause a gp fault. The resident name table is checked to
|
|
* make sure that it can be scanned without causing a gp fault.
|
|
*
|
|
* If the module that is being loaded is a 16-bit module the 16-bit
|
|
* exe header was expanded into a 32-bit exe header when file
|
|
* was opened.
|
|
*
|
|
* ENTRY pe32 - pointer to link exe image
|
|
* plv - pointer to local variables
|
|
* - ptda and search buff are setup
|
|
*
|
|
* EXIT none - return successful or call load_error
|
|
*/
|
|
|
|
APIRET ldrCreateMte(pe32, plv)
|
|
struct e32_exe *pe32; /* pointer to linker exe image */
|
|
register ldrlv_t *plv; /* pointer to local variables */
|
|
|
|
{
|
|
ldrmte_t *pmte = NULL; /* pointer to loader MTE */
|
|
ldrsmte_t *psmte = NULL; /* pointer to swappable loader MTE */
|
|
struct ImpHdr *piat = NULL; /* pointer to iat memory */
|
|
int rc;
|
|
ULONG csmte; /* size of swappable MTE */
|
|
ULONG mte_16_32_constant; /* adjustment constant for ptrs */
|
|
ULONG cbpathlen; /* length of pathname in TempBuf */
|
|
USHORT hobmte = 0; /* MTE pseudo handle */
|
|
ULONG lobjnum; /* object number count */
|
|
ldrste_t *pste; /* pointer to segment table entry */
|
|
ldrote_t *pote; /* pointer to object table entry */
|
|
ldrote_t *poteiat = NULL; /* pointer to ote for IAT */
|
|
ldrote_t *potersrc = NULL; /* pointer to ote for resource dir */
|
|
ldrrsrcinfo_t *prsrcinfo;
|
|
ULONG cbfile; /* Amount of data for seg in file */
|
|
ULONG cbseg; /* Size of segment */
|
|
ULONG *pdst; /* used to copy MTE */
|
|
//VMAC ac; /* buffer for VMReserve */
|
|
ULONG cimpmod; /* count of import modules */
|
|
ULONG cpad;
|
|
PCHAR pac;
|
|
UCHAR length;
|
|
struct ExpHdr *pexp; /* pointer to export dircetory */
|
|
struct ImpHdr *pimpdir; /* pointer to import directory */
|
|
struct ImpHdr *pprevimpdir; /* pointer to import directory */
|
|
ULONG vsize = 0; /* virtaul size of module */
|
|
ULONG lsize;
|
|
ULONG lfixtab;
|
|
ULONG cpages = 1; /* count of pages in module */
|
|
ULONG lconstant;
|
|
ULONG lcount;
|
|
ULONG cbiat = 0; /* size of IAT */
|
|
ULONG cbrsrc = 0;
|
|
ULONG iataddr;
|
|
USHORT i;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
LARGE_INTEGER ByteOffset;
|
|
|
|
#define MAXRESMOD 33
|
|
|
|
/***ET+ mte_alloc - memory allocation for resident MTE section
|
|
*
|
|
* pe32 - Pointer to memory for resident MTE.
|
|
*
|
|
* The MTE consists of two parts the MTE pointers section and the table
|
|
* section. The pointer section is allocated in two parts the resident
|
|
* section and the swappable section. The table section of the mte is
|
|
* also allocated from the swappable heap.
|
|
*
|
|
* The first section of the pointer section allocated from the resident
|
|
* heap will also contain the module name and the pointers to the import
|
|
* modules.
|
|
* The second section of the pointer section is allocated from the swappable
|
|
* heap, also attached to this heap object will be the loader's table
|
|
* sections. The loader's table section will contain space for the pathname,
|
|
* object table, loader info and the fixup table.
|
|
*
|
|
*
|
|
* Memory resident object Resident heap object
|
|
* pe32->+----------------+ -+ Copy ->+----------------+<-pmte
|
|
* | Linker EXE info| |------------| | MTE pointers |
|
|
* +----------------+ -+ | ->|----------------|
|
|
* | | Module name |
|
|
* | +----------------+
|
|
* | |Space for Modptr|
|
|
* | +----------------+
|
|
* |
|
|
* | Swappable heap object
|
|
* | +----------------+<-psmte
|
|
* +-------->| MTE pointers |
|
|
* +----------------+
|
|
* |Space for pathnm|
|
|
* +----------------+
|
|
* | Object table |
|
|
* |or segment table|
|
|
* +----------------+
|
|
* | Export Section |
|
|
* +----------------+
|
|
* | Import Section |
|
|
* +----------------+
|
|
* | Fixup Records |
|
|
* +----------------+
|
|
*/
|
|
/*end*/
|
|
|
|
#if DBG
|
|
IF_OL2_DEBUG ( TRACE ) {
|
|
DbgPrint("OS2LDR: ldrCreateMte() was called\n");
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* allocate memory for MTE from resident heap
|
|
*/
|
|
|
|
/*
|
|
* Compute size of resident heap object to hold resident loader MTE.
|
|
* The size is madeup of:
|
|
* size of resident MTE struct
|
|
* 4 bytes * number of import module - to hold pointers to MTEs
|
|
* 9 bytes to hold max module name plus a null this will avoid
|
|
* the realloc needed because we do not know the length of the
|
|
* string till we read the rest of the header
|
|
*/
|
|
|
|
/*
|
|
* Set import module count
|
|
*/
|
|
cimpmod = (*(short *) (pe32->e32_magic) == LEMAGIC ?
|
|
((pe32->e32_unit[IMP].size > 0) ?
|
|
(pe32->e32_unit[IMP].size / IMPHDR_SIZE) - 1 : 0) :
|
|
(ulong_t) ((struct new_exe *) pe32)->ne_cmod);
|
|
if ((pmte = (ldrmte_t *) RtlAllocateHeap(LDRNEHeap, HEAP_ZERO_MEMORY, sizeof(ldrmte_t)
|
|
+ (4 * cimpmod) + MAXRESMOD)) == NULL) {
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto createerror;
|
|
}
|
|
|
|
/*
|
|
* Copy fields from the Linker EXE image to the loader MTE allocated
|
|
* from the resident heap.
|
|
*/
|
|
pdst = (ulong_t *) pmte;
|
|
|
|
for(i = 0; ExeToResMTETbl[i].offset != ENDMTETBL; i++) {
|
|
|
|
if (ExeToResMTETbl[i].offset == (USHORT) SKIPCOPY)
|
|
*pdst++ = 0;
|
|
else {
|
|
/*
|
|
* fetch word value from 16-bit linker EXE image and place in
|
|
* loader mte
|
|
*/
|
|
*pdst++ = *(ulong_t *) ((ulong_t) pe32 +
|
|
(ulong_t) ExeToResMTETbl[i].offset);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Setup fields in resident MTE
|
|
*/
|
|
|
|
pmte->mte_usecnt = 0; /* clear out e32_bworder */
|
|
pmte->mte_dldchain = NULL;
|
|
|
|
/*
|
|
* Initialize MTE Flags
|
|
*/
|
|
pmte->mte_mflags |= plv->lv_class;
|
|
if (plv->lv_type == EXT_DEVICE) /* is this a device driver module? */
|
|
pmte->mte_mflags |= DEVDRVMOD;
|
|
else if (plv->lv_type == EXT_FSD) { /* or is it an FSD module */
|
|
pmte->mte_mflags |= FSDMOD;
|
|
|
|
/*
|
|
* force all segments to swappable
|
|
*/
|
|
pmte->mte_mflags &= ~MTE_MEDIAFIXED;
|
|
}
|
|
|
|
pmte->mte_mflags &= ~MTE_INTNL_MASK; /* Clear internal flags */
|
|
|
|
/*
|
|
* allocate memory for swappable heap object for loader tables
|
|
*/
|
|
|
|
/*
|
|
* Round pathname up to a Dword
|
|
*/
|
|
cbpathlen = ((strlen(LdrBuf) + 4) & ~3);
|
|
|
|
/*
|
|
* compute size of swappable heap object which is madeup of the
|
|
* swappable MTE pointers, the pathname, import, export and fixup
|
|
* sections.
|
|
*/
|
|
if (ldrIsLE(pmte)) {
|
|
cpad = 0;
|
|
csmte = pe32->e32_hdrsize - (plv->lv_new_exe_off +
|
|
sizeof(struct e32_exe));
|
|
if (pe32->e32_unit[RES].rva != 0) {
|
|
cbrsrc = pe32->e32_unit[RES].size +
|
|
(pe32->e32_rescnt * sizeof(ldrrsrc32_t));
|
|
csmte += cbrsrc;
|
|
}
|
|
}
|
|
else {
|
|
/*
|
|
* Compute size of 16-bit loader tables also add space for
|
|
* expanded segment table for 16-bit modules
|
|
*/
|
|
cpad = ((struct new_exe *)pe32)->ne_cseg * (sizeof(ldrste_t) -
|
|
sizeof(struct new_seg));
|
|
csmte = (ulong_t) (((struct new_exe *) pe32)->ne_cbenttab +
|
|
(((struct new_exe *) pe32)->ne_enttab -
|
|
sizeof(struct new_exe))) + cpad;
|
|
|
|
}
|
|
csmte += sizeof(ldrsmte_t) + cbpathlen;
|
|
|
|
/*
|
|
* allocate memory for swappable MTE from swappable heap
|
|
*/
|
|
if ((psmte = (ldrsmte_t *) RtlAllocateHeap(LDRNEHeap, HEAP_ZERO_MEMORY, csmte)) == 0) {
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto createerror;
|
|
}
|
|
|
|
/*
|
|
* Copy fields from the Linker EXE image to the loader swappable MTE
|
|
* pointers.
|
|
*/
|
|
pdst = (ulong_t *) psmte;
|
|
|
|
if (ldrIsLE(pmte)) {
|
|
|
|
for (i = 0; ExeTo32SwapMTETbl[i].offset != ENDMTETBL; i++) {
|
|
|
|
if (ExeTo32SwapMTETbl[i].offset == (USHORT) SKIPCOPY)
|
|
*pdst++ = 0;
|
|
else {
|
|
/*
|
|
* fetch value from linker EXE image and place in loader
|
|
* mte
|
|
*/
|
|
*pdst++ = *(ulong_t *) ((ulong_t) pe32 +
|
|
(ulong_t) ExeTo32SwapMTETbl[i].offset);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
for (i = 0; ExeTo16SwapMTETbl[i].offset != ENDMTETBL; i++) {
|
|
|
|
if (ExeTo16SwapMTETbl[i].offset == (USHORT) SKIPCOPY)
|
|
*pdst++ = 0;
|
|
else {
|
|
/*
|
|
* fetch value from linker EXE image and place in loader
|
|
* mte
|
|
*/
|
|
*pdst++ = (*(ulong_t *) ((ulong_t) pe32 +
|
|
(ulong_t) ExeTo16SwapMTETbl[i].offset)) &
|
|
WORDMASK;
|
|
}
|
|
}
|
|
psmte->smte_cbnrestab = ((struct new_exe *)pe32)->ne_cbnrestab;
|
|
psmte->smte_NEflagsothers =
|
|
((struct new_exe *)pe32)->ne_flagsothers;
|
|
psmte->smte_NEexpver =
|
|
(USHORT) (((struct new_exe *)pe32)->ne_res[6]);
|
|
}
|
|
pmte->mte_swapmte = psmte;
|
|
|
|
/*
|
|
* Read the data into the swappable part of the MTE which contains the
|
|
* object table, Export section and Import section.
|
|
*
|
|
*
|
|
* Swappable heap object
|
|
* +----------------+<-psmte
|
|
* | MTE pointers |
|
|
* |----------------|
|
|
* |Space for pathnm|
|
|
* --->|----------------|
|
|
* cpad-->| | 16-bit pad for |
|
|
* | | expand for seg |
|
|
* | | table |
|
|
* --->|----------------|<-start read here
|
|
* | Object table |
|
|
* | or segment tbl|
|
|
* |----------------|
|
|
* | Export Section |
|
|
* |----------------|
|
|
* | Import Section |
|
|
* |----------------|
|
|
* | Fixup records |
|
|
* +----------------+
|
|
*/
|
|
|
|
lconstant = (ulong_t) psmte + sizeof(ldrsmte_t) + cpad + cbpathlen;
|
|
ByteOffset.LowPart = ldrIsNE(pmte) ? psmte->smte_objtab +
|
|
plv->lv_new_exe_off :
|
|
psmte->smte_objtab;
|
|
ByteOffset.HighPart = 0;
|
|
|
|
if ((rc = NtReadFile( plv->lv_sfn,
|
|
0,
|
|
0,
|
|
0,
|
|
&IoStatusBlock,
|
|
(PCHAR) lconstant,
|
|
csmte - (sizeof(ldrsmte_t)+cbpathlen) - cpad -
|
|
cbrsrc,
|
|
&ByteOffset,
|
|
0 )) != 0) {
|
|
rc = Or2MapNtStatusToOs2Error(rc, ERROR_ACCESS_DENIED);
|
|
goto createerror;
|
|
}
|
|
|
|
/*
|
|
* An adjustment constant has to be added to pointers in MTE. The
|
|
* pointers in MTE are relative to the beginning of the MTE header.
|
|
* Since space has been added between the header and the tables,
|
|
* the pointers need to be updated by a constant.
|
|
*/
|
|
mte_16_32_constant = lconstant - psmte->smte_objtab;
|
|
|
|
psmte->smte_objtab = lconstant - cpad;
|
|
|
|
/*
|
|
* check that ptrs in MTE are valid
|
|
*/
|
|
if ((rc = ldrMTEValidatePtrs(pmte, csmte + (ulong_t) psmte,
|
|
mte_16_32_constant)) != NO_ERROR) {
|
|
goto createerror;
|
|
}
|
|
|
|
if (cbrsrc != 0) {
|
|
/*
|
|
* Set first dword of space used to convert resource table
|
|
* to ENDMTETBL to indicate that the table has not been
|
|
* converted. The table will be convert for each module
|
|
* when the first resource is gotten.
|
|
*/
|
|
psmte->smte_rsrccnt = pe32->e32_rescnt;
|
|
psmte->smte_rsrctab = (ulong_t) psmte + (csmte - cbrsrc);
|
|
prsrcinfo = (ldrrsrcinfo_t *) psmte->smte_rsrctab;
|
|
prsrcinfo->ldrrsrcinfo_flag = ENDMTETBL;
|
|
|
|
/*
|
|
* Also save the resource directory size and pote and the
|
|
* size of the iat and object page map.
|
|
*/
|
|
prsrcinfo->ldrrsrcinfo_size = pe32->e32_unit[RES].size;
|
|
prsrcinfo->ldrrsrcinfo_iatsize = csmte - cbrsrc;
|
|
pote = (ldrote_t *) psmte->smte_objtab;
|
|
for (lobjnum = 0; lobjnum < psmte->smte_objcnt;lobjnum++,pote++) {
|
|
if (pe32->e32_unit[RES].rva >= pote->ote_base &&
|
|
pe32->e32_unit[RES].rva < pote->ote_base + pote->ote_psize)
|
|
break;
|
|
}
|
|
if (lobjnum == psmte->smte_objcnt) {
|
|
rc = ERROR_BAD_EXE_FORMAT;
|
|
}
|
|
|
|
prsrcinfo->ldrrsrcinfo_pote = (ulong_t) pote;
|
|
|
|
}
|
|
|
|
/*
|
|
* Reallocate resident heap space for MTE to include module name.
|
|
* We will copy the module entry in the export name table since this
|
|
* table is in the swappable heap. The module name for 32-bit modules
|
|
* is found by a pointer in the export directory table. For 16-bit
|
|
* modules it is the first entry in the resident name table
|
|
*/
|
|
if (ldrIsLE(pmte)) {
|
|
pexp = (struct ExpHdr *) psmte->smte_expdir;
|
|
pac = (PCHAR) (psmte->smte_expdir + pexp->exp_dllname);
|
|
length = (UCHAR) (strlen(pac) + 1);
|
|
}
|
|
else {
|
|
pac = (PCHAR) psmte->smte_restab;
|
|
length = *((PCHAR) psmte->smte_restab) + (UCHAR) 1;
|
|
}
|
|
if (length > MAXRESMOD) {
|
|
rc = ERROR_BAD_FORMAT;
|
|
goto createerror;
|
|
}
|
|
plv->lv_pmte = pmte;
|
|
|
|
/*
|
|
* Setup import module pointer table
|
|
*/
|
|
pmte->mte_modptrs = (ulong_t) ((PCHAR) pmte + sizeof(ldrmte_t));
|
|
pmte->mte_impmodcnt = cimpmod;
|
|
if (pmte->mte_impmodcnt > 0) {
|
|
memset((void *) pmte->mte_modptrs, '\0',
|
|
pmte->mte_impmodcnt << 2);
|
|
}
|
|
|
|
/*
|
|
* create a handle to use
|
|
*/
|
|
if ((rc = Allocate16BHandle((PUSHORT) &hobmte,
|
|
(ULONG) pmte)) != NO_ERROR) {
|
|
goto createerror;
|
|
}
|
|
|
|
plv->lv_hobmte = pmte->mte_handle = hobmte;
|
|
|
|
pmte->mte_modname = (ULONG) pmte + sizeof(ldrmte_t) + (4 * cimpmod);
|
|
|
|
/*
|
|
* copy module name into resident MTE resident heap object for 32-bit
|
|
* modules place length byte before string.
|
|
*/
|
|
memcpy((ldrIsLE(pmte) ? (PCHAR) pmte->mte_modname + 1 :
|
|
(PCHAR) pmte->mte_modname),
|
|
pac,
|
|
(ldrIsLE(pmte) ? length - 1 : length));
|
|
|
|
if (ldrIsLE(pmte))
|
|
*((PCHAR) pmte->mte_modname) = length - (uchar_t) 1;
|
|
|
|
/*
|
|
* upper case module name
|
|
*/
|
|
ldrUCaseString((PCHAR) pmte->mte_modname + 1,
|
|
*((PCHAR) pmte->mte_modname));
|
|
|
|
/*
|
|
* Set size of pathname (not including terminating NUL).
|
|
*/
|
|
cbpathlen =
|
|
psmte->smte_pathlen = (USHORT) strlen(LdrBuf);
|
|
cbpathlen++;
|
|
|
|
/*
|
|
* copy pathname from TempBuf into MTE
|
|
*/
|
|
psmte->smte_path = (ulong_t) psmte + sizeof(ldrsmte_t);
|
|
memcpy((void *) psmte->smte_path, &LdrBuf, cbpathlen);
|
|
|
|
/*
|
|
* Upper case pathname
|
|
*/
|
|
ldrUCaseString((PCHAR) psmte->smte_path, cbpathlen - 1);
|
|
|
|
if (ldrIsNE(pmte) ||
|
|
(plv->lv_type != EXT_PROGRAM && !(ldrIsLE(pmte)))) {
|
|
/*
|
|
* zero init call gate selector value in entry table for all
|
|
* objects.
|
|
*/
|
|
if ((rc = ldrEachObjEntry(0, pmte, ldrInitEntry, 0)) != NO_ERROR){
|
|
goto createerror;
|
|
}
|
|
}
|
|
|
|
if (ldrIsNE(pmte)) {
|
|
|
|
/*
|
|
* Save size of swappable mte in mte_fpagetab so
|
|
* the debugger command .lm <addr> works for 16-bit modules
|
|
*/
|
|
psmte->smte_fpagetab = csmte;
|
|
|
|
/*
|
|
* expand segments by adding a handle and selector field
|
|
* after each segment table entry
|
|
*/
|
|
ldrExpandSegment(pmte, plv->lv_type);
|
|
|
|
/*
|
|
* Check for porthole modules
|
|
*/
|
|
if ((psmte->smte_NEexetype == 2) || (psmte->smte_NEexetype == 0 &&
|
|
((psmte->smte_NEexpver & 0xff00) == 0x200 ||
|
|
(psmte->smte_NEexpver & 0xff00) == 0x300)))
|
|
pmte->mte_mflags |= MTEPORTHOLE;
|
|
else
|
|
pmte->mte_mflags &= ~MTEPORTHOLE;
|
|
|
|
/*
|
|
* check for program modules
|
|
*/
|
|
if (plv->lv_type == EXT_PROGRAM) {
|
|
|
|
/*
|
|
* Validate start segment
|
|
*/
|
|
if (psmte->smte_startobj == 0 ||
|
|
ldrNumToSte(pmte, psmte->smte_startobj) == 0) {
|
|
rc = ERROR_INVALID_STARTING_CODESEG;
|
|
goto createerror;
|
|
}
|
|
|
|
/*
|
|
* Validate stack segment
|
|
*/
|
|
if (psmte->smte_stackobj == 0 ||
|
|
(pste = ldrNumToSte(pmte, psmte->smte_stackobj)) == 0 ||
|
|
pste->ste_flags & STE_SHARED) {
|
|
rc = ERROR_INVALID_STACKSEG;
|
|
goto createerror;
|
|
}
|
|
|
|
/*
|
|
* Validate auto data segment
|
|
*/
|
|
if (psmte->smte_autods != 0 &&
|
|
ldrNumToSte(pmte, psmte->smte_autods) == 0) {
|
|
rc = ERROR_INVALID_STARTING_CODESEG;
|
|
goto createerror;
|
|
}
|
|
|
|
/*
|
|
* if SS = DS and SP = 0
|
|
*/
|
|
if (psmte->smte_stackobj == psmte->smte_autods &&
|
|
psmte->smte_esp == 0) {
|
|
|
|
/*
|
|
* Set SP to top of auto data segment just below
|
|
* the additional heap
|
|
*/
|
|
psmte->smte_esp = RESIZE64K(pste->ste_minsiz) +
|
|
psmte->smte_stacksize;
|
|
}
|
|
|
|
} /* end if for EXT_PROGRAM */
|
|
else if (psmte->smte_startobj == 0) {
|
|
/*
|
|
* DLL has no init routine: mark it as global
|
|
* complete. This way libinit will not bother about
|
|
* it. Also clear instance libinit bit as linker can
|
|
* turn this on even without an init routine; this
|
|
* should be an error, but is not for compatibility
|
|
* reasons.
|
|
*/
|
|
pmte->mte_mflags |= GINISETUP | GINIDONE;
|
|
pmte->mte_mflags &= ~INSTLIBINIT;
|
|
}
|
|
else {
|
|
/*
|
|
* if SS = DS and SP = 0 (this is a dll, so ignore the case
|
|
* where SS = DS = 0).
|
|
*/
|
|
if (psmte->smte_stackobj == psmte->smte_autods &&
|
|
psmte->smte_stackobj != 0 &&
|
|
psmte->smte_esp == 0) {
|
|
|
|
/*
|
|
* Validate stack segment
|
|
*/
|
|
if ((pste = ldrNumToSte(pmte, psmte->smte_stackobj)) == 0 ||
|
|
pste->ste_flags & STE_SHARED) {
|
|
rc = ERROR_INVALID_STACKSEG;
|
|
goto createerror;
|
|
}
|
|
|
|
/*
|
|
* Set SP to top of auto data segment just below
|
|
* the additional heap
|
|
*/
|
|
psmte->smte_esp = RESIZE64K(pste->ste_minsiz) +
|
|
psmte->smte_stacksize;
|
|
}
|
|
}
|
|
} /* end if for NE module */
|
|
else { /* 32-bit module */
|
|
|
|
struct FmtDir *pfmtdir;
|
|
struct ComDir *pcomdir;
|
|
|
|
/*
|
|
* Make sure that pointers are zero if size in header is zero
|
|
*/
|
|
if ((pe32->e32_unit[EXP].size == 0 &&
|
|
psmte->smte_expdir != 0) ||
|
|
(pe32->e32_unit[IMP].size == 0 && psmte->smte_impdir != 0) ||
|
|
(pe32->e32_unit[RES].size == 0 && psmte->smte_rsrctab != 0) ||
|
|
(pe32->e32_unit[FIX].size == 0 && psmte->smte_fixtab != 0) ||
|
|
(pe32->e32_unit[DEB].size == 0 &&
|
|
psmte->smte_debuginfo != 0)) {
|
|
rc = ERROR_BAD_EXE_FORMAT;
|
|
goto createerror;
|
|
}
|
|
|
|
psmte->smte_fixupsize = pe32->e32_unit[FIX].size;
|
|
|
|
/*
|
|
* Check for wild pointers in names ptr table
|
|
*/
|
|
for (lcount = 0; lcount < pexp->exp_namecnt; lcount++) {
|
|
pac = (uchar_t *) (*(ulong_t *)
|
|
(pexp->exp_name + (lcount * sizeof(ulong_t)) +
|
|
(ulong_t) pexp) + (ulong_t) pexp);
|
|
lconstant = strlen(pac) + 1;
|
|
if (psmte + lconstant > psmte + csmte) {
|
|
rc = ERROR_BAD_EXE_FORMAT;
|
|
goto createerror;
|
|
}
|
|
}
|
|
|
|
pimpdir = (struct ImpHdr *) psmte->smte_impdir;
|
|
|
|
/*
|
|
* Remove info from module directives table:
|
|
* For module with 16-bit code get stack object & auto ds.
|
|
* Get count of resources for this module.
|
|
*/
|
|
if (pe32->e32_dircnt != 0) {
|
|
pfmtdir = (struct FmtDir *) (pe32->e32_dirtab +
|
|
mte_16_32_constant);
|
|
for (lcount = 0; lcount < pe32->e32_dircnt; lcount++,
|
|
pfmtdir++) {
|
|
|
|
if ((ulong_t) pfmtdir >
|
|
psmte->smte_objtab + csmte) {
|
|
rc = ERROR_BAD_EXE_FORMAT;
|
|
}
|
|
|
|
switch (pfmtdir->dir) {
|
|
|
|
case OS2LDR16:
|
|
if (pfmtdir->length != sizeof(struct ComDir)) {
|
|
rc = ERROR_BAD_EXE_FORMAT;
|
|
goto createerror;
|
|
}
|
|
pcomdir = (struct ComDir *) (pe32->e32_dirtab +
|
|
mte_16_32_constant +
|
|
pfmtdir->offset);
|
|
if ((ulong_t) pcomdir >
|
|
psmte->smte_objtab + csmte) {
|
|
rc = ERROR_BAD_EXE_FORMAT;
|
|
goto createerror;
|
|
}
|
|
psmte->smte_autods = pcomdir->autods;
|
|
psmte->smte_stackobj = pcomdir->stackobj;
|
|
break;
|
|
|
|
// LTS - 1/16/91
|
|
// Moved count back to header
|
|
|
|
case OS2RSRCNT:
|
|
// prsrccnt = (ulong_t *) (pe32->e32_dirtab +
|
|
// mte_16_32_constant +
|
|
// pfmtdir->offset);
|
|
// if ((ulong_t) prsrccnt >
|
|
// psmte->smte_objtab + csmte) {
|
|
// rc = ERROR_BAD_EXE_FORMAT;
|
|
// goto createerror;
|
|
// }
|
|
break;
|
|
|
|
case OS2FIXMAP:
|
|
psmte->smte_fpagetab = pfmtdir->offset +
|
|
pe32->e32_dirtab +
|
|
mte_16_32_constant;
|
|
psmte->smte_mpages = pfmtdir->length /
|
|
sizeof(ulong_t);
|
|
for (lfixtab = 0; lfixtab < psmte->smte_mpages;
|
|
lfixtab++) {
|
|
lsize =
|
|
((ulong_t *) psmte->smte_fpagetab)[lfixtab];
|
|
/*
|
|
* check if any fixups exist
|
|
*/
|
|
if (lsize == 0xffffffff)
|
|
continue;
|
|
lsize += psmte->smte_fixtab;
|
|
if (lsize > psmte->smte_fixtab +
|
|
pe32->e32_unit[FIX].size) {
|
|
rc = ERROR_BAD_EXE_FORMAT;
|
|
goto createerror;
|
|
}
|
|
else {
|
|
((ulong_t *) psmte->smte_fpagetab)[lfixtab] =
|
|
lsize;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
rc = ERROR_BAD_EXE_FORMAT;
|
|
goto createerror;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (plv->lv_type == EXT_PROGRAM) {
|
|
|
|
/*
|
|
* Init call gate value for Exec's
|
|
*/
|
|
ldrInitCallGate = 0;
|
|
/*
|
|
* Validate stack
|
|
*/
|
|
if (psmte->smte_stackobj <= psmte->smte_objcnt) {
|
|
pote =
|
|
&((ldrote_t *)psmte->smte_objtab)[psmte->smte_stackobj-1];
|
|
pote->ote_vsize += psmte->smte_stackinit;
|
|
}
|
|
else {
|
|
rc = ERROR_INVALID_STACKSEG;
|
|
goto createerror;
|
|
}
|
|
|
|
/*
|
|
* Validate starting code object
|
|
*/
|
|
if (psmte->smte_eip == 0) {
|
|
rc = ERROR_INVALID_STARTING_CODESEG;
|
|
goto createerror;
|
|
}
|
|
}
|
|
else { /* Else some flavor of DLL */
|
|
/*
|
|
* For 32-bit DLLs, fail the load if
|
|
*
|
|
* A. The specified starting address is bad, or
|
|
* B. no starting object is specified, but either
|
|
* instance DLL initialization or instance DLL
|
|
* termination is requested, or
|
|
* C. instance DLL termination is requested, but the
|
|
* the starting object is 16-bit.
|
|
*/
|
|
pote = (ldrote_t *) psmte->smte_objtab;
|
|
for (lobjnum = 0; lobjnum < psmte->smte_objcnt; lobjnum++,
|
|
pote++) {
|
|
|
|
if ((psmte->smte_eip > pote->ote_base) &&
|
|
(psmte->smte_eip < (pote->ote_base + pote->ote_psize)))
|
|
break;
|
|
if (lobjnum == psmte->smte_objcnt) {
|
|
rc = ERROR_INVALID_STARTING_CODESEG;
|
|
goto createerror;
|
|
}
|
|
}
|
|
|
|
if ((psmte->smte_eip == 0 &&
|
|
(pmte->mte_mflags & (MTEDLLTERM | INSTLIBINIT))) ||
|
|
((pmte->mte_mflags & MTEDLLTERM) &&
|
|
!(pote->ote_flags & OBJ_BIGDEF))) {
|
|
rc = ERROR_INVALID_STARTING_CODESEG;
|
|
goto createerror;
|
|
}
|
|
if (psmte->smte_eip == 0)
|
|
pmte->mte_mflags |= GINISETUP | GINIDONE;
|
|
/* Fake global initialization done */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check each segment or object in module
|
|
*/
|
|
for (lobjnum = 0; lobjnum < psmte->smte_objcnt; lobjnum++) {
|
|
|
|
if (ldrIsNE(pmte)) {
|
|
pste = &((ldrste_t *) psmte->smte_objtab)[lobjnum];
|
|
|
|
/*
|
|
* Check that the amount of data in the file does
|
|
* not exceed the size of the segment.
|
|
*/
|
|
if ((cbseg = pste->ste_minsiz) == 0)
|
|
cbseg = _64K; /* Get size of segment */
|
|
if ((cbfile = pste->ste_size) == 0 && pste->ste_offset != 0)
|
|
cbfile = _64K; /* Get amount of data in file */
|
|
if (cbfile > cbseg) {
|
|
/* Error if file size > segment size */
|
|
rc = ERROR_INVALID_MINALLOCSIZE;
|
|
goto createerror;
|
|
}
|
|
|
|
/*
|
|
* Check for auto data segment. If found, add in stack
|
|
* and heap sizes and store in ste entry and check for
|
|
* overflow
|
|
*/
|
|
if (lobjnum + 1 == psmte->smte_autods) {
|
|
if ((cbseg += psmte->smte_heapsize +
|
|
psmte->smte_stacksize) > _64K) {
|
|
rc = ERROR_AUTODATASEG_EXCEEDS_64k;
|
|
goto createerror;
|
|
}
|
|
}
|
|
pste->ste_minsiz = (USHORT) cbseg;
|
|
}
|
|
/* 32-bit module */
|
|
else {
|
|
pote = &((ldrote_t *) psmte->smte_objtab)[lobjnum];
|
|
|
|
/*
|
|
* Check if IAT in this object
|
|
*/
|
|
if (pimpdir != NULL &&
|
|
pimpdir->imp_address >= pote->ote_base &&
|
|
pimpdir->imp_address < pote->ote_base + pote->ote_psize) {
|
|
|
|
/*
|
|
* Save object table pointer to iat
|
|
*/
|
|
poteiat = pote;
|
|
}
|
|
|
|
/*
|
|
* Check for auto data object. If found, add heap size
|
|
* to virtual size of object. If virtual size > 64k
|
|
* and this is USE16 object goto error.
|
|
*/
|
|
if (lobjnum + 1 == psmte->smte_autods &&
|
|
(pote->ote_vsize += psmte->smte_heapsize) > _64K &&
|
|
!(pote->ote_flags & OBJ_BIGDEF)) {
|
|
rc = ERROR_AUTODATASEG_EXCEEDS_64k;
|
|
goto createerror;
|
|
}
|
|
|
|
/*
|
|
* 1/24/91 - LTS
|
|
* If we are to preload resources set the object flag
|
|
* preload. This only has meaning for resources not
|
|
* for any other objects.
|
|
*/
|
|
if (pote->ote_flags & OBJ_RSRC) {
|
|
if (!(pmte->mte_mflags & MTE_MEDIAFIXED))
|
|
pote->ote_flags |= OBJ_PRELOAD;
|
|
}
|
|
|
|
if (!(pote->ote_flags & OBJ_DEBUG)) {
|
|
vsize += ((pote->ote_vsize + (_64K - 1)) / _64K) * _64K;
|
|
cpages += (pote->ote_vsize + PAGEMASK) / PAGESIZE;
|
|
}
|
|
|
|
if (pote->ote_flags & OBJ_DEBUG) {
|
|
pote->ote_base =
|
|
pote->ote_selector =
|
|
pote->ote_handle = 0;
|
|
}
|
|
|
|
/*
|
|
* Clear bit in flags to use as allocation flag
|
|
*/
|
|
pote->ote_flags &= ~OBJALLOC;
|
|
|
|
/*
|
|
* check that executable objects don't have write access also
|
|
*/
|
|
if (pote->ote_flags & OBJ_EXEC &&
|
|
pote->ote_flags & OBJ_WRITE) {
|
|
rc = ERROR_BAD_EXE_FORMAT;
|
|
goto createerror;
|
|
}
|
|
|
|
/*
|
|
* if object readonly force it to be shared
|
|
*/
|
|
if (!(pote->ote_flags & OBJ_WRITE))
|
|
pote->ote_flags |= OBJ_SHARED;
|
|
}
|
|
} /* end of for loop for each object */
|
|
|
|
if (ldrIsLE(pmte)) {
|
|
|
|
/*
|
|
* Compute size of IAT
|
|
*/
|
|
if (poteiat != NULL) {
|
|
|
|
/*
|
|
* See if IAT exists already
|
|
*/
|
|
if (!(pimpdir->imp_flags & HDRIAT)) {
|
|
if (poteiat->ote_vsize < poteiat->ote_psize)
|
|
cbiat = poteiat->ote_vsize;
|
|
else
|
|
cbiat = poteiat->ote_psize;
|
|
cbiat -= pimpdir->imp_address - poteiat->ote_base;
|
|
|
|
// if ((rc = VMAllocKHB(VM_HKH_PUB_SWAPRW,
|
|
// cbiat,
|
|
// (VMHOB) LDRMTEOWNER,
|
|
// NA,
|
|
// SSToDS(&piat))) != NO_ERROR) {
|
|
// goto createerror;
|
|
// }
|
|
psmte->smte_iat = (ulong_t) piat;
|
|
|
|
/*
|
|
* Read IAT if it exits
|
|
*/
|
|
// if ((rc=ldrRead(plv->lv_sfn,
|
|
// poteiat->ote_pages +
|
|
// (pimpdir->imp_address -
|
|
// poteiat->ote_base),
|
|
// (PCHAR) psmte->smte_iat,
|
|
// NULL,
|
|
// cbiat,
|
|
// pmte)) != NO_ERROR) {
|
|
// goto createerror;
|
|
// }
|
|
}
|
|
|
|
if (pimpdir->imp_flags & HDRIAT) {
|
|
piat = (struct ImpHdr *) ((pimpdir->imp_reserved -
|
|
pe32->e32_objtab) +
|
|
psmte->smte_objtab);
|
|
psmte->smte_iat = (ulong_t) piat;
|
|
cbiat = pe32->e32_unit[FIX].rva - pimpdir->imp_reserved;
|
|
}
|
|
|
|
/*
|
|
* Update Import directory entries to point to the
|
|
* swappable heap copy of the IAT.
|
|
*/
|
|
iataddr = pimpdir->imp_address;
|
|
for (lcount = 0; lcount < pmte->mte_impmodcnt; lcount++,
|
|
pimpdir++) {
|
|
/*
|
|
* Save imp_address in imp_ver for check if page
|
|
* that is being faulted contains iat
|
|
*/
|
|
pimpdir->imp_ver = pimpdir->imp_address;
|
|
pimpdir->imp_address = (pimpdir->imp_address -
|
|
iataddr) + (ulong_t) piat;
|
|
|
|
/*
|
|
* Store in imp_flags field size of iat
|
|
*/
|
|
if (lcount != 0) {
|
|
pprevimpdir->imp_flags = pimpdir->imp_address;
|
|
}
|
|
pprevimpdir = pimpdir;
|
|
}
|
|
|
|
/*
|
|
* Update size of last iat (imp_flags)
|
|
*/
|
|
pimpdir--;
|
|
pdst = (ulong_t *) pimpdir->imp_address;
|
|
while ((*pdst != 0) &&
|
|
((ulong_t) pdst < (ulong_t) piat + cbiat)) {
|
|
pdst++;
|
|
}
|
|
if ((ulong_t) pdst >= (ulong_t) piat + cbiat) {
|
|
rc = ERROR_BAD_EXE_FORMAT;
|
|
goto createerror;
|
|
}
|
|
/*
|
|
* Add one to size for terminator of directory
|
|
*/
|
|
pdst++;
|
|
pimpdir->imp_flags = (ulong_t) pdst;
|
|
cbiat = (ulong_t) pdst - (ulong_t) piat;
|
|
psmte->smte_iatsize = cbiat;
|
|
}
|
|
|
|
|
|
/*
|
|
* reserve address space for dlls
|
|
*/
|
|
// if (pmte->mte_mflags & LIBRARYMOD && vsize > 0 &&
|
|
// !(pmte->mte_mflags & (FSDMOD | DEVDRVMOD | VDDMOD))) {
|
|
// pote = (ldrote_t *) psmte->smte_objtab;
|
|
// ac.ac_va = pote->ote_base + psmte->smte_vbase;
|
|
// if (ac.ac_va > SEL_512MEG - _64MEG) {
|
|
// /*
|
|
// * The address we are to reserve at is greater than
|
|
// * the reserved space for DLLs. Set the address to zero
|
|
// * so we will fail the first reserve and than we can
|
|
// * reserve at any address.
|
|
// */
|
|
// ac.ac_va = 0;
|
|
// }
|
|
|
|
// /*
|
|
// * Try to reserve address space for module at which it was
|
|
// * linked at. If that fails allocate at any address.
|
|
// */
|
|
// fl = VMAC_ARENASHR | VMAC_ALIGNSEL | VMAC_PRERES |
|
|
// VMAC_LOCSPECIFIC;
|
|
// for (i = 0; i < 2; i++) {
|
|
// if ((rc = VMReserveMem(vsize,
|
|
// fl,
|
|
// pPTDACur->ptda_handle,
|
|
// NULL,
|
|
// SSToDS(&ac))) == NO_ERROR)
|
|
// break;
|
|
|
|
// /*
|
|
// * At this point we have failed to allocate at the address
|
|
// * the linker assigned. Check to see if fixups have been
|
|
// * removed. If they have fail to load this module.
|
|
// */
|
|
// if (pmte->mte_mflags & E32_NOINTFIX) {
|
|
// rc = ERROR_BAD_EXE_FORMAT;
|
|
// goto createerror;
|
|
// }
|
|
// fl &= ~VMAC_LOCSPECIFIC;
|
|
// fl |= VMAC_LOCANY;
|
|
// }
|
|
// if (rc != NO_ERROR) {
|
|
// goto createerror;
|
|
// }
|
|
// if ((vsize = ac.ac_va-pote->ote_base) != psmte->smte_vbase) {
|
|
// psmte->smte_delta = ac.ac_va - (psmte->smte_vbase +
|
|
// pote->ote_base);
|
|
// psmte->smte_vbase = vsize;
|
|
// }
|
|
|
|
// }
|
|
}
|
|
|
|
/*
|
|
* Check if internal name for a LIBRARY matches the module name
|
|
* but not for porthole apps.
|
|
*/
|
|
if ((plv->lv_type == EXT_LIBRARY) &&
|
|
!(pmte->mte_mflags & MTEPORTHOLE) &&
|
|
(rc = ldrCheckInternalName(pmte)) != NO_ERROR) {
|
|
goto createerror;
|
|
}
|
|
|
|
pmte->mte_sfn = plv->lv_sfn; /* save system file number in mte */
|
|
|
|
// if (IOPLEnabled || (ldrChkIOPLTable(psmte) == NO_ERROR))
|
|
// pmte->mte_mflags |= MTEIOPLALLOWED;
|
|
|
|
/*
|
|
* link mte in list of mtes
|
|
*/
|
|
ldrLinkMTE(pmte);
|
|
|
|
pmte->mte_mflags |= MTEVALID;
|
|
|
|
createerror:
|
|
if (rc != NO_ERROR) {
|
|
/*
|
|
* Check if Pseudo Handle allocated
|
|
*/
|
|
if (hobmte != 0) {
|
|
Free16BHandle(hobmte);
|
|
}
|
|
|
|
/*
|
|
* check if swappable MTE allocated
|
|
*/
|
|
if (psmte != NULL) {
|
|
/*
|
|
* check if page table, IAT and resource table allocated
|
|
*/
|
|
if (ldrIsLE(pmte) && psmte->smte_fpagetab != 0)
|
|
RtlFreeHeap(LDRNEHeap, 0, (void *) psmte->smte_fpagetab);
|
|
|
|
RtlFreeHeap(LDRNEHeap, 0, (void *) psmte);
|
|
}
|
|
|
|
/*
|
|
* check if resident MTE allocated
|
|
*/
|
|
if (pmte != NULL)
|
|
RtlFreeHeap(LDRNEHeap, 0, (void *) pmte);
|
|
|
|
}
|
|
return(rc);
|
|
}
|
|
|
|
|
|
/***LP ldrMTEValidatePtrs - Validate pointers in MTE table and update to new
|
|
* values
|
|
*
|
|
* Check for any wild pointers in MTE before converting to new
|
|
* value.
|
|
*
|
|
* ENTRY pmte - pointer to loader MTE
|
|
* limit - max value any ptrs may be
|
|
* constant - value to update pointers by
|
|
*
|
|
* EXIT int - return code (NO_ERROR if successful)
|
|
*/
|
|
|
|
int ldrMTEValidatePtrs(pmte, limit, constant)
|
|
ldrmte_t *pmte; /* pointer to loader MTE */
|
|
ULONG limit;
|
|
ULONG constant;
|
|
{
|
|
ldrsmte_t *psmte;
|
|
register PULONG p;
|
|
register unsigned int i;
|
|
|
|
psmte = pmte->mte_swapmte;
|
|
|
|
/*
|
|
* do for each entry in MTE found in validatetbl
|
|
*/
|
|
|
|
for (i = 0; validatetbl[i] != ENDMTETBL; i++) {
|
|
|
|
/*
|
|
* Since the resource table is no longer part of the
|
|
* header for a 32-bit module do not validate it.
|
|
*/
|
|
if (ldrIsLE(pmte) && i == rsrcvalidatetbl)
|
|
continue;
|
|
/*
|
|
* point to entry in exe image
|
|
*/
|
|
(PCHAR ) p = ((PCHAR ) psmte + validatetbl[i]);
|
|
|
|
/*
|
|
* check if pointer valid, non-zero
|
|
*/
|
|
if (*p != 0)
|
|
/*
|
|
* range check and add constant to value at pointer
|
|
*/
|
|
if ((*p += constant) > limit)
|
|
return(ERROR_BAD_EXE_FORMAT);
|
|
}
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
|
|
/***LP ldrExpandSegment - expand segments in place
|
|
*
|
|
* copy each segment table entry from pointer at psrc to
|
|
* pmte->mte_objtab, the region starting immediately after the space for
|
|
* pathname, and expand each entry by adding two bytes for the segment
|
|
* handle and 4 bytes for the linear address of the segment
|
|
*
|
|
* ENTRY pmte - pointer to mte
|
|
* type - module type
|
|
*
|
|
* EXIT none - segments expanded
|
|
*/
|
|
|
|
void ldrExpandSegment(pmte, type)
|
|
ldrmte_t *pmte; /* pointer to module table entry */
|
|
UCHAR type; /* module type */
|
|
{
|
|
register ldrste_t *psrc; /* pointer to source */
|
|
register ldrste_t *pdst; /* pointer to destination */
|
|
register int i; /* count of segments */
|
|
ldrsmte_t *psmte; /* pointer to swappable mte */
|
|
ulong_t ldrccodeseg = 0;/* count of seg that can be packed */
|
|
ulong_t ldrcsegpack = 0;/* running size of packed segs */
|
|
|
|
psmte = pmte->mte_swapmte;
|
|
pdst = (ldrste_t *) psmte->smte_objtab;
|
|
|
|
psrc = (ldrste_t *) (psmte->smte_objtab + (psmte->smte_objcnt *
|
|
(sizeof(ldrste_t) - sizeof(struct new_seg))));
|
|
|
|
/* loop for all STEs */
|
|
for (i = 0; pdst != psrc; i++, ((struct new_seg *) psrc)++, pdst++) {
|
|
|
|
/*
|
|
* Make sure the following flags are cleared:
|
|
*/
|
|
psrc->ste_flags &= ~(STE_PACKED | STE_SEMAPHORE | STE_SELALLOC |
|
|
STE_HUGE | STE_WAITING);
|
|
|
|
if ((type == EXT_DEVICE)) {
|
|
/*
|
|
* For a device driver module.
|
|
* If it is a first or the second segment, set the GDTSEG flag.
|
|
* If the segment is ring 2 segment (IOPL), set the GDTSEG flag.
|
|
*/
|
|
if (i >= 2) {
|
|
if ((psrc->ste_flags & STE_SEGDPL) == STE_RING_2)
|
|
psrc->ste_flags |= STE_GDTSEG;
|
|
}
|
|
else
|
|
psrc->ste_flags |= STE_GDTSEG;
|
|
}
|
|
|
|
if ((type == EXT_DEVICE) || (type == EXT_FSD)) {
|
|
/*
|
|
* This is an FSD/DD module. We need to force the seg's to be
|
|
* movable, preloaded and have DPL = 3(because the init routine
|
|
* will run in ring 3). These segments cannot be shared, cannot
|
|
* be conforming and cannot be discarded.
|
|
*/
|
|
psrc->ste_flags |= (STE_PRELOAD | STE_RING_3);
|
|
psrc->ste_flags &= ~(STE_SHARED | STE_CONFORM);
|
|
}
|
|
|
|
/*
|
|
* if swapping is not on or loading from removable media
|
|
* force preloading of segment
|
|
*/
|
|
if (!(pmte->mte_mflags & MTE_MEDIAFIXED))
|
|
psrc->ste_flags |= STE_PRELOAD;
|
|
|
|
/*
|
|
* if readonly, force segment to be shared
|
|
*/
|
|
if (psrc->ste_flags & STE_ERONLY)
|
|
psrc->ste_flags |= STE_SHARED;
|
|
|
|
/*
|
|
* if this is a code segment, force it to be shared
|
|
*/
|
|
else if ((psrc->ste_flags & STE_TYPE_MASK) == STE_CODE) {
|
|
psrc->ste_flags |= STE_SHARED;
|
|
ldrccodeseg++;
|
|
}
|
|
|
|
/*
|
|
* Set Pageable bit:
|
|
* If read-only data and fixed media, then it is pageable
|
|
*/
|
|
if (((psrc->ste_flags & STE_DATA) &&
|
|
!(psrc->ste_flags & STE_ERONLY)) ||
|
|
!(pmte->mte_mflags & MTE_MEDIAFIXED))
|
|
psrc->ste_flags &= ~STE_PAGEABLE;
|
|
else
|
|
psrc->ste_flags |= STE_PAGEABLE;
|
|
|
|
/*
|
|
* copy ste to final destination
|
|
*/
|
|
|
|
*(struct new_seg *) pdst = *(struct new_seg *) psrc;
|
|
|
|
/*
|
|
* initialize segment handle and selector to zero
|
|
*/
|
|
pdst->ste_selector = 0;
|
|
pdst->ste_seghdl = 0;
|
|
|
|
/*
|
|
* initialize segment fixup table to null
|
|
*/
|
|
pdst->ste_fixups = 0;
|
|
}
|
|
|
|
/*
|
|
* Check if we can pack the segments
|
|
*/
|
|
if (type == EXT_PROGRAM && ldrccodeseg > MINSEGPACKCNT) {
|
|
pdst = (ldrste_t *) psmte->smte_objtab;
|
|
ldrccodeseg = 0;
|
|
for (i = 0; i < (int) psmte->smte_objcnt; i++, pdst++) {
|
|
|
|
ulong_t minsiz_l = RESIZE64K(pdst->ste_minsiz);
|
|
|
|
if ((pdst->ste_flags & STE_TYPE_MASK) == STE_CODE &&
|
|
((USHORT)(pdst->ste_minsiz % (USHORT) PAGEMASK) <
|
|
(USHORT) MINPGPACKSIZE) &&
|
|
minsiz_l < MAXSEGPACKSIZE) {
|
|
ldrccodeseg++;
|
|
pdst->ste_flags |= STE_PACKED;
|
|
pdst->ste_flags &= ~STE_PRESENT;
|
|
pdst->ste_minsiz = (pdst->ste_minsiz + (USHORT) 3) &
|
|
(USHORT) ~3;
|
|
ldrcsegpack += minsiz_l;
|
|
}
|
|
}
|
|
psmte->smte_csegpack = ldrccodeseg;
|
|
psmte->smte_ssegpack = ldrcsegpack;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/***LP ldrCheckInternalName - Check if internal name of a library matches
|
|
* its module name
|
|
*
|
|
* ENTRY pmte pointer to its MTE
|
|
* File name assumed to be in pPTDACur->ptda_pLdrBuf
|
|
*
|
|
* EFFECTS The internal name is changed to Upper Case and NULL terminated
|
|
*
|
|
* EXIT NO_ERROR name matches
|
|
* ERROR_INVALID_NAME mismatch
|
|
*/
|
|
int ldrCheckInternalName(pmte)
|
|
register ldrmte_t *pmte;
|
|
{
|
|
PUCHAR pchintname; /* pointer to internal name */
|
|
USHORT cchintname; /* length of internal name */
|
|
PCHAR pchmodname; /* pointer to module name */
|
|
USHORT cchmodname; /* length of module name */
|
|
PCHAR ptemp;
|
|
PCHAR ptemp2;
|
|
USHORT count;
|
|
|
|
pchintname = (PCHAR) pmte->mte_modname;
|
|
cchintname = *pchintname++; /* length of internal name */
|
|
|
|
/*
|
|
* For library modules, the internal name must match the name
|
|
* by which the module is being loaded. We extract the name from
|
|
* the fully qualified name in LdrBuf for comparison.
|
|
*/
|
|
if (pmte->mte_mflags & LIBRARYMOD) {
|
|
ptemp = LdrBuf;
|
|
while (ptemp != NULL) {
|
|
pchmodname = ptemp;
|
|
ptemp = strpbrk(ptemp, "\\/");
|
|
if (ptemp != NULL) {
|
|
ptemp++;
|
|
}
|
|
}
|
|
ptemp = strchr(pchmodname, '.');
|
|
if (ptemp == NULL) {
|
|
ptemp = strchr(pchmodname, '\0');
|
|
}
|
|
cchmodname = (USHORT) (ptemp - pchmodname);
|
|
if (cchintname != cchmodname) {
|
|
return(ERROR_INVALID_NAME);
|
|
}
|
|
|
|
count = cchmodname;
|
|
ptemp = pchmodname;
|
|
ptemp2 = pchintname;
|
|
#ifdef DBCS
|
|
// MSKK Apr.20.1993 V-AkihiS
|
|
while (count-- > 0) {
|
|
if (IsDBCSLeadByte(*ptemp)) {
|
|
ptemp++;
|
|
if (count > 0) {
|
|
count--;
|
|
ptemp++;
|
|
}
|
|
} else {
|
|
*ptemp = (CHAR) toupper(*(PUCHAR)ptemp);
|
|
ptemp++;
|
|
}
|
|
}
|
|
count = cchmodname;
|
|
while (count-- > 0) {
|
|
if (IsDBCSLeadByte(*ptemp2)) {
|
|
ptemp2++;
|
|
if (count > 0) {
|
|
count--;
|
|
ptemp2++;
|
|
}
|
|
} else {
|
|
*ptemp2 = (CHAR) toupper(*(PUCHAR)ptemp2);
|
|
ptemp2++;
|
|
}
|
|
}
|
|
#else
|
|
while (count-- > 0) {
|
|
*ptemp = (CHAR) toupper(*(PUCHAR)ptemp);
|
|
ptemp++;
|
|
*ptemp2 = (CHAR) toupper(*(PUCHAR)ptemp2);
|
|
ptemp2++;
|
|
}
|
|
#endif
|
|
|
|
if (strncmp(pchintname, pchmodname, cchintname) != 0) {
|
|
return(ERROR_INVALID_NAME);
|
|
}
|
|
|
|
}
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
|
|
/***LP ldrChkLoadType - Check if module matches requested load type
|
|
*
|
|
* ENTRY lflags - flags
|
|
* plv - pointer to local variables
|
|
*
|
|
* EXIT none - return successful or call load_error
|
|
*/
|
|
|
|
void ldrChkLoadType(lflags, plv)
|
|
ULONG lflags; /* module table entry flags */
|
|
register ldrlv_t *plv; /* pointer to local variables */
|
|
{
|
|
if (!((plv->lv_type != EXT_PROGRAM) ^ (!(lflags & LIBRARYMOD)))) {
|
|
if (plv->lv_sfn != 0)
|
|
NtClose(plv->lv_sfn);
|
|
load_error(ERROR_INVALID_MODULETYPE, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
/***LP ldrIsAttached - Check if process is already attached to module
|
|
*
|
|
* Check if the current (or child) process is attached to
|
|
* each of the objects in the given module.
|
|
*
|
|
* This procedure performs the following steps:
|
|
*
|
|
* for each segment (object) in the module,
|
|
* if shared,
|
|
* if (error from VMIsAttached)
|
|
* return (FALSE)
|
|
* else (it is private)
|
|
* if no handle maps the segment (object) address
|
|
* retun (FALSE)
|
|
* return (TRUE)
|
|
*
|
|
* ENTRY pmte - pointer to mte to check
|
|
*
|
|
* EXIT int
|
|
* FALSE - Process is not attached to module
|
|
* TRUE - Process is attached to module
|
|
*
|
|
*/
|
|
int ldrIsAttached(pmte)
|
|
register ldrmte_t *pmte;
|
|
{
|
|
ldrsmte_t *psmte; /* pointer to swappable mte */
|
|
// ULONG objno;
|
|
// VMHOB hptda;
|
|
// VMHOB hob;
|
|
ULONG lnonrsrccnt;
|
|
// register ldrote_t *pote;
|
|
// register ldrste_t *pste;
|
|
|
|
psmte = pmte->mte_swapmte;
|
|
/*
|
|
* Do not process resource objects for 16-bit modules
|
|
*/
|
|
if (ldrIsNE(pmte))
|
|
lnonrsrccnt = psmte->smte_objcnt - psmte->smte_rsrccnt;
|
|
else
|
|
lnonrsrccnt = psmte->smte_objcnt;
|
|
|
|
/*
|
|
* If there are no non-resource objects, then we must
|
|
* say we are not attached, since this may be a forwarder
|
|
* module, and we need to process its list of static
|
|
* links.
|
|
*/
|
|
if (lnonrsrccnt == 0)
|
|
return(FALSE);
|
|
|
|
// (ULONG) pste = (ULONG) pote = psmte->smte_objtab;
|
|
// for (objno = 0; objno < lnonrsrccnt; objno++, pote++, pste++) {
|
|
|
|
/*
|
|
* skip resource objects for 32-bit modules
|
|
*/
|
|
// if (ldrIsLE(pmte) && pote->ote_flags & (OBJ_RSRC | OBJ_DEBUG))
|
|
// continue;
|
|
|
|
/*
|
|
* get handle from object or segment table
|
|
*/
|
|
// if (ldrIsNE(pmte)) {
|
|
// if (pste-> ste_flags & STE_SHARED) {
|
|
// if (pste->ste_seghdl == HOBNULL)
|
|
// return(FALSE);
|
|
// if (VMIsAttached((VMHOB)pste->ste_seghdl,hptda) != NO_ERROR)
|
|
// return(FALSE);
|
|
// }
|
|
// else if (VMGetHandle(SelToLaTiled(pste->ste_selector), hptda,
|
|
// SSToDS (&hob)) != NO_ERROR)
|
|
// return (FALSE);
|
|
// }
|
|
// else {
|
|
// if (pote-> ote_flags & OBJ_SHARED) {
|
|
// if (pote->ote_handle == HOBNULL)
|
|
// return(FALSE);
|
|
// if (VMIsAttached((VMHOB)pote->ote_handle,hptda) != NO_ERROR)
|
|
// return(FALSE);
|
|
// }
|
|
// else if (VMGetHandle(pote->ote_base, hptda,
|
|
// SSToDS (&hob)) != NO_ERROR)
|
|
// return (FALSE);
|
|
// }
|
|
// }
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/***LP ldrWriteErrTxt - write error message into user's message buffer
|
|
*
|
|
* This procedure preforms the following steps:
|
|
*
|
|
* - if user supplied buffer zero error message will not be setup
|
|
* - else copy module name into user suppiled buffer
|
|
* - if errcode = ERROR_PROC_NOT_FOUND copy procedure name
|
|
* to user buffer
|
|
*
|
|
* ENTRY errcode - loader error code
|
|
* pmte - pointer to module table entry
|
|
*
|
|
* EXIT int - return code (NO_ERROR if successful)
|
|
* - else ERROR_PROTECTION_VIOLATION
|
|
*
|
|
* EFFECTS error message copied into user's message buffer
|
|
*/
|
|
|
|
VOID
|
|
ldrWriteErrTxt( errcode )
|
|
int errcode; /* loader error code */
|
|
{
|
|
int rc = NO_ERROR;
|
|
USHORT cnt;
|
|
USHORT BufferLen;
|
|
char ordbuf[20]; // Buffer to translate ordinal number
|
|
char *pordbuf;
|
|
PSZ pstring;
|
|
|
|
pstring = pErrText->Buffer;
|
|
BufferLen = pErrText->MaximumLength - 1;
|
|
if ((pstring == NULL) || (BufferLen == 0)) {
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Check if module name setup by ldrSetupSrcErrTxt. If so use that
|
|
* module else check the MTE passed.
|
|
*/
|
|
cnt = ldrSrcModNameBufL;
|
|
if (cnt != 0) {
|
|
if (cnt > BufferLen)
|
|
cnt = BufferLen;
|
|
RtlMoveMemory(pstring, ldrSrcModNameBuf, (ULONG) cnt);
|
|
pstring += (UCHAR) cnt;
|
|
BufferLen -= cnt;
|
|
}
|
|
|
|
if (ldrTgtModNameBufL != 0) {
|
|
/*
|
|
* First, place a '->' in the buffer to delimit the source
|
|
* and target module names. Protect against small buffers...
|
|
*/
|
|
cnt = (USHORT) 2;
|
|
if (cnt > BufferLen)
|
|
cnt = BufferLen;
|
|
RtlMoveMemory(pstring, "->", (ULONG) cnt);
|
|
pstring += (UCHAR) cnt;
|
|
BufferLen -= cnt;
|
|
cnt = ldrTgtModNameBufL;
|
|
if (cnt > BufferLen)
|
|
cnt = BufferLen;
|
|
RtlMoveMemory(pstring, ldrTgtModNameBuf, (ULONG) cnt);
|
|
pstring += (UCHAR) cnt;
|
|
BufferLen -= cnt;
|
|
}
|
|
|
|
/*
|
|
* If errcode == ERROR_PROC_NOT_FOUND, then ldrProcNameBuf has
|
|
* the procedure name. Else if errocode == ERROR_INVALID_ORDINAL
|
|
* then ldrProcNameBuf has the ordinal.
|
|
*/
|
|
if ((errcode == ERROR_PROC_NOT_FOUND)
|
|
|| (errcode == ERROR_INVALID_ORDINAL)) {
|
|
/*
|
|
* First, place a '.' in the buffer to delimit the module
|
|
* and procedure names. Protect against small buffers...
|
|
*/
|
|
cnt = 1;
|
|
if (cnt > BufferLen)
|
|
cnt = BufferLen;
|
|
RtlMoveMemory(pstring, ".", (ULONG) cnt);
|
|
pstring += (UCHAR) cnt;
|
|
BufferLen -= cnt;
|
|
if (errcode == ERROR_PROC_NOT_FOUND) {
|
|
cnt = ldrProcNameBufL;
|
|
if (cnt > BufferLen)
|
|
cnt = BufferLen;
|
|
RtlMoveMemory(pstring, ldrProcNameBuf, (ULONG) cnt);
|
|
pstring += (UCHAR) cnt;
|
|
BufferLen -= cnt;
|
|
}
|
|
else { /* errcode == ERROR_INVALID_ORDINAL */
|
|
pordbuf = _itoa((int) ldrProcNameBuf, ordbuf, 10);
|
|
cnt = (USHORT) strlen(pordbuf);
|
|
if (cnt > BufferLen)
|
|
cnt = BufferLen;
|
|
RtlMoveMemory(pstring, pordbuf, (ULONG) cnt);
|
|
pstring += (UCHAR) cnt;
|
|
BufferLen -= cnt;
|
|
}
|
|
}
|
|
|
|
pErrText->Length = (pErrText->MaximumLength - 1) - BufferLen;
|
|
}
|
|
|
|
#if PMNT
|
|
|
|
BOOLEAN
|
|
ldrSaveErrInfo( errcode )
|
|
int errcode; /* loader error code */
|
|
{
|
|
|
|
if (ldrSaveSrcModNameBufL=ldrSrcModNameBufL) {
|
|
if (!(ldrSaveSrcModNameBuf=
|
|
RtlAllocateHeap(LDRNEHeap, 0, ldrSrcModNameBufL))) {
|
|
KdPrint(("ldrSaveErrInfo() failed\n"));
|
|
return(FALSE);
|
|
}
|
|
strncpy(ldrSaveSrcModNameBuf,ldrSrcModNameBuf,ldrSrcModNameBufL);
|
|
}
|
|
if (ldrSaveTgtModNameBufL=ldrTgtModNameBufL) {
|
|
if (!(ldrSaveTgtModNameBuf=
|
|
RtlAllocateHeap(LDRNEHeap, 0, ldrTgtModNameBufL))){
|
|
KdPrint(("ldrSaveErrInfo() failed\n"));
|
|
return(FALSE);
|
|
}
|
|
strncpy(ldrSaveTgtModNameBuf,ldrTgtModNameBuf,ldrTgtModNameBufL);
|
|
}
|
|
if (errcode==ERROR_PROC_NOT_FOUND) {
|
|
if (ldrSaveProcNameBufL=ldrProcNameBufL) {
|
|
if (!(ldrSaveProcNameBuf=
|
|
RtlAllocateHeap(LDRNEHeap, 0, ldrProcNameBufL))) {
|
|
KdPrint(("ldrSaveErrInfo() failed\n"));
|
|
return(FALSE);
|
|
}
|
|
strncpy(ldrSaveProcNameBuf,ldrProcNameBuf,ldrProcNameBufL);
|
|
}
|
|
}
|
|
else {
|
|
ldrSaveProcNameBuf = ldrProcNameBuf;
|
|
}
|
|
ldrSaveRc = errcode;
|
|
return(TRUE);
|
|
}
|
|
|
|
VOID
|
|
ldrRestoreErrInfo( errcode )
|
|
int *errcode; /* loader error code */
|
|
{
|
|
|
|
if (ldrSrcModNameBufL = ldrSaveSrcModNameBufL) {
|
|
ldrSrcModNameBuf = ldrSaveSrcModNameBuf;
|
|
}
|
|
if (ldrTgtModNameBufL = ldrSaveTgtModNameBufL) {
|
|
ldrTgtModNameBuf = ldrSaveTgtModNameBuf;
|
|
}
|
|
if (ldrSaveRc==ERROR_PROC_NOT_FOUND) {
|
|
ldrProcNameBufL = ldrSaveProcNameBufL;
|
|
}
|
|
ldrProcNameBuf = ldrSaveProcNameBuf;
|
|
*errcode = ldrSaveRc;
|
|
}
|
|
|
|
BOOLEAN
|
|
ldrFreeErrInfo( )
|
|
{
|
|
if (ldrSaveSrcModNameBuf) {
|
|
if (!(RtlFreeHeap(LDRNEHeap, 0, ldrSaveSrcModNameBuf))){
|
|
KdPrint(("ldrFreeErrInfo() failed\n"));
|
|
return(FALSE);
|
|
}
|
|
ldrSaveSrcModNameBuf=NULL;
|
|
}
|
|
if (ldrSaveTgtModNameBuf) {
|
|
if (!(RtlFreeHeap(LDRNEHeap, 0, ldrSaveTgtModNameBuf))){
|
|
KdPrint(("ldrFreeErrInfo() failed\n"));
|
|
return(FALSE);
|
|
}
|
|
ldrSaveTgtModNameBuf=NULL;
|
|
}
|
|
if (ldrSaveRc == ERROR_PROC_NOT_FOUND && ldrSaveProcNameBuf) {
|
|
if (!(RtlFreeHeap(LDRNEHeap, 0, ldrSaveProcNameBuf))){
|
|
KdPrint(("ldrFreeErrInfo() failed\n"));
|
|
return(FALSE);
|
|
}
|
|
ldrSaveProcNameBuf=NULL;
|
|
}
|
|
ldrSaveSrcModNameBufL = ldrSaveTgtModNameBufL = ldrSaveProcNameBufL= 0;
|
|
ldrSaveRc = 0;
|
|
return(TRUE);
|
|
}
|
|
|
|
#endif
|
|
|
|
/***LP load_error - General error handler for new EXE load errors
|
|
*
|
|
* ENTRY errcode - load error code
|
|
* pmte - pointer to mte if it exists
|
|
*
|
|
* EXIT none
|
|
*
|
|
*/
|
|
|
|
void load_error(errcode, pmte)
|
|
int errcode; /* load error code */
|
|
ldrmte_t *pmte; /* pointer to module table entry */
|
|
{
|
|
/*
|
|
* ldrOpen returns ERROR_OPEN_FAILED for non-existent files. This
|
|
* is incorrect with the definition of the error-code. It should
|
|
* be ERROR_FILE_NOT_FOUND instead
|
|
*/
|
|
|
|
if (errcode == ERROR_OPEN_FAILED)
|
|
errcode = ERROR_FILE_NOT_FOUND;
|
|
|
|
ldrWriteErrTxt(errcode);
|
|
}
|
|
|
|
VOID ldrInvalidateDesc(
|
|
SEL Selector // selector to be invalidated
|
|
)
|
|
{
|
|
PROCESS_LDT_INFORMATION LdtInfo;
|
|
NTSTATUS Status;
|
|
|
|
LdtInfo.Start = Selector & 0xfff8;
|
|
LdtInfo.Length = sizeof(LDT_ENTRY);
|
|
|
|
RtlZeroMemory(LdtInfo.LdtEntries, sizeof(LDT_ENTRY));
|
|
|
|
Status = NtSetInformationProcess( CurrentThread->Process->ProcessHandle,
|
|
ProcessLdtInformation,
|
|
&LdtInfo,
|
|
sizeof(PROCESS_LDT_INFORMATION)
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint ("ldrSetDescInfo: Invalid request\n");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ldrTagModuleTree(
|
|
ldrmte_t *pmte
|
|
)
|
|
{
|
|
ldrmte_t **ppmte;
|
|
ULONG lindex;
|
|
ULONG i;
|
|
|
|
pmte->mte_mflags |= INGRAPH;
|
|
|
|
ppmte = (ldrmte_t **) pmte->mte_modptrs;
|
|
for (i = 1; i <= pmte->mte_impmodcnt; i++) {
|
|
/*
|
|
* It is required for 16-bit modules to load the
|
|
* referneced module in reverse order.
|
|
*/
|
|
lindex = pmte->mte_impmodcnt-i;
|
|
|
|
//
|
|
// Check if the referenced module has already been processed.
|
|
// Processing the modules is done in reverse order.
|
|
//
|
|
if ((ppmte[lindex]->mte_mflags & INGRAPH) == 0) {
|
|
ldrTagModuleTree(ppmte[lindex]);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ldrTagModuleTree_USED(
|
|
ldrmte_t *pmte
|
|
)
|
|
{
|
|
ldrmte_t **ppmte;
|
|
ULONG lindex;
|
|
ULONG i;
|
|
|
|
pmte->mte_mflags |= INGRAPH | USED;
|
|
|
|
ppmte = (ldrmte_t **) pmte->mte_modptrs;
|
|
for (i = 1; i <= pmte->mte_impmodcnt; i++) {
|
|
/*
|
|
* It is required for 16-bit modules to load the
|
|
* referneced module in reverse order.
|
|
*/
|
|
lindex = pmte->mte_impmodcnt-i;
|
|
|
|
//
|
|
// Check if the referenced module has already been processed.
|
|
// Processing the modules is done in reverse order.
|
|
//
|
|
if ((ppmte[lindex]->mte_mflags & INGRAPH) == 0) {
|
|
ldrTagModuleTree_USED(ppmte[lindex]);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
ldrUnloadTagedModules(
|
|
IN POS2_PROCESS Process
|
|
)
|
|
{
|
|
ldrmte_t *pmte;
|
|
ldrmte_t *ptmte;
|
|
ldrsmte_t *psmte;
|
|
ldrste_t *pste;
|
|
ULONG i;
|
|
NTSTATUS Status;
|
|
APIRET rc;
|
|
|
|
#if DBG
|
|
IF_OL2_DEBUG ( TRACE ) {
|
|
DbgPrint("OS2LDR: LDRUnloadTagedModules() was called\n");
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Scan loaded module chain for referenced modules
|
|
//
|
|
pmte = mte_h;
|
|
while (pmte != NULL) {
|
|
//
|
|
// skip non tagged modules
|
|
//
|
|
if (((pmte->mte_mflags & INGRAPH) == 0) ||
|
|
((pmte->mte_mflags & (USED | DOSMOD)) != 0)
|
|
) {
|
|
pmte = pmte->mte_link;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Handle the case where the first loaded app failed
|
|
// and DOSCALLS was loaded. Allow to release it.
|
|
//
|
|
if (((pmte->mte_mflags & DOSLIB) != 0) &&
|
|
(!DoscallsLoaded)
|
|
) {
|
|
pmte->mte_usecnt--;
|
|
}
|
|
|
|
//
|
|
// Tagged modules are processed here
|
|
//
|
|
|
|
//
|
|
// Unmap the segments of the current module from the address
|
|
// space of the current process.
|
|
//
|
|
psmte = pmte->mte_swapmte;
|
|
pste = (ldrste_t *)psmte->smte_objtab;
|
|
|
|
for (i = 1; i <= psmte->smte_objcnt; i++, pste++) {
|
|
//
|
|
// If we are terminating an app then no need to unmap the
|
|
// sections from the address space of the terminating process.
|
|
// The section will be unmapped by themself.
|
|
// In fact, trying to unmap will return status of
|
|
// STATUS_PROCESS_IS_TERMINATING
|
|
if (fForceUnmap) {
|
|
Status = NtUnmapViewOfSection(
|
|
CurrentThread->Process->ProcessHandle,
|
|
(PVOID)SELTOFLAT(pste->ste_selector)
|
|
);
|
|
//
|
|
// Error while unmapping resources is acceptable since
|
|
// resources are not mapped when the module is loaded,
|
|
// but we need to try to unmap them in case they were
|
|
// loaded by DosGetResource().
|
|
//
|
|
if ((!NT_SUCCESS(Status)) &&
|
|
(i <= psmte->smte_objcnt - psmte->smte_rsrccnt)
|
|
) {
|
|
#if DBG
|
|
DbgPrint("OS2LDR: ldrUnloadModule(): Unable to unmap a segment form the app, Status=%x\n", Status);
|
|
#endif
|
|
}
|
|
//
|
|
// Invalidate the descriptor of the unmapped section
|
|
//
|
|
ldrInvalidateDesc(pste->ste_selector);
|
|
}
|
|
|
|
//
|
|
// If this was the last module referencing this mte
|
|
// then close the section and its mappings
|
|
//
|
|
if ((pmte->mte_usecnt == 0) &&
|
|
(pste->ste_seghdl != (ulong_t)R2XferSegHandle)
|
|
) {
|
|
Status = NtUnmapViewOfSection(
|
|
NtCurrentProcess(),
|
|
(PVOID)SELTOFLAT(pste->ste_selector)
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint("OS2LDR: ldrUnloadModule(): Unable to self unmap a segment, Status=%x\n", Status);
|
|
#endif
|
|
return(FALSE);
|
|
}
|
|
Status = NtClose((HANDLE)pste->ste_seghdl);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint("OS2LDR: ldrUnloadModule(): Unable to close segment section, Status=%x\n", Status);
|
|
#endif
|
|
return(FALSE);
|
|
}
|
|
//
|
|
// Check if the module has ring 2 segments which have entry points.
|
|
// If yes, delete the call gate entries
|
|
//
|
|
if (((pste->ste_flags & STE_SEGDPL) == STE_RING_2) && // ring 2 segment
|
|
((pste->ste_flags & STE_DATA) == 0) && // code segment
|
|
((pste->ste_flags & STE_CONFORM) == 0) // non conforming
|
|
) {
|
|
ldrEachObjEntry(i, pmte, ldrFreeCallGate, NULL);
|
|
}
|
|
//
|
|
// Don't free the bit map entries of the DOSCALLS selectors
|
|
// as these were not allocated explicity
|
|
//
|
|
if ((pmte->mte_mflags & DOSLIB) == 0) {
|
|
ldrFreeSel(pste->ste_selector, 1);
|
|
}
|
|
}
|
|
}
|
|
ptmte = pmte;
|
|
pmte = pmte->mte_link;
|
|
//
|
|
// If this module is no more referenced, disconnect it from
|
|
// the MTE chain and free its allocated memory
|
|
//
|
|
if (ptmte->mte_usecnt == 0) {
|
|
if (ptmte->mte_sfn != NULL) {
|
|
NtClose(ptmte->mte_sfn);
|
|
}
|
|
rc = Free16BHandle(ptmte->mte_handle);
|
|
ASSERT(rc == NO_ERROR);
|
|
ldrUnlinkMTE(ptmte);
|
|
RtlFreeHeap(LDRNEHeap, 0, ptmte->mte_swapmte);
|
|
RtlFreeHeap(LDRNEHeap, 0, ptmte);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
LDRUnloadExe(
|
|
IN POS2_PROCESS Process
|
|
)
|
|
{
|
|
//
|
|
// Unload the .EXE file
|
|
//
|
|
|
|
ldrmte_t *pmte;
|
|
ldrmte_t *ptmte;
|
|
ldrdld_t *pdld;
|
|
ldrdld_t *prev_pdld;
|
|
ldrdld_t *pcurdld;
|
|
|
|
#if DBG
|
|
IF_OL2_DEBUG ( TRACE ) {
|
|
DbgPrint("OS2LDR: LDRUnloadExe() called for NT process handle %x\n",
|
|
Process->ProcessHandle);
|
|
}
|
|
#endif
|
|
|
|
pmte = (ldrmte_t *)Process->ProcessMTE;
|
|
if (pmte == NULL) {
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// Set the fForceUnmap flag to FALSE so that ldrUnloadTagedModules()
|
|
// does not unmap the app's segments from the app's address space
|
|
// since the app is in a terminating satate
|
|
//
|
|
fForceUnmap = FALSE;
|
|
|
|
//
|
|
// Loop over the DLD chain.
|
|
// For Each entry, tag all referenced DLD modules with the INGRAPH flag
|
|
// The tagged modules will be then unloaded
|
|
//
|
|
pdld = pmte->mte_dldchain;
|
|
prev_pdld = (ldrdld_t *)&pmte->mte_dldchain;
|
|
while (pdld != NULL) {
|
|
if (pdld->Cookie == (ULONG)Process) {
|
|
//
|
|
// Clear the INGRAPH flag of all modules so that we
|
|
// know that this module has already been processed
|
|
//
|
|
ldrClearAllMteFlag(INGRAPH | USED);
|
|
|
|
ldrTagModuleTree(pdld->dld_mteptr);
|
|
|
|
//
|
|
// Remove the DLD entry
|
|
//
|
|
pcurdld = pdld;
|
|
pdld = pdld->dld_next;
|
|
prev_pdld->dld_next = pdld;
|
|
RtlFreeHeap(LDRNEHeap, 0, pcurdld);
|
|
|
|
//
|
|
// Decrement the usecnt of the marked modules
|
|
//
|
|
ptmte = mte_h;
|
|
while (ptmte != NULL) {
|
|
if ((ptmte->mte_mflags & INGRAPH) != 0) {
|
|
ptmte->mte_usecnt--;
|
|
}
|
|
ptmte = ptmte->mte_link;
|
|
}
|
|
|
|
ldrUnloadTagedModules(Process);
|
|
}
|
|
else {
|
|
prev_pdld = pdld;
|
|
pdld = pdld->dld_next;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Clear the INGRAPH flag of all modules so that we
|
|
// know that this module has already been processed
|
|
//
|
|
ldrClearAllMteFlag(INGRAPH | USED);
|
|
|
|
//
|
|
// Tag all referenced modules with the INGRAPH flag
|
|
// The tagged modules will be then unloaded
|
|
//
|
|
ldrTagModuleTree(pmte);
|
|
|
|
//
|
|
// Decrement the usecnt of the marked modules
|
|
//
|
|
ptmte = mte_h;
|
|
while (ptmte != NULL) {
|
|
if ((ptmte->mte_mflags & INGRAPH) != 0) {
|
|
ptmte->mte_usecnt--;
|
|
}
|
|
ptmte = ptmte->mte_link;
|
|
}
|
|
|
|
ldrUnloadTagedModules(Process);
|
|
|
|
#if DBG
|
|
IF_OL2_DEBUG ( MTE ) {
|
|
DbgPrint("\nDumping segmenst after LDRUnloadExe()\n");
|
|
ldrDisplaySegmentTable();
|
|
}
|
|
#endif
|
|
Process->ProcessMTE = NULL;
|
|
return(TRUE);
|
|
}
|
|
|