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