Sync with trunk r63343.
[reactos.git] / 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
14 #define NDEBUG
15 #include <debug.h>
16
17 SIZE_T RtlpAllocDeallocQueryBufferSize = PAGE_SIZE;
18 PTEB LdrpTopLevelDllBeingLoadedTeb = NULL;
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(VOID)
41 {
42 /* Return the flag in the PEB */
43 return NtCurrentPeb()->BeingDebugged;
44 }
45
46 BOOLEAN
47 NTAPI
48 RtlpSetInDbgPrint(VOID)
49 {
50 /* Check if it's already set and return TRUE if so */
51 if (NtCurrentTeb()->InDbgPrint) return TRUE;
52
53 /* Set it and return */
54 NtCurrentTeb()->InDbgPrint = TRUE;
55 return FALSE;
56 }
57
58 VOID
59 NTAPI
60 RtlpClearInDbgPrint(VOID)
61 {
62 /* Clear the flag */
63 NtCurrentTeb()->InDbgPrint = 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 RtlEnterCriticalSection(Peb->FastPebLock);
91 }
92
93 /*
94 * @implemented
95 */
96 VOID NTAPI
97 RtlReleasePebLock(VOID)
98 {
99 PPEB Peb = NtCurrentPeb ();
100 RtlLeaveCriticalSection(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(IN OUT PHEAP_LOCK Lock)
117 {
118 return RtlDeleteCriticalSection(&Lock->CriticalSection);
119 }
120
121 NTSTATUS
122 NTAPI
123 RtlEnterHeapLock(IN OUT PHEAP_LOCK Lock, IN BOOLEAN Exclusive)
124 {
125 UNREFERENCED_PARAMETER(Exclusive);
126
127 return RtlEnterCriticalSection(&Lock->CriticalSection);
128 }
129
130 NTSTATUS
131 NTAPI
132 RtlInitializeHeapLock(IN OUT PHEAP_LOCK *Lock)
133 {
134 return RtlInitializeCriticalSection(&(*Lock)->CriticalSection);
135 }
136
137 NTSTATUS
138 NTAPI
139 RtlLeaveHeapLock(IN OUT PHEAP_LOCK Lock)
140 {
141 return RtlLeaveCriticalSection(&Lock->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 VOID
179 NTAPI
180 RtlpSetHeapParameters(IN PRTL_HEAP_PARAMETERS Parameters)
181 {
182 PPEB Peb;
183
184 /* Get PEB */
185 Peb = RtlGetCurrentPeb();
186
187 /* Apply defaults for non-set parameters */
188 if (!Parameters->SegmentCommit) Parameters->SegmentCommit = Peb->HeapSegmentCommit;
189 if (!Parameters->SegmentReserve) Parameters->SegmentReserve = Peb->HeapSegmentReserve;
190 if (!Parameters->DeCommitFreeBlockThreshold) Parameters->DeCommitFreeBlockThreshold = Peb->HeapDeCommitFreeBlockThreshold;
191 if (!Parameters->DeCommitTotalFreeThreshold) Parameters->DeCommitTotalFreeThreshold = Peb->HeapDeCommitTotalFreeThreshold;
192 }
193
194 BOOLEAN
195 NTAPI
196 RtlpHandleDpcStackException(IN PEXCEPTION_REGISTRATION_RECORD RegistrationFrame,
197 IN ULONG_PTR RegistrationFrameEnd,
198 IN OUT PULONG_PTR StackLow,
199 IN OUT PULONG_PTR StackHigh)
200 {
201 /* There's no such thing as a DPC stack in user-mode */
202 return FALSE;
203 }
204
205 VOID
206 NTAPI
207 RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord,
208 IN PCONTEXT ContextRecord,
209 IN PVOID ContextData,
210 IN ULONG Size)
211 {
212 /* Exception logging is not done in user-mode */
213 }
214
215 BOOLEAN
216 NTAPI
217 RtlpCaptureStackLimits(IN ULONG_PTR Ebp,
218 IN ULONG_PTR *StackBegin,
219 IN ULONG_PTR *StackEnd)
220 {
221 /* FIXME: Verify */
222 *StackBegin = (ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit;
223 *StackEnd = (ULONG_PTR)NtCurrentTeb()->NtTib.StackBase;
224 return TRUE;
225 }
226
227 #ifdef _AMD64_
228 VOID
229 NTAPI
230 RtlpGetStackLimits(
231 OUT PULONG_PTR LowLimit,
232 OUT PULONG_PTR HighLimit)
233 {
234 *LowLimit = (ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit;
235 *HighLimit = (ULONG_PTR)NtCurrentTeb()->NtTib.StackBase;
236 return;
237 }
238 #endif
239
240 BOOLEAN
241 NTAPI
242 RtlIsThreadWithinLoaderCallout(VOID)
243 {
244 return LdrpTopLevelDllBeingLoadedTeb == NtCurrentTeb();
245 }
246
247 /* RTL Atom Tables ************************************************************/
248
249 typedef struct _RTL_ATOM_HANDLE
250 {
251 RTL_HANDLE_TABLE_ENTRY Handle;
252 PRTL_ATOM_TABLE_ENTRY AtomEntry;
253 } RTL_ATOM_HANDLE, *PRTL_ATOM_HANDLE;
254
255 NTSTATUS
256 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable)
257 {
258 RtlInitializeCriticalSection(&AtomTable->CriticalSection);
259 return STATUS_SUCCESS;
260 }
261
262
263 VOID
264 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable)
265 {
266 RtlDeleteCriticalSection(&AtomTable->CriticalSection);
267 }
268
269
270 BOOLEAN
271 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable)
272 {
273 RtlEnterCriticalSection(&AtomTable->CriticalSection);
274 return TRUE;
275 }
276
277
278 VOID
279 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable)
280 {
281 RtlLeaveCriticalSection(&AtomTable->CriticalSection);
282 }
283
284
285 /* handle functions */
286
287 BOOLEAN
288 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
289 {
290 RtlInitializeHandleTable(0xCFFF,
291 sizeof(RTL_ATOM_HANDLE),
292 &AtomTable->RtlHandleTable);
293
294 return TRUE;
295 }
296
297 VOID
298 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
299 {
300 RtlDestroyHandleTable(&AtomTable->RtlHandleTable);
301 }
302
303 PRTL_ATOM_TABLE
304 RtlpAllocAtomTable(ULONG Size)
305 {
306 return (PRTL_ATOM_TABLE)RtlAllocateHeap(RtlGetProcessHeap(),
307 HEAP_ZERO_MEMORY,
308 Size);
309 }
310
311 VOID
312 RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable)
313 {
314 RtlFreeHeap(RtlGetProcessHeap(),
315 0,
316 AtomTable);
317 }
318
319 PRTL_ATOM_TABLE_ENTRY
320 RtlpAllocAtomTableEntry(ULONG Size)
321 {
322 return (PRTL_ATOM_TABLE_ENTRY)RtlAllocateHeap(RtlGetProcessHeap(),
323 HEAP_ZERO_MEMORY,
324 Size);
325 }
326
327 VOID
328 RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry)
329 {
330 RtlFreeHeap(RtlGetProcessHeap(),
331 0,
332 Entry);
333 }
334
335 VOID
336 RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
337 {
338 PRTL_HANDLE_TABLE_ENTRY RtlHandleEntry;
339
340 if (RtlIsValidIndexHandle(&AtomTable->RtlHandleTable,
341 (ULONG)Entry->HandleIndex,
342 &RtlHandleEntry))
343 {
344 RtlFreeHandle(&AtomTable->RtlHandleTable,
345 RtlHandleEntry);
346 }
347 }
348
349 BOOLEAN
350 RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
351 {
352 ULONG HandleIndex;
353 PRTL_HANDLE_TABLE_ENTRY RtlHandle;
354
355 RtlHandle = RtlAllocateHandle(&AtomTable->RtlHandleTable,
356 &HandleIndex);
357 if (RtlHandle != NULL)
358 {
359 PRTL_ATOM_HANDLE AtomHandle = (PRTL_ATOM_HANDLE)RtlHandle;
360
361 /* FIXME - Handle Indexes >= 0xC000 ?! */
362 if (HandleIndex < 0xC000)
363 {
364 Entry->HandleIndex = (USHORT)HandleIndex;
365 Entry->Atom = 0xC000 + (USHORT)HandleIndex;
366
367 AtomHandle->AtomEntry = Entry;
368 AtomHandle->Handle.Flags = RTL_HANDLE_VALID;
369
370 return TRUE;
371 }
372 else
373 {
374 /* set the valid flag, otherwise RtlFreeHandle will fail! */
375 AtomHandle->Handle.Flags = RTL_HANDLE_VALID;
376
377 RtlFreeHandle(&AtomTable->RtlHandleTable,
378 RtlHandle);
379 }
380 }
381
382 return FALSE;
383 }
384
385 PRTL_ATOM_TABLE_ENTRY
386 RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable, ULONG Index)
387 {
388 PRTL_HANDLE_TABLE_ENTRY RtlHandle;
389
390 if (RtlIsValidIndexHandle(&AtomTable->RtlHandleTable,
391 Index,
392 &RtlHandle))
393 {
394 PRTL_ATOM_HANDLE AtomHandle = (PRTL_ATOM_HANDLE)RtlHandle;
395
396 return AtomHandle->AtomEntry;
397 }
398
399 return NULL;
400 }
401
402
403 /*
404 * Ldr Resource support code
405 */
406
407 IMAGE_RESOURCE_DIRECTORY *find_entry_by_name( IMAGE_RESOURCE_DIRECTORY *dir,
408 LPCWSTR name, void *root,
409 int want_dir );
410 IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( IMAGE_RESOURCE_DIRECTORY *dir,
411 WORD id, void *root, int want_dir );
412 IMAGE_RESOURCE_DIRECTORY *find_first_entry( IMAGE_RESOURCE_DIRECTORY *dir,
413 void *root, int want_dir );
414 int push_language( USHORT *list, ULONG pos, WORD lang );
415
416 /**********************************************************************
417 * find_entry
418 *
419 * Find a resource entry
420 */
421 NTSTATUS find_entry( PVOID BaseAddress, LDR_RESOURCE_INFO *info,
422 ULONG level, void **ret, int want_dir )
423 {
424 ULONG size;
425 void *root;
426 IMAGE_RESOURCE_DIRECTORY *resdirptr;
427 USHORT list[9]; /* list of languages to try */
428 int i, pos = 0;
429 LCID user_lcid, system_lcid;
430
431 root = RtlImageDirectoryEntryToData( BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size );
432 if (!root) return STATUS_RESOURCE_DATA_NOT_FOUND;
433 resdirptr = root;
434
435 if (!level--) goto done;
436 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Type, root, want_dir || level )))
437 return STATUS_RESOURCE_TYPE_NOT_FOUND;
438 if (!level--) return STATUS_SUCCESS;
439
440 resdirptr = *ret;
441 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Name, root, want_dir || level )))
442 return STATUS_RESOURCE_NAME_NOT_FOUND;
443 if (!level--) return STATUS_SUCCESS;
444 if (level) return STATUS_INVALID_PARAMETER; /* level > 3 */
445
446 /* 1. specified language */
447 pos = push_language( list, pos, info->Language );
448
449 /* 2. specified language with neutral sublanguage */
450 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(info->Language), SUBLANG_NEUTRAL ) );
451
452 /* 3. neutral language with neutral sublanguage */
453 pos = push_language( list, pos, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ) );
454
455 /* if no explicitly specified language, try some defaults */
456 if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL)
457 {
458 /* user defaults, unless SYS_DEFAULT sublanguage specified */
459 if (SUBLANGID(info->Language) != SUBLANG_SYS_DEFAULT)
460 {
461 /* 4. current thread locale language */
462 pos = push_language( list, pos, LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale) );
463
464 if (NT_SUCCESS(NtQueryDefaultLocale(TRUE, &user_lcid)))
465 {
466 /* 5. user locale language */
467 pos = push_language( list, pos, LANGIDFROMLCID(user_lcid) );
468
469 /* 6. user locale language with neutral sublanguage */
470 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(user_lcid), SUBLANG_NEUTRAL ) );
471 }
472 }
473
474 /* now system defaults */
475
476 if (NT_SUCCESS(NtQueryDefaultLocale(FALSE, &system_lcid)))
477 {
478 /* 7. system locale language */
479 pos = push_language( list, pos, LANGIDFROMLCID( system_lcid ) );
480
481 /* 8. system locale language with neutral sublanguage */
482 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(system_lcid), SUBLANG_NEUTRAL ) );
483 }
484
485 /* 9. English */
486 pos = push_language( list, pos, MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT ) );
487 }
488
489 resdirptr = *ret;
490 for (i = 0; i < pos; i++)
491 if ((*ret = find_entry_by_id( resdirptr, list[i], root, want_dir ))) return STATUS_SUCCESS;
492
493 /* if no explicitly specified language, return the first entry */
494 if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL)
495 {
496 if ((*ret = find_first_entry( resdirptr, root, want_dir ))) return STATUS_SUCCESS;
497 }
498 return STATUS_RESOURCE_LANG_NOT_FOUND;
499
500 done:
501 *ret = resdirptr;
502 return STATUS_SUCCESS;
503 }
504
505 /*
506 * @implemented
507 */
508 PVOID NTAPI
509 RtlPcToFileHeader(IN PVOID PcValue,
510 PVOID* BaseOfImage)
511 {
512 PLIST_ENTRY ModuleListHead;
513 PLIST_ENTRY Entry;
514 PLDR_DATA_TABLE_ENTRY Module;
515 PVOID ImageBase = NULL;
516
517 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
518 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
519 Entry = ModuleListHead->Flink;
520 while (Entry != ModuleListHead)
521 {
522 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
523
524 if ((ULONG_PTR)PcValue >= (ULONG_PTR)Module->DllBase &&
525 (ULONG_PTR)PcValue < (ULONG_PTR)Module->DllBase + Module->SizeOfImage)
526 {
527 ImageBase = Module->DllBase;
528 break;
529 }
530 Entry = Entry->Flink;
531 }
532 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
533
534 *BaseOfImage = ImageBase;
535 return ImageBase;
536 }
537
538 /*
539 * @unimplemented
540 */
541 NTSYSAPI
542 NTSTATUS
543 NTAPI
544 RtlDosApplyFileIsolationRedirection_Ustr(IN ULONG Flags,
545 IN PUNICODE_STRING OriginalName,
546 IN PUNICODE_STRING Extension,
547 IN OUT PUNICODE_STRING StaticString,
548 IN OUT PUNICODE_STRING DynamicString,
549 IN OUT PUNICODE_STRING *NewName,
550 IN PULONG NewFlags,
551 IN PSIZE_T FileNameSize,
552 IN PSIZE_T RequiredLength)
553 {
554 return STATUS_SXS_KEY_NOT_FOUND;
555 }
556
557 /*
558 * @implemented
559 */
560 NTSYSAPI
561 NTSTATUS
562 NTAPI
563 RtlWow64EnableFsRedirection(IN BOOLEAN Wow64FsEnableRedirection)
564 {
565 /* This is what Windows returns on x86 */
566 return STATUS_NOT_IMPLEMENTED;
567 }
568
569 /*
570 * @implemented
571 */
572 NTSYSAPI
573 NTSTATUS
574 NTAPI
575 RtlWow64EnableFsRedirectionEx(IN PVOID Wow64FsEnableRedirection,
576 OUT PVOID *OldFsRedirectionLevel)
577 {
578 /* This is what Windows returns on x86 */
579 return STATUS_NOT_IMPLEMENTED;
580 }
581
582 /*
583 * @unimplemented
584 */
585 NTSYSAPI
586 NTSTATUS
587 NTAPI
588 RtlComputeImportTableHash(IN HANDLE FileHandle,
589 OUT PCHAR Hash,
590 IN ULONG ImporTTableHashSize)
591 {
592 UNIMPLEMENTED;
593 return STATUS_NOT_IMPLEMENTED;
594 }
595
596 NTSTATUS
597 NTAPI
598 RtlpSafeCopyMemory(
599 _Out_writes_bytes_all_(Length) VOID UNALIGNED *Destination,
600 _In_reads_bytes_(Length) CONST VOID UNALIGNED *Source,
601 _In_ SIZE_T Length)
602 {
603 _SEH2_TRY
604 {
605 RtlCopyMemory(Destination, Source, Length);
606 }
607 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
608 {
609 _SEH2_YIELD(return _SEH2_GetExceptionCode());
610 }
611 _SEH2_END;
612
613 return STATUS_SUCCESS;
614 }
615
616 /* FIXME: code duplication with kernel32/client/time.c */
617 ULONG
618 NTAPI
619 RtlGetTickCount(VOID)
620 {
621 ULARGE_INTEGER TickCount;
622
623 #ifdef _WIN64
624 TickCount.QuadPart = *((volatile ULONG64*)&SharedUserData->TickCount);
625 #else
626 while (TRUE)
627 {
628 TickCount.HighPart = (ULONG)SharedUserData->TickCount.High1Time;
629 TickCount.LowPart = SharedUserData->TickCount.LowPart;
630
631 if (TickCount.HighPart == (ULONG)SharedUserData->TickCount.High2Time)
632 break;
633
634 YieldProcessor();
635 }
636 #endif
637
638 return (ULONG)((UInt32x32To64(TickCount.LowPart,
639 SharedUserData->TickCountMultiplier) >> 24) +
640 UInt32x32To64((TickCount.HighPart << 8) & 0xFFFFFFFF,
641 SharedUserData->TickCountMultiplier));
642 }
643
644 /* EOF */