Merge trunk head (r43756)
[reactos.git] / reactos / dll / ntdll / rtl / libsupp.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NT User-Mode DLL
4 * FILE: lib/ntdll/rtl/libsup.c
5 * PURPOSE: RTL Support Routines
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Gunnar Dalsnes
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntdll.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 SIZE_T RtlpAllocDeallocQueryBufferSize = PAGE_SIZE;
17 PTEB LdrpTopLevelDllBeingLoadedTeb = NULL;
18 #define IMAGE_DOS_MAGIC 0x5a4d
19 #define IMAGE_PE_MAGIC 0x00004550
20
21 /* FUNCTIONS ***************************************************************/
22
23 #ifndef _M_AMD64
24 // FIXME: Why "Not implemented"???
25 /*
26 * @implemented
27 */
28 ULONG
29 NTAPI
30 RtlWalkFrameChain(OUT PVOID *Callers,
31 IN ULONG Count,
32 IN ULONG Flags)
33 {
34 /* Not implemented for user-mode */
35 return 0;
36 }
37 #endif
38
39 BOOLEAN
40 NTAPI
41 RtlpCheckForActiveDebugger(VOID)
42 {
43 /* Return the flag in the PEB */
44 return NtCurrentPeb()->BeingDebugged;
45 }
46
47 BOOLEAN
48 NTAPI
49 RtlpSetInDbgPrint(IN BOOLEAN NewValue)
50 {
51 /* If we're setting it to false, do it and return */
52 if (NewValue == FALSE)
53 {
54 NtCurrentTeb()->InDbgPrint = FALSE;
55 return FALSE;
56 }
57
58 /* Setting to true; check if it's not already */
59 if (NtCurrentTeb()->InDbgPrint) return TRUE;
60
61 /* Set it and return */
62 NtCurrentTeb()->InDbgPrint = TRUE;
63 return FALSE;
64 }
65
66 KPROCESSOR_MODE
67 NTAPI
68 RtlpGetMode()
69 {
70 return UserMode;
71 }
72
73 /*
74 * @implemented
75 */
76 PPEB
77 NTAPI
78 RtlGetCurrentPeb(VOID)
79 {
80 return NtCurrentPeb();
81 }
82
83 /*
84 * @implemented
85 */
86 VOID NTAPI
87 RtlAcquirePebLock(VOID)
88 {
89 PPEB Peb = NtCurrentPeb ();
90 Peb->FastPebLockRoutine (Peb->FastPebLock);
91 }
92
93 /*
94 * @implemented
95 */
96 VOID NTAPI
97 RtlReleasePebLock(VOID)
98 {
99 PPEB Peb = NtCurrentPeb ();
100 Peb->FastPebUnlockRoutine (Peb->FastPebLock);
101 }
102
103 /*
104 * @implemented
105 */
106 ULONG
107 NTAPI
108 RtlGetNtGlobalFlags(VOID)
109 {
110 PPEB pPeb = NtCurrentPeb();
111 return pPeb->NtGlobalFlag;
112 }
113
114 NTSTATUS
115 NTAPI
116 RtlDeleteHeapLock(
117 PRTL_CRITICAL_SECTION CriticalSection)
118 {
119 return RtlDeleteCriticalSection(CriticalSection);
120 }
121
122 NTSTATUS
123 NTAPI
124 RtlEnterHeapLock(
125 PRTL_CRITICAL_SECTION CriticalSection)
126 {
127 return RtlEnterCriticalSection(CriticalSection);
128 }
129
130 NTSTATUS
131 NTAPI
132 RtlInitializeHeapLock(
133 PRTL_CRITICAL_SECTION CriticalSection)
134 {
135 return RtlInitializeCriticalSection(CriticalSection);
136 }
137
138 NTSTATUS
139 NTAPI
140 RtlLeaveHeapLock(
141 PRTL_CRITICAL_SECTION CriticalSection)
142 {
143 return RtlLeaveCriticalSection(CriticalSection );
144 }
145
146 PVOID
147 NTAPI
148 RtlpAllocateMemory(UINT Bytes,
149 ULONG Tag)
150 {
151 UNREFERENCED_PARAMETER(Tag);
152
153 return RtlAllocateHeap(RtlGetProcessHeap(),
154 0,
155 Bytes);
156 }
157
158
159 VOID
160 NTAPI
161 RtlpFreeMemory(PVOID Mem,
162 ULONG Tag)
163 {
164 UNREFERENCED_PARAMETER(Tag);
165
166 RtlFreeHeap(RtlGetProcessHeap(),
167 0,
168 Mem);
169 }
170
171
172 #if DBG
173 VOID FASTCALL
174 CHECK_PAGED_CODE_RTL(char *file, int line)
175 {
176 /* meaningless in user mode */
177 }
178 #endif
179
180 BOOLEAN
181 NTAPI
182 RtlpHandleDpcStackException(IN PEXCEPTION_REGISTRATION_RECORD RegistrationFrame,
183 IN ULONG_PTR RegistrationFrameEnd,
184 IN OUT PULONG_PTR StackLow,
185 IN OUT PULONG_PTR StackHigh)
186 {
187 /* There's no such thing as a DPC stack in user-mode */
188 return FALSE;
189 }
190
191 VOID
192 NTAPI
193 RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord,
194 IN PCONTEXT ContextRecord,
195 IN PVOID ContextData,
196 IN ULONG Size)
197 {
198 /* Exception logging is not done in user-mode */
199 }
200
201 BOOLEAN
202 NTAPI
203 RtlpCaptureStackLimits(IN ULONG_PTR Ebp,
204 IN ULONG_PTR *StackBegin,
205 IN ULONG_PTR *StackEnd)
206 {
207 /* FIXME: Verify */
208 *StackBegin = (ULONG_PTR)NtCurrentTeb()->Tib.StackLimit;
209 *StackEnd = (ULONG_PTR)NtCurrentTeb()->Tib.StackBase;
210 return TRUE;
211 }
212
213 #ifdef _AMD64_
214 VOID
215 NTAPI
216 RtlpGetStackLimits(
217 OUT PULONG_PTR LowLimit,
218 OUT PULONG_PTR HighLimit)
219 {
220 *LowLimit = (ULONG_PTR)NtCurrentTeb()->Tib.StackLimit;
221 *HighLimit = (ULONG_PTR)NtCurrentTeb()->Tib.StackBase;
222 return;
223 }
224 #endif
225
226 BOOLEAN
227 NTAPI
228 RtlIsThreadWithinLoaderCallout(VOID)
229 {
230 return LdrpTopLevelDllBeingLoadedTeb == NtCurrentTeb();
231 }
232
233 /* RTL Atom Tables ************************************************************/
234
235 typedef struct _RTL_ATOM_HANDLE
236 {
237 RTL_HANDLE_TABLE_ENTRY Handle;
238 PRTL_ATOM_TABLE_ENTRY AtomEntry;
239 } RTL_ATOM_HANDLE, *PRTL_ATOM_HANDLE;
240
241 NTSTATUS
242 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable)
243 {
244 RtlInitializeCriticalSection(&AtomTable->CriticalSection);
245 return STATUS_SUCCESS;
246 }
247
248
249 VOID
250 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable)
251 {
252 RtlDeleteCriticalSection(&AtomTable->CriticalSection);
253 }
254
255
256 BOOLEAN
257 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable)
258 {
259 RtlEnterCriticalSection(&AtomTable->CriticalSection);
260 return TRUE;
261 }
262
263
264 VOID
265 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable)
266 {
267 RtlLeaveCriticalSection(&AtomTable->CriticalSection);
268 }
269
270
271 /* handle functions */
272
273 BOOLEAN
274 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
275 {
276 RtlInitializeHandleTable(0xCFFF,
277 sizeof(RTL_ATOM_HANDLE),
278 &AtomTable->RtlHandleTable);
279
280 return TRUE;
281 }
282
283 VOID
284 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
285 {
286 RtlDestroyHandleTable(&AtomTable->RtlHandleTable);
287 }
288
289 PRTL_ATOM_TABLE
290 RtlpAllocAtomTable(ULONG Size)
291 {
292 return (PRTL_ATOM_TABLE)RtlAllocateHeap(RtlGetProcessHeap(),
293 HEAP_ZERO_MEMORY,
294 Size);
295 }
296
297 VOID
298 RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable)
299 {
300 RtlFreeHeap(RtlGetProcessHeap(),
301 0,
302 AtomTable);
303 }
304
305 PRTL_ATOM_TABLE_ENTRY
306 RtlpAllocAtomTableEntry(ULONG Size)
307 {
308 return (PRTL_ATOM_TABLE_ENTRY)RtlAllocateHeap(RtlGetProcessHeap(),
309 HEAP_ZERO_MEMORY,
310 Size);
311 }
312
313 VOID
314 RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry)
315 {
316 RtlFreeHeap(RtlGetProcessHeap(),
317 0,
318 Entry);
319 }
320
321 VOID
322 RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
323 {
324 PRTL_HANDLE_TABLE_ENTRY RtlHandleEntry;
325
326 if (RtlIsValidIndexHandle(&AtomTable->RtlHandleTable,
327 (ULONG)Entry->HandleIndex,
328 &RtlHandleEntry))
329 {
330 RtlFreeHandle(&AtomTable->RtlHandleTable,
331 RtlHandleEntry);
332 }
333 }
334
335 BOOLEAN
336 RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
337 {
338 ULONG HandleIndex;
339 PRTL_HANDLE_TABLE_ENTRY RtlHandle;
340
341 RtlHandle = RtlAllocateHandle(&AtomTable->RtlHandleTable,
342 &HandleIndex);
343 if (RtlHandle != NULL)
344 {
345 PRTL_ATOM_HANDLE AtomHandle = (PRTL_ATOM_HANDLE)RtlHandle;
346
347 /* FIXME - Handle Indexes >= 0xC000 ?! */
348 if (HandleIndex < 0xC000)
349 {
350 Entry->HandleIndex = (USHORT)HandleIndex;
351 Entry->Atom = 0xC000 + (USHORT)HandleIndex;
352
353 AtomHandle->AtomEntry = Entry;
354 AtomHandle->Handle.Flags = RTL_HANDLE_VALID;
355
356 return TRUE;
357 }
358 else
359 {
360 /* set the valid flag, otherwise RtlFreeHandle will fail! */
361 AtomHandle->Handle.Flags = RTL_HANDLE_VALID;
362
363 RtlFreeHandle(&AtomTable->RtlHandleTable,
364 RtlHandle);
365 }
366 }
367
368 return FALSE;
369 }
370
371 PRTL_ATOM_TABLE_ENTRY
372 RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable, ULONG Index)
373 {
374 PRTL_HANDLE_TABLE_ENTRY RtlHandle;
375
376 if (RtlIsValidIndexHandle(&AtomTable->RtlHandleTable,
377 Index,
378 &RtlHandle))
379 {
380 PRTL_ATOM_HANDLE AtomHandle = (PRTL_ATOM_HANDLE)RtlHandle;
381
382 return AtomHandle->AtomEntry;
383 }
384
385 return NULL;
386 }
387
388 PVOID
389 NTAPI
390 RtlpLookupModuleBase(
391 PVOID Address)
392 {
393 NTSTATUS Status;
394 MEMORY_BASIC_INFORMATION MemoryInformation;
395 ULONG_PTR Base, Limit;
396 PIMAGE_DOS_HEADER DosHeader;
397 PIMAGE_NT_HEADERS NtHeader;
398
399 Status = NtQueryVirtualMemory(NtCurrentProcess(),
400 Address,
401 MemoryBasicInformation,
402 &MemoryInformation,
403 sizeof(MEMORY_BASIC_INFORMATION),
404 NULL);
405 if (!NT_SUCCESS(Status))
406 {
407 return NULL;
408 }
409
410 /* FIXME: remove these checks? */
411 Base = (ULONG_PTR)MemoryInformation.BaseAddress;
412 Limit = Base + MemoryInformation.RegionSize;
413 if ( ((ULONG_PTR)Address < Base) ||
414 ((ULONG_PTR)Address >= Limit) )
415 {
416 /* WTF? */
417 return NULL;
418 }
419
420 /* Check if we got the right kind of memory */
421 if ( (MemoryInformation.State != MEM_COMMIT) ||
422 (MemoryInformation.Type != MEM_IMAGE) )
423 {
424 return NULL;
425 }
426
427 /* Check DOS magic */
428 DosHeader = MemoryInformation.AllocationBase;
429 if (DosHeader->e_magic != IMAGE_DOS_MAGIC)
430 {
431 return NULL;
432 }
433
434 /* Check NT header */
435 NtHeader = (PVOID)((ULONG_PTR)DosHeader + DosHeader->e_lfanew);
436 if (NtHeader->Signature != IMAGE_PE_MAGIC)
437 {
438 return NULL;
439 }
440
441 return MemoryInformation.AllocationBase;
442 }
443
444
445 /*
446 * Ldr Resource support code
447 */
448
449 IMAGE_RESOURCE_DIRECTORY *find_entry_by_name( IMAGE_RESOURCE_DIRECTORY *dir,
450 LPCWSTR name, void *root,
451 int want_dir );
452 IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( IMAGE_RESOURCE_DIRECTORY *dir,
453 WORD id, void *root, int want_dir );
454 IMAGE_RESOURCE_DIRECTORY *find_first_entry( IMAGE_RESOURCE_DIRECTORY *dir,
455 void *root, int want_dir );
456 int push_language( USHORT *list, ULONG pos, WORD lang );
457
458 /**********************************************************************
459 * find_entry
460 *
461 * Find a resource entry
462 */
463 NTSTATUS find_entry( PVOID BaseAddress, LDR_RESOURCE_INFO *info,
464 ULONG level, void **ret, int want_dir )
465 {
466 ULONG size;
467 void *root;
468 IMAGE_RESOURCE_DIRECTORY *resdirptr;
469 USHORT list[9]; /* list of languages to try */
470 int i, pos = 0;
471 LCID user_lcid, system_lcid;
472
473 root = RtlImageDirectoryEntryToData( BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size );
474 if (!root) return STATUS_RESOURCE_DATA_NOT_FOUND;
475 resdirptr = root;
476
477 if (!level--) goto done;
478 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Type, root, want_dir || level )))
479 return STATUS_RESOURCE_TYPE_NOT_FOUND;
480 if (!level--) return STATUS_SUCCESS;
481
482 resdirptr = *ret;
483 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Name, root, want_dir || level )))
484 return STATUS_RESOURCE_NAME_NOT_FOUND;
485 if (!level--) return STATUS_SUCCESS;
486 if (level) return STATUS_INVALID_PARAMETER; /* level > 3 */
487
488 /* 1. specified language */
489 pos = push_language( list, pos, info->Language );
490
491 /* 2. specified language with neutral sublanguage */
492 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(info->Language), SUBLANG_NEUTRAL ) );
493
494 /* 3. neutral language with neutral sublanguage */
495 pos = push_language( list, pos, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ) );
496
497 /* if no explicitly specified language, try some defaults */
498 if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL)
499 {
500 /* user defaults, unless SYS_DEFAULT sublanguage specified */
501 if (SUBLANGID(info->Language) != SUBLANG_SYS_DEFAULT)
502 {
503 /* 4. current thread locale language */
504 pos = push_language( list, pos, LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale) );
505
506 if (NT_SUCCESS(NtQueryDefaultLocale(TRUE, &user_lcid)))
507 {
508 /* 5. user locale language */
509 pos = push_language( list, pos, LANGIDFROMLCID(user_lcid) );
510
511 /* 6. user locale language with neutral sublanguage */
512 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(user_lcid), SUBLANG_NEUTRAL ) );
513 }
514 }
515
516 /* now system defaults */
517
518 if (NT_SUCCESS(NtQueryDefaultLocale(FALSE, &system_lcid)))
519 {
520 /* 7. system locale language */
521 pos = push_language( list, pos, LANGIDFROMLCID( system_lcid ) );
522
523 /* 8. system locale language with neutral sublanguage */
524 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(system_lcid), SUBLANG_NEUTRAL ) );
525 }
526
527 /* 9. English */
528 pos = push_language( list, pos, MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT ) );
529 }
530
531 resdirptr = *ret;
532 for (i = 0; i < pos; i++)
533 if ((*ret = find_entry_by_id( resdirptr, list[i], root, want_dir ))) return STATUS_SUCCESS;
534
535 /* if no explicitly specified language, return the first entry */
536 if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL)
537 {
538 if ((*ret = find_first_entry( resdirptr, root, want_dir ))) return STATUS_SUCCESS;
539 }
540 return STATUS_RESOURCE_LANG_NOT_FOUND;
541
542 done:
543 *ret = resdirptr;
544 return STATUS_SUCCESS;
545 }