* PURPOSE: Process startup for PE executables
* PROGRAMMERS: Jean Michault
* Rex Jolliff (rex@lvcablemodem.com)
+ * Michael Martin
*/
/*
/* GLOBALS *******************************************************************/
#ifdef NDEBUG
-#if defined(__GNUC__)
-#define TRACE_LDR(args...) if (RtlGetNtGlobalFlags() & FLG_SHOW_LDR_SNAPS) { DbgPrint("(LDR:%s:%d) ",__FILE__,__LINE__); DbgPrint(args); }
-#elif defined(_MSC_VER)
-#define TRACE_LDR(args, ...) if (RtlGetNtGlobalFlags() & FLG_SHOW_LDR_SNAPS) { DbgPrint("(LDR:%s:%d) ",__FILE__,__LINE__); DbgPrint(__VA_ARGS__); }
-#endif /* __GNUC__ */
-#else
-#define TRACE_LDR(args...) do { DbgPrint("(LDR:%s:%d) ",__FILE__,__LINE__); DbgPrint(args); } while(0)
+#define TRACE_LDR(...) if (RtlGetNtGlobalFlags() & FLG_SHOW_LDR_SNAPS) { DbgPrint("(LDR:%s:%d) ",__FILE__,__LINE__); DbgPrint(__VA_ARGS__); }
#endif
typedef struct _TLS_DATA
OUT PVOID *BaseAddress OPTIONAL);
static NTSTATUS LdrpAttachProcess(VOID);
static VOID LdrpDetachProcess(BOOLEAN UnloadAll);
+static NTSTATUS LdrpUnloadModule(PLDR_DATA_TABLE_ENTRY Module, BOOLEAN Unload);
-/* FUNCTIONS *****************************************************************/
-
-#if defined(DBG) || defined(KDBG)
-
-VOID
-LdrpLoadUserModuleSymbols(PLDR_DATA_TABLE_ENTRY LdrModule)
-{
- NtSystemDebugControl(
- SysDbgQueryVersion,
- (PVOID)LdrModule,
- 0,
- NULL,
- 0,
- NULL);
-}
+NTSTATUS find_actctx_dll( LPCWSTR libname, WCHAR *fulldosname );
+NTSTATUS create_module_activation_context( LDR_DATA_TABLE_ENTRY *module );
-#endif /* DBG || KDBG */
+/* FUNCTIONS *****************************************************************/
BOOLEAN
LdrMappedAsDataFile(PVOID *BaseAddress)
IN BOOLEAN MapAsDataFile,
OUT PHANDLE SectionHandle)
{
- WCHAR SearchPathBuffer[MAX_PATH];
+ WCHAR *SearchPathBuffer = NULL;
+ WCHAR *ImagePathNameBufferPtr = NULL;
WCHAR DosName[MAX_PATH];
UNICODE_STRING FullNtFileName;
+ UNICODE_STRING PathEnvironmentVar_U;
+ UNICODE_STRING PathName_U;
OBJECT_ATTRIBUTES FileObjectAttributes;
HANDLE FileHandle;
char BlockBuffer [1024];
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
ULONG len;
+ ULONG ImagePathLen;
DPRINT("LdrpMapDllImageFile() called\n");
if (SearchPath == NULL)
{
/* get application running path */
+ ImagePathNameBufferPtr = NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer;
- wcscpy (SearchPathBuffer, NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer);
+ /* Length of ImagePathName */
+ ImagePathLen = wcslen(ImagePathNameBufferPtr);
- len = wcslen (SearchPathBuffer);
+ /* Subtract application name leaveing only the directory length */
+ while (ImagePathLen && ImagePathNameBufferPtr[ImagePathLen - 1] != L'\\')
+ ImagePathLen--;
- while (len && SearchPathBuffer[len - 1] != L'\\')
- len--;
+ /* Length of directory + semicolon */
+ len = ImagePathLen + 1;
- if (len) SearchPathBuffer[len-1] = L'\0';
+ /* Length of SystemRoot + "//system32" + semicolon*/
+ len += wcslen(SharedUserData->NtSystemRoot) + 10;
+ /* Length of SystemRoot + semicolon */
+ len += wcslen(SharedUserData->NtSystemRoot) + 1;
- wcscat (SearchPathBuffer, L";");
+ RtlInitUnicodeString (&PathName_U, L"PATH");
+ PathEnvironmentVar_U.Length = 0;
+ PathEnvironmentVar_U.MaximumLength = 0;
+ PathEnvironmentVar_U.Buffer = NULL;
+
+ /* Get the path environment variable */
+ Status = RtlQueryEnvironmentVariable_U(NULL, &PathName_U, &PathEnvironmentVar_U);
+ /* Check that valid information was returned */
+ if ((Status == STATUS_BUFFER_TOO_SMALL) && (PathEnvironmentVar_U.Length > 0))
+ {
+ /* Allocate memory for the path env var */
+ PathEnvironmentVar_U.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, PathEnvironmentVar_U.Length + sizeof(WCHAR));
+ if (!PathEnvironmentVar_U.Buffer)
+ {
+ DPRINT1("Fatal! Out of Memory!!\n");
+ return STATUS_NO_MEMORY;
+ }
+ PathEnvironmentVar_U.MaximumLength = PathEnvironmentVar_U.Length + sizeof(WCHAR);
+
+ /* Retry */
+ Status = RtlQueryEnvironmentVariable_U(NULL, &PathName_U, &PathEnvironmentVar_U);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Unable to get path environment string!\n");
+ ASSERT(FALSE);
+ }
+ /* Length of path evn var + semicolon */
+ len += (PathEnvironmentVar_U.Length / sizeof(WCHAR)) + 1;
+ }
+
+ /* Allocate the size needed to hold all the above paths + period */
+ SearchPathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, (len + 2) * sizeof(WCHAR));
+ if (!SearchPathBuffer)
+ {
+ DPRINT1("Fatal! Out of Memory!!\n");
+ return STATUS_NO_MEMORY;
+ }
+
+ wcsncpy(SearchPathBuffer, ImagePathNameBufferPtr, ImagePathLen);
+ wcscat (SearchPathBuffer, L";");
wcscat (SearchPathBuffer, SharedUserData->NtSystemRoot);
wcscat (SearchPathBuffer, L"\\system32;");
wcscat (SearchPathBuffer, SharedUserData->NtSystemRoot);
- wcscat (SearchPathBuffer, L";.");
+ wcscat (SearchPathBuffer, L";");
+
+ if (PathEnvironmentVar_U.Buffer)
+ {
+ wcscat (SearchPathBuffer, PathEnvironmentVar_U.Buffer);
+ wcscat (SearchPathBuffer, L";");
+ RtlFreeHeap(RtlGetProcessHeap(), 0, PathEnvironmentVar_U.Buffer);
+ }
+ wcscat (SearchPathBuffer, L".");
SearchPath = SearchPathBuffer;
}
MAX_PATH,
DosName,
NULL) == 0)
- return STATUS_DLL_NOT_FOUND;
+ {
+ /* try to find active context dll */
+ Status = find_actctx_dll(DllName->Buffer, DosName);
+ if(Status == STATUS_SUCCESS)
+ DPRINT("found %S for %S\n", DosName,DllName->Buffer);
+ else
+ return STATUS_DLL_NOT_FOUND;
+ }
if (!RtlDosPathNameToNtPathName_U (DosName,
&FullNtFileName,
NULL,
NULL))
+ {
+ DPRINT("Dll %wZ not found!\n", DllName);
return STATUS_DLL_NOT_FOUND;
+ }
DPRINT("FullNtFileName %wZ\n", &FullNtFileName);
{
NTSTATUS Status;
PLDR_DATA_TABLE_ENTRY Module;
-
+ ULONG_PTR cookie;
PPEB Peb = NtCurrentPeb();
- TRACE_LDR("LdrLoadDll, loading %wZ%s%S\n",
+ TRACE_LDR("LdrLoadDll loading %wZ%S%S with flags %d\n",
Name,
SearchPath ? L" from " : L"",
- SearchPath ? SearchPath : L"");
+ SearchPath ? SearchPath : L"",
+ LoadFlags ? *LoadFlags : 0);
Status = LdrpLoadModule(SearchPath, LoadFlags ? *LoadFlags : 0, Name, &Module, BaseAddress);
if (NT_SUCCESS(Status) &&
(!LoadFlags || 0 == (*LoadFlags & LOAD_LIBRARY_AS_DATAFILE)))
{
+ if (!create_module_activation_context( Module ))
+ {
+ RtlActivateActivationContext(0, Module->EntryPointActivationContext, &cookie);
+ }
+
if (!(Module->Flags & LDRP_PROCESS_ATTACH_CALLED))
{
RtlEnterCriticalSection(Peb->LoaderLock);
Status = LdrpAttachProcess();
RtlLeaveCriticalSection(Peb->LoaderLock);
}
+ if (Module->EntryPointActivationContext) RtlDeactivateActivationContext(0, cookie);
}
if ((!Module) && (NT_SUCCESS(Status)))
ULONG Count, ProtectSize, OldProtect, OldProtect2;
PVOID Page, ProtectPage, ProtectPage2;
PUSHORT TypeOffset;
- ULONG_PTR Delta;
+ LONG_PTR Delta;
NTSTATUS Status;
if (NTHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
if (Load && !NT_SUCCESS(Status))
{
Status = LdrpLoadModule(SearchPath,
- 0,
+ 0,
&DllName,
Module,
- NULL);
+ NULL);
if (NT_SUCCESS(Status))
{
Status = LdrFindEntryForName (&DllName, Module, FALSE);
if (!NT_SUCCESS(Status))
{
ULONG ErrorResponse;
- ULONG_PTR ErrorParameter = (ULONG_PTR)&DllName;
+ ULONG_PTR ErrorParameter = (ULONG_PTR)&AnsiDllName;
DPRINT1("failed to load %wZ\n", &DllName);
+
NtRaiseHardError(STATUS_DLL_NOT_FOUND,
1,
1,
IATSize++;
}
+ /* No need to fixup anything if IAT is empty */
+ if (IATSize == 0) return STATUS_SUCCESS;
+
/* Unprotect the region we are about to write into. */
IATBase = (PVOID)ImportAddressList;
IATSize *= sizeof(PVOID*);
PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent;
PIMAGE_TLS_DIRECTORY TlsDirectory;
ULONG TlsSize = 0;
- NTSTATUS Status;
+ NTSTATUS Status = STATUS_SUCCESS;
PLDR_DATA_TABLE_ENTRY ImportedModule;
PCHAR ImportedName;
PWSTR ModulePath;
ULONG Size;
+ ULONG_PTR cookie;
DPRINT("LdrFixupImports(SearchPath %S, Module %p)\n", SearchPath, Module);
}
}
+ if (!create_module_activation_context( Module ))
+ {
+ if (Module->EntryPointActivationContext == NULL)
+ {
+ DPRINT("EntryPointActivationContext has not be allocated\n");
+ DPRINT("Module->DllBaseName %wZ\n", Module->BaseDllName);
+ }
+ RtlActivateActivationContext( 0, Module->EntryPointActivationContext, &cookie );
+ }
+
/*
* Process each import module.
*/
if (!NT_SUCCESS(Status))
{
DPRINT1("failed to load %s\n", ImportedName);
- return Status;
+ break;
}
Success:
if (Module == ImportedModule)
if (!NT_SUCCESS(Status))
{
DPRINT1("failed to import %s\n", ImportedName);
- return Status;
+ break;
}
ImportModuleDirectoryCurrent++;
}
+
+ if (!NT_SUCCESS(Status))
+ {
+ NTSTATUS errorStatus = Status;
+
+ while (ImportModuleDirectoryCurrent >= ImportModuleDirectory)
+ {
+ ImportedName = (PCHAR)Module->DllBase + ImportModuleDirectoryCurrent->Name;
+
+ Status = LdrpGetOrLoadModule(NULL, ImportedName, &ImportedModule, FALSE);
+ if (NT_SUCCESS(Status) && Module != ImportedModule)
+ {
+ Status = LdrpUnloadModule(ImportedModule, FALSE);
+ if (!NT_SUCCESS(Status)) DPRINT1("unable to unload %s\n", ImportedName);
+ }
+ ImportModuleDirectoryCurrent--;
+ }
+ return errorStatus;
+ }
}
if (TlsDirectory && TlsSize > 0)
LdrpAcquireTlsSlot(Module, TlsSize, FALSE);
}
+ if (Module->EntryPointActivationContext) RtlDeactivateActivationContext( 0, cookie );
+
return STATUS_SUCCESS;
}
PIMAGE_DOS_HEADER DosHeader;
PIMAGE_NT_HEADERS NTHeaders;
PLDR_DATA_TABLE_ENTRY tmpModule;
+ PVOID ActivationContextStack;
DPRINT("LdrPEStartup(ImageBase %p SectionHandle %p)\n",
ImageBase, SectionHandle);
(*Module)->Flags |= LDRP_IMAGE_NOT_AT_BASE;
}
+ /* Allocate memory for the ActivationContextStack */
+ /* FIXME: Verify RtlAllocateActivationContextStack behavior */
+ Status = RtlAllocateActivationContextStack(&ActivationContextStack);
+ if (NT_SUCCESS(Status))
+ {
+ DPRINT("ActivationContextStack %x\n",ActivationContextStack);
+ DPRINT("ActiveFrame %x\n", ((PACTIVATION_CONTEXT_STACK)ActivationContextStack)->ActiveFrame);
+ NtCurrentTeb()->ActivationContextStackPointer = ActivationContextStack;
+ NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = NULL;
+ }
+ else
+ DPRINT1("Warning: Unable to allocate ActivationContextStack\n");
+
/*
* If the DLL's imports symbols from other
* modules, fixup the imported calls entry points.
/* Map the dll into the process */
ViewSize = 0;
ImageBase = 0;
- ArbitraryUserPointer = NtCurrentTeb()->Tib.ArbitraryUserPointer;
- NtCurrentTeb()->Tib.ArbitraryUserPointer = FullDosName.Buffer;
+ ArbitraryUserPointer = NtCurrentTeb()->NtTib.ArbitraryUserPointer;
+ NtCurrentTeb()->NtTib.ArbitraryUserPointer = FullDosName.Buffer;
Status = NtMapViewOfSection(SectionHandle,
NtCurrentProcess(),
&ImageBase,
ViewShare,
0,
PAGE_READONLY);
- NtCurrentTeb()->Tib.ArbitraryUserPointer = ArbitraryUserPointer;
+ NtCurrentTeb()->NtTib.ArbitraryUserPointer = ArbitraryUserPointer;
if (!NT_SUCCESS(Status))
{
DPRINT1("map view of section failed (Status 0x%08lx)\n", Status);
if (!NT_SUCCESS(Status))
{
DPRINT1("LdrFixupImports failed for %wZ, status=%x\n", &(*Module)->BaseDllName, Status);
+ NtUnmapViewOfSection (NtCurrentProcess (), ImageBase);
+ NtClose (SectionHandle);
+ RtlFreeUnicodeString (&FullDosName);
+ RtlFreeUnicodeString (&(*Module)->FullDllName);
+ RtlFreeUnicodeString (&(*Module)->BaseDllName);
+ RemoveEntryList (&(*Module)->InLoadOrderLinks);
+ RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
return Status;
}
-#if defined(DBG) || defined(KDBG)
- LdrpLoadUserModuleSymbols(*Module);
-#endif /* DBG || KDBG */
+
RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
&(*Module)->InInitializationOrderModuleList);
PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent;
PCHAR ImportedName;
PLDR_DATA_TABLE_ENTRY ImportedModule;
- NTSTATUS Status;
+ NTSTATUS Status = 0;
LONG LoadCount;
ULONG Size;
OUT PULONG Disposition OPTIONAL,
OUT PULONG Cookie OPTIONAL)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ NTSTATUS Status;
+ BOOLEAN Ret;
+ BOOLEAN CookieSet = FALSE;
+
+ if ((Flags != 0x01) && (Flags != 0x02))
+ return STATUS_INVALID_PARAMETER_1;
+
+ if (!Cookie) return STATUS_INVALID_PARAMETER_3;
+
+ /* Set some defaults for failure while verifying params */
+ _SEH2_TRY
+ {
+ *Cookie = 0;
+ CookieSet = TRUE;
+ if (Disposition) *Disposition = 0;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (CookieSet)
+ Status = STATUS_INVALID_PARAMETER_3;
+ else
+ Status = STATUS_INVALID_PARAMETER_2;
+ }
+ _SEH2_END;
+
+ if (Flags == 0x01)
+ {
+ DPRINT1("Warning: Reporting errors with exception not supported yet!\n");
+ RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
+ Status = STATUS_SUCCESS;
+
+ }
+ else
+ {
+ if (!Disposition) return STATUS_INVALID_PARAMETER_2;
+
+ Ret = RtlTryEnterCriticalSection(NtCurrentPeb()->LoaderLock);
+
+ if (Ret)
+ *Disposition = 0x01;
+ else
+ *Disposition = 0x02;
+
+ Status = STATUS_SUCCESS;
+ }
+
+ /* FIXME: Cookie is based on part of the thread id */
+ *Cookie = (ULONG)NtCurrentTeb()->RealClientId.UniqueThread;
+ return Status;
}
NTSTATUS
LdrUnlockLoaderLock(IN ULONG Flags,
IN ULONG Cookie OPTIONAL)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ if (Flags != 0x01)
+ return STATUS_INVALID_PARAMETER_1;
+
+ if (Cookie != (ULONG)NtCurrentTeb()->RealClientId.UniqueThread)
+ return STATUS_INVALID_PARAMETER_2;
+
+ RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+
+ return STATUS_SUCCESS;
}
BOOLEAN