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