https://git.reactos.org/?p=reactos.git;a=commitdiff;h=12e579567c0df0008bd1eb02dcdb92bcb31eb8e3
commit 12e579567c0df0008bd1eb02dcdb92bcb31eb8e3 Author: Pierre Schweitzer <pie...@reactos.org> AuthorDate: Sun Jan 6 11:54:05 2019 +0100 Commit: Pierre Schweitzer <pie...@reactos.org> CommitDate: Sun Jan 6 11:56:38 2019 +0100 [NTOSKRNL] Implement !poolfind command in KDBG For now, it allows searching for pool allocations in both paged and non paged pool. It is based on Andreas Schuster work to identify POOL_HEADER structures. --- ntoskrnl/kdbg/kdb_cli.c | 2 + ntoskrnl/mm/ARM3/expool.c | 222 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 224 insertions(+) diff --git a/ntoskrnl/kdbg/kdb_cli.c b/ntoskrnl/kdbg/kdb_cli.c index 37ad987b79..ef97693414 100644 --- a/ntoskrnl/kdbg/kdb_cli.c +++ b/ntoskrnl/kdbg/kdb_cli.c @@ -93,6 +93,7 @@ static BOOLEAN KdbpCmdDmesg(ULONG Argc, PCHAR Argv[]); BOOLEAN ExpKdbgExtPool(ULONG Argc, PCHAR Argv[]); BOOLEAN ExpKdbgExtPoolUsed(ULONG Argc, PCHAR Argv[]); +BOOLEAN ExpKdbgExtPoolFind(ULONG Argc, PCHAR Argv[]); BOOLEAN ExpKdbgExtFileCache(ULONG Argc, PCHAR Argv[]); BOOLEAN ExpKdbgExtDefWrites(ULONG Argc, PCHAR Argv[]); @@ -190,6 +191,7 @@ static const struct { "help", "help", "Display help screen.", KdbpCmdHelp }, { "!pool", "!pool [Address [Flags]]", "Display information about pool allocations.", ExpKdbgExtPool }, { "!poolused", "!poolused [Flags [Tag]]", "Display pool usage.", ExpKdbgExtPoolUsed }, + { "!poolfind", "!poolfind Tag [Pool]", "Search for pool tag allocations.", ExpKdbgExtPoolFind }, { "!filecache", "!filecache", "Display cache usage.", ExpKdbgExtFileCache }, { "!defwrites", "!defwrites", "Display cache write values.", ExpKdbgExtDefWrites }, { "!irpfind", "!irpfind [criteria data]", "Lists IRPs potentially matching criteria", PspKdbgIrpFind }, diff --git a/ntoskrnl/mm/ARM3/expool.c b/ntoskrnl/mm/ARM3/expool.c index af83d88f05..b321b52044 100644 --- a/ntoskrnl/mm/ARM3/expool.c +++ b/ntoskrnl/mm/ARM3/expool.c @@ -3106,6 +3106,228 @@ ExpKdbgExtPoolUsed( return TRUE; } +static +BOOLEAN +ExpKdbgExtValidatePoolHeader( + PVOID BaseVa, + PPOOL_HEADER Entry, + POOL_TYPE BasePoolTye) +{ + /* Block size cannot be NULL or negative and it must cover the page */ + if (Entry->BlockSize <= 0) + { + return FALSE; + } + if (Entry->BlockSize * 8 + (ULONG_PTR)Entry - (ULONG_PTR)BaseVa > PAGE_SIZE) + { + return FALSE; + } + + /* + * PreviousSize cannot be 0 unless on page begin + * And it cannot be bigger that our current + * position in page + */ + if (Entry->PreviousSize == 0 && BaseVa != Entry) + { + return FALSE; + } + if (Entry->PreviousSize * 8 > (ULONG_PTR)Entry - (ULONG_PTR)BaseVa) + { + return FALSE; + } + + /* Must be paged pool */ + if (((Entry->PoolType - 1) & BASE_POOL_TYPE_MASK) != BasePoolTye) + { + return FALSE; + } + + /* Match tag mask */ + if ((Entry->PoolTag & 0x00808080) != 0) + { + return FALSE; + } + + return TRUE; +} + +static +VOID +ExpKdbgExtPoolFindPagedPool( + ULONG Tag, + ULONG Mask) +{ + ULONG i = 0; + PPOOL_HEADER Entry; + PVOID BaseVa; + PMMPTE PointerPte; + PMMPDE PointerPde; + + KdbpPrint("Searching Paged pool (%p : %p) for Tag: %.4s\n", MmPagedPoolStart, MmPagedPoolEnd, (PCHAR)&Tag); + + /* + * To speed up paged pool search, we will use the allocation bipmap. + * This is possible because we live directly in the kernel :-) + */ + i = RtlFindSetBits(MmPagedPoolInfo.PagedPoolAllocationMap, 1, 0); + while (i != 0xFFFFFFFF) + { + BaseVa = (PVOID)((ULONG_PTR)MmPagedPoolStart + (i << PAGE_SHIFT)); + Entry = BaseVa; + + /* Validate our address */ + if ((ULONG_PTR)BaseVa > (ULONG_PTR)MmPagedPoolEnd || (ULONG_PTR)BaseVa + PAGE_SIZE > (ULONG_PTR)MmPagedPoolEnd) + { + break; + } + + /* Check whether we are beyond expansion */ + PointerPde = MiAddressToPde(BaseVa); + if (PointerPde >= MmPagedPoolInfo.NextPdeForPagedPoolExpansion) + { + break; + } + + /* Check if allocation is valid */ + PointerPte = MiAddressToPte(BaseVa); + if ((ULONG_PTR)PointerPte > PTE_TOP) + { + break; + } + + if (PointerPte->u.Hard.Valid) + { + for (Entry = BaseVa; + (ULONG_PTR)Entry + sizeof(POOL_HEADER) < (ULONG_PTR)BaseVa + PAGE_SIZE; + Entry = (PVOID)((ULONG_PTR)Entry + 8)) + { + /* Try to find whether we have a pool entry */ + if (!ExpKdbgExtValidatePoolHeader(BaseVa, Entry, PagedPool)) + { + continue; + } + + if ((Entry->PoolTag & Mask) == (Tag & Mask)) + { + /* Print the line */ + KdbpPrint("%p size: %4d previous size: %4d %s %.4s\n", + Entry, Entry->BlockSize, Entry->PreviousSize, + Entry->PoolType ? "(Allocated)" : "(Free) ", + (PCHAR)&Entry->PoolTag); + } + } + } + + i = RtlFindSetBits(MmPagedPoolInfo.PagedPoolAllocationMap, 1, i + 1); + } +} + +extern PVOID MmNonPagedPoolEnd0; +static +VOID +ExpKdbgExtPoolFindNonPagedPool( + ULONG Tag, + ULONG Mask) +{ + PPOOL_HEADER Entry; + PVOID BaseVa; + PMMPTE PointerPte; + + KdbpPrint("Searching NonPaged pool (%p : %p) for Tag: %.4s\n", MmNonPagedPoolStart, MmNonPagedPoolEnd0, (PCHAR)&Tag); + + /* Brute force search: start browsing the whole non paged pool */ + for (BaseVa = MmNonPagedPoolStart; + (ULONG_PTR)BaseVa + PAGE_SIZE <= (ULONG_PTR)MmNonPagedPoolEnd0; + BaseVa = (PVOID)((ULONG_PTR)BaseVa + PAGE_SIZE)) + { + Entry = BaseVa; + + /* Check whether we are beyond expansion */ + if (BaseVa >= MmNonPagedPoolExpansionStart) + { + break; + } + + /* Check if allocation is valid */ + PointerPte = MiAddressToPte(BaseVa); + if ((ULONG_PTR)PointerPte > PTE_TOP) + { + break; + } + + if (PointerPte->u.Hard.Valid) + { + for (Entry = BaseVa; + (ULONG_PTR)Entry + sizeof(POOL_HEADER) < (ULONG_PTR)BaseVa + PAGE_SIZE; + Entry = (PVOID)((ULONG_PTR)Entry + 8)) + { + /* Try to find whether we have a pool entry */ + if (!ExpKdbgExtValidatePoolHeader(BaseVa, Entry, NonPagedPool)) + { + continue; + } + + if ((Entry->PoolTag & Mask) == (Tag & Mask)) + { + /* Print the line */ + KdbpPrint("%p size: %4d previous size: %4d %s %.4s\n", + Entry, Entry->BlockSize, Entry->PreviousSize, + Entry->PoolType ? "(Allocated)" : "(Free) ", + (PCHAR)&Entry->PoolTag); + } + } + } + } +} + +BOOLEAN +ExpKdbgExtPoolFind( + ULONG Argc, + PCHAR Argv[]) +{ + ULONG Tag = 0; + ULONG Mask = 0; + ULONG PoolType = NonPagedPool; + + if (Argc == 1) + { + KdbpPrint("Specify a tag string\n"); + return TRUE; + } + + /* First arg is tag */ + if (strlen(Argv[1]) != 1 || Argv[1][0] != '*') + { + ExpKdbgExtPoolUsedGetTag(Argv[1], &Tag, &Mask); + } + + /* Second arg might be pool to search */ + if (Argc > 2) + { + PoolType = strtoul(Argv[2], NULL, 0); + + if (PoolType > 1) + { + KdbpPrint("Only (non) paged pool are supported\n"); + return TRUE; + } + } + + /* FIXME: What about large pool? */ + + if (PoolType == NonPagedPool) + { + ExpKdbgExtPoolFindNonPagedPool(Tag, Mask); + } + else if (PoolType == PagedPool) + { + ExpKdbgExtPoolFindPagedPool(Tag, Mask); + } + + return TRUE; +} + #endif // DBG && KDBG /* EOF */