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