change a few #ifdefs to allow loading of SYM files for user modules in DBG builds
[reactos.git] / reactos / lib / ntdll / ldr / startup.c
1 /* $Id: startup.c,v 1.60 2004/12/15 03:00:33 royce Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: lib/ntdll/ldr/startup.c
6 * PURPOSE: Process startup for PE executables
7 * PROGRAMMERS: Jean Michault
8 * Rex Jolliff (rex@lvcablemodem.com)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <reactos/config.h>
14 #include <ddk/ntddk.h>
15 #include <windows.h>
16 #include <ntdll/ldr.h>
17 #include <ntdll/rtl.h>
18 #include <csrss/csrss.h>
19 #include <ntdll/csr.h>
20 #include <user32/callback.h>
21 #include <rosrtl/string.h>
22
23 #define NDEBUG
24 #include <ntdll/ntdll.h>
25
26
27 VOID RtlInitializeHeapManager (VOID);
28 VOID LdrpInitLoader(VOID);
29
30 /* GLOBALS *******************************************************************/
31
32
33 extern unsigned int _image_base__;
34
35 static CRITICAL_SECTION PebLock;
36 static CRITICAL_SECTION LoaderLock;
37 static RTL_BITMAP TlsBitMap;
38 PLDR_MODULE ExeModule;
39
40 ULONG NtGlobalFlag = 0;
41
42 NTSTATUS LdrpAttachThread (VOID);
43
44
45 #define VALUE_BUFFER_SIZE 256
46
47 BOOL FASTCALL
48 ReadCompatibilitySetting(HANDLE Key, LPWSTR Value, PKEY_VALUE_PARTIAL_INFORMATION ValueInfo, DWORD *Buffer)
49 {
50 UNICODE_STRING ValueName;
51 NTSTATUS Status;
52 ULONG Length;
53
54 RtlInitUnicodeString(&ValueName, Value);
55 Status = NtQueryValueKey(Key,
56 &ValueName,
57 KeyValuePartialInformation,
58 ValueInfo,
59 VALUE_BUFFER_SIZE,
60 &Length);
61
62 if (!NT_SUCCESS(Status) || (ValueInfo->Type != REG_DWORD))
63 {
64 RtlFreeUnicodeString(&ValueName);
65 return FALSE;
66 }
67 RtlCopyMemory(Buffer, &ValueInfo->Data[0], sizeof(DWORD));
68 RtlFreeUnicodeString(&ValueName);
69 return TRUE;
70 }
71
72 VOID FASTCALL
73 LoadImageFileExecutionOptions(PPEB Peb)
74 {
75 NTSTATUS Status = STATUS_SUCCESS;
76 ULONG Value = 0;
77 UNICODE_STRING ValueString;
78 WCHAR ValueBuffer[64];
79 ULONG ValueSize;
80
81 if (Peb->ProcessParameters &&
82 Peb->ProcessParameters->ImagePathName.Length > 0)
83 {
84 /* global flag */
85 Status = LdrQueryImageFileExecutionOptions (&Peb->ProcessParameters->ImagePathName,
86 L"GlobalFlag",
87 REG_SZ,
88 (PVOID)ValueBuffer,
89 sizeof(ValueBuffer),
90 &ValueSize);
91 if (NT_SUCCESS(Status))
92 {
93 ValueString.Buffer = ValueBuffer + 1;
94 ValueString.Length = ValueSize - 2 * sizeof(WCHAR);
95 ValueString.MaximumLength = sizeof(ValueBuffer);
96 RtlUnicodeStringToInteger(&ValueString, 16, &Value);
97 Peb->NtGlobalFlag |= Value;
98 DPRINT("GlobalFlag: Key='%S', Value=%08x\n", ValueBuffer, Value);
99 }
100 /*
101 * FIXME:
102 * read more options
103 */
104 }
105 NtGlobalFlag = Peb->NtGlobalFlag;
106 }
107
108
109
110
111 BOOL FASTCALL
112 LoadCompatibilitySettings(PPEB Peb)
113 {
114 NTSTATUS Status;
115 HANDLE UserKey = NULL;
116 HANDLE KeyHandle;
117 HANDLE SubKeyHandle;
118 OBJECT_ATTRIBUTES ObjectAttributes;
119 UNICODE_STRING KeyName;
120 UNICODE_STRING ValueName;
121 UCHAR ValueBuffer[VALUE_BUFFER_SIZE];
122 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
123 ULONG Length;
124 DWORD MajorVersion, MinorVersion, BuildNumber, PlatformId,
125 SPMajorVersion, SPMinorVersion= 0;
126
127 if(Peb->ProcessParameters &&
128 (Peb->ProcessParameters->ImagePathName.Length > 0))
129 {
130 Status = RtlOpenCurrentUser(KEY_READ,
131 &UserKey);
132 if (!NT_SUCCESS(Status))
133 {
134 return FALSE;
135 }
136
137 RtlRosInitUnicodeStringFromLiteral(&KeyName,
138 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers");
139
140 InitializeObjectAttributes(&ObjectAttributes,
141 &KeyName,
142 OBJ_CASE_INSENSITIVE,
143 UserKey,
144 NULL);
145
146 Status = NtOpenKey(&KeyHandle,
147 KEY_QUERY_VALUE,
148 &ObjectAttributes);
149
150 if (!NT_SUCCESS(Status))
151 {
152 if (UserKey) NtClose(UserKey);
153 return FALSE;
154 }
155
156 /* query version name for application */
157 ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
158 Status = NtQueryValueKey(KeyHandle,
159 &Peb->ProcessParameters->ImagePathName,
160 KeyValuePartialInformation,
161 ValueBuffer,
162 VALUE_BUFFER_SIZE,
163 &Length);
164
165 if (!NT_SUCCESS(Status) || (ValueInfo->Type != REG_SZ))
166 {
167 NtClose(KeyHandle);
168 if (UserKey) NtClose(UserKey);
169 return FALSE;
170 }
171
172 ValueName.Length = ValueInfo->DataLength;
173 ValueName.MaximumLength = ValueInfo->DataLength;
174 ValueName.Buffer = (PWSTR)ValueInfo->Data;
175
176 /* load version info */
177 InitializeObjectAttributes(&ObjectAttributes,
178 &ValueName,
179 OBJ_CASE_INSENSITIVE,
180 KeyHandle,
181 NULL);
182
183 Status = NtOpenKey(&SubKeyHandle,
184 KEY_QUERY_VALUE,
185 &ObjectAttributes);
186
187 if (!NT_SUCCESS(Status))
188 {
189 NtClose(KeyHandle);
190 if (UserKey) NtClose(UserKey);
191 return FALSE;
192 }
193
194 DPRINT("Loading version information for: %wZ\n", &ValueName);
195
196 /* read settings from registry */
197 if(!ReadCompatibilitySetting(SubKeyHandle, L"MajorVersion", ValueInfo, &MajorVersion))
198 goto finish;
199 if(!ReadCompatibilitySetting(SubKeyHandle, L"MinorVersion", ValueInfo, &MinorVersion))
200 goto finish;
201 if(!ReadCompatibilitySetting(SubKeyHandle, L"BuildNumber", ValueInfo, &BuildNumber))
202 goto finish;
203 if(!ReadCompatibilitySetting(SubKeyHandle, L"PlatformId", ValueInfo, &PlatformId))
204 goto finish;
205
206 /* now assign the settings */
207 Peb->OSMajorVersion = (ULONG)MajorVersion;
208 Peb->OSMinorVersion = (ULONG)MinorVersion;
209 Peb->OSBuildNumber = (USHORT)BuildNumber;
210 Peb->OSPlatformId = (ULONG)PlatformId;
211
212 /* optional service pack version numbers */
213 if(ReadCompatibilitySetting(SubKeyHandle, L"SPMajorVersion", ValueInfo, &SPMajorVersion))
214 Peb->SPMajorVersion = (UCHAR)SPMajorVersion;
215 if(ReadCompatibilitySetting(SubKeyHandle, L"SPMinorVersion", ValueInfo, &SPMinorVersion))
216 Peb->SPMinorVersion = (UCHAR)SPMinorVersion;
217
218 finish:
219 /* we're finished */
220 NtClose(SubKeyHandle);
221 NtClose(KeyHandle);
222 if (UserKey) NtClose(UserKey);
223 return TRUE;
224 }
225 return FALSE;
226 }
227
228
229 /* FUNCTIONS *****************************************************************/
230
231 VOID STDCALL
232 __true_LdrInitializeThunk (ULONG Unknown1,
233 ULONG Unknown2,
234 ULONG Unknown3,
235 ULONG Unknown4)
236 {
237 PIMAGE_NT_HEADERS NTHeaders;
238 PEPFUNC EntryPoint;
239 PIMAGE_DOS_HEADER PEDosHeader;
240 PVOID ImageBase;
241 PPEB Peb;
242 PLDR_MODULE NtModule; // ntdll
243 NLSTABLEINFO NlsTable;
244 WCHAR FullNtDllPath[MAX_PATH];
245
246 DPRINT("LdrInitializeThunk()\n");
247 if (NtCurrentPeb()->Ldr == NULL || NtCurrentPeb()->Ldr->Initialized == FALSE)
248 {
249 Peb = (PPEB)(PEB_BASE);
250 DPRINT("Peb %x\n", Peb);
251 ImageBase = Peb->ImageBaseAddress;
252 DPRINT("ImageBase %x\n", ImageBase);
253 if (ImageBase <= (PVOID)0x1000)
254 {
255 DPRINT("ImageBase is null\n");
256 ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL);
257 }
258
259 /* If MZ header exists */
260 PEDosHeader = (PIMAGE_DOS_HEADER) ImageBase;
261 DPRINT("PEDosHeader %x\n", PEDosHeader);
262 if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC ||
263 PEDosHeader->e_lfanew == 0L ||
264 *(PULONG)((PUCHAR)ImageBase + PEDosHeader->e_lfanew) != IMAGE_PE_MAGIC)
265 {
266 DPRINT1("Image has bad header\n");
267 ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL);
268 }
269
270 /* normalize process parameters */
271 RtlNormalizeProcessParams (Peb->ProcessParameters);
272
273 /* Initialize NLS data */
274 RtlInitNlsTables (Peb->AnsiCodePageData,
275 Peb->OemCodePageData,
276 Peb->UnicodeCaseTableData,
277 &NlsTable);
278 RtlResetRtlTranslations (&NlsTable);
279
280 NTHeaders = (PIMAGE_NT_HEADERS)(ImageBase + PEDosHeader->e_lfanew);
281
282 /* create process heap */
283 RtlInitializeHeapManager();
284 Peb->ProcessHeap = RtlCreateHeap(HEAP_GROWABLE,
285 NULL,
286 NTHeaders->OptionalHeader.SizeOfHeapReserve,
287 NTHeaders->OptionalHeader.SizeOfHeapCommit,
288 NULL,
289 NULL);
290 if (Peb->ProcessHeap == 0)
291 {
292 DPRINT1("Failed to create process heap\n");
293 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
294 }
295
296 /* initalize peb lock support */
297 RtlInitializeCriticalSection (&PebLock);
298 Peb->FastPebLock = &PebLock;
299 Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
300 Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
301
302 /* initialize tls bitmap */
303 RtlInitializeBitMap (&TlsBitMap,
304 Peb->TlsBitmapBits,
305 TLS_MINIMUM_AVAILABLE);
306 Peb->TlsBitmap = &TlsBitMap;
307 Peb->TlsExpansionCounter = TLS_MINIMUM_AVAILABLE;
308
309 /* Initialize table of callbacks for the kernel. */
310 Peb->KernelCallbackTable =
311 RtlAllocateHeap(RtlGetProcessHeap(),
312 0,
313 sizeof(PVOID) * (USER32_CALLBACK_MAXIMUM + 1));
314
315 /* initalize loader lock */
316 RtlInitializeCriticalSection (&LoaderLock);
317 Peb->LoaderLock = &LoaderLock;
318
319 /* create loader information */
320 Peb->Ldr = (PPEB_LDR_DATA)RtlAllocateHeap (Peb->ProcessHeap,
321 0,
322 sizeof(PEB_LDR_DATA));
323 if (Peb->Ldr == NULL)
324 {
325 DPRINT1("Failed to create loader data\n");
326 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
327 }
328 Peb->Ldr->Length = sizeof(PEB_LDR_DATA);
329 Peb->Ldr->Initialized = FALSE;
330 Peb->Ldr->SsHandle = NULL;
331 InitializeListHead(&Peb->Ldr->InLoadOrderModuleList);
332 InitializeListHead(&Peb->Ldr->InMemoryOrderModuleList);
333 InitializeListHead(&Peb->Ldr->InInitializationOrderModuleList);
334
335 /* Load compatibility settings */
336 LoadCompatibilitySettings(Peb);
337
338 /* Load execution options */
339 LoadImageFileExecutionOptions(Peb);
340
341 /* build full ntdll path */
342 wcscpy (FullNtDllPath, SharedUserData->NtSystemRoot);
343 wcscat (FullNtDllPath, L"\\system32\\ntdll.dll");
344
345 /* add entry for ntdll */
346 NtModule = (PLDR_MODULE)RtlAllocateHeap (Peb->ProcessHeap,
347 0,
348 sizeof(LDR_MODULE));
349 if (NtModule == NULL)
350 {
351 DPRINT1("Failed to create loader module entry (NTDLL)\n");
352 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
353 }
354 memset(NtModule, 0, sizeof(LDR_MODULE));
355
356 NtModule->BaseAddress = (PVOID)&_image_base__;
357 NtModule->EntryPoint = 0; /* no entry point */
358 RtlCreateUnicodeString (&NtModule->FullDllName,
359 FullNtDllPath);
360 RtlCreateUnicodeString (&NtModule->BaseDllName,
361 L"ntdll.dll");
362 NtModule->Flags = IMAGE_DLL|ENTRY_PROCESSED;
363
364 NtModule->LoadCount = -1; /* don't unload */
365 NtModule->TlsIndex = -1;
366 NtModule->SectionHandle = NULL;
367 NtModule->CheckSum = 0;
368
369 NTHeaders = RtlImageNtHeader (NtModule->BaseAddress);
370 NtModule->SizeOfImage = NTHeaders->OptionalHeader.SizeOfImage;
371 NtModule->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
372
373 InsertTailList(&Peb->Ldr->InLoadOrderModuleList,
374 &NtModule->InLoadOrderModuleList);
375 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
376 &NtModule->InInitializationOrderModuleList);
377
378 #if defined(DBG) || defined(KDBG)
379
380 LdrpLoadUserModuleSymbols(NtModule);
381
382 #endif /* DBG || KDBG */
383
384 /* add entry for executable (becomes first list entry) */
385 ExeModule = (PLDR_MODULE)RtlAllocateHeap (Peb->ProcessHeap,
386 0,
387 sizeof(LDR_MODULE));
388 if (ExeModule == NULL)
389 {
390 DPRINT1("Failed to create loader module infomation\n");
391 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
392 }
393 ExeModule->BaseAddress = Peb->ImageBaseAddress;
394
395 if ((Peb->ProcessParameters == NULL) ||
396 (Peb->ProcessParameters->ImagePathName.Length == 0))
397 {
398 DPRINT1("Failed to access the process parameter block\n");
399 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
400 }
401
402 RtlCreateUnicodeString(&ExeModule->FullDllName,
403 Peb->ProcessParameters->ImagePathName.Buffer);
404 RtlCreateUnicodeString(&ExeModule->BaseDllName,
405 wcsrchr(ExeModule->FullDllName.Buffer, L'\\') + 1);
406
407 DPRINT("BaseDllName '%wZ' FullDllName '%wZ'\n",
408 &ExeModule->BaseDllName,
409 &ExeModule->FullDllName);
410
411 ExeModule->Flags = ENTRY_PROCESSED;
412 ExeModule->LoadCount = -1; /* don't unload */
413 ExeModule->TlsIndex = -1;
414 ExeModule->SectionHandle = NULL;
415 ExeModule->CheckSum = 0;
416
417 NTHeaders = RtlImageNtHeader (ExeModule->BaseAddress);
418 ExeModule->SizeOfImage = NTHeaders->OptionalHeader.SizeOfImage;
419 ExeModule->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
420
421 InsertHeadList(&Peb->Ldr->InLoadOrderModuleList,
422 &ExeModule->InLoadOrderModuleList);
423
424 LdrpInitLoader();
425
426 #if defined(DBG) || defined(KDBG)
427
428 LdrpLoadUserModuleSymbols(ExeModule);
429
430 #endif /* DBG || KDBG */
431
432 EntryPoint = LdrPEStartup((PVOID)ImageBase, NULL, NULL, NULL);
433 ExeModule->EntryPoint = (ULONG)EntryPoint;
434
435 /* all required dlls are loaded now */
436 Peb->Ldr->Initialized = TRUE;
437
438 /* Check before returning that we can run the image safely. */
439 if (EntryPoint == NULL)
440 {
441 DPRINT1("Failed to initialize image\n");
442 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
443 }
444 }
445 /* attach the thread */
446 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
447 LdrpAttachThread();
448 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
449 }
450
451 /* EOF */