+#if defined(DBG) || defined(KDBG)
+
+VOID
+LdrpLoadUserModuleSymbols(PLDR_MODULE LdrModule)
+{
+ NtSystemDebugControl(
+ DebugDbgLoadSymbols,
+ (PVOID)LdrModule,
+ 0,
+ NULL,
+ 0,
+ NULL);
+}
+
+#endif /* DBG || KDBG */
+
+static inline LONG LdrpDecrementLoadCount(PLDR_MODULE Module, BOOL Locked)
+{
+ LONG LoadCount;
+ if (!Locked)
+ {
+ RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
+ }
+ LoadCount = Module->LoadCount;
+ if (Module->LoadCount > 0)
+ {
+ Module->LoadCount--;
+ }
+ if (!Locked)
+ {
+ RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+ }
+ return LoadCount;
+}
+
+static inline LONG LdrpIncrementLoadCount(PLDR_MODULE Module, BOOL Locked)
+{
+ LONG LoadCount;
+ if (!Locked)
+ {
+ RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
+ }
+ LoadCount = Module->LoadCount;
+ if (Module->LoadCount >= 0)
+ {
+ Module->LoadCount++;
+ }
+ if (!Locked)
+ {
+ RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+ }
+ return LoadCount;
+}
+
+static inline VOID LdrpAcquireTlsSlot(PLDR_MODULE Module, ULONG Size, BOOL Locked)
+{
+ if (!Locked)
+ {
+ RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
+ }
+ Module->TlsIndex = (SHORT)LdrpTlsCount;
+ LdrpTlsCount++;
+ LdrpTlsSize += Size;
+ if (!Locked)
+ {
+ RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+ }
+}
+
+static inline VOID LdrpTlsCallback(PLDR_MODULE Module, ULONG dwReason)
+{
+ PIMAGE_TLS_CALLBACK TlsCallback;
+ if (Module->TlsIndex >= 0 && Module->LoadCount == -1)
+ {
+ TlsCallback = LdrpTlsArray[Module->TlsIndex].TlsAddressOfCallBacks;
+ if (TlsCallback)
+ {
+ while (*TlsCallback)
+ {
+ TRACE_LDR("%wZ - Calling tls callback at %x\n",
+ &Module->BaseDllName, TlsCallback);
+ TlsCallback(Module->BaseAddress, dwReason, NULL);
+ TlsCallback++;
+ }
+ }
+ }
+}
+
+static BOOL LdrpCallDllEntry(PLDR_MODULE Module, DWORD dwReason, PVOID lpReserved)
+{
+ if (!(Module->Flags & IMAGE_DLL) ||
+ Module->EntryPoint == 0)
+ {
+ return TRUE;
+ }
+ LdrpTlsCallback(Module, dwReason);
+ return ((PDLLMAIN_FUNC)Module->EntryPoint)(Module->BaseAddress, dwReason, lpReserved);
+}
+
+static NTSTATUS
+LdrpInitializeTlsForThread(VOID)
+{
+ PVOID* TlsPointers;
+ PTLS_DATA TlsInfo;
+ PVOID TlsData;
+ ULONG i;
+
+ DPRINT("LdrpInitializeTlsForThread() called for %wZ\n", &ExeModule->BaseDllName);
+
+ if (LdrpTlsCount > 0)
+ {
+ TlsPointers = RtlAllocateHeap(RtlGetProcessHeap(),
+ 0,
+ LdrpTlsCount * sizeof(PVOID) + LdrpTlsSize);
+ if (TlsPointers == NULL)
+ {
+ DPRINT1("failed to allocate thread tls data\n");
+ return STATUS_NO_MEMORY;
+ }
+
+ TlsData = (PVOID)TlsPointers + LdrpTlsCount * sizeof(PVOID);
+ NtCurrentTeb()->ThreadLocalStoragePointer = TlsPointers;
+
+ TlsInfo = LdrpTlsArray;
+ for (i = 0; i < LdrpTlsCount; i++, TlsInfo++)
+ {
+ TRACE_LDR("Initialize tls data for %wZ\n", &TlsInfo->Module->BaseDllName);
+ TlsPointers[i] = TlsData;
+ if (TlsInfo->TlsDataSize)
+ {
+ memcpy(TlsData, TlsInfo->StartAddressOfRawData, TlsInfo->TlsDataSize);
+ TlsData += TlsInfo->TlsDataSize;
+ }
+ if (TlsInfo->TlsZeroSize)
+ {
+ memset(TlsData, 0, TlsInfo->TlsZeroSize);
+ TlsData += TlsInfo->TlsZeroSize;
+ }
+ }
+ }
+ DPRINT("LdrpInitializeTlsForThread() done\n");
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+LdrpInitializeTlsForProccess(VOID)
+{
+ PLIST_ENTRY ModuleListHead;
+ PLIST_ENTRY Entry;
+ PLDR_MODULE Module;
+ PIMAGE_TLS_DIRECTORY TlsDirectory;
+ PTLS_DATA TlsData;
+
+ DPRINT("LdrpInitializeTlsForProccess() called for %wZ\n", &ExeModule->BaseDllName);
+
+ if (LdrpTlsCount > 0)
+ {
+ LdrpTlsArray = RtlAllocateHeap(RtlGetProcessHeap(),
+ 0,
+ LdrpTlsCount * sizeof(TLS_DATA));
+ if (LdrpTlsArray == NULL)
+ {
+ DPRINT1("Failed to allocate global tls data\n");
+ return STATUS_NO_MEMORY;
+ }
+
+ ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
+ Entry = ModuleListHead->Flink;
+ while (Entry != ModuleListHead)
+ {
+ Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
+ if (Module->LoadCount == -1 &&
+ Module->TlsIndex >= 0)
+ {
+ TlsDirectory = (PIMAGE_TLS_DIRECTORY)
+ RtlImageDirectoryEntryToData(Module->BaseAddress,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_TLS,
+ NULL);
+ assert(Module->TlsIndex < LdrpTlsCount);
+ TlsData = &LdrpTlsArray[Module->TlsIndex];
+ TlsData->StartAddressOfRawData = (PVOID)TlsDirectory->StartAddressOfRawData;
+ TlsData->TlsDataSize = TlsDirectory->EndAddressOfRawData - TlsDirectory->StartAddressOfRawData;
+ TlsData->TlsZeroSize = TlsDirectory->SizeOfZeroFill;
+ if (TlsDirectory->AddressOfCallBacks)
+ TlsData->TlsAddressOfCallBacks = *TlsDirectory->AddressOfCallBacks;
+ else
+ TlsData->TlsAddressOfCallBacks = NULL;
+ TlsData->Module = Module;
+#if 0
+ DbgPrint("TLS directory for %wZ\n", &Module->BaseDllName);
+ DbgPrint("StartAddressOfRawData: %x\n", TlsDirectory->StartAddressOfRawData);
+ DbgPrint("EndAddressOfRawData: %x\n", TlsDirectory->EndAddressOfRawData);
+ DbgPrint("SizeOfRawData: %d\n", TlsDirectory->EndAddressOfRawData - TlsDirectory->StartAddressOfRawData);
+ DbgPrint("AddressOfIndex: %x\n", TlsDirectory->AddressOfIndex);
+ DbgPrint("AddressOfCallBacks: %x (%x)\n", TlsDirectory->AddressOfCallBacks, *TlsDirectory->AddressOfCallBacks);
+ DbgPrint("SizeOfZeroFill: %d\n", TlsDirectory->SizeOfZeroFill);
+ DbgPrint("Characteristics: %x\n", TlsDirectory->Characteristics);
+#endif
+ /*
+ * FIXME:
+ * Is this region allways writable ?
+ */
+ *(PULONG)TlsDirectory->AddressOfIndex = Module->TlsIndex;
+ CHECKPOINT1;
+ }
+ Entry = Entry->Flink;
+ }
+ }
+ DPRINT("LdrpInitializeTlsForProccess() done\n");
+ return STATUS_SUCCESS;
+}
+
+VOID
+LdrpInitLoader(VOID)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING LinkTarget;
+ UNICODE_STRING Name;
+ HANDLE LinkHandle;
+ ULONG Length;
+ NTSTATUS Status;
+
+ DPRINT("LdrpInitLoader() called for %wZ\n", &ExeModule->BaseDllName);
+
+ /* Get handle to the 'KnownDlls' directory */
+ RtlInitUnicodeString(&Name,
+ L"\\KnownDlls");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &Name,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = NtOpenDirectoryObject(&LdrpKnownDllsDirHandle,
+ DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
+ &ObjectAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("NtOpenDirectoryObject() failed (Status %lx)\n", Status);
+ LdrpKnownDllsDirHandle = NULL;
+ return;
+ }
+
+ /* Allocate target name string */
+ LinkTarget.Length = 0;
+ LinkTarget.MaximumLength = MAX_PATH * sizeof(WCHAR);
+ LinkTarget.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
+ 0,
+ MAX_PATH * sizeof(WCHAR));
+ if (LinkTarget.Buffer == NULL)
+ {
+ NtClose(LdrpKnownDllsDirHandle);
+ LdrpKnownDllsDirHandle = NULL;
+ return;
+ }
+
+ RtlInitUnicodeString(&Name,
+ L"KnownDllPath");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &Name,
+ OBJ_CASE_INSENSITIVE | OBJ_OPENLINK,
+ LdrpKnownDllsDirHandle,
+ NULL);
+ Status = NtOpenSymbolicLinkObject(&LinkHandle,
+ SYMBOLIC_LINK_ALL_ACCESS,
+ &ObjectAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ RtlFreeUnicodeString(&LinkTarget);
+ NtClose(LdrpKnownDllsDirHandle);
+ LdrpKnownDllsDirHandle = NULL;
+ return;
+ }
+
+ Status = NtQuerySymbolicLinkObject(LinkHandle,
+ &LinkTarget,
+ &Length);
+ NtClose(LinkHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ RtlFreeUnicodeString(&LinkTarget);
+ NtClose(LdrpKnownDllsDirHandle);
+ LdrpKnownDllsDirHandle = NULL;
+ }
+
+ RtlCreateUnicodeString(&LdrpKnownDllPath,
+ LinkTarget.Buffer);
+
+ RtlFreeUnicodeString(&LinkTarget);
+
+ DPRINT("LdrpInitLoader() done\n");
+}
+
+