Sync with trunk r63831.
[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 if (size < sizeof(*resdirptr)) return STATUS_RESOURCE_DATA_NOT_FOUND;
434 resdirptr = root;
435
436 if (!level--) goto done;
437 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Type, root, want_dir || level )))
438 return STATUS_RESOURCE_TYPE_NOT_FOUND;
439 if (!level--) return STATUS_SUCCESS;
440
441 resdirptr = *ret;
442 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Name, root, want_dir || level )))
443 return STATUS_RESOURCE_NAME_NOT_FOUND;
444 if (!level--) return STATUS_SUCCESS;
445 if (level) return STATUS_INVALID_PARAMETER; /* level > 3 */
446
447 /* 1. specified language */
448 pos = push_language( list, pos, info->Language );
449
450 /* 2. specified language with neutral sublanguage */
451 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(info->Language), SUBLANG_NEUTRAL ) );
452
453 /* 3. neutral language with neutral sublanguage */
454 pos = push_language( list, pos, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ) );
455
456 /* if no explicitly specified language, try some defaults */
457 if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL)
458 {
459 /* user defaults, unless SYS_DEFAULT sublanguage specified */
460 if (SUBLANGID(info->Language) != SUBLANG_SYS_DEFAULT)
461 {
462 /* 4. current thread locale language */
463 pos = push_language( list, pos, LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale) );
464
465 if (NT_SUCCESS(NtQueryDefaultLocale(TRUE, &user_lcid)))
466 {
467 /* 5. user locale language */
468 pos = push_language( list, pos, LANGIDFROMLCID(user_lcid) );
469
470 /* 6. user locale language with neutral sublanguage */
471 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(user_lcid), SUBLANG_NEUTRAL ) );
472 }
473 }
474
475 /* now system defaults */
476
477 if (NT_SUCCESS(NtQueryDefaultLocale(FALSE, &system_lcid)))
478 {
479 /* 7. system locale language */
480 pos = push_language( list, pos, LANGIDFROMLCID( system_lcid ) );
481
482 /* 8. system locale language with neutral sublanguage */
483 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(system_lcid), SUBLANG_NEUTRAL ) );
484 }
485
486 /* 9. English */
487 pos = push_language( list, pos, MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT ) );
488 }
489
490 resdirptr = *ret;
491 for (i = 0; i < pos; i++)
492 if ((*ret = find_entry_by_id( resdirptr, list[i], root, want_dir ))) return STATUS_SUCCESS;
493
494 /* if no explicitly specified language, return the first entry */
495 if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL)
496 {
497 if ((*ret = find_first_entry( resdirptr, root, want_dir ))) return STATUS_SUCCESS;
498 }
499 return STATUS_RESOURCE_LANG_NOT_FOUND;
500
501 done:
502 *ret = resdirptr;
503 return STATUS_SUCCESS;
504 }
505
506 /*
507 * @implemented
508 */
509 PVOID NTAPI
510 RtlPcToFileHeader(IN PVOID PcValue,
511 PVOID* BaseOfImage)
512 {
513 PLIST_ENTRY ModuleListHead;
514 PLIST_ENTRY Entry;
515 PLDR_DATA_TABLE_ENTRY Module;
516 PVOID ImageBase = NULL;
517
518 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
519 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
520 Entry = ModuleListHead->Flink;
521 while (Entry != ModuleListHead)
522 {
523 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
524
525 if ((ULONG_PTR)PcValue >= (ULONG_PTR)Module->DllBase &&
526 (ULONG_PTR)PcValue < (ULONG_PTR)Module->DllBase + Module->SizeOfImage)
527 {
528 ImageBase = Module->DllBase;
529 break;
530 }
531 Entry = Entry->Flink;
532 }
533 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
534
535 *BaseOfImage = ImageBase;
536 return ImageBase;
537 }
538
539 /*
540 * @unimplemented
541 */
542 NTSYSAPI
543 NTSTATUS
544 NTAPI
545 RtlDosApplyFileIsolationRedirection_Ustr(IN ULONG Flags,
546 IN PUNICODE_STRING OriginalName,
547 IN PUNICODE_STRING Extension,
548 IN OUT PUNICODE_STRING StaticString,
549 IN OUT PUNICODE_STRING DynamicString,
550 IN OUT PUNICODE_STRING *NewName,
551 IN PULONG NewFlags,
552 IN PSIZE_T FileNameSize,
553 IN PSIZE_T RequiredLength)
554 {
555 return STATUS_SXS_KEY_NOT_FOUND;
556 }
557
558 /*
559 * @implemented
560 */
561 NTSYSAPI
562 NTSTATUS
563 NTAPI
564 RtlWow64EnableFsRedirection(IN BOOLEAN Wow64FsEnableRedirection)
565 {
566 /* This is what Windows returns on x86 */
567 return STATUS_NOT_IMPLEMENTED;
568 }
569
570 /*
571 * @implemented
572 */
573 NTSYSAPI
574 NTSTATUS
575 NTAPI
576 RtlWow64EnableFsRedirectionEx(IN PVOID Wow64FsEnableRedirection,
577 OUT PVOID *OldFsRedirectionLevel)
578 {
579 /* This is what Windows returns on x86 */
580 return STATUS_NOT_IMPLEMENTED;
581 }
582
583 /*
584 * @unimplemented
585 */
586 NTSYSAPI
587 NTSTATUS
588 NTAPI
589 RtlComputeImportTableHash(IN HANDLE FileHandle,
590 OUT PCHAR Hash,
591 IN ULONG ImporTTableHashSize)
592 {
593 UNIMPLEMENTED;
594 return STATUS_NOT_IMPLEMENTED;
595 }
596
597 NTSTATUS
598 NTAPI
599 RtlpSafeCopyMemory(
600 _Out_writes_bytes_all_(Length) VOID UNALIGNED *Destination,
601 _In_reads_bytes_(Length) CONST VOID UNALIGNED *Source,
602 _In_ SIZE_T Length)
603 {
604 _SEH2_TRY
605 {
606 RtlCopyMemory(Destination, Source, Length);
607 }
608 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
609 {
610 _SEH2_YIELD(return _SEH2_GetExceptionCode());
611 }
612 _SEH2_END;
613
614 return STATUS_SUCCESS;
615 }
616
617 /* FIXME: code duplication with kernel32/client/time.c */
618 ULONG
619 NTAPI
620 RtlGetTickCount(VOID)
621 {
622 ULARGE_INTEGER TickCount;
623
624 #ifdef _WIN64
625 TickCount.QuadPart = *((volatile ULONG64*)&SharedUserData->TickCount);
626 #else
627 while (TRUE)
628 {
629 TickCount.HighPart = (ULONG)SharedUserData->TickCount.High1Time;
630 TickCount.LowPart = SharedUserData->TickCount.LowPart;
631
632 if (TickCount.HighPart == (ULONG)SharedUserData->TickCount.High2Time)
633 break;
634
635 YieldProcessor();
636 }
637 #endif
638
639 return (ULONG)((UInt32x32To64(TickCount.LowPart,
640 SharedUserData->TickCountMultiplier) >> 24) +
641 UInt32x32To64((TickCount.HighPart << 8) & 0xFFFFFFFF,
642 SharedUserData->TickCountMultiplier));
643 }
644
645 /* EOF */