#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 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); }