windows-nt/Source/XPSP1/NT/sdktools/memsnap/poolsnap.c
2020-09-26 16:20:57 +08:00

472 lines
11 KiB
C

// poolsnap.c
// this program takes a snapshot of all the kernel pool tags.
// and appends it to the logfile (arg)
// pmon was model for this
/* includes */
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <io.h>
#include <srvfsctl.h>
#include <search.h>
#include "tags.c"
//
// declarations
//
int __cdecl ulcomp(const void *e1,const void *e2);
NTSTATUS
QueryPoolTagInformationIterative(
PUCHAR *CurrentBuffer,
size_t *CurrentBufferSize
);
//
// definitions
//
#define NONPAGED 0
#define PAGED 1
#define BOTH 2
// from poolmon
// raw input
PSYSTEM_POOLTAG_INFORMATION PoolInfo;
//
// the amount of memory to increase the size
// of the buffer for NtQuerySystemInformation at each step
//
#define BUFFER_SIZE_STEP 65536
//
// the buffer used for NtQuerySystemInformation
//
PUCHAR CurrentBuffer = NULL;
//
// the size of the buffer used for NtQuerySystemInformation
//
size_t CurrentBufferSize = 0;
//
// formatted output
//
typedef struct _POOLMON_OUT {
union {
UCHAR Tag[4];
ULONG TagUlong;
};
UCHAR NullByte;
BOOL Changed;
ULONG Type;
SIZE_T Allocs;
SIZE_T AllocsDiff;
SIZE_T Frees;
SIZE_T FreesDiff;
SIZE_T Allocs_Frees;
SIZE_T Used;
SIZE_T UsedDiff;
SIZE_T Each;
} POOLMON_OUT, *PPOOLMON_OUT;
PPOOLMON_OUT OutBuffer;
PPOOLMON_OUT Out;
UCHAR *PoolType[] = {
"Nonp ",
"Paged"};
VOID Usage(VOID)
{
printf("poolsnap [-?] [-t] [<logfile>]\n");
printf("poolsnap logs system pool usage to <logfile>\n");
printf("-? Gives this help\n");
printf("-t Output extra tagged information\n");
printf("<logfile> = poolsnap.log by default\n");
exit(-1);
}
/*
* FUNCTION: Main
*
* ARGUMENTS: See Usage
*
* RETURNS: 0
*
*/
int __cdecl main(int argc, char* argv[])
{
NTSTATUS Status; // status from NT api
FILE* LogFile= NULL; // log file handle
DWORD x= 0; // counter
SIZE_T NumberOfPoolTags;
INT iCmdIndex; // index into argv
BOOL bOutputTags= FALSE; // if true, output standard tags
// get higher priority in case system is bogged down
if ( GetPriorityClass(GetCurrentProcess()) == NORMAL_PRIORITY_CLASS) {
SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS);
}
//
// parse command line arguments
//
for( iCmdIndex=1; iCmdIndex < argc; iCmdIndex++ ) {
CHAR chr;
chr= *argv[iCmdIndex];
if( (chr=='-') || (chr=='/') ) {
chr= argv[iCmdIndex][1];
switch( chr ) {
case '?':
Usage();
break;
case 't': case 'T':
bOutputTags= TRUE;
break;
default:
printf("Invalid switch: %s\n",argv[iCmdIndex]);
Usage();
break;
}
}
else {
if( LogFile ) {
printf("Error: more than one file specified: %s\n",argv[iCmdIndex]);
return(0);
}
LogFile= fopen(argv[iCmdIndex],"a");
if( !LogFile ) {
printf("Error: Opening file %s\n",argv[iCmdIndex]);
return(0);
}
}
}
//
// if no file specified, use default name
//
if( !LogFile ) {
if( (LogFile = fopen("poolsnap.log","a")) == NULL ) {
printf("Error: opening file poolsnap.log\n");
return(0);
}
}
//
// print file header once
//
if( _filelength(_fileno(LogFile)) == 0 ) {
fprintf(LogFile," Tag Type Allocs Frees Diff Bytes Per Alloc\n");
}
fprintf(LogFile,"\n");
if( bOutputTags ) {
OutputStdTags(LogFile, "poolsnap" );
}
// grab all pool information
// log line format, fixed column format
Status = QueryPoolTagInformationIterative(
&CurrentBuffer,
&CurrentBufferSize
);
if (! NT_SUCCESS(Status)) {
printf("Failed to query pool tags information (status %08X). \n", Status);
printf("Please check if pool tags are enabled. \n");
return (0);
}
PoolInfo = (PSYSTEM_POOLTAG_INFORMATION)CurrentBuffer;
//
// Allocate the output buffer.
//
OutBuffer = malloc (PoolInfo->Count * sizeof(POOLMON_OUT));
if (OutBuffer == NULL) {
printf ("Error: cannot allocate internal buffer of %p bytes \n",
PoolInfo->Count * sizeof(POOLMON_OUT));
return (0);
}
Out = OutBuffer;
if( NT_SUCCESS(Status) ) {
for (x = 0; x < (int)PoolInfo->Count; x++) {
// get pool info from buffer
// non-paged
if (PoolInfo->TagInfo[x].NonPagedAllocs != 0) {
Out->Allocs = PoolInfo->TagInfo[x].NonPagedAllocs;
Out->Frees = PoolInfo->TagInfo[x].NonPagedFrees;
Out->Used = PoolInfo->TagInfo[x].NonPagedUsed;
Out->Allocs_Frees = PoolInfo->TagInfo[x].NonPagedAllocs -
PoolInfo->TagInfo[x].NonPagedFrees;
Out->TagUlong = PoolInfo->TagInfo[x].TagUlong;
Out->Type = NONPAGED;
Out->Changed = FALSE;
Out->NullByte = '\0';
Out->Each = Out->Used / (Out->Allocs_Frees?Out->Allocs_Frees:1);
}
// paged
if (PoolInfo->TagInfo[x].PagedAllocs != 0) {
Out->Allocs = PoolInfo->TagInfo[x].PagedAllocs;
Out->Frees = PoolInfo->TagInfo[x].PagedFrees;
Out->Used = PoolInfo->TagInfo[x].PagedUsed;
Out->Allocs_Frees = PoolInfo->TagInfo[x].PagedAllocs -
PoolInfo->TagInfo[x].PagedFrees;
Out->TagUlong = PoolInfo->TagInfo[x].TagUlong;
Out->Type = PAGED;
Out->Changed = FALSE;
Out->NullByte = '\0';
Out->Each = Out->Used / (Out->Allocs_Frees?Out->Allocs_Frees:1);
}
Out += 1;
}
}
else {
fprintf(LogFile, "Query pooltags Failed %lx\n",Status);
fprintf(LogFile, " Be sure to turn on 'enable pool tagging' in gflags and reboot.\n");
if( bOutputTags ) {
fprintf(LogFile, "!Error:Query pooltags failed %lx\n",Status);
fprintf(LogFile, "!Error: Be sure to turn on 'enable pool tagging' in gflags and reboot.\n");
}
// If there is an operator around, wake him up, but keep moving
Beep(1000,350); Beep(500,350); Beep(1000,350);
exit(0);
}
//
// sort by tag value which is big endian
//
NumberOfPoolTags = Out - OutBuffer;
qsort((void *)OutBuffer,
(size_t)NumberOfPoolTags,
(size_t)sizeof(POOLMON_OUT),
ulcomp);
//
// print in file
//
for (x = 0; x < (int)PoolInfo->Count; x++) {
fprintf(LogFile,
#ifdef _WIN64
" %4s %5s %18I64d %18I64d %16I64d %14I64d %12I64d\n",
#else
" %4s %5s %9ld %9ld %8ld %7ld %6ld\n",
#endif
OutBuffer[x].Tag,
PoolType[OutBuffer[x].Type],
OutBuffer[x].Allocs,
OutBuffer[x].Frees,
OutBuffer[x].Allocs_Frees,
OutBuffer[x].Used,
OutBuffer[x].Each
);
}
// close file
fclose(LogFile);
return 0;
}
// comparison function for qsort
// Tags are big endian
int __cdecl ulcomp(const void *e1,const void *e2)
{
ULONG u1;
u1 = ((PUCHAR)e1)[0] - ((PUCHAR)e2)[0];
if (u1 != 0) {
return u1;
}
u1 = ((PUCHAR)e1)[1] - ((PUCHAR)e2)[1];
if (u1 != 0) {
return u1;
}
u1 = ((PUCHAR)e1)[2] - ((PUCHAR)e2)[2];
if (u1 != 0) {
return u1;
}
u1 = ((PUCHAR)e1)[3] - ((PUCHAR)e2)[3];
return u1;
}
/*
* FUNCTION:
*
* QueryPoolTagInformationIterative
*
* ARGUMENTS:
*
* CurrentBuffer - a pointer to the buffer currently used for
* NtQuerySystemInformation( SystemPoolTagInformation ).
* It will be allocated if NULL or its size grown
* if necessary.
*
* CurrentBufferSize - a pointer to a variable that holds the current
* size of the buffer.
*
*
* RETURNS:
*
* NTSTATUS returned by NtQuerySystemInformation or
* STATUS_INSUFFICIENT_RESOURCES if the buffer must grow and the
* heap allocation for it fails.
*
*/
NTSTATUS
QueryPoolTagInformationIterative(
PUCHAR *CurrentBuffer,
size_t *CurrentBufferSize
)
{
size_t NewBufferSize;
NTSTATUS ReturnedStatus = STATUS_SUCCESS;
if( CurrentBuffer == NULL || CurrentBufferSize == NULL ) {
return STATUS_INVALID_PARAMETER;
}
if( *CurrentBufferSize == 0 || *CurrentBuffer == NULL ) {
//
// there is no buffer allocated yet
//
NewBufferSize = sizeof( UCHAR ) * BUFFER_SIZE_STEP;
*CurrentBuffer = (PUCHAR) malloc( NewBufferSize );
if( *CurrentBuffer != NULL ) {
*CurrentBufferSize = NewBufferSize;
} else {
//
// insufficient memory
//
ReturnedStatus = STATUS_INSUFFICIENT_RESOURCES;
}
}
//
// iterate by buffer's size
//
while( *CurrentBuffer != NULL ) {
ReturnedStatus = NtQuerySystemInformation (
SystemPoolTagInformation,
*CurrentBuffer,
(ULONG)*CurrentBufferSize,
NULL );
if( ! NT_SUCCESS(ReturnedStatus) ) {
//
// free the current buffer
//
free( *CurrentBuffer );
*CurrentBuffer = NULL;
if (ReturnedStatus == STATUS_INFO_LENGTH_MISMATCH) {
//
// try with a greater buffer size
//
NewBufferSize = *CurrentBufferSize + BUFFER_SIZE_STEP;
*CurrentBuffer = (PUCHAR) malloc( NewBufferSize );
if( *CurrentBuffer != NULL ) {
//
// allocated new buffer
//
*CurrentBufferSize = NewBufferSize;
} else {
//
// insufficient memory
//
ReturnedStatus = STATUS_INSUFFICIENT_RESOURCES;
*CurrentBufferSize = 0;
}
} else {
*CurrentBufferSize = 0;
}
} else {
//
// NtQuerySystemInformation returned success
//
break;
}
}
return ReturnedStatus;
}