{
if ((Tag >= 'a' && Tag <= 'z') ||
(Tag >= 'A' && Tag <= 'Z') ||
- Tag == ' ')
+ (Tag >= '0' && Tag <= '9') ||
+ Tag == ' ' || Tag == '=' ||
+ Tag == '?' || Tag == '@')
{
return TRUE;
}
return FALSE;
}
+#ifdef KDBG
+#define MiDumperPrint(dbg, fmt, ...) \
+ if (dbg) KdbpPrint(fmt, ##__VA_ARGS__); \
+ else DPRINT1(fmt, ##__VA_ARGS__)
+#else
+#define MiDumperPrint(dbg, fmt, ...) \
+ DPRINT1(fmt, ##__VA_ARGS__)
+#endif
+
VOID
-MiDumpNonPagedPoolConsumers(VOID)
+MiDumpPoolConsumers(BOOLEAN CalledFromDbg, ULONG Tag, ULONG Mask, ULONG Flags)
{
SIZE_T i;
+ BOOLEAN Verbose;
+
+ //
+ // Only print header if called from OOM situation
+ //
+ if (!CalledFromDbg)
+ {
+ DPRINT1("---------------------\n");
+ DPRINT1("Out of memory dumper!\n");
+ }
+#ifdef KDBG
+ else
+ {
+ KdbpPrint("Pool Used:\n");
+ }
+#endif
+
+ //
+ // Remember whether we'll have to be verbose
+ // This is the only supported flag!
+ //
+ Verbose = BooleanFlagOn(Flags, 1);
- DPRINT1("---------------------\n");
- DPRINT1("Out of memory dumper!\n");
+ //
+ // Print table header
+ //
+ if (Verbose)
+ {
+ MiDumperPrint(CalledFromDbg, "\t\t\t\tNonPaged\t\t\t\t\t\t\tPaged\n");
+ MiDumperPrint(CalledFromDbg, "Tag\t\tAllocs\t\tFrees\t\tDiff\t\tUsed\t\tAllocs\t\tFrees\t\tDiff\t\tUsed\n");
+ }
+ else
+ {
+ MiDumperPrint(CalledFromDbg, "\t\tNonPaged\t\t\tPaged\n");
+ MiDumperPrint(CalledFromDbg, "Tag\t\tAllocs\t\tUsed\t\tAllocs\t\tUsed\n");
+ }
//
// We'll extract allocations for all the tracked pools
TableEntry = &PoolTrackTable[i];
//
- // We only care about non paged
+ // We only care about tags which have allocated memory
//
- if (TableEntry->NonPagedBytes != 0)
+ if (TableEntry->NonPagedBytes != 0 || TableEntry->PagedBytes != 0)
{
//
// If there's a tag, attempt to do a pretty print
+ // only if it matches the caller's tag, or if
+ // any tag is allowed
+ // For checking whether it matches caller's tag,
+ // use the mask to make sure not to mess with the wildcards
//
- if (TableEntry->Key != 0 && TableEntry->Key != TAG_NONE)
+ if (TableEntry->Key != 0 && TableEntry->Key != TAG_NONE &&
+ (Tag == 0 || (TableEntry->Key & Mask) == (Tag & Mask)))
{
CHAR Tag[4];
if (ExpTagAllowPrint(Tag[0]) && ExpTagAllowPrint(Tag[1]) && ExpTagAllowPrint(Tag[2]) && ExpTagAllowPrint(Tag[3]))
{
//
- // Print in reversed order to match what is in source code
+ // Print in direct order to make !poolused TAG usage easier
//
- DPRINT1("Tag: '%c%c%c%c', Size: %ld\n", Tag[3], Tag[2], Tag[1], Tag[0], TableEntry->NonPagedBytes);
+ if (Verbose)
+ {
+ MiDumperPrint(CalledFromDbg, "'%c%c%c%c'\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\n", Tag[0], Tag[1], Tag[2], Tag[3],
+ TableEntry->NonPagedAllocs, TableEntry->NonPagedFrees,
+ (TableEntry->NonPagedAllocs - TableEntry->NonPagedFrees), TableEntry->NonPagedBytes,
+ TableEntry->PagedAllocs, TableEntry->PagedFrees,
+ (TableEntry->PagedAllocs - TableEntry->PagedFrees), TableEntry->PagedBytes);
+ }
+ else
+ {
+ MiDumperPrint(CalledFromDbg, "'%c%c%c%c'\t\t%ld\t\t%ld\t\t%ld\t\t%ld\n", Tag[0], Tag[1], Tag[2], Tag[3],
+ TableEntry->NonPagedAllocs, TableEntry->NonPagedBytes,
+ TableEntry->PagedAllocs, TableEntry->PagedBytes);
+ }
}
else
{
- DPRINT1("Tag: %x, Size: %ld\n", TableEntry->Key, TableEntry->NonPagedBytes);
+ if (Verbose)
+ {
+ MiDumperPrint(CalledFromDbg, "%x\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\n", TableEntry->Key,
+ TableEntry->NonPagedAllocs, TableEntry->NonPagedFrees,
+ (TableEntry->NonPagedAllocs - TableEntry->NonPagedFrees), TableEntry->NonPagedBytes,
+ TableEntry->PagedAllocs, TableEntry->PagedFrees,
+ (TableEntry->PagedAllocs - TableEntry->PagedFrees), TableEntry->PagedBytes);
+ }
+ else
+ {
+ MiDumperPrint(CalledFromDbg, "%x\t%ld\t\t%ld\t\t%ld\t\t%ld\n", TableEntry->Key,
+ TableEntry->NonPagedAllocs, TableEntry->NonPagedBytes,
+ TableEntry->PagedAllocs, TableEntry->PagedBytes);
+ }
}
}
- else
+ else if (Tag == 0 || (Tag & Mask) == (TAG_NONE & Mask))
{
- DPRINT1("Anon, Size: %ld\n", TableEntry->NonPagedBytes);
+ if (Verbose)
+ {
+ MiDumperPrint(CalledFromDbg, "Anon\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\n",
+ TableEntry->NonPagedAllocs, TableEntry->NonPagedFrees,
+ (TableEntry->NonPagedAllocs - TableEntry->NonPagedFrees), TableEntry->NonPagedBytes,
+ TableEntry->PagedAllocs, TableEntry->PagedFrees,
+ (TableEntry->PagedAllocs - TableEntry->PagedFrees), TableEntry->PagedBytes);
+ }
+ else
+ {
+ MiDumperPrint(CalledFromDbg, "Anon\t\t%ld\t\t%ld\t\t%ld\t\t%ld\n",
+ TableEntry->NonPagedAllocs, TableEntry->NonPagedBytes,
+ TableEntry->PagedAllocs, TableEntry->PagedBytes);
+ }
}
}
}
- DPRINT1("---------------------\n");
+ if (!CalledFromDbg)
+ {
+ DPRINT1("---------------------\n");
+ }
}
#endif
/* PRIVATE FUNCTIONS **********************************************************/
+INIT_FUNCTION
VOID
NTAPI
-INIT_SECTION
ExpSeedHotTags(VOID)
{
ULONG i, Key, Hash, Index;
DPRINT1("Out of pool tag space, ignoring...\n");
}
+INIT_FUNCTION
VOID
NTAPI
-INIT_SECTION
ExInitializePoolDescriptor(IN PPOOL_DESCRIPTOR PoolDescriptor,
IN POOL_TYPE PoolType,
IN ULONG PoolIndex,
ASSERT(PoolType != PagedPoolSession);
}
+INIT_FUNCTION
VOID
NTAPI
-INIT_SECTION
InitializePool(IN POOL_TYPE PoolType,
IN ULONG Threshold)
{
#endif
//
- // FIXME: Not yet supported
+ // Get the amount of hits in the system lookaside lists
//
- *NonPagedPoolLookasideHits += 0;
- *PagedPoolLookasideHits += 0;
+ if (!IsListEmpty(&ExPoolLookasideListHead))
+ {
+ PLIST_ENTRY ListEntry;
+
+ for (ListEntry = ExPoolLookasideListHead.Flink;
+ ListEntry != &ExPoolLookasideListHead;
+ ListEntry = ListEntry->Flink)
+ {
+ PGENERAL_LOOKASIDE Lookaside;
+
+ Lookaside = CONTAINING_RECORD(ListEntry, GENERAL_LOOKASIDE, ListEntry);
+
+ if (Lookaside->Type == NonPagedPool)
+ {
+ *NonPagedPoolLookasideHits += Lookaside->AllocateHits;
+ }
+ else
+ {
+ *PagedPoolLookasideHits += Lookaside->AllocateHits;
+ }
+ }
+ }
}
VOID
{
#if DBG
//
- // If non paged backed, display current consumption
+ // Out of memory, display current consumption
+ // Let's consider that if the caller wanted more
+ // than a hundred pages, that's a bogus caller
+ // and we are not out of memory
//
- if ((OriginalType & BASE_POOL_TYPE_MASK) == NonPagedPool)
+ if (NumberOfBytes < 100 * PAGE_SIZE)
{
- MiDumpNonPagedPoolConsumers();
+ MiDumpPoolConsumers(FALSE, 0, 0, 0);
}
#endif
{
#if DBG
//
- // If non paged backed, display current consumption
+ // Out of memory, display current consumption
+ // Let's consider that if the caller wanted more
+ // than a hundred pages, that's a bogus caller
+ // and we are not out of memory
//
- if ((OriginalType & BASE_POOL_TYPE_MASK) == NonPagedPool)
+ if (NumberOfBytes < 100 * PAGE_SIZE)
{
- MiDumpNonPagedPoolConsumers();
+ MiDumpPoolConsumers(FALSE, 0, 0, 0);
}
#endif
return TRUE;
}
+static
+VOID
+ExpKdbgExtPoolUsedGetTag(PCHAR Arg, PULONG Tag, PULONG Mask)
+{
+ CHAR Tmp[4];
+ ULONG Len;
+ USHORT i;
+
+ /* Get the tag */
+ Len = strlen(Arg);
+ if (Len > 4)
+ {
+ Len = 4;
+ }
+
+ /* Generate the mask to have wildcards support */
+ for (i = 0; i < Len; ++i)
+ {
+ Tmp[i] = Arg[i];
+ if (Tmp[i] != '?')
+ {
+ *Mask |= (0xFF << i * 8);
+ }
+ }
+
+ /* Get the tag in the ulong form */
+ *Tag = *((PULONG)Tmp);
+}
+
+BOOLEAN
+ExpKdbgExtPoolUsed(
+ ULONG Argc,
+ PCHAR Argv[])
+{
+ ULONG Tag = 0;
+ ULONG Mask = 0;
+ ULONG Flags = 0;
+
+ if (Argc > 1)
+ {
+ /* If we have 2+ args, easy: flags then tag */
+ if (Argc > 2)
+ {
+ ExpKdbgExtPoolUsedGetTag(Argv[2], &Tag, &Mask);
+ if (!KdbpGetHexNumber(Argv[1], &Flags))
+ {
+ KdbpPrint("Invalid parameter: %s\n", Argv[0]);
+ }
+ }
+ else
+ {
+ /* Otherwise, try to find out whether that's flags */
+ if (strlen(Argv[1]) == 1 ||
+ (strlen(Argv[1]) == 3 && Argv[1][0] == '0' && Argv[1][1] == 'x'))
+ {
+ /* Fallback: if reading flags failed, assume it's a tag */
+ if (!KdbpGetHexNumber(Argv[1], &Flags))
+ {
+ ExpKdbgExtPoolUsedGetTag(Argv[1], &Tag, &Mask);
+ }
+ }
+ /* Or tag */
+ else
+ {
+ ExpKdbgExtPoolUsedGetTag(Argv[1], &Tag, &Mask);
+ }
+ }
+ }
+
+ /* Call the dumper */
+ MiDumpPoolConsumers(TRUE, Tag, Mask, Flags);
+
+ 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 */