624 lines
18 KiB
C
624 lines
18 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
pooldump.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the implementation of the temporary routine
|
||
to dump non-paged pool usage.
|
||
|
||
Usage:
|
||
|
||
Set TRACE_ALLOC to 1 in pool.c and rebuild the kernel.
|
||
When pooldump is run, the colllected pool counts are returned
|
||
and analyzed.
|
||
|
||
Author:
|
||
|
||
Lou Perazzoli (loup) 22-Aug-1991
|
||
|
||
Envirnoment:
|
||
|
||
|
||
User mode, debug version of the kernel.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include <assert.h>
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
#include <memory.h>
|
||
#include <nt.h>
|
||
#include <ntrtl.h>
|
||
#include <nturtl.h>
|
||
#include <windows.h>
|
||
|
||
#define DbgPrint printf
|
||
//#define DBG_PROFILE 1
|
||
|
||
|
||
NTSTATUS
|
||
LoadSymbols (
|
||
VOID
|
||
);
|
||
|
||
NTSTATUS
|
||
LookupSymbolNameAndLocation (
|
||
IN ULONG CodeAddress,
|
||
OUT PSTRING SymbolName,
|
||
OUT PULONG OffsetFromSymbol,
|
||
OUT PULONG ImageIndex
|
||
);
|
||
|
||
#define PAGE_SIZE 4096
|
||
|
||
typedef struct _IMAGE_BLOCK {
|
||
ULONG ImageBase; //actual base where mapped locally.
|
||
PIMAGE_DEBUG_INFO DebugInfo;
|
||
ULONG CodeStart;
|
||
ULONG CodeEnd;
|
||
ULONG TextNumber;
|
||
BOOLEAN KernelCode;
|
||
UNICODE_STRING ImageName;
|
||
} IMAGE_BLOCK;
|
||
|
||
|
||
#define MAX_PROFILE_COUNT 30
|
||
|
||
IMAGE_BLOCK ImageInformation[MAX_PROFILE_COUNT+1];
|
||
|
||
ULONG NumberOfImages = 0;
|
||
|
||
//
|
||
// Define map data file if the produced data file should be
|
||
// a mapped file (currently named "kernprof.dat").
|
||
//
|
||
|
||
// #define MAP_DATA_FILE
|
||
|
||
//
|
||
// Define map as image if the image to be profiled should be mapped
|
||
// as an image rather than as data.
|
||
//
|
||
|
||
// #define MAP_AS_IMAGE
|
||
|
||
#define MAX_POOL_ENTRIES 1024
|
||
|
||
typedef struct _POOLUSAGE {
|
||
ULONG Caller;
|
||
ULONG Allocations;
|
||
ULONG Frees;
|
||
ULONG Usage;
|
||
} POOLUSAGE;
|
||
|
||
POOLUSAGE Buffer[MAX_POOL_ENTRIES];
|
||
__cdecl main(
|
||
int argc,
|
||
char *argv[],
|
||
char *envp[]
|
||
)
|
||
{
|
||
NTSTATUS status;
|
||
ULONG i, Offset;
|
||
ULONG TotalAllocs = 0;
|
||
ULONG TotalFrees = 0;
|
||
ULONG TotalUsage = 0;
|
||
ULONG Start;
|
||
STRING SymbolName;
|
||
UCHAR String[80];
|
||
STRING OutString;
|
||
ULONG ImageIndex;
|
||
|
||
RtlZeroMemory (&Buffer, MAX_POOL_ENTRIES * sizeof (POOLUSAGE));
|
||
|
||
SymbolName.MaximumLength = 80;
|
||
SymbolName.Buffer = String;
|
||
|
||
status = NtPartyByNumber (PARTY_DUMP_POOL_USAGE, &Buffer);
|
||
if (!NT_SUCCESS (status)) {
|
||
return(status);
|
||
}
|
||
LoadSymbols ();
|
||
|
||
printf("Allocs Frees Used At\n");
|
||
|
||
for (i =0; i < MAX_POOL_ENTRIES ; i++ ) {
|
||
if (Buffer[i].Caller == 0) {
|
||
break;
|
||
}
|
||
|
||
String[0] = 0;
|
||
SymbolName.MaximumLength = 80;
|
||
SymbolName.Length = 0;
|
||
Offset = Buffer[i].Caller;
|
||
LookupSymbolNameAndLocation (Buffer[i].Caller,
|
||
&SymbolName,
|
||
&Offset,
|
||
&ImageIndex);
|
||
|
||
RtlUnicodeStringToAnsiString(&OutString,
|
||
&ImageInformation[ImageIndex].ImageName,
|
||
TRUE);
|
||
|
||
printf("%6ld %6ld %6ld %s + 0x%lx (%s)\n",
|
||
Buffer[i].Allocations,
|
||
Buffer[i].Frees,
|
||
Buffer[i].Usage,
|
||
SymbolName.Buffer,
|
||
Offset,
|
||
OutString.Buffer
|
||
);
|
||
|
||
RtlFreeAnsiString(&OutString);
|
||
TotalAllocs += Buffer[i].Allocations;
|
||
TotalFrees += Buffer[i].Frees;
|
||
TotalUsage += Buffer[i].Usage;
|
||
}
|
||
|
||
|
||
printf("Total: allocations %ld Frees %ld Difference (A-F) %ld Usage %ld\n",
|
||
TotalAllocs, TotalFrees, (TotalAllocs - TotalFrees), TotalUsage);
|
||
|
||
return(status);
|
||
}
|
||
|
||
NTSTATUS
|
||
LoadSymbols (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initializes symbols for the kernel.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
Status of operations.
|
||
|
||
--*/
|
||
|
||
{
|
||
IO_STATUS_BLOCK IoStatus;
|
||
HANDLE FileHandle, KernelSection;
|
||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
PVOID ImageBase;
|
||
ULONG ViewSize;
|
||
ULONG CodeLength;
|
||
NTSTATUS status;
|
||
HANDLE CurrentProcessHandle;
|
||
ULONG DebugSize;
|
||
PVOID KernelBase;
|
||
PIMAGE_DEBUG_DIRECTORY DebugDirectory;
|
||
UCHAR StringBuf[250];
|
||
UNICODE_STRING NameString;
|
||
ULONG TotalOffset;
|
||
CHAR ModuleInfo[8000];
|
||
ULONG ReturnedLength;
|
||
PSYSTEM_LOAD_MODULE_INFORMATION Module;
|
||
ANSI_STRING String;
|
||
STRING SysdiskA;
|
||
STRING SysrootA;
|
||
UNICODE_STRING Sysdisk;
|
||
UNICODE_STRING Sysroot;
|
||
PIMAGE_DEBUG_INFO KernelDebugInfo;
|
||
|
||
CurrentProcessHandle = NtCurrentProcess();
|
||
|
||
//
|
||
// Locate system drivers.
|
||
//
|
||
|
||
status = NtQuerySystemInformation (
|
||
SystemLoadModuleInformation,
|
||
ModuleInfo,
|
||
8000,
|
||
&ReturnedLength);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
printf("query system info failed status - %lx\n",status);
|
||
return(status);
|
||
}
|
||
|
||
RtlInitString (&SysdiskA,"\\SystemRoot");
|
||
RtlAnsiStringToUnicodeString (&Sysdisk, (PANSI_STRING)&SysdiskA, TRUE);
|
||
|
||
RtlInitString (&SysrootA,"\\SystemRoot\\Driver\\");
|
||
RtlAnsiStringToUnicodeString (&Sysroot, (PANSI_STRING)&SysrootA, TRUE);
|
||
|
||
NameString.Buffer = &StringBuf[0];
|
||
NameString.Length = 0;
|
||
NameString.MaximumLength = 250;
|
||
|
||
Module = &ModuleInfo[0];
|
||
TotalOffset = 0;
|
||
while (TRUE) {
|
||
|
||
#if DBG_PROFILE
|
||
printf("module base %lx\n",Module->BaseAddress);
|
||
printf("module dll buffer address %lx %lx %lx\n",
|
||
Module->ModuleDllName.Buffer,
|
||
Module->ModuleFileName.Buffer, Module);
|
||
RtlUnicodeStringToAnsiString(&String, &Module->ModuleDllName, TRUE);
|
||
printf("module dll name %s\n",String.Buffer);
|
||
RtlUnicodeStringToAnsiString(&String, &Module->ModuleFileName, TRUE);
|
||
printf("module file name %s\n",String.Buffer);
|
||
#endif
|
||
|
||
if ( Module->ModuleFileName.Buffer[0] == (WCHAR) '\\' ) {
|
||
Module->ModuleFileName.Buffer++;
|
||
Module->ModuleFileName.Length -= sizeof(WCHAR);
|
||
Module->ModuleFileName.MaximumLength -= sizeof(WCHAR);
|
||
while (Module->ModuleFileName.Buffer[0] != (WCHAR) '\\' ) {
|
||
Module->ModuleFileName.Buffer++;
|
||
Module->ModuleFileName.Length -= sizeof(WCHAR);
|
||
Module->ModuleFileName.MaximumLength -= sizeof(WCHAR);
|
||
}
|
||
}
|
||
|
||
NameString.Length = 0;
|
||
status = RtlAppendStringToString (&NameString, (PSTRING)&Sysdisk);
|
||
if (!NT_SUCCESS(status)) {
|
||
printf("append string failed status - %lx\n",status);
|
||
return(status);
|
||
}
|
||
|
||
status = RtlAppendStringToString (&NameString, (PSTRING)&Module->ModuleFileName);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
printf("append string failed status - %lx\n",status);
|
||
return(status);
|
||
}
|
||
|
||
InitializeObjectAttributes( &ObjectAttributes,
|
||
&NameString,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL );
|
||
|
||
//
|
||
// Open the file as readable and executable.
|
||
//
|
||
|
||
#if DBG_PROFILE
|
||
RtlUnicodeStringToAnsiString(&String, &NameString, TRUE);
|
||
printf("Opening file name %s\n",String.Buffer);
|
||
#endif
|
||
|
||
status = NtOpenFile ( &FileHandle,
|
||
FILE_READ_DATA | FILE_EXECUTE,
|
||
&ObjectAttributes,
|
||
&IoStatus,
|
||
FILE_SHARE_READ,
|
||
0L);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Try a different name - in SystemRoot\Driver directory.
|
||
//
|
||
|
||
NameString.Length = 0;
|
||
status = RtlAppendStringToString (&NameString, &Sysroot);
|
||
if (!NT_SUCCESS(status)) {
|
||
printf("append string failed status - %lx\n",status);
|
||
return(status);
|
||
}
|
||
|
||
status = RtlAppendStringToString (&NameString, &Module->ModuleFileName);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
printf("append string failed status - %lx\n",status);
|
||
return(status);
|
||
}
|
||
|
||
InitializeObjectAttributes( &ObjectAttributes,
|
||
&NameString,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL );
|
||
|
||
//
|
||
// Open the file as readable and executable.
|
||
//
|
||
|
||
#if DBG_PROFILE
|
||
RtlUnicodeStringToAnsiString(&String, &NameString, TRUE);
|
||
printf("Opening file name %s\n",String.Buffer);
|
||
#endif
|
||
status = NtOpenFile ( &FileHandle,
|
||
FILE_READ_DATA,
|
||
&ObjectAttributes,
|
||
&IoStatus,
|
||
FILE_SHARE_READ,
|
||
0L);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
RtlUnicodeStringToAnsiString(&String, &NameString, TRUE);
|
||
DbgPrint("open file %s failed status %lx\n",
|
||
String.Buffer, status);
|
||
return(status);
|
||
}
|
||
}
|
||
|
||
InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL );
|
||
|
||
//
|
||
// For normal images they would be mapped as an image, but
|
||
// the kernel has no debug section (as yet) information, hence it
|
||
// must be mapped as a file.
|
||
//
|
||
|
||
status = NtCreateSection (&KernelSection,
|
||
SECTION_MAP_READ,
|
||
&ObjectAttributes,
|
||
0,
|
||
PAGE_READONLY,
|
||
SEC_COMMIT,
|
||
FileHandle);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
DbgPrint("create image section failed status %lx\n", status);
|
||
return(status);
|
||
}
|
||
|
||
ViewSize = 0;
|
||
|
||
//
|
||
// Map a view of the section into the address space.
|
||
//
|
||
|
||
KernelBase = NULL;
|
||
|
||
status = NtMapViewOfSection (KernelSection,
|
||
CurrentProcessHandle,
|
||
&KernelBase,
|
||
0L,
|
||
0,
|
||
NULL,
|
||
&ViewSize,
|
||
ViewUnmap,
|
||
0,
|
||
PAGE_READONLY);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
if (status != STATUS_IMAGE_NOT_AT_BASE) {
|
||
DbgPrint("map section status %lx base %lx size %lx\n", status,
|
||
(ULONG)KernelBase, ViewSize);
|
||
}
|
||
}
|
||
|
||
ImageBase = Module->BaseAddress;
|
||
|
||
DebugDirectory = (PIMAGE_DEBUG_DIRECTORY)RtlImageDirectoryEntryToData(
|
||
KernelBase, FALSE, IMAGE_DIRECTORY_ENTRY_DEBUG, &DebugSize);
|
||
|
||
//printf("Mapped base %lx Debug dir %lx\n", (ULONG)KernelBase, DebugDirectory);
|
||
|
||
if (!DebugDirectory) {
|
||
DbgPrint("InitializeKernelProfile : No debug directory\n");
|
||
return STATUS_INVALID_IMAGE_FORMAT;
|
||
}
|
||
|
||
|
||
KernelDebugInfo = (PIMAGE_DEBUG_INFO)((ULONG)KernelBase + DebugDirectory->PointerToRawData);
|
||
CodeLength = KernelDebugInfo->RvaToLastByteOfCode - KernelDebugInfo->RvaToFirstByteOfCode;
|
||
|
||
ImageInformation[NumberOfImages].KernelCode = TRUE;
|
||
ImageInformation[NumberOfImages].DebugInfo = KernelDebugInfo;
|
||
ImageInformation[NumberOfImages].CodeStart = ((ULONG)ImageBase +
|
||
KernelDebugInfo->RvaToFirstByteOfCode);
|
||
ImageInformation[NumberOfImages].CodeEnd =
|
||
ImageInformation[NumberOfImages].CodeStart + CodeLength;
|
||
ImageInformation[NumberOfImages].TextNumber = 1;
|
||
ImageInformation[NumberOfImages].ImageBase = ImageBase;
|
||
ImageInformation[NumberOfImages].ImageName = Module->ModuleDllName;
|
||
|
||
NumberOfImages += 1;
|
||
if (NumberOfImages == MAX_PROFILE_COUNT) {
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
if (Module->NextEntryOffset == 0) {
|
||
break;
|
||
}
|
||
|
||
TotalOffset += Module->NextEntryOffset;
|
||
Module = (PSYSTEM_LOAD_MODULE_INFORMATION)&ModuleInfo[TotalOffset];
|
||
}
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LookupSymbolNameAndLocation (
|
||
IN ULONG CodeAddress,
|
||
OUT PSTRING SymbolName,
|
||
OUT PULONG OffsetFromSymbol,
|
||
OUT PULONG ImageIndex
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Given a code address, this routine returns the nearest symbol
|
||
name and the offset from the symbol to that name. If the
|
||
nearest symbol is not within 100k of the location, no name
|
||
is returned and the offset is the value of the CodeAddress.
|
||
|
||
Arguments:
|
||
|
||
CodeAddress - Supplies the address to lookup a symbol for.
|
||
|
||
SymbolName - Returns the name of the symbol.
|
||
|
||
OffsetFromSymbol - Returns the offset from the symbol to the
|
||
code address.
|
||
|
||
Return Value:
|
||
|
||
Status of operations.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
ULONG j, nextSymbol, imageNumber;
|
||
ULONG NewCodeAddress;
|
||
IMAGE_SYMBOL PreviousSymbol;
|
||
PIMAGE_DEBUG_INFO DebugInfo;
|
||
PIMAGE_SYMBOL SymbolEntry;
|
||
IMAGE_SYMBOL Symbol;
|
||
PUCHAR StringTable;
|
||
ULONG EightChar[3];
|
||
BOOLEAN NoSymbols;
|
||
|
||
for (imageNumber = 0; imageNumber < NumberOfImages; imageNumber++) {
|
||
if ((CodeAddress >= ImageInformation[imageNumber].ImageBase) &&
|
||
(CodeAddress <= ImageInformation[imageNumber].CodeEnd)) {
|
||
break;
|
||
}
|
||
}
|
||
*ImageIndex = imageNumber;
|
||
|
||
if (imageNumber == NumberOfImages) {
|
||
|
||
//
|
||
// Address not found.
|
||
//
|
||
|
||
SymbolName->Length = 0;
|
||
*OffsetFromSymbol = CodeAddress;
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NewCodeAddress = CodeAddress - ImageInformation[imageNumber].ImageBase;
|
||
|
||
//
|
||
// Locate debug section.
|
||
//
|
||
|
||
DebugInfo = ImageInformation[imageNumber].DebugInfo;
|
||
|
||
//
|
||
// Crack the symbol table.
|
||
//
|
||
|
||
SymbolEntry = (PIMAGE_SYMBOL)((ULONG)DebugInfo + DebugInfo->LvaToFirstSymbol);
|
||
StringTable = (PUCHAR)((ULONG)DebugInfo + DebugInfo->LvaToFirstSymbol +
|
||
DebugInfo->NumberOfSymbols * (ULONG)IMAGE_SIZEOF_SYMBOL);
|
||
|
||
//
|
||
// Find the "header" symbol (skipping all the section names)
|
||
//
|
||
|
||
nextSymbol = 0;
|
||
// printf("number of symbols %ld\n", DebugInfo->NumberOfSymbols);
|
||
for (j = 0; j < DebugInfo->NumberOfSymbols; j++) {
|
||
EightChar[0] = SymbolEntry->N.Name.Short;
|
||
EightChar[1] = SymbolEntry->N.Name.Long;
|
||
if (!strcmp((PSZ)&EightChar[0], "header")) {
|
||
nextSymbol = j;
|
||
// printf("found header at %ld\n",j);
|
||
break;
|
||
}
|
||
SymbolEntry = (PIMAGE_SYMBOL)((ULONG)SymbolEntry +
|
||
IMAGE_SIZEOF_SYMBOL);
|
||
}
|
||
if (j >= DebugInfo->NumberOfSymbols) {
|
||
SymbolEntry = (PIMAGE_SYMBOL)((ULONG)DebugInfo + DebugInfo->LvaToFirstSymbol);
|
||
}
|
||
|
||
NoSymbols = TRUE;
|
||
|
||
//
|
||
// Loop through all symbols in the symbol table. For each symbol,
|
||
// if it is within the code section, subtract off the bias and
|
||
// see if there are any hits within the profile buffer for
|
||
// that symbol.
|
||
//
|
||
|
||
// printf("number of symbols %ld\n", DebugInfo->NumberOfSymbols);
|
||
for (j = nextSymbol; j < DebugInfo->NumberOfSymbols; j++) {
|
||
|
||
|
||
try {
|
||
// printf("numberof aux symbols %ld\n",SymbolEntry->NumberOfAuxSymbols );
|
||
while ( SymbolEntry->NumberOfAuxSymbols ) {
|
||
j = j + 1 + SymbolEntry->NumberOfAuxSymbols;
|
||
SymbolEntry = (PIMAGE_SYMBOL)((ULONG)SymbolEntry +
|
||
IMAGE_SIZEOF_SYMBOL +
|
||
SymbolEntry->NumberOfAuxSymbols*IMAGE_SIZEOF_SYMBOL);
|
||
|
||
}
|
||
RtlMoveMemory (&Symbol, SymbolEntry, IMAGE_SIZEOF_SYMBOL);
|
||
}
|
||
except(EXCEPTION_EXECUTE_HANDLER) {
|
||
printf("breaking excpt\n");
|
||
break;
|
||
}
|
||
|
||
// printf("value %lx number %lx start %lx\n",Symbol.Value,Symbol.SectionNumber,CodeAddress);
|
||
if (Symbol.SectionNumber == (SHORT)1) {
|
||
|
||
//
|
||
// This symbol is within the code.
|
||
//
|
||
|
||
if (Symbol.Value < NewCodeAddress) {
|
||
PreviousSymbol = Symbol;
|
||
NoSymbols = FALSE;
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
SymbolEntry = (PIMAGE_SYMBOL)((ULONG)SymbolEntry +
|
||
IMAGE_SIZEOF_SYMBOL);
|
||
|
||
}
|
||
|
||
if ((NoSymbols) || (NewCodeAddress - PreviousSymbol.Value) > 0x100000) {
|
||
|
||
SymbolName->Length = 0;
|
||
*OffsetFromSymbol = CodeAddress;
|
||
} else {
|
||
if (PreviousSymbol.N.Name.Short) {
|
||
SymbolName->Length = 8;
|
||
if (SymbolName->Length > SymbolName->MaximumLength) {
|
||
SymbolName->Length = SymbolName->MaximumLength;
|
||
}
|
||
|
||
EightChar[0] = PreviousSymbol.N.Name.Short;
|
||
EightChar[1] = PreviousSymbol.N.Name.Long;
|
||
RtlMoveMemory (SymbolName->Buffer, EightChar, SymbolName->Length);
|
||
|
||
} else {
|
||
SymbolName->Length =
|
||
strlen(&StringTable[PreviousSymbol.N.Name.Long] ) + 1;
|
||
if (SymbolName->Length > SymbolName->MaximumLength) {
|
||
SymbolName->Length = SymbolName->MaximumLength;
|
||
}
|
||
RtlMoveMemory (SymbolName->Buffer,
|
||
&StringTable[PreviousSymbol.N.Name.Long],
|
||
SymbolName->Length);
|
||
SymbolName->Buffer[SymbolName->Length] = 0;
|
||
}
|
||
*OffsetFromSymbol = NewCodeAddress - PreviousSymbol.Value;
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|