From: Royce Mitchell III Date: Sat, 11 Dec 2004 00:13:37 +0000 (+0000) Subject: PagedPool improvements: differenciate between hiredzone and loredzone, added double... X-Git-Tag: backups/ELF_support@12700~7^2~65 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=2c781cf79e359570c1167496fed26778813e7892 PagedPool improvements: differenciate between hiredzone and loredzone, added double-free detection including stack trace of free'er, keep track of Tags, two new utility functions for debugging ( VOID ExRosDumpPagedPoolByTag(ULONG) and ULONG ExRosQueryPoolTag(PVOID) ). svn path=/trunk/; revision=12006 --- diff --git a/reactos/include/ddk/exfuncs.h b/reactos/include/ddk/exfuncs.h index 962fe2eb460..44084344a12 100644 --- a/reactos/include/ddk/exfuncs.h +++ b/reactos/include/ddk/exfuncs.h @@ -678,6 +678,16 @@ ExReleaseRundownProtectionEx ( IN PEX_RUNDOWN_REF RunRef, IN ULONG Count ); +/* ReactOS Specific: begin */ +VOID STDCALL +ExRosDumpPagedPoolByTag ( + IN ULONG Tag + ); +ULONG STDCALL +ExRosQueryPoolTag ( + IN PVOID Block + ); +/* ReactOS Specific: end */ VOID FASTCALL ExRundownCompleted ( diff --git a/reactos/lib/rtl/heap.c b/reactos/lib/rtl/heap.c index a9d7d4b44e4..144f28c9207 100644 --- a/reactos/lib/rtl/heap.c +++ b/reactos/lib/rtl/heap.c @@ -937,7 +937,30 @@ int HEAP_IsInsideHeap( } - +void DumpStackFrames ( PULONG Frame, ULONG FrameCount ) +{ + ULONG i=0; + + DbgPrint("Frames: "); + if ( !Frame ) + { +#if defined __GNUC__ + __asm__("mov %%ebp, %%ebx" : "=b" (Frame) : ); +#elif defined(_MSC_VER) + __asm mov [Frame], ebp +#endif + Frame = (PULONG)Frame[0]; // step out of DumpStackFrames + } + while ( Frame != 0 && (ULONG)Frame != 0xDEADBEEF && (ULONG)Frame != 0xcdcdcdcd && (ULONG)Frame != 0xcccccccc && i++ < FrameCount ) + { + DbgPrint("<%X>", (PVOID)Frame[1]); + if (Frame[1] == 0xdeadbeef) + break; + Frame = (PULONG)Frame[0]; + DbgPrint(" "); + } + DbgPrint("\n"); +} /*********************************************************************** * HEAP_IsRealArena [Internal] @@ -985,11 +1008,13 @@ static BOOLEAN HEAP_IsRealArena( { DPRINT("Heap %p: block %p is not inside heap\n", heap, block ); + DumpStackFrames(NULL,10); } else if (WARN_ON(heap)) { DPRINT1("Heap %p: block %p is not inside heap\n", heap, block ); + DumpStackFrames(NULL,10); } ret = FALSE; } diff --git a/reactos/ntoskrnl/mm/pool.c b/reactos/ntoskrnl/mm/pool.c index 701fc3a0752..75426430ef9 100644 --- a/reactos/ntoskrnl/mm/pool.c +++ b/reactos/ntoskrnl/mm/pool.c @@ -1,4 +1,4 @@ -/* $Id: pool.c,v 1.35 2004/10/01 20:51:29 arty Exp $ +/* $Id: pool.c,v 1.36 2004/12/11 00:13:37 royce Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -24,6 +24,9 @@ extern MM_STATS MmStats; #define TAG_NONE (ULONG)(('N'<<0) + ('o'<<8) + ('n'<<16) + ('e'<<24)) +ULONG STDCALL +ExRosQueryPagedPoolTag ( PVOID Block ); + /* FUNCTIONS ***************************************************************/ STATIC PVOID STDCALL @@ -336,4 +339,20 @@ MiRaisePoolQuota( } } +ULONG STDCALL +ExRosQueryPoolTag ( PVOID Block ) +{ + ASSERT_IRQL(DISPATCH_LEVEL); + + if (Block >= MmPagedPoolBase && (char*)Block < ((char*)MmPagedPoolBase + MmPagedPoolSize)) + { + return ExRosQueryPagedPoolTag(Block); + } + else + { + UNIMPLEMENTED; + return 0; + } +} + /* EOF */ diff --git a/reactos/ntoskrnl/mm/ppool.c b/reactos/ntoskrnl/mm/ppool.c index 581ce5f650b..edaf1daf538 100644 --- a/reactos/ntoskrnl/mm/ppool.c +++ b/reactos/ntoskrnl/mm/ppool.c @@ -1,4 +1,4 @@ -/* $Id: ppool.c,v 1.33 2004/11/20 21:16:38 navaraf Exp $ +/* $Id: ppool.c,v 1.34 2004/12/11 00:13:37 royce Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -22,28 +22,46 @@ #undef assert #define assert(x) if (!(x)) {DbgPrint("Assertion "#x" failed at %s:%d\n", __FILE__,__LINE__); KeBugCheck(0); } -#define ASSERT_SIZE(n) assert ( (n) <= MmPagedPoolSize && (n) >= 0 ) -#define ASSERT_PTR(p) assert ( ((size_t)(p)) >= ((size_t)MmPagedPoolBase) && ((size_t)(p)) < ((size_t)((size_t)MmPagedPoolBase+MmPagedPoolSize)) ) +#define ASSERT_SIZE(n) assert ( (n) <= MmPagedPoolSize && (n) > 0 ) +#define IS_PPOOL_PTR(p) ((size_t)(p)) >= ((size_t)MmPagedPoolBase) && ((size_t)(p)) < ((size_t)((size_t)MmPagedPoolBase+MmPagedPoolSize)) +#define ASSERT_PTR(p) assert ( IS_PPOOL_PTR(p) ) // to disable buffer over/under-run detection, set the following macro to 0 +#if !defined(DBG) && !defined(KDBG) +#define MM_PPOOL_REDZONE_BYTES 0 +#else #define MM_PPOOL_REDZONE_BYTES 4 -#define MM_PPOOL_REDZONE_VALUE 0xCD +#define MM_PPOOL_REDZONE_LOVALUE 0x87 +#define MM_PPOOL_REDZONE_HIVALUE 0xA5 +#define MM_PPOOL_FREEMAGIC (ULONG)(('F'<<0) + ('r'<<8) + ('E'<<16) + ('e'<<24)) +#define MM_PPOOL_USEDMAGIC (ULONG)(('u'<<0) + ('S'<<8) + ('e'<<16) + ('D'<<24)) +#define MM_PPOOL_LASTOWNER_ENTRIES 3 +#endif typedef struct _MM_PPOOL_FREE_BLOCK_HEADER { +#if MM_PPOOL_REDZONE_BYTES + ULONG FreeMagic; +#endif//MM_PPOOL_REDZONE_BYTES ULONG Size; struct _MM_PPOOL_FREE_BLOCK_HEADER* NextFree; +#if MM_PPOOL_REDZONE_BYTES + ULONG LastOwnerStack[MM_PPOOL_LASTOWNER_ENTRIES]; +#endif//MM_PPOOL_REDZONE_BYTES } MM_PPOOL_FREE_BLOCK_HEADER, *PMM_PPOOL_FREE_BLOCK_HEADER; typedef struct _MM_PPOOL_USED_BLOCK_HEADER { +#if MM_PPOOL_REDZONE_BYTES + ULONG UsedMagic; +#endif//MM_PPOOL_REDZONE_BYTES ULONG Size; #if MM_PPOOL_REDZONE_BYTES - ULONG UserSize; // how many bytes the user actually asked for... - struct _MM_PPOOL_USED_BLOCK_HEADER* NextUsed; #endif//MM_PPOOL_REDZONE_BYTES + struct _MM_PPOOL_USED_BLOCK_HEADER* NextUsed; + ULONG Tag; } MM_PPOOL_USED_BLOCK_HEADER, *PMM_PPOOL_USED_BLOCK_HEADER; @@ -52,9 +70,7 @@ ULONG MmPagedPoolSize; ULONG MmTotalPagedPoolQuota = 0; static FAST_MUTEX MmPagedPoolLock; static PMM_PPOOL_FREE_BLOCK_HEADER MmPagedPoolFirstFreeBlock; -#if MM_PPOOL_REDZONE_BYTES static PMM_PPOOL_USED_BLOCK_HEADER MmPagedPoolFirstUsedBlock; -#endif//MM_PPOOL_REDZONE_BYTES /* FUNCTIONS *****************************************************************/ @@ -86,6 +102,12 @@ MmInitializePagedPool(VOID) MmPagedPoolFirstFreeBlock->NextFree = NULL; #if MM_PPOOL_REDZONE_BYTES + MmPagedPoolFirstFreeBlock->FreeMagic = MM_PPOOL_FREEMAGIC; + { + int i; + for ( i = 0; i < MM_PPOOL_LASTOWNER_ENTRIES; i++ ) + MmPagedPoolFirstFreeBlock->LastOwnerStack[i] = 0; + } MmPagedPoolFirstUsedBlock = NULL; #endif//MM_PPOOL_REDZONE_BYTES @@ -102,6 +124,9 @@ static void VerifyPagedPool ( int line ) while ( p ) { DPRINT ( " 0x%x: %lu bytes (next 0x%x)\n", p, p->Size, p->NextFree ); +#if MM_PPOOL_REDZONE_BYTES + ASSERT ( p->FreeMagic == MM_PPOOL_FREEMAGIC ); +#endif//MM_PPOOL_REDZONE_BYTES ASSERT_PTR(p); ASSERT_SIZE(p->Size); count++; @@ -114,34 +139,84 @@ static void VerifyPagedPool ( int line ) #define VerifyPagedPool() #endif +BOOLEAN STDCALL +KeRosPrintAddress(PVOID address); + +#if !MM_PPOOL_REDZONE_BYTES +#define MmpRedZoneCheck(pUsed,Addr,file,line) +#else//MM_PPOOL_REDZONE_BYTES +static VOID FASTCALL +MmpRedZoneCheck ( PMM_PPOOL_USED_BLOCK_HEADER pUsed, PUCHAR Addr, const char* file, int line ) +{ + int i; + PUCHAR AddrEnd = Addr + pUsed->UserSize; + BOOL bLow = TRUE; + BOOL bHigh = TRUE; + + ASSERT_PTR(Addr); + if ( pUsed->UsedMagic == MM_PPOOL_FREEMAGIC ) + { + PMM_PPOOL_FREE_BLOCK_HEADER pFree = (PMM_PPOOL_FREE_BLOCK_HEADER)pUsed; + DPRINT1 ( "Double-free detected for Block 0x%x (kthread=0x%x)!\n", Addr, KeGetCurrentThread() ); + DbgPrint ( "First Free Stack Frames:" ); + for ( i = 0; i < MM_PPOOL_LASTOWNER_ENTRIES; i++ ) + { + if ( pFree->LastOwnerStack[i] != 0xDEADBEEF ) + { + DbgPrint(" "); + if (!KeRosPrintAddress ((PVOID)pFree->LastOwnerStack[i]) ) + { + DbgPrint("<%X>", pFree->LastOwnerStack[i] ); + } + } + } + DbgPrint ( "\n" ); + KEBUGCHECK(BAD_POOL_HEADER); + } + if ( pUsed->UsedMagic != MM_PPOOL_USEDMAGIC ) + { + DPRINT1 ( "Bad magic in Block 0x%x!\n", Addr ); + KEBUGCHECK(BAD_POOL_HEADER); + } + ASSERT_SIZE(pUsed->Size); + ASSERT_SIZE(pUsed->UserSize); + ASSERT_PTR(AddrEnd); + Addr -= MM_PPOOL_REDZONE_BYTES; // this is to simplify indexing below... + for ( i = 0; i < MM_PPOOL_REDZONE_BYTES && bLow && bHigh; i++ ) + { + bLow = bLow && ( Addr[i] == MM_PPOOL_REDZONE_LOVALUE ); + bHigh = bHigh && ( AddrEnd[i] == MM_PPOOL_REDZONE_HIVALUE ); + } + if ( !bLow || !bHigh ) + { + const char* violation = "High and Low-side"; + if ( bHigh ) // high is okay, so it was just low failed + violation = "Low-side"; + else if ( bLow ) // low side is okay, so it was just high failed + violation = "High-side"; + DbgPrint("%s(%i): %s redzone violation detected for paged pool address 0x%x\n", + file, line, violation, Addr ); + DbgPrint ( "UsedMagic 0x%x, LoZone ", pUsed->UsedMagic ); + for ( i = 0; i < MM_PPOOL_REDZONE_BYTES; i++ ) + DbgPrint ( "%02x", Addr[i] ); + DbgPrint ( ", HiZone " ); + for ( i = 0; i < MM_PPOOL_REDZONE_BYTES; i++ ) + DbgPrint ( "%02x", AddrEnd[i] ); + DbgPrint ( "\n" ); + KEBUGCHECK(BAD_POOL_HEADER); + } +} +#endif//MM_PPOOL_REDZONE_BYTES + VOID STDCALL MmDbgPagedPoolRedZoneCheck ( const char* file, int line ) { #if MM_PPOOL_REDZONE_BYTES PMM_PPOOL_USED_BLOCK_HEADER pUsed = MmPagedPoolFirstUsedBlock; - int i; - BOOL bLow = TRUE; - BOOL bHigh = TRUE; while ( pUsed ) { - PUCHAR Addr = (PUCHAR)block_to_address(pUsed); - for ( i = 0; i < MM_PPOOL_REDZONE_BYTES; i++ ) - { - bLow = bLow && ( *(Addr-i-1) == MM_PPOOL_REDZONE_VALUE ); - bHigh = bHigh && ( *(Addr+pUsed->UserSize+i) == MM_PPOOL_REDZONE_VALUE ); - } - if ( !bLow || !bHigh ) - { - const char* violation = "High and Low-side"; - if ( bHigh ) // high is okay, so it was just low failed - violation = "Low-side"; - else if ( bLow ) // low side is okay, so it was just high failed - violation = "High-side"; - DbgPrint("%s(%i): %s redzone violation detected for paged pool address 0x%x\n", - file, line, violation, Addr ); - KEBUGCHECK(0); - } + MmpRedZoneCheck ( pUsed, block_to_address(pUsed), __FILE__, __LINE__ ); pUsed = pUsed->NextUsed; } #endif//MM_PPOOL_REDZONE_BYTES @@ -270,6 +345,9 @@ ExAllocatePagedPoolWithTag (IN POOL_TYPE PoolType, (PMM_PPOOL_FREE_BLOCK_HEADER)address_to_block(BestAlignedAddr); assert ( BestAlignedAddr > Addr ); NewFreeBlock->Size = (char*)Addr + BestBlock->Size - (char*)BestAlignedAddr; +#if MM_PPOOL_REDZONE_BYTES + NewFreeBlock->FreeMagic = MM_PPOOL_FREEMAGIC; +#endif//MM_PPOOL_REDZONE_BYTES ASSERT_SIZE(NewFreeBlock->Size); BestBlock->Size = (size_t)NewFreeBlock - (size_t)Addr; ASSERT_SIZE(BestBlock->Size); @@ -344,6 +422,9 @@ ExAllocatePagedPoolWithTag (IN POOL_TYPE PoolType, NextBlock = (PMM_PPOOL_FREE_BLOCK_HEADER)((char*)BestBlock + BlockSize); //DPRINT("."); NextBlock->Size = NewSize; +#if MM_PPOOL_REDZONE_BYTES + NextBlock->FreeMagic = MM_PPOOL_FREEMAGIC; +#endif//MM_PPOOL_REDZONE_BYTES ASSERT_SIZE ( NextBlock->Size ); //DPRINT("."); NextBlock->NextFree = BestBlock->NextFree; @@ -372,6 +453,9 @@ ExAllocatePagedPoolWithTag (IN POOL_TYPE PoolType, NewBlock = (PMM_PPOOL_USED_BLOCK_HEADER)BestBlock; //DPRINT("."); NewBlock->Size = BlockSize; +#if MM_PPOOL_REDZONE_BYTES + NewBlock->UsedMagic = MM_PPOOL_USEDMAGIC; +#endif//MM_PPOOL_REDZONE_BYTES ASSERT_SIZE ( NewBlock->Size ); //DPRINT(".\n"); } @@ -397,14 +481,17 @@ ExAllocatePagedPoolWithTag (IN POOL_TYPE PoolType, */ NewBlock = (PMM_PPOOL_USED_BLOCK_HEADER)BestBlock; NewBlock->Size = NewSize; +#if MM_PPOOL_REDZONE_BYTES + NewBlock->UsedMagic = MM_PPOOL_USEDMAGIC; +#endif//MM_PPOOL_REDZONE_BYTES ASSERT_SIZE ( NewBlock->Size ); } -#if MM_PPOOL_REDZONE_BYTES // now add the block to the used block list NewBlock->NextUsed = MmPagedPoolFirstUsedBlock; MmPagedPoolFirstUsedBlock = NewBlock; -#endif//MM_PPOOL_REDZONE_BYTES + + NewBlock->Tag = Tag; VerifyPagedPool(); @@ -421,17 +508,9 @@ ExAllocatePagedPoolWithTag (IN POOL_TYPE PoolType, PUCHAR Addr = (PUCHAR)BlockAddress; //DbgPrint ( "writing buffer-overrun detection bytes" ); memset ( Addr - MM_PPOOL_REDZONE_BYTES, - MM_PPOOL_REDZONE_VALUE, MM_PPOOL_REDZONE_BYTES ); - memset ( Addr + NewBlock->UserSize, MM_PPOOL_REDZONE_VALUE, + MM_PPOOL_REDZONE_LOVALUE, MM_PPOOL_REDZONE_BYTES ); + memset ( Addr + NewBlock->UserSize, MM_PPOOL_REDZONE_HIVALUE, MM_PPOOL_REDZONE_BYTES ); - /*for ( i = 0; i < MM_PPOOL_REDZONE_BYTES; i++ ) - { - //DbgPrint("."); - *(Addr-i-1) = 0xCD; - //DbgPrint("o"); - *(Addr+NewBlock->UserSize+i) = 0xCD; - }*/ - //DbgPrint ( "done!\n" ); } #endif//MM_PPOOL_REDZONE_BYTES @@ -452,33 +531,14 @@ ExFreePagedPool(IN PVOID Block) ASSERT_IRQL(APC_LEVEL); -#if MM_PPOOL_REDZONE_BYTES - // write out buffer-overrun detection bytes - { - int i; - PUCHAR Addr = (PUCHAR)Block; - //DbgPrint ( "checking buffer-overrun detection bytes..." ); - for ( i = 0; i < MM_PPOOL_REDZONE_BYTES; i++ ) - { - if (*(Addr-i-1) != MM_PPOOL_REDZONE_VALUE) - { - DPRINT1("Attempt to free memory %#08x. Redzone underrun!\n", Block); - } - if (*(Addr+UsedBlock->UserSize+i) != MM_PPOOL_REDZONE_VALUE) - { - DPRINT1("Attempt to free memory %#08x. Redzone overrun!\n", Block); - } + MmpRedZoneCheck ( UsedBlock, Block, __FILE__, __LINE__ ); - assert ( *(Addr-i-1) == MM_PPOOL_REDZONE_VALUE ); - assert ( *(Addr+UsedBlock->UserSize+i) == MM_PPOOL_REDZONE_VALUE ); - } - //DbgPrint ( "done!\n" ); - } -#endif//MM_PPOOL_REDZONE_BYTES +#if MM_PPOOL_REDZONE_BYTES + memset ( Block, 0xCD, UsedBlock->UserSize ); +#endif ExAcquireFastMutex(&MmPagedPoolLock); -#if MM_PPOOL_REDZONE_BYTES // remove from used list... { PMM_PPOOL_USED_BLOCK_HEADER pPrev = MmPagedPoolFirstUsedBlock; @@ -497,12 +557,38 @@ ExFreePagedPool(IN PVOID Block) pPrev->NextUsed = UsedBlock->NextUsed; } } -#endif//MM_PPOOL_REDZONE_BYTES /* * Begin setting up the newly freed block's header. */ FreeBlock->Size = UsedSize; +#if MM_PPOOL_REDZONE_BYTES + FreeBlock->FreeMagic = MM_PPOOL_FREEMAGIC; + { + PULONG Frame; + int i; +#if defined __GNUC__ + __asm__("mov %%ebp, %%ebx" : "=b" (Frame) : ); +#elif defined(_MSC_VER) + __asm mov [Frame], ebp +#endif + //DbgPrint ( "Stack Frames for Free Block 0x%x:", Block ); + Frame = (PULONG)Frame[0]; // step out of ExFreePagedPool + for ( i = 0; i < MM_PPOOL_LASTOWNER_ENTRIES; i++ ) + { + if ( Frame == 0 || (ULONG)Frame == 0xDEADBEEF ) + FreeBlock->LastOwnerStack[i] = 0xDEADBEEF; + else + { + //DbgPrint ( " 0x%x", Frame[1] ); + FreeBlock->LastOwnerStack[i] = Frame[1]; + Frame = (PULONG)Frame[0]; + } + } + //DbgPrint ( "\n" ); + //KeRosDumpStackFrames ( NULL, 4 ); + } +#endif//MM_PPOOL_REDZONE_BYTES ASSERT_SIZE ( FreeBlock->Size ); /* @@ -533,6 +619,7 @@ ExFreePagedPool(IN PVOID Block) /* * If the next block is immediately adjacent to the newly freed one then * merge them. + * PLEASE DO NOT WIPE OUT 'MAGIC' OR 'LASTOWNER' DATA FOR MERGED FREE BLOCKS */ if (NextBlock != NULL && ((char*)FreeBlock + FreeBlock->Size) == (char*)NextBlock) @@ -550,6 +637,7 @@ ExFreePagedPool(IN PVOID Block) /* * If the previous block is adjacent to the newly freed one then * merge them. + * PLEASE DO NOT WIPE OUT 'MAGIC' OR 'LASTOWNER' DATA FOR MERGED FREE BLOCKS */ if (PreviousBlock != NULL && ((char*)PreviousBlock + PreviousBlock->Size) == (char*)FreeBlock) @@ -564,4 +652,40 @@ ExFreePagedPool(IN PVOID Block) ExReleaseFastMutex(&MmPagedPoolLock); } +VOID STDCALL +ExRosDumpPagedPoolByTag ( ULONG Tag ) +{ + PMM_PPOOL_USED_BLOCK_HEADER UsedBlock = MmPagedPoolFirstUsedBlock; + int count = 0; + char tag[5]; + + // TODO FIXME - should we validate params or ASSERT_IRQL? + *(ULONG*)&tag[0] = Tag; + tag[4] = 0; + DbgPrint ( "PagedPool Dump by tag '%s'\n", tag ); + DbgPrint ( " -BLOCK-- --SIZE--\n" ); + while ( IS_PPOOL_PTR(UsedBlock) ) + { + if ( UsedBlock->Tag == Tag ) + { + DbgPrint ( " %08X %08X\n", UsedBlock, UsedBlock->Size ); + ++count; + } + UsedBlock = UsedBlock->NextUsed; + } + if ( UsedBlock && !IS_PPOOL_PTR(UsedBlock) ) + { + DPRINT1 ( "!!NextUsed took me to lala land: 0x%08X\n", UsedBlock ); + } + DbgPrint ( "Entries found for tag '%s': %i\n", tag, count ); +} + +ULONG STDCALL +ExRosQueryPagedPoolTag ( PVOID Block ) +{ + PMM_PPOOL_USED_BLOCK_HEADER UsedBlock = address_to_block(Block); + // TODO FIXME - should we validate params or ASSERT_IRQL? + return UsedBlock->Tag; +} + /* EOF */ diff --git a/reactos/ntoskrnl/ntoskrnl.def b/reactos/ntoskrnl/ntoskrnl.def index 8548d963fa5..e3d6408fefd 100644 --- a/reactos/ntoskrnl/ntoskrnl.def +++ b/reactos/ntoskrnl/ntoskrnl.def @@ -1,4 +1,4 @@ -; $Id: ntoskrnl.def,v 1.202 2004/11/27 13:04:06 navaraf Exp $ +; $Id: ntoskrnl.def,v 1.203 2004/12/11 00:13:37 royce Exp $ ; ; reactos/ntoskrnl/ntoskrnl.def ; @@ -139,6 +139,8 @@ ExReleaseResourceForThreadLite@8 @ExReleaseResourceLite@4 @ExReleaseRundownProtection@4 @ExReleaseRundownProtectionEx@8 +ExRosDumpPagedPoolByTag@4 +ExRosQueryPoolTag@4 @ExRundownCompleted@4 ExSetResourceOwnerPointer@8 ExSetTimerResolution@8