Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenlibsupp.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: ReactOS kernel 00004 * FILE: ntoskrnl/rtl/libsupp.c 00005 * PURPOSE: RTL Support Routines 00006 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 00007 * Gunnar Dalsnes 00008 */ 00009 00010 /* INCLUDES ******************************************************************/ 00011 00012 #include <ntoskrnl.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 #define TAG_ATMT 'TotA' /* Atom table */ 00017 00018 extern ULONG NtGlobalFlag; 00019 00020 typedef struct _RTL_RANGE_ENTRY 00021 { 00022 LIST_ENTRY Entry; 00023 RTL_RANGE Range; 00024 } RTL_RANGE_ENTRY, *PRTL_RANGE_ENTRY; 00025 00026 PAGED_LOOKASIDE_LIST RtlpRangeListEntryLookasideList; 00027 SIZE_T RtlpAllocDeallocQueryBufferSize = 128; 00028 00029 /* FUNCTIONS *****************************************************************/ 00030 00031 PVOID 00032 NTAPI 00033 RtlPcToFileHeader( 00034 IN PVOID PcValue, 00035 OUT PVOID *BaseOfImage) 00036 { 00037 PLDR_DATA_TABLE_ENTRY LdrEntry; 00038 BOOLEAN InSystem; 00039 00040 /* Get the base for this file */ 00041 if ((ULONG_PTR)PcValue > (ULONG_PTR)MmHighestUserAddress) 00042 { 00043 /* We are in kernel */ 00044 *BaseOfImage = KiPcToFileHeader(PcValue, &LdrEntry, FALSE, &InSystem); 00045 } 00046 else 00047 { 00048 /* We are in user land */ 00049 *BaseOfImage = KiRosPcToUserFileHeader(PcValue, &LdrEntry); 00050 } 00051 00052 return *BaseOfImage; 00053 } 00054 00055 VOID 00056 NTAPI 00057 RtlInitializeRangeListPackage(VOID) 00058 { 00059 /* Setup the lookaside list for allocations (not used yet) */ 00060 ExInitializePagedLookasideList(&RtlpRangeListEntryLookasideList, 00061 NULL, 00062 NULL, 00063 POOL_COLD_ALLOCATION, 00064 sizeof(RTL_RANGE_ENTRY), 00065 'elRR', 00066 16); 00067 } 00068 00069 BOOLEAN 00070 NTAPI 00071 RtlpCheckForActiveDebugger(VOID) 00072 { 00073 /* This check is meaningless in kernel-mode */ 00074 return FALSE; 00075 } 00076 00077 BOOLEAN 00078 NTAPI 00079 RtlpSetInDbgPrint(VOID) 00080 { 00081 /* Nothing to set in kernel mode */ 00082 return FALSE; 00083 } 00084 00085 VOID 00086 NTAPI 00087 RtlpClearInDbgPrint(VOID) 00088 { 00089 /* Nothing to clear in kernel mode */ 00090 } 00091 00092 KPROCESSOR_MODE 00093 NTAPI 00094 RtlpGetMode() 00095 { 00096 return KernelMode; 00097 } 00098 00099 PVOID 00100 NTAPI 00101 RtlpAllocateMemory(ULONG Bytes, 00102 ULONG Tag) 00103 { 00104 return ExAllocatePoolWithTag(PagedPool, 00105 (SIZE_T)Bytes, 00106 Tag); 00107 } 00108 00109 00110 #define TAG_USTR 'RTSU' 00111 #define TAG_ASTR 'RTSA' 00112 #define TAG_OSTR 'RTSO' 00113 VOID 00114 NTAPI 00115 RtlpFreeMemory(PVOID Mem, 00116 ULONG Tag) 00117 { 00118 if (Tag == TAG_ASTR || Tag == TAG_OSTR || Tag == TAG_USTR) 00119 ExFreePool(Mem); 00120 else 00121 ExFreePoolWithTag(Mem, Tag); 00122 } 00123 00124 /* 00125 * @implemented 00126 */ 00127 VOID NTAPI 00128 RtlAcquirePebLock(VOID) 00129 { 00130 00131 } 00132 00133 /* 00134 * @implemented 00135 */ 00136 VOID NTAPI 00137 RtlReleasePebLock(VOID) 00138 { 00139 00140 } 00141 00142 NTSTATUS 00143 NTAPI 00144 LdrShutdownThread(VOID) 00145 { 00146 return STATUS_SUCCESS; 00147 } 00148 00149 00150 PPEB 00151 NTAPI 00152 RtlGetCurrentPeb(VOID) 00153 { 00154 return ((PEPROCESS)(KeGetCurrentThread()->ApcState.Process))->Peb; 00155 } 00156 00157 NTSTATUS 00158 NTAPI 00159 RtlDeleteHeapLock(IN OUT PHEAP_LOCK Lock) 00160 { 00161 ExDeleteResourceLite(&Lock->Resource); 00162 ExFreePool(Lock); 00163 00164 return STATUS_SUCCESS; 00165 } 00166 00167 NTSTATUS 00168 NTAPI 00169 RtlEnterHeapLock(IN OUT PHEAP_LOCK Lock, IN BOOLEAN Exclusive) 00170 { 00171 KeEnterCriticalRegion(); 00172 00173 if (Exclusive) 00174 ExAcquireResourceExclusiveLite(&Lock->Resource, TRUE); 00175 else 00176 ExAcquireResourceSharedLite(&Lock->Resource, TRUE); 00177 00178 return STATUS_SUCCESS; 00179 } 00180 00181 NTSTATUS 00182 NTAPI 00183 RtlInitializeHeapLock(IN OUT PHEAP_LOCK *Lock) 00184 { 00185 PHEAP_LOCK HeapLock = ExAllocatePool(NonPagedPool, sizeof(HEAP_LOCK)); 00186 if (HeapLock == NULL) 00187 return STATUS_NO_MEMORY; 00188 00189 ExInitializeResourceLite(&HeapLock->Resource); 00190 *Lock = HeapLock; 00191 00192 return STATUS_SUCCESS; 00193 } 00194 00195 NTSTATUS 00196 NTAPI 00197 RtlLeaveHeapLock(IN OUT PHEAP_LOCK Lock) 00198 { 00199 ExReleaseResourceLite(&Lock->Resource); 00200 KeLeaveCriticalRegion(); 00201 00202 return STATUS_SUCCESS; 00203 } 00204 00205 #if DBG 00206 VOID FASTCALL 00207 CHECK_PAGED_CODE_RTL(char *file, int line) 00208 { 00209 if(KeGetCurrentIrql() > APC_LEVEL) 00210 { 00211 DbgPrint("%s:%i: Pagable code called at IRQL > APC_LEVEL (%d)\n", file, line, KeGetCurrentIrql()); 00212 ASSERT(FALSE); 00213 } 00214 } 00215 #endif 00216 00217 VOID 00218 NTAPI 00219 RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord, 00220 IN PCONTEXT ContextRecord, 00221 IN PVOID ContextData, 00222 IN ULONG Size) 00223 { 00224 /* Check the global flag */ 00225 if (NtGlobalFlag & FLG_ENABLE_EXCEPTION_LOGGING) 00226 { 00227 /* FIXME: Log this exception */ 00228 } 00229 } 00230 00231 BOOLEAN 00232 NTAPI 00233 RtlpHandleDpcStackException(IN PEXCEPTION_REGISTRATION_RECORD RegistrationFrame, 00234 IN ULONG_PTR RegistrationFrameEnd, 00235 IN OUT PULONG_PTR StackLow, 00236 IN OUT PULONG_PTR StackHigh) 00237 { 00238 PKPRCB Prcb; 00239 ULONG_PTR DpcStack; 00240 00241 /* Check if we are at DISPATCH or higher */ 00242 if (KeGetCurrentIrql() >= DISPATCH_LEVEL) 00243 { 00244 /* Get the PRCB and DPC Stack */ 00245 Prcb = KeGetCurrentPrcb(); 00246 DpcStack = (ULONG_PTR)Prcb->DpcStack; 00247 00248 /* Check if we are in a DPC and the stack matches */ 00249 if ((Prcb->DpcRoutineActive) && 00250 (RegistrationFrameEnd <= DpcStack) && 00251 ((ULONG_PTR)RegistrationFrame >= DpcStack - KERNEL_STACK_SIZE)) 00252 { 00253 /* Update the limits to the DPC Stack's */ 00254 *StackHigh = DpcStack; 00255 *StackLow = DpcStack - KERNEL_STACK_SIZE; 00256 return TRUE; 00257 } 00258 } 00259 00260 /* Not in DPC stack */ 00261 return FALSE; 00262 } 00263 00264 #if !defined(_ARM_) && !defined(_AMD64_) 00265 00266 BOOLEAN 00267 NTAPI 00268 RtlpCaptureStackLimits(IN ULONG_PTR Ebp, 00269 IN ULONG_PTR *StackBegin, 00270 IN ULONG_PTR *StackEnd) 00271 { 00272 PKTHREAD Thread = KeGetCurrentThread(); 00273 00274 /* Don't even try at ISR level or later */ 00275 if (KeGetCurrentIrql() > DISPATCH_LEVEL) return FALSE; 00276 00277 /* Start with defaults */ 00278 *StackBegin = Thread->StackLimit; 00279 *StackEnd = (ULONG_PTR)Thread->StackBase; 00280 00281 /* Check if EBP is inside the stack */ 00282 if ((*StackBegin <= Ebp) && (Ebp <= *StackEnd)) 00283 { 00284 /* Then make the stack start at EBP */ 00285 *StackBegin = Ebp; 00286 } 00287 else 00288 { 00289 /* Now we're going to assume we're on the DPC stack */ 00290 *StackEnd = (ULONG_PTR)(KeGetPcr()->Prcb->DpcStack); 00291 *StackBegin = *StackEnd - KERNEL_STACK_SIZE; 00292 00293 /* Check if we seem to be on the DPC stack */ 00294 if ((*StackEnd) && (*StackBegin < Ebp) && (Ebp <= *StackEnd)) 00295 { 00296 /* We're on the DPC stack */ 00297 *StackBegin = Ebp; 00298 } 00299 else 00300 { 00301 /* We're somewhere else entirely... use EBP for safety */ 00302 *StackBegin = Ebp; 00303 *StackEnd = (ULONG_PTR)PAGE_ALIGN(*StackBegin); 00304 } 00305 } 00306 00307 /* Return success */ 00308 return TRUE; 00309 } 00310 00311 /* 00312 * @implemented 00313 */ 00314 ULONG 00315 NTAPI 00316 RtlWalkFrameChain(OUT PVOID *Callers, 00317 IN ULONG Count, 00318 IN ULONG Flags) 00319 { 00320 ULONG_PTR Stack, NewStack, StackBegin, StackEnd = 0; 00321 ULONG Eip; 00322 BOOLEAN Result, StopSearch = FALSE; 00323 ULONG i = 0; 00324 PETHREAD Thread = PsGetCurrentThread(); 00325 PTEB Teb; 00326 PKTRAP_FRAME TrapFrame; 00327 00328 /* Get current EBP */ 00329 #if defined(_M_IX86) 00330 #if defined __GNUC__ 00331 __asm__("mov %%ebp, %0" : "=r" (Stack) : ); 00332 #elif defined(_MSC_VER) 00333 __asm mov Stack, ebp 00334 #endif 00335 #elif defined(_M_MIPS) 00336 __asm__("move $sp, %0" : "=r" (Stack) : ); 00337 #elif defined(_M_PPC) 00338 __asm__("mr %0,1" : "=r" (Stack) : ); 00339 #elif defined(_M_ARM) 00340 __asm__("mov sp, %0" : "=r"(Stack) : ); 00341 #else 00342 #error Unknown architecture 00343 #endif 00344 00345 /* Set it as the stack begin limit as well */ 00346 StackBegin = (ULONG_PTR)Stack; 00347 00348 /* Check if we're called for non-logging mode */ 00349 if (!Flags) 00350 { 00351 /* Get the actual safe limits */ 00352 Result = RtlpCaptureStackLimits((ULONG_PTR)Stack, 00353 &StackBegin, 00354 &StackEnd); 00355 if (!Result) return 0; 00356 } 00357 00358 /* Use a SEH block for maximum protection */ 00359 _SEH2_TRY 00360 { 00361 /* Check if we want the user-mode stack frame */ 00362 if (Flags == 1) 00363 { 00364 /* Get the trap frame and TEB */ 00365 TrapFrame = KeGetTrapFrame(&Thread->Tcb); 00366 Teb = Thread->Tcb.Teb; 00367 00368 /* Make sure we can trust the TEB and trap frame */ 00369 if (!(Teb) || 00370 (KeIsAttachedProcess()) || 00371 (KeGetCurrentIrql() >= DISPATCH_LEVEL)) 00372 { 00373 /* Invalid or unsafe attempt to get the stack */ 00374 _SEH2_YIELD(return 0;) 00375 } 00376 00377 /* Get the stack limits */ 00378 StackBegin = (ULONG_PTR)Teb->NtTib.StackLimit; 00379 StackEnd = (ULONG_PTR)Teb->NtTib.StackBase; 00380 #ifdef _M_IX86 00381 Stack = TrapFrame->Ebp; 00382 #elif defined(_M_PPC) 00383 Stack = TrapFrame->Gpr1; 00384 #else 00385 #error Unknown architecture 00386 #endif 00387 00388 /* Validate them */ 00389 if (StackEnd <= StackBegin) return 0; 00390 ProbeForRead((PVOID)StackBegin, 00391 StackEnd - StackBegin, 00392 sizeof(CHAR)); 00393 } 00394 00395 /* Loop the frames */ 00396 for (i = 0; i < Count; i++) 00397 { 00398 /* 00399 * Leave if we're past the stack, 00400 * if we're before the stack, 00401 * or if we've reached ourselves. 00402 */ 00403 if ((Stack >= StackEnd) || 00404 (!i ? (Stack < StackBegin) : (Stack <= StackBegin)) || 00405 ((StackEnd - Stack) < (2 * sizeof(ULONG_PTR)))) 00406 { 00407 /* We're done or hit a bad address */ 00408 break; 00409 } 00410 00411 /* Get new stack and EIP */ 00412 NewStack = *(PULONG_PTR)Stack; 00413 Eip = *(PULONG_PTR)(Stack + sizeof(ULONG_PTR)); 00414 00415 /* Check if the new pointer is above the oldone and past the end */ 00416 if (!((Stack < NewStack) && (NewStack < StackEnd))) 00417 { 00418 /* Stop searching after this entry */ 00419 StopSearch = TRUE; 00420 } 00421 00422 /* Also make sure that the EIP isn't a stack address */ 00423 if ((StackBegin < Eip) && (Eip < StackEnd)) break; 00424 00425 /* Check if we reached a user-mode address */ 00426 if (!(Flags) && !(Eip & 0x80000000)) break; // FIXME: 3GB breakage 00427 00428 /* Save this frame */ 00429 Callers[i] = (PVOID)Eip; 00430 00431 /* Check if we should continue */ 00432 if (StopSearch) 00433 { 00434 /* Return the next index */ 00435 i++; 00436 break; 00437 } 00438 00439 /* Move to the next stack */ 00440 Stack = NewStack; 00441 } 00442 } 00443 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00444 { 00445 /* No index */ 00446 i = 0; 00447 } 00448 _SEH2_END; 00449 00450 /* Return frames parsed */ 00451 return i; 00452 } 00453 00454 #endif 00455 00456 #ifdef _AMD64_ 00457 VOID 00458 NTAPI 00459 RtlpGetStackLimits( 00460 OUT PULONG_PTR LowLimit, 00461 OUT PULONG_PTR HighLimit) 00462 { 00463 PKTHREAD CurrentThread = KeGetCurrentThread(); 00464 *HighLimit = (ULONG_PTR)CurrentThread->InitialStack; 00465 *LowLimit = (ULONG_PTR)CurrentThread->StackLimit; 00466 } 00467 #endif 00468 00469 /* RTL Atom Tables ************************************************************/ 00470 00471 NTSTATUS 00472 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable) 00473 { 00474 ExInitializeFastMutex(&AtomTable->FastMutex); 00475 00476 return STATUS_SUCCESS; 00477 } 00478 00479 00480 VOID 00481 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable) 00482 { 00483 } 00484 00485 00486 BOOLEAN 00487 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable) 00488 { 00489 ExAcquireFastMutex(&AtomTable->FastMutex); 00490 return TRUE; 00491 } 00492 00493 VOID 00494 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable) 00495 { 00496 ExReleaseFastMutex(&AtomTable->FastMutex); 00497 } 00498 00499 BOOLEAN 00500 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable) 00501 { 00502 AtomTable->ExHandleTable = ExCreateHandleTable(NULL); 00503 return (AtomTable->ExHandleTable != NULL); 00504 } 00505 00506 VOID 00507 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable) 00508 { 00509 if (AtomTable->ExHandleTable) 00510 { 00511 ExSweepHandleTable(AtomTable->ExHandleTable, 00512 NULL, 00513 NULL); 00514 ExDestroyHandleTable(AtomTable->ExHandleTable, NULL); 00515 AtomTable->ExHandleTable = NULL; 00516 } 00517 } 00518 00519 PRTL_ATOM_TABLE 00520 RtlpAllocAtomTable(ULONG Size) 00521 { 00522 PRTL_ATOM_TABLE Table = ExAllocatePool(NonPagedPool, 00523 Size); 00524 if (Table != NULL) 00525 { 00526 RtlZeroMemory(Table, 00527 Size); 00528 } 00529 00530 return Table; 00531 } 00532 00533 VOID 00534 RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable) 00535 { 00536 ExFreePool(AtomTable); 00537 } 00538 00539 PRTL_ATOM_TABLE_ENTRY 00540 RtlpAllocAtomTableEntry(ULONG Size) 00541 { 00542 PRTL_ATOM_TABLE_ENTRY Entry; 00543 00544 Entry = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_ATMT); 00545 if (Entry != NULL) 00546 { 00547 RtlZeroMemory(Entry, Size); 00548 } 00549 00550 return Entry; 00551 } 00552 00553 VOID 00554 RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry) 00555 { 00556 ExFreePoolWithTag(Entry, TAG_ATMT); 00557 } 00558 00559 VOID 00560 RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry) 00561 { 00562 ExDestroyHandle(AtomTable->ExHandleTable, 00563 (HANDLE)((ULONG_PTR)Entry->HandleIndex << 2), 00564 NULL); 00565 } 00566 00567 BOOLEAN 00568 RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry) 00569 { 00570 HANDLE_TABLE_ENTRY ExEntry; 00571 HANDLE Handle; 00572 USHORT HandleIndex; 00573 00574 /* Initialize ex handle table entry */ 00575 ExEntry.Object = Entry; 00576 ExEntry.GrantedAccess = 0x1; /* FIXME - valid handle */ 00577 00578 /* Create ex handle */ 00579 Handle = ExCreateHandle(AtomTable->ExHandleTable, 00580 &ExEntry); 00581 if (!Handle) return FALSE; 00582 00583 /* Calculate HandleIndex (by getting rid of the first two bits) */ 00584 HandleIndex = (USHORT)((ULONG_PTR)Handle >> 2); 00585 00586 /* Index must be less than 0xC000 */ 00587 if (HandleIndex >= 0xC000) 00588 { 00589 /* Destroy ex handle */ 00590 ExDestroyHandle(AtomTable->ExHandleTable, 00591 Handle, 00592 NULL); 00593 00594 /* Return failure */ 00595 return FALSE; 00596 } 00597 00598 /* Initialize atom table entry */ 00599 Entry->HandleIndex = HandleIndex; 00600 Entry->Atom = 0xC000 + HandleIndex; 00601 00602 /* Return success */ 00603 return TRUE; 00604 } 00605 00606 PRTL_ATOM_TABLE_ENTRY 00607 RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable, ULONG Index) 00608 { 00609 PHANDLE_TABLE_ENTRY ExEntry; 00610 PRTL_ATOM_TABLE_ENTRY Entry = NULL; 00611 00612 /* NOTE: There's no need to explicitly enter a critical region because it's 00613 guaranteed that we're in a critical region right now (as we hold 00614 the atom table lock) */ 00615 00616 ExEntry = ExMapHandleToPointer(AtomTable->ExHandleTable, 00617 (HANDLE)((ULONG_PTR)Index << 2)); 00618 if (ExEntry != NULL) 00619 { 00620 Entry = ExEntry->Object; 00621 00622 ExUnlockHandleTableEntry(AtomTable->ExHandleTable, 00623 ExEntry); 00624 } 00625 00626 return Entry; 00627 } 00628 00629 /* 00630 * Ldr Resource support code 00631 */ 00632 00633 IMAGE_RESOURCE_DIRECTORY *find_entry_by_name( IMAGE_RESOURCE_DIRECTORY *dir, 00634 LPCWSTR name, void *root, 00635 int want_dir ); 00636 IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( IMAGE_RESOURCE_DIRECTORY *dir, 00637 USHORT id, void *root, int want_dir ); 00638 IMAGE_RESOURCE_DIRECTORY *find_first_entry( IMAGE_RESOURCE_DIRECTORY *dir, 00639 void *root, int want_dir ); 00640 00641 /********************************************************************** 00642 * find_entry 00643 * 00644 * Find a resource entry 00645 */ 00646 NTSTATUS find_entry( PVOID BaseAddress, LDR_RESOURCE_INFO *info, 00647 ULONG level, void **ret, int want_dir ) 00648 { 00649 ULONG size; 00650 void *root; 00651 IMAGE_RESOURCE_DIRECTORY *resdirptr; 00652 00653 root = RtlImageDirectoryEntryToData( BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size ); 00654 if (!root) return STATUS_RESOURCE_DATA_NOT_FOUND; 00655 resdirptr = root; 00656 00657 if (!level--) goto done; 00658 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Type, root, want_dir || level ))) 00659 return STATUS_RESOURCE_TYPE_NOT_FOUND; 00660 if (!level--) return STATUS_SUCCESS; 00661 00662 resdirptr = *ret; 00663 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Name, root, want_dir || level ))) 00664 return STATUS_RESOURCE_NAME_NOT_FOUND; 00665 if (!level--) return STATUS_SUCCESS; 00666 if (level) return STATUS_INVALID_PARAMETER; /* level > 3 */ 00667 00668 resdirptr = *ret; 00669 00670 if ((*ret = find_first_entry( resdirptr, root, want_dir ))) return STATUS_SUCCESS; 00671 00672 return STATUS_RESOURCE_DATA_NOT_FOUND; 00673 00674 done: 00675 *ret = resdirptr; 00676 return STATUS_SUCCESS; 00677 } 00678 00679 00680 /* EOF */ Generated on Fri May 25 2012 04:17:23 for ReactOS by
1.7.6.1
|