Windows2003-3790/sdktools/perfmtr/poolmon.c
2020-09-30 16:53:55 +02:00

2813 lines
88 KiB
C

/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
poolmon.c
Abstract:
This module contains the NT/Win32 Pool Monitor
Author:
Lou Perazzoli (loup) 13-Sep-1993
Revision History:
Swetha Narayanaswamy (swethan) 25th-Mar-2002 Added functionality to provide driver description from pooltag files
and to dynamically build a local tag file from driver binaries in the system
--*/
#include "perfmtrp.h"
#include <search.h>
#include <malloc.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <io.h>
#include <stddef.h>
#if !defined (_WIN64)
extern BOOL MakeLocalTagFile();
#endif
//
// the amount of memory to increase the size
// of the buffer for NtQuerySystemInformation at each step
//
#define BUFFER_SIZE_STEP 65536
#define CPU_USAGE 0
#define QUOTAS 1
#define TAG 0
#define ALLOC 1
#define FREE 2
#define DIFF 3
#define BYTES 4
#define EACH 5
#define LIGHT 6
#define NONPAGED 0
#define PAGED 1
#define BOTH 2
#define OUTPUTBUFFERSIZE 512
UCHAR *PoolType[] = {
"Nonp ",
"Paged" };
PUCHAR LargeBuffer1 = NULL;
PUCHAR LargeBuffer2 = NULL;
SIZE_T LargeBuffer1Size = 0;
SIZE_T LargeBuffer2Size = 0;
PCHAR pchLogFile = NULL; //log file name for snapshot
PCHAR pchLocalTagFile = NULL; //local tag file name
PCHAR pchPoolTagFile = NULL; //pool tag file name
typedef struct _POOLMON_OUT {
union {
UCHAR Tag[4];
ULONG TagUlong;
};
UCHAR NullByte;
BOOLEAN 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;
POOLMON_OUT *OutBuffer = NULL;
SIZE_T OutBufferSize = 0;
#define TAGMAPLEN 971
// There are about 90 wild card tags in pooltag.txt
// All wild-card tag entries will have at least one starting letter
// Tags do not begin with a wild-card
#define WILDCARDTAGMAPLEN 26
#define POOLTAGFILE "pooltag.txt"
#define LOCALTAGFILE "localtag.txt"
#define DRIVERNAMELEN 64
#define INVALID_INDEX WILDCARDTAGMAPLEN+1
// Tag file size of 1000000 allows for 10000 tag entries of 100 bytes each
// 100 bytes for each tag entry would allow for a driver length of 64 bytes, tag size of 4 bytes and the rest for formatting
// Note: The MAXTAGFILESIZE check really does not prevent a bad tag file from being opened, it just prevents the process
// from stalling for too long if a file open is done on a very large file.
#define MAXTAGFILESIZE 1000000
typedef struct _TAGNODE{
UCHAR Tag[5];
UCHAR Driver[DRIVERNAMELEN];
struct _TAGNODE *next;
} TAGNODE, *PTAGNODE;
PTAGNODE* TagMap = NULL;
PTAGNODE* WildCardTagMap=NULL;
BOOL BuildTagMap();
VOID FreeTagMap();
PTAGNODE LookupTag(PUCHAR tag);
ULONG DisplayType = BOTH;
ULONG SortBy = TAG;
ULONG Paren = 0;
BOOL DisplaySessionPool = FALSE;
ULONG DisplaySessionId = (ULONG)-1;
ULONG SessionBufferSize = 0;
PSYSTEM_SESSION_POOLTAG_INFORMATION SessionBuffer = NULL;
ULONG DelayTimeMsec = 5000;
BOOLEAN Interactive;
BOOLEAN IsSnap = FALSE;
BOOL fLocalTag = FALSE;
BOOL fPoolTag = FALSE;
BOOL fPrintSummaryInfo = FALSE;
ULONG NumberOfInputRecords;
INPUT_RECORD InputRecord;
HANDLE InputHandle;
HANDLE OriginalOutputHandle;
HANDLE OutputHandle;
DWORD OriginalInputMode;
WORD NormalAttribute;
WORD HighlightAttribute;
ULONG NumberOfCols;
ULONG NumberOfRows;
ULONG NumberOfDetailLines;
SIZE_T FirstDetailLine;
CONSOLE_SCREEN_BUFFER_INFO OriginalConsoleInfo;
ULONG NoHighlight = 0;
BOOLEAN DisplayTotals = FALSE;
POOLMON_OUT Totals[2];
typedef struct _FILTER {
union {
UCHAR Tag[4];
ULONG TagUlong;
};
BOOLEAN Exclude;
} FILTER, *PFILTER;
#define MAX_FILTER 64
FILTER Filter[MAX_FILTER];
ULONG FilterCount = 0;
PCHAR UsageStrings[] = {
"poolmon [-? | -h | -s | -n [LogFile] | -l [LocalTagFile] | -g [PoolTagFile] |",
" [-i'tag']*[-x'tag']*[-e][-t | -a | -u |",
" -b | -f | -d | -m][-l][-p[-p]][-( | -)]*| -r]",
"",
" -? and -h Display this help",
" -s Display session pool",
"",
" -n [Logfile] Take a pool snapshot",
" Logfile maybe specified, default is poolsnap.log",
#if !defined (_WIN64)
" -c [LocalTagFile] Display driver information using LocalTagFile",
" If LocalTagFile is not specified",
" use 'localtag.txt' from current directory",
#endif
" -g [PoolTagFile] Display driver information using PoolTagFile",
" If PoolTagFile is not specified",
" use 'pooltag.txt' from current directory",
"",
" -itag Include the tag",
" -xtag Exclude the tag",
" -e Display totals",
" -t Sort by tags",
" -a Sort by allocs",
" -u | -b Sort by Bytes",
" -f Sort by free",
" -d Sort by diff",
" -m Sort by each",
" -l Highlight",
" -p First turns on nonpaged, second turns on paged",
" -( | -) Increase parenthesis",
" -r Print memory summary information"
};
VOID Usage(VOID)
{
int i = 0;
for(i = 0; i < sizeof(UsageStrings)/sizeof(PCHAR); i++)
{
puts(UsageStrings[i]);
}
exit(-1);
}
int HashString(PUCHAR sz)
{
long page_index = 0;
UCHAR c;
if(!sz)return -1;
while(*sz)
{
c = *(sz++);
page_index = (page_index<<2) ^ c;
}
//
// Calculate hash value.
//
return (page_index & 0x7fffffff);
}
VOID
ShowHelpPopup( VOID );
int __cdecl
PoolSnap(FILE *LogFile);
VOID
ShowSessionPopup( VOID );
int __cdecl
ulcomp(const void *e1,const void *e2);
BOOL
GetSnapShotInfo(LPWSTR szBuf, LPDWORD lpdwSize);
int __cdecl
ulcomp(const void *e1,const void *e2)
{
LONG_PTR u1;
switch (SortBy) {
case TAG:
u1 = ((PUCHAR)e1)[0] - ((PUCHAR)e2)[0];
if (u1 != 0) {
return u1 > 0 ? 1 : -1;
}
u1 = ((PUCHAR)e1)[1] - ((PUCHAR)e2)[1];
if (u1 != 0) {
return u1 > 0 ? 1 : -1;
}
u1 = ((PUCHAR)e1)[2] - ((PUCHAR)e2)[2];
if (u1 != 0) {
return u1 > 0 ? 1 : -1;
}
u1 = ((PUCHAR)e1)[3] - ((PUCHAR)e2)[3];
if (u1 == 0) {
return 0;
} else {
return u1 > 0 ? 1 : -1;
}
break;
case ALLOC:
if (Paren & 1) {
u1 = ((PPOOLMON_OUT)e2)->AllocsDiff -
((PPOOLMON_OUT)e1)->AllocsDiff;
} else {
u1 = ((PPOOLMON_OUT)e2)->Allocs -
((PPOOLMON_OUT)e1)->Allocs;
}
if (u1 == 0) {
return 0;
} else {
return u1 > 0 ? 1 : -1;
}
break;
case FREE:
if (Paren & 1) {
u1 = ((PPOOLMON_OUT)e2)->FreesDiff -
((PPOOLMON_OUT)e1)->FreesDiff;
} else {
u1 = ((PPOOLMON_OUT)e2)->Frees -
((PPOOLMON_OUT)e1)->Frees;
}
if (u1 == 0) {
return 0;
} else {
return u1 > 0 ? 1 : -1;
}
break;
case BYTES:
if (Paren & 1) {
u1 = ((PPOOLMON_OUT)e2)->UsedDiff -
((PPOOLMON_OUT)e1)->UsedDiff;
} else {
u1 = ((PPOOLMON_OUT)e2)->Used -
((PPOOLMON_OUT)e1)->Used;
}
if (u1 == 0) {
return 0;
} else {
return u1 > 0 ? 1 : -1;
}
break;
case DIFF:
u1 = ((PPOOLMON_OUT)e2)->Allocs_Frees -
((PPOOLMON_OUT)e1)->Allocs_Frees;
if (u1 == 0) {
return 0;
} else {
return u1 > 0 ? 1 : -1;
}
break;
case EACH:
u1 = ((PPOOLMON_OUT)e2)->Each -
((PPOOLMON_OUT)e1)->Each;
if (u1 == 0) {
return 0;
} else {
return u1 > 0 ? 1 : -1;
}
break;
default:
return(0);
break;
}
}
BOOLEAN
CheckSingleFilter (
PCHAR Tag,
PCHAR Filter
)
{
ULONG i;
CHAR tc;
CHAR fc;
for ( i = 0; i < 4; i++ ) {
tc = *Tag++;
fc = *Filter++;
if ( fc == '*' ) return TRUE;
if ( fc == '?' ) continue;
if ( tc != fc ) return FALSE;
}
return TRUE;
}
BOOLEAN
CheckFilters (
PSYSTEM_POOLTAG TagInfo
)
{
BOOLEAN pass;
ULONG i;
PCHAR tag;
//
// If there are no filters, all tags pass.
//
if ( FilterCount == 0 ) {
return TRUE;
}
//
// There are filters. If the first filter excludes tags, then any
// tag not explicitly mentioned passes. If the first filter includes
// tags, then any tag not explicitly mentioned fails.
//
if ( Filter[0].Exclude ) {
pass = TRUE;
} else {
pass = FALSE;
}
tag = TagInfo->Tag;
for ( i = 0; i < FilterCount; i++ ) {
if ( CheckSingleFilter( tag, (PCHAR)&Filter[i].Tag ) ) {
pass = !Filter[i].Exclude;
}
}
return pass;
}
VOID
AddFilter (
BOOLEAN Exclude,
PCHAR FilterString
)
{
PFILTER f;
PCHAR p;
ULONG i;
if ( FilterCount == MAX_FILTER ) {
printf( "Poolmon: Too many filters specified. Limit is %d\n", MAX_FILTER );
return;
}
f = &Filter[FilterCount];
p = f->Tag;
for ( i = 0; i < 4; i++ ) {
if ( *FilterString == 0 ) break;
*p++ = *FilterString++;
}
for ( ; i < 4; i++ ) {
*p++ = ' ';
}
f->Exclude = Exclude;
FilterCount++;
return;
}
VOID
ParseArgs (
int argc,
char *argv[]
)
{
char *p, *prev=NULL;
BOOLEAN exclude;
PCHAR *filep;
argc--;
argv++;
while ( argc-- > 0 ) {
p = *argv++;
if ( *p == '-' || *p == '/' ) {
p++;
exclude = TRUE;
switch ( tolower(*p) ) {
case '?':
case 'h':
Usage();
ExitProcess( 1 );
break;
case 'n':
//
// Taking a snap.
//
IsSnap = TRUE;
filep = &pchLogFile;
break;
#if !defined (_WIN64)
case 'c':
// build or use existing local tag file to display driver information
fLocalTag = TRUE;
filep = &pchLocalTagFile;
break;
#endif
case 'g':
// use existing pooltag file to display driver information
fPoolTag = TRUE;
filep = &pchPoolTagFile;
break;
case 'i':
exclude = FALSE;
case 'x':
p++;
if ( strlen(p) == 0 ) {
printf( "Poolmon: missing filter string\n" );
ExitProcess( 1 );
} else if ( strlen(p) <= sizeof(ULONG) ) {
AddFilter( exclude, p );
} else {
printf( "Poolmon: filter string too long: %s\n", p );
ExitProcess( 1 );
}
break;
case 'e':
DisplayTotals = TRUE;
break;
case 't':
SortBy = TAG;
break;
case 'a':
SortBy = ALLOC;
break;
case 'u':
case 'b':
SortBy = BYTES;
break;
case 'f':
SortBy = FREE;
break;
case 'd':
SortBy = DIFF;
break;
case 'm':
SortBy = EACH;
case 'l':
NoHighlight = 1 - NoHighlight;
break;
case 'p':
DisplayType += 1;
if (DisplayType > BOTH) {
DisplayType = NONPAGED;
}
break;
case '(':
case ')':
Paren += 1;
break;
case 's':
DisplaySessionPool = TRUE;
if (*(p+1) != 0) {
DisplaySessionId = atoi (p+1);
} else {
DisplaySessionId = (ULONG)-1;
}
break;
case 'r':
// print memory summary info
fPrintSummaryInfo = TRUE;
break;
default:
printf( "Poolmon: unknown switch: %s\n", p );
ExitProcess( 2 );
}
}else {
if(! IsSnap && !fLocalTag && !fPoolTag )
{
printf("Poolmon: unknown switch: %s\n", p );
ExitProcess( 2 );
}
if (prev != NULL)
{
// The filename must be immediately after the option
if (*prev != '-' && *prev != '/')
{
printf("Poolmon: unknown switch: %s\n", p );
ExitProcess( 2 );
}
//Check if the previous option is one that allows a file name after it
if (*++prev != 'n' && *prev != 'g' && *prev != 'c')
{
printf("Poolmon: unknown switch: %s\n", p );
ExitProcess( 2 );
}
}
if (*filep != NULL)
{
printf("Poolmon: Duplicate file name: %s\n", p );
ExitProcess( 2 );
}
*filep = p;
}
prev = --p;
}
return;
}
BOOL
WriteConsoleLine(
HANDLE OutputHandle,
WORD LineNumber,
LPSTR Text,
BOOL Highlight
)
{
COORD WriteCoord;
DWORD NumberWritten;
DWORD TextLength;
WriteCoord.X = 0;
WriteCoord.Y = LineNumber;
if (!FillConsoleOutputCharacter( OutputHandle,
' ',
NumberOfCols,
WriteCoord,
&NumberWritten
)
) {
return FALSE;
}
if (!FillConsoleOutputAttribute( OutputHandle,
(WORD)((Highlight && !NoHighlight) ? HighlightAttribute : NormalAttribute),
NumberOfCols,
WriteCoord,
&NumberWritten
)
) {
return FALSE;
}
if (Text == NULL || (TextLength = strlen( Text )) == 0) {
return TRUE;
}
else {
return WriteConsoleOutputCharacter( OutputHandle,
Text,
TextLength,
WriteCoord,
&NumberWritten
);
}
}
NTSTATUS
QueryPoolTagInformationIterative(
PUCHAR *CurrentBuffer,
SIZE_T *CurrentBufferSize
)
{
size_t NewBufferSize;
NTSTATUS ReturnedStatus = STATUS_SUCCESS;
if( CurrentBuffer == NULL || CurrentBufferSize == NULL ) {
return STATUS_INVALID_PARAMETER;
}
//
// There is no buffer allocated yet.
//
if( *CurrentBufferSize == 0 || *CurrentBuffer == NULL ) {
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 larger 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;
}
ULONG
GetExtraPooltagEntriesNeeded (
PSYSTEM_POOLTAG_INFORMATION SystemPooltagInfoBuffer,
PSYSTEM_SESSION_POOLTAG_INFORMATION SessionPooltagInfo
)
{
ULONG ExtraNeeded;
ULONG SessionTag;
ULONG SystemTag;
ExtraNeeded = 0;
for (SessionTag = 0; SessionTag < SessionPooltagInfo->Count; SessionTag += 1) {
for (SystemTag = 0; SystemTag < SystemPooltagInfoBuffer->Count; SystemTag += 1) {
if (SessionPooltagInfo->TagInfo[ SessionTag ].TagUlong ==
SystemPooltagInfoBuffer->TagInfo[ SystemTag ].TagUlong) {
//
// This session tag is already in our system buffer so we don't
// need extra space for it.
//
break;
}
}
if (SystemTag >= SystemPooltagInfoBuffer->Count) {
//
// We didn't find the current session pooltag in the system buffer
// so we need an extra entry for it.
//
ExtraNeeded += 1;
}
}
return ExtraNeeded;
}
VOID
AddSessionInfoToSystemPooltagInfo (
PSYSTEM_POOLTAG_INFORMATION SystemPooltagInfoBuffer,
PSYSTEM_SESSION_POOLTAG_INFORMATION SessionPooltagInfo
)
{
ULONG SessionTag;
ULONG SystemTag;
ASSERT (SystemPooltagInfoBuffer != NULL);
ASSERT (SessionPooltagInfo != NULL);
for (SessionTag = 0; SessionTag < SessionPooltagInfo->Count; SessionTag += 1) {
for (SystemTag = 0; SystemTag < SystemPooltagInfoBuffer->Count; SystemTag += 1) {
if (SessionPooltagInfo->TagInfo[ SessionTag ].TagUlong ==
SystemPooltagInfoBuffer->TagInfo[ SystemTag ].TagUlong) {
//
// This session tag is already in our system tag buffer.
// Add the counters for this session.
//
SystemPooltagInfoBuffer->TagInfo[ SystemTag ].PagedAllocs +=
SessionPooltagInfo->TagInfo[ SessionTag ].PagedAllocs;
SystemPooltagInfoBuffer->TagInfo[ SystemTag ].PagedFrees +=
SessionPooltagInfo->TagInfo[ SessionTag ].PagedFrees;
SystemPooltagInfoBuffer->TagInfo[ SystemTag ].PagedUsed +=
SessionPooltagInfo->TagInfo[ SessionTag ].PagedUsed;
SystemPooltagInfoBuffer->TagInfo[ SystemTag ].NonPagedAllocs +=
SessionPooltagInfo->TagInfo[ SessionTag ].NonPagedAllocs;
SystemPooltagInfoBuffer->TagInfo[ SystemTag ].NonPagedFrees +=
SessionPooltagInfo->TagInfo[ SessionTag ].NonPagedFrees;
SystemPooltagInfoBuffer->TagInfo[ SystemTag ].NonPagedUsed +=
SessionPooltagInfo->TagInfo[ SessionTag ].NonPagedUsed;
break;
}
}
if (SystemTag == SystemPooltagInfoBuffer->Count) {
//
// We didn't find the current session pooltag in the system buffer
// so we need to add it.
//
// N.B.
//
// Our caller guarantees that there is enough space in
// SystemPooltagInfoBuffer to add this extra information.
//
SystemPooltagInfoBuffer->TagInfo[ SystemTag ].TagUlong =
SessionPooltagInfo->TagInfo[ SessionTag ].TagUlong;
SystemPooltagInfoBuffer->TagInfo[ SystemTag ].PagedAllocs =
SessionPooltagInfo->TagInfo[ SessionTag ].PagedAllocs;
SystemPooltagInfoBuffer->TagInfo[ SystemTag ].PagedFrees =
SessionPooltagInfo->TagInfo[ SessionTag ].PagedFrees;
SystemPooltagInfoBuffer->TagInfo[ SystemTag ].PagedUsed =
SessionPooltagInfo->TagInfo[ SessionTag ].PagedUsed;
SystemPooltagInfoBuffer->TagInfo[ SystemTag ].NonPagedAllocs =
SessionPooltagInfo->TagInfo[ SessionTag ].NonPagedAllocs;
SystemPooltagInfoBuffer->TagInfo[ SystemTag ].NonPagedFrees =
SessionPooltagInfo->TagInfo[ SessionTag ].NonPagedFrees;
SystemPooltagInfoBuffer->TagInfo[ SystemTag ].NonPagedUsed =
SessionPooltagInfo->TagInfo[ SessionTag ].NonPagedUsed;
SystemPooltagInfoBuffer->Count += 1;
}
}
}
NTSTATUS
TranslateSessionBufferToSystemPoolBuffer (
PSYSTEM_POOLTAG_INFORMATION *SystemPooltagInfoBuffer,
SIZE_T *SystemPooltagInfoBufferSize
)
{
PSYSTEM_SESSION_POOLTAG_INFORMATION CrtSessionPooltagInfo;
PVOID NewSystemPooltagInfoBuffer;
SIZE_T NewSystemPooltagInfoBufferSize;
ULONG AdditionPooltagsNeeded;
ASSERT (SystemPooltagInfoBuffer != NULL);
ASSERT (SystemPooltagInfoBufferSize != NULL);
CrtSessionPooltagInfo = SessionBuffer;
//
// Make sure we have at least space to translate the first
// session information into SystemPooltagInfoBuffer.
//
if (SessionBuffer == NULL) {
//
// This can happen if we are querying for a non-existant session.
//
NewSystemPooltagInfoBufferSize = sizeof ((*SystemPooltagInfoBuffer)->Count);
}
else {
NewSystemPooltagInfoBufferSize = sizeof ((*SystemPooltagInfoBuffer)->Count) +
CrtSessionPooltagInfo->Count * sizeof (SYSTEM_POOLTAG);
}
if (*SystemPooltagInfoBuffer == NULL || *SystemPooltagInfoBufferSize < NewSystemPooltagInfoBufferSize) {
if (*SystemPooltagInfoBuffer != NULL) {
free (*SystemPooltagInfoBuffer);
}
*SystemPooltagInfoBuffer = malloc (NewSystemPooltagInfoBufferSize);
if (*SystemPooltagInfoBuffer == NULL) {
//
// Bad luck, we cannot allocate so much memory.
//
*SystemPooltagInfoBufferSize = 0;
return STATUS_NO_MEMORY;
}
*SystemPooltagInfoBufferSize = NewSystemPooltagInfoBufferSize;
}
if (SessionBuffer == NULL) {
//
// This can happen if we are querying for a non-existant session.
//
(*SystemPooltagInfoBuffer)->Count = 0;
}
else {
ASSERT (SessionBuffer->Count == 0 ||
DisplaySessionId == (ULONG)-1 ||
DisplaySessionId == SessionBuffer->SessionId);
//
// Copy the information for the current session.
//
(*SystemPooltagInfoBuffer)->Count = CrtSessionPooltagInfo->Count;
CopyMemory (&(*SystemPooltagInfoBuffer)->TagInfo[0],
&CrtSessionPooltagInfo->TagInfo[0],
(*SystemPooltagInfoBuffer)->Count * sizeof (SYSTEM_POOLTAG));
//
// Now look if we are looking for data for more than one session.
// We might need to change the size of SystemPooltagInfoBuffer,
// realloc it and copy the whole data one more time.
//
if (DisplaySessionId == (ULONG)-1) {
//
// We have data for all sessions.
//
while (CrtSessionPooltagInfo->NextEntryOffset > 0) {
CrtSessionPooltagInfo = (PSYSTEM_SESSION_POOLTAG_INFORMATION)
((PCHAR)CrtSessionPooltagInfo + CrtSessionPooltagInfo->NextEntryOffset);
AdditionPooltagsNeeded = GetExtraPooltagEntriesNeeded (*SystemPooltagInfoBuffer,
CrtSessionPooltagInfo);
if (AdditionPooltagsNeeded > 0) {
NewSystemPooltagInfoBufferSize = sizeof ((*SystemPooltagInfoBuffer)->Count) +
((*SystemPooltagInfoBuffer)->Count + AdditionPooltagsNeeded) *
sizeof (SYSTEM_POOLTAG);
if (NewSystemPooltagInfoBufferSize > *SystemPooltagInfoBufferSize) {
//
// We need to reallocate our SystemPooltagInfoBuffer,
// copy the data we already have, then add these extra pooltags.
//
NewSystemPooltagInfoBuffer = malloc (NewSystemPooltagInfoBufferSize);
if (NewSystemPooltagInfoBuffer == NULL) {
//
// Bad luck, we cannot allocate so much memory.
//
return STATUS_NO_MEMORY;
}
//
// Make a copy of the current buffer then continue with its larger copy.
//
CopyMemory (NewSystemPooltagInfoBuffer,
*SystemPooltagInfoBuffer,
*SystemPooltagInfoBufferSize);
free (*SystemPooltagInfoBuffer);
*SystemPooltagInfoBuffer = NewSystemPooltagInfoBuffer;
*SystemPooltagInfoBufferSize = NewSystemPooltagInfoBufferSize;
}
}
//
// At this point we should have enough space in SystemPooltagInfoBuffer
// to fit all the pooltag info from CrtSessionPooltagInfo.
//
AddSessionInfoToSystemPooltagInfo (*SystemPooltagInfoBuffer,
CrtSessionPooltagInfo);
}
}
}
return STATUS_SUCCESS;
}
NTSTATUS
QuerySessionPoolTagInformationIterative (
PSYSTEM_POOLTAG_INFORMATION *CurrentSystemBuffer,
SIZE_T *CurrentSystemBufferSize
)
{
NTSTATUS Status;
ULONG NewBufferSize;
SYSTEM_SESSION_PROCESS_INFORMATION SessionProcessInformation;
SessionProcessInformation.SessionId = DisplaySessionId;
while (TRUE)
{
SessionProcessInformation.SizeOfBuf = SessionBufferSize;
SessionProcessInformation.Buffer = SessionBuffer;
Status = NtQuerySystemInformation (SystemSessionPoolTagInformation,
&SessionProcessInformation,
sizeof (SessionProcessInformation),
& NewBufferSize);
if (Status == STATUS_INFO_LENGTH_MISMATCH) {
if (SessionBufferSize != 0) {
//
// Our buffer is just not large enough. Add BUFFER_SIZE_STEP
// to its size. We are not trying to use the size returned
// by NtQuery here because theoretically some other pool
// tag might always show up between the two consecutive
// queries and we would loop forever in that case.
//
free (SessionBuffer);
NewBufferSize = SessionBufferSize + BUFFER_SIZE_STEP;
}
SessionBuffer = malloc (NewBufferSize);
if (SessionBuffer == NULL) {
//
// Bad luck, we cannot allocate so much memory
// so bail out.
//
SessionBufferSize = 0;
return STATUS_NO_MEMORY;
}
SessionBufferSize = NewBufferSize;
}
else if (Status == STATUS_INVALID_INFO_CLASS) {
//
// This is probably a Win2k or XP box so we just ignore the error.
//
ASSERT (SessionBuffer == NULL);
break;
}
else if (!NT_SUCCESS(Status)) {
//
// Query failed for some reason.
//
return Status;
}
else {
//
// All set - we have the information.
//
if (NewBufferSize == 0 && SessionBuffer != NULL) {
//
// We didn't get back any information (e.g. the session doesn't exist).
//
SessionBuffer->Count = 0;
}
break;
}
}
return TranslateSessionBufferToSystemPoolBuffer (CurrentSystemBuffer,
CurrentSystemBufferSize);
}
int
__cdecl
main(
int argc,
char *argv[]
)
{
NTSTATUS Status;
ULONG LastCount = 0;
SYSTEM_BASIC_INFORMATION BasicInfo;
SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
PSYSTEM_POOLTAG_INFORMATION PoolInfo;
PSYSTEM_POOLTAG_INFORMATION PoolInfoOld;
PUCHAR *PreviousBuffer;
PUCHAR *CurrentBuffer;
PUCHAR *TempBuffer;
SIZE_T *PreviousBufferSize;
SIZE_T *CurrentBufferSize;
SIZE_T *TempBufferSize;
BOOLEAN DoHelp;
BOOLEAN DoQuit;
SIZE_T NumberOfPoolTags;
SIZE_T i;
UCHAR LastKey;
PPOOLMON_OUT Out;
LONG ScrollDelta;
WORD DisplayLine, LastDetailRow,BottomDisplayedLine;
CHAR OutputBuffer[ OUTPUTBUFFERSIZE ];
FILE *LogFile = NULL;
INT LastKeyUpper;
ULONG PoolCount=0;
DoHelp = FALSE;
DoQuit = FALSE;
Interactive = TRUE;
BottomDisplayedLine = 0;
ParseArgs( argc, argv );
if (fPoolTag || fLocalTag) BuildTagMap();
if(IsSnap)
{
if(pchLogFile)
{
LogFile = fopen(pchLogFile, "a");
if(!LogFile)
{
printf("Poolmon: Error Opening file %s: %d\n", pchLogFile, GetLastError());
return(0);
}
}
else if( (LogFile = fopen("poolsnap.log","a")) == NULL ) {
printf("Poolmon: Error Opening file poolsnap.log: %d\n", GetLastError());
return(0);
}
PoolSnap(LogFile);
// close file
fclose(LogFile);
return 0;
}
InputHandle = GetStdHandle( STD_INPUT_HANDLE );
OriginalOutputHandle = GetStdHandle( STD_OUTPUT_HANDLE );
if (Interactive) {
if (InputHandle == NULL ||
OriginalOutputHandle == NULL ||
!GetConsoleMode( InputHandle, &OriginalInputMode )
) {
Interactive = FALSE;
} else {
OutputHandle = CreateConsoleScreenBuffer( GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
if (OutputHandle == NULL ||
!GetConsoleScreenBufferInfo( OriginalOutputHandle, &OriginalConsoleInfo ) ||
!SetConsoleScreenBufferSize( OutputHandle, OriginalConsoleInfo.dwSize ) ||
!SetConsoleActiveScreenBuffer( OutputHandle ) ||
!SetConsoleMode( InputHandle, 0 )
) {
if (OutputHandle != NULL) {
CloseHandle( OutputHandle );
OutputHandle = NULL;
}
Interactive = FALSE;
} else {
NormalAttribute = 0x1F;
HighlightAttribute = 0x71;
NumberOfCols = OriginalConsoleInfo.dwSize.X;
NumberOfRows = OriginalConsoleInfo.dwSize.Y;
NumberOfDetailLines = NumberOfRows;
}
}
}
NtQuerySystemInformation( SystemBasicInformation,
&BasicInfo,
sizeof(BasicInfo),
NULL
);
if (GetPriorityClass(GetCurrentProcess()) == NORMAL_PRIORITY_CLASS) {
SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS);
}
PreviousBuffer = &LargeBuffer2; // NULL at this point
PreviousBufferSize = &LargeBuffer2Size; // 0 at this point
CurrentBuffer = &LargeBuffer1; // NULL at this point
CurrentBufferSize = &LargeBuffer1Size; // 0 at this point
while(TRUE) {
Status = NtQuerySystemInformation(
SystemPerformanceInformation,
&PerfInfo,
sizeof(PerfInfo),
NULL
);
if ( !NT_SUCCESS(Status) ) {
printf("Poolmon: Query perf Failed (returned: %lx)\n",
Status);
break;
}
if (DisplaySessionPool == FALSE) {
Status = QueryPoolTagInformationIterative (CurrentBuffer,
CurrentBufferSize);
}
else {
Status = QuerySessionPoolTagInformationIterative ((PSYSTEM_POOLTAG_INFORMATION *)CurrentBuffer,
CurrentBufferSize);
}
if ( !NT_SUCCESS(Status) ) {
printf("Poolmon: Query pooltags failed (returned: %lx)\n"
"Did you remember to enable pool tagging with gflags.exe and reboot?\n",
Status);
break;
}
//
// Calculate pool tags and display information.
//
//
PoolInfo = (PSYSTEM_POOLTAG_INFORMATION)( *CurrentBuffer );
i = PoolInfo->Count;
PoolInfoOld = (PSYSTEM_POOLTAG_INFORMATION)( *PreviousBuffer );
DisplayLine = 0;
_snprintf( OutputBuffer, OUTPUTBUFFERSIZE,
" Memory:%8ldK Avail:%8ldK PageFlts:%6ld InRam Krnl:%5ldK P:%5ldK",
BasicInfo.NumberOfPhysicalPages*(BasicInfo.PageSize/1024),
PerfInfo.AvailablePages*(BasicInfo.PageSize/1024),
PerfInfo.PageFaultCount - LastCount,
(PerfInfo.ResidentSystemCodePage + PerfInfo.ResidentSystemDriverPage)*(BasicInfo.PageSize/1024),
(PerfInfo.ResidentPagedPoolPage)*(BasicInfo.PageSize/1024)
);
OutputBuffer[OUTPUTBUFFERSIZE-1] = '\0';
WriteConsoleLine( OutputHandle,
DisplayLine++,
OutputBuffer,
FALSE
);
LastCount = PerfInfo.PageFaultCount;
_snprintf( OutputBuffer, OUTPUTBUFFERSIZE,
" Commit:%7ldK Limit:%7ldK Peak:%7ldK Pool N:%5ldK P:%5ldK",
PerfInfo.CommittedPages*(BasicInfo.PageSize/1024),
PerfInfo.CommitLimit*(BasicInfo.PageSize/1024),
PerfInfo.PeakCommitment*(BasicInfo.PageSize/1024),
PerfInfo.NonPagedPoolPages*(BasicInfo.PageSize/1024),
PerfInfo.PagedPoolPages*(BasicInfo.PageSize/1024)
);
OutputBuffer[OUTPUTBUFFERSIZE-1] = '\0';
WriteConsoleLine( OutputHandle,
DisplayLine++,
OutputBuffer,
FALSE
);
if (DisplaySessionPool == FALSE) {
WriteConsoleLine( OutputHandle,
DisplayLine++,
" System pool information",
FALSE
);
}
else {
if (DisplaySessionId == (ULONG)-1) {
WriteConsoleLine( OutputHandle,
DisplayLine++,
" All sessions pool information",
FALSE
);
}
else {
_snprintf( OutputBuffer, OUTPUTBUFFERSIZE,
" Session %u pool information",
DisplaySessionId
);
OutputBuffer[OUTPUTBUFFERSIZE-1] = '\0';
WriteConsoleLine( OutputHandle,
DisplayLine++,
OutputBuffer,
FALSE
);
}
}
// If driver information is not needed to be displayed don't display "Mapped_Driver"
if (fLocalTag || fPoolTag)
{
#if !defined (_WIN64)
WriteConsoleLine( OutputHandle,
DisplayLine++,
" Tag Type Allocs Frees Diff Bytes Per Alloc Mapped_Driver",
FALSE
);
#else
WriteConsoleLine( OutputHandle,
DisplayLine++,
" Tag Type Allocs Frees Diff Bytes Per Alloc Mapped_Driver",
FALSE
);
#endif //#if !defined (_WIN64)
}
else
{
#if !defined (_WIN64)
WriteConsoleLine( OutputHandle,
DisplayLine++,
" Tag Type Allocs Frees Diff Bytes Per Alloc",
FALSE
);
#else
WriteConsoleLine( OutputHandle,
DisplayLine++,
" Tag Type Allocs Frees Diff Bytes Per Alloc",
FALSE
);
#endif //#if !defined (_WIN64)
}
WriteConsoleLine( OutputHandle,
DisplayLine++,
NULL,
FALSE
);
PoolCount = PoolInfo->Count;
if(OutBufferSize < PoolInfo->Count)
{
POOLMON_OUT *tempOutBuffer = OutBuffer;
OutBuffer = (PPOOLMON_OUT)malloc(PoolInfo->Count * sizeof(POOLMON_OUT));
// Don't let go of the memory you have if you don't get more memory
if(!OutBuffer)
{
// This is the first allocation and it failed
if (!tempOutBuffer)
{
printf("Poolmon: Memory allocation failed: %d\n", GetLastError());
FreeTagMap();
ExitProcess( 1 );
}
// If there was an outbuffer we should retain what we have and display
// the number of pool entries that we can
else
{
// We can only display as many entries as outbuffer can hold
PoolCount = (ULONG)OutBufferSize;
OutBuffer = tempOutBuffer;
}
}
else
{
if (tempOutBuffer) free (tempOutBuffer);
OutBufferSize = PoolInfo->Count;
}
}
Out = OutBuffer;
if (DisplayTotals) {
RtlZeroMemory( Totals, sizeof(POOLMON_OUT)*2 );
}
for (i = 0; i < PoolCount; i++) {
if ( !CheckFilters(&PoolInfo->TagInfo[i]) ) {
continue;
}
if ((PoolInfo->TagInfo[i].NonPagedAllocs != 0) &&
(DisplayType != PAGED)) {
Out->Allocs = PoolInfo->TagInfo[i].NonPagedAllocs;
Out->Frees = PoolInfo->TagInfo[i].NonPagedFrees;
Out->Used = PoolInfo->TagInfo[i].NonPagedUsed;
Out->Allocs_Frees = PoolInfo->TagInfo[i].NonPagedAllocs -
PoolInfo->TagInfo[i].NonPagedFrees;
Out->TagUlong = PoolInfo->TagInfo[i].TagUlong;
Out->Type = NONPAGED;
Out->Changed = FALSE;
Out->NullByte = '\0';
if (PoolInfoOld != NULL &&
PoolInfoOld->Count > i &&
PoolInfoOld->TagInfo[i].TagUlong == PoolInfo->TagInfo[i].TagUlong
) {
Out->AllocsDiff = PoolInfo->TagInfo[i].NonPagedAllocs - PoolInfoOld->TagInfo[i].NonPagedAllocs;
Out->FreesDiff = PoolInfo->TagInfo[i].NonPagedFrees - PoolInfoOld->TagInfo[i].NonPagedFrees;
Out->UsedDiff = PoolInfo->TagInfo[i].NonPagedUsed - PoolInfoOld->TagInfo[i].NonPagedUsed;
if (Out->AllocsDiff != 0 ||
Out->FreesDiff != 0 ||
Out->UsedDiff != 0
) {
Out->Changed = TRUE;
}
} else {
Out->AllocsDiff = 0;
Out->UsedDiff = 0;
Out->FreesDiff = 0;
}
Out->Each = Out->Used / (Out->Allocs_Frees?Out->Allocs_Frees:1);
if (DisplayTotals) {
Totals[NONPAGED].Allocs += Out->Allocs;
Totals[NONPAGED].AllocsDiff += Out->AllocsDiff;
Totals[NONPAGED].Frees += Out->Frees;
Totals[NONPAGED].FreesDiff += Out->FreesDiff;
Totals[NONPAGED].Allocs_Frees += Out->Allocs_Frees;
Totals[NONPAGED].Used += Out->Used;
Totals[NONPAGED].UsedDiff += Out->UsedDiff;
}
Out += 1;
}
else if ((PoolInfo->TagInfo[i].PagedAllocs != 0) &&
(DisplayType != NONPAGED)) {
Out->Allocs = PoolInfo->TagInfo[i].PagedAllocs;
Out->Frees = PoolInfo->TagInfo[i].PagedFrees;
Out->Used = PoolInfo->TagInfo[i].PagedUsed;
Out->Allocs_Frees = PoolInfo->TagInfo[i].PagedAllocs -
PoolInfo->TagInfo[i].PagedFrees;
Out->TagUlong = PoolInfo->TagInfo[i].TagUlong;
Out->Type = PAGED;
Out->Changed = FALSE;
Out->NullByte = '\0';
if (PoolInfoOld != NULL &&
PoolInfoOld->Count > i &&
PoolInfoOld->TagInfo[i].TagUlong == PoolInfo->TagInfo[i].TagUlong
) {
Out->AllocsDiff = PoolInfo->TagInfo[i].PagedAllocs - PoolInfoOld->TagInfo[i].PagedAllocs;
Out->FreesDiff = PoolInfo->TagInfo[i].PagedFrees - PoolInfoOld->TagInfo[i].PagedFrees;
Out->UsedDiff = PoolInfo->TagInfo[i].PagedUsed - PoolInfoOld->TagInfo[i].PagedUsed;
if (Out->AllocsDiff != 0 ||
Out->FreesDiff != 0 ||
Out->UsedDiff != 0
) {
Out->Changed = TRUE;
}
} else {
Out->AllocsDiff = 0;
Out->UsedDiff = 0;
Out->FreesDiff = 0;
}
Out->Each = Out->Used / (Out->Allocs_Frees?Out->Allocs_Frees:1);
if (DisplayTotals) {
Totals[PAGED].Allocs += Out->Allocs;
Totals[PAGED].AllocsDiff += Out->AllocsDiff;
Totals[PAGED].Frees += Out->Frees;
Totals[PAGED].FreesDiff += Out->FreesDiff;
Totals[PAGED].Allocs_Frees += Out->Allocs_Frees;
Totals[PAGED].Used += Out->Used;
Totals[PAGED].UsedDiff += Out->UsedDiff;
}
Out += 1;
}
} //end for
//
// Sort the running working set buffer
//
NumberOfPoolTags = Out - OutBuffer;
qsort((void *)OutBuffer,
(size_t)NumberOfPoolTags,
(size_t)sizeof(POOLMON_OUT),
ulcomp);
LastDetailRow = (WORD)(NumberOfRows - (DisplayTotals ? (DisplayType == BOTH ? 3 : 2) : 0));
Out = (PPOOLMON_OUT)OutBuffer;
for (i = FirstDetailLine; i < NumberOfPoolTags; i++) {
PTAGNODE pn = NULL;
int cnt = 0;
if (DisplayLine >= LastDetailRow) {
break;
}
pn = LookupTag(Out->Tag);
if(! pn)
{
#if !defined (_WIN64)
_snprintf( OutputBuffer, OUTPUTBUFFERSIZE,
" %4s %5s %9ld (%4ld) %9ld (%4ld) %8ld %7ld (%6ld) %6ld %s",
Out->Tag,
PoolType[Out->Type],
Out->Allocs,
Out->AllocsDiff,
Out->Frees,
Out->FreesDiff,
Out->Allocs_Frees,
Out->Used,
Out->UsedDiff,
Out->Each,
(fLocalTag || fPoolTag) ? "Unknown Driver" : ""
);
OutputBuffer[OUTPUTBUFFERSIZE-1] = '\0';
#else
_snprintf( OutputBuffer, OUTPUTBUFFERSIZE,
" %4s %5s %9I64u (%4I64d) %9I64u (%4I64d) %8I64u %11I64u (%11I64d) %11I64u %s",
Out->Tag,
PoolType[Out->Type],
Out->Allocs,
Out->AllocsDiff,
Out->Frees,
Out->FreesDiff,
Out->Allocs_Frees,
Out->Used,
Out->UsedDiff,
Out->Each,
(fLocalTag || fPoolTag) ? "Unknown Driver" : ""
);
OutputBuffer[OUTPUTBUFFERSIZE-1] = '\0';
#endif
WriteConsoleLine( OutputHandle,
DisplayLine++,
OutputBuffer,
Out->Changed
);
}
else
{
#if !defined (_WIN64)
_snprintf( OutputBuffer, OUTPUTBUFFERSIZE,
" %4s %5s %9ld (%4ld) %9ld (%4ld) %8ld %7ld (%6ld) %6ld %s",
Out->Tag,
PoolType[Out->Type],
Out->Allocs,
Out->AllocsDiff,
Out->Frees,
Out->FreesDiff,
Out->Allocs_Frees,
Out->Used,
Out->UsedDiff,
Out->Each,
pn->Driver
);
OutputBuffer[OUTPUTBUFFERSIZE-1] = '\0';
#else
_snprintf( OutputBuffer, OUTPUTBUFFERSIZE,
" %4s %5s %9I64u (%4I64d) %9I64u (%4I64d) %8I64u %11I64u (%11I64d) %11I64u %s",
Out->Tag,
PoolType[Out->Type],
Out->Allocs,
Out->AllocsDiff,
Out->Frees,
Out->FreesDiff,
Out->Allocs_Frees,
Out->Used,
Out->UsedDiff,
Out->Each,
pn->Driver
);
OutputBuffer[OUTPUTBUFFERSIZE-1] = '\0';
#endif
WriteConsoleLine( OutputHandle,
DisplayLine++,
OutputBuffer,
Out->Changed
);
}
Out->Changed = FALSE;
Out++;
}
if (DisplayTotals) {
WriteConsoleLine( OutputHandle,
DisplayLine++,
NULL,
FALSE
);
for (i = 0; i < 2; i++) {
if ( (int)DisplayType == i || DisplayType == BOTH ) {
#if !defined (_WIN64)
_snprintf( OutputBuffer, OUTPUTBUFFERSIZE,
"Total %5s %9ld (%4ld) %9ld (%4ld) %8ld %7ld (%6ld) %6ld",
PoolType[i],
Totals[i].Allocs,
Totals[i].AllocsDiff,
Totals[i].Frees,
Totals[i].FreesDiff,
Totals[i].Allocs_Frees,
Totals[i].Used,
Totals[i].UsedDiff,
Totals[i].Each
);
OutputBuffer[OUTPUTBUFFERSIZE-1] = '\0';
#else
_snprintf( OutputBuffer, OUTPUTBUFFERSIZE,
"Total %5s %9I64u (%4I64d) %9I64u (%4I64d) %8I64u %11I64u (%11I64d) %11I64u",
PoolType[i],
Totals[i].Allocs,
Totals[i].AllocsDiff,
Totals[i].Frees,
Totals[i].FreesDiff,
Totals[i].Allocs_Frees,
Totals[i].Used,
Totals[i].UsedDiff,
Totals[i].Each
);
OutputBuffer[OUTPUTBUFFERSIZE-1] = '\0';
#endif //#if !defined (_WIN64)
WriteConsoleLine( OutputHandle,
DisplayLine++,
OutputBuffer,
FALSE
);
}
}
}
//
// If we had less lines to display this time than last time
// erase the rest of the console output.
//
while (DisplayLine < BottomDisplayedLine) {
WriteConsoleLine( OutputHandle,
DisplayLine++,
NULL,
FALSE
);
}
BottomDisplayedLine = DisplayLine;
TempBuffer = PreviousBuffer;
TempBufferSize = PreviousBufferSize;
PreviousBuffer = CurrentBuffer;
PreviousBufferSize = CurrentBufferSize;
CurrentBuffer = TempBuffer;
CurrentBufferSize = TempBufferSize;
while (WaitForSingleObject( InputHandle, DelayTimeMsec ) == STATUS_WAIT_0) {
//
// Check for input record
//
if (ReadConsoleInput( InputHandle, &InputRecord, 1, &NumberOfInputRecords ) &&
InputRecord.EventType == KEY_EVENT &&
InputRecord.Event.KeyEvent.bKeyDown
) {
LastKey = InputRecord.Event.KeyEvent.uChar.AsciiChar;
if (LastKey < ' ') {
ScrollDelta = 0;
if (LastKey == 'C'-'A'+1) {
DoQuit = TRUE;
} else switch (InputRecord.Event.KeyEvent.wVirtualKeyCode) {
case VK_ESCAPE:
DoQuit = TRUE;
break;
case VK_PRIOR:
ScrollDelta = -(LONG)(InputRecord.Event.KeyEvent.wRepeatCount * NumberOfDetailLines);
break;
case VK_NEXT:
ScrollDelta = InputRecord.Event.KeyEvent.wRepeatCount * NumberOfDetailLines;
break;
case VK_UP:
ScrollDelta = -InputRecord.Event.KeyEvent.wRepeatCount;
break;
case VK_DOWN:
ScrollDelta = InputRecord.Event.KeyEvent.wRepeatCount;
break;
case VK_HOME:
FirstDetailLine = 0;
break;
case VK_END:
FirstDetailLine = NumberOfPoolTags - NumberOfDetailLines;
break;
}
if (ScrollDelta != 0) {
if (ScrollDelta < 0) {
if (FirstDetailLine <= (ULONG)-ScrollDelta) {
FirstDetailLine = 0;
} else {
FirstDetailLine += ScrollDelta;
}
} else {
FirstDetailLine += ScrollDelta;
if (FirstDetailLine >= (NumberOfPoolTags - NumberOfDetailLines)) {
FirstDetailLine = NumberOfPoolTags - NumberOfDetailLines;
}
}
}
} else {
LastKeyUpper = toupper(LastKey);
switch (LastKeyUpper) {
case 'Q':
//
// Go to the bottom of the current screen when
// we quit.
//
DoQuit = TRUE;
break;
case 'T':
SortBy = TAG;
FirstDetailLine = 0;
break;
case 'A':
SortBy = ALLOC;
FirstDetailLine = 0;
break;
case 'U':
case 'B':
SortBy = BYTES;
FirstDetailLine = 0;
break;
case 'F':
SortBy = FREE;
FirstDetailLine = 0;
break;
case 'D':
SortBy = DIFF;
FirstDetailLine = 0;
break;
case 'M':
SortBy = EACH;
FirstDetailLine = 0;
break;
case 'L':
NoHighlight = 1 - NoHighlight;
break;
case 'P':
DisplayType += 1;
if (DisplayType > BOTH) {
DisplayType = NONPAGED;
}
FirstDetailLine = 0;
break;
case 'X':
case '(':
case ')':
Paren += 1;
break;
case 'E':
DisplayTotals = !DisplayTotals;
FirstDetailLine = 0;
break;
case 'H':
case '?':
DoHelp = TRUE;
break;
case 'S':
DisplaySessionPool = !DisplaySessionPool;
break;
case 'I':
ShowSessionPopup ();
break;
default:
if (LastKeyUpper >= '0' && LastKeyUpper <= '9')
{
DisplaySessionPool = TRUE;
DisplaySessionId = LastKeyUpper - '0';
}
break;
}
}
break;
}
}
if (DoQuit) {
break;
}
if (DoHelp) {
DoHelp = FALSE;
ShowHelpPopup();
}
}
if (Interactive) {
SetConsoleActiveScreenBuffer( OriginalOutputHandle );
SetConsoleMode( InputHandle, OriginalInputMode );
CloseHandle( OutputHandle );
}
FreeTagMap();
if(OutBuffer)
free(OutBuffer);
ExitProcess( 0 );
return 0;
}
int __cdecl
PoolSnap(
FILE *LogFile // Snapshot log file
)
/*++
Routine Description:
This function collects the list of active drivers in the system and stores the relevant
pool allocation information along with the tag information (if available) in the
snapshot LogFile
Return Value:
0: If there is no error
1: Otherwise
--*/
{
NTSTATUS Status; // status from NT api
DWORD x= 0; // counter
SIZE_T NumberOfPoolTags;
SYSTEM_BASIC_INFORMATION BasicInfo;
SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
PSYSTEM_POOLTAG_INFORMATION PoolInfo;
PPOOLMON_OUT Out;
PUCHAR CurrentBuffer = NULL;
size_t CurrentBufferSize = 0;
int res = 0;
LONG FileSize = 0;
FileSize = _filelength(_fileno(LogFile));
if( FileSize == -1 ) {
printf("Poolmon: Bad file length of snapshot Logfile\n");
goto Error;
}
fprintf(LogFile,"\n");
if (fPrintSummaryInfo)
{
Status = NtQuerySystemInformation( SystemBasicInformation,
&BasicInfo,
sizeof(BasicInfo),
NULL
);
if ( !NT_SUCCESS(Status) ) {
printf("Poolmon: Query Basic Info Failed (returned: %lx)\n",
Status);
goto Error;
}
if (GetPriorityClass(GetCurrentProcess()) == NORMAL_PRIORITY_CLASS) {
SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS);
}
Status = NtQuerySystemInformation(
SystemPerformanceInformation,
&PerfInfo,
sizeof(PerfInfo),
NULL
);
if ( !NT_SUCCESS(Status) ) {
printf("Poolmon: Query perf Failed (returned: %lx)\n",
Status);
goto Error;
}
fprintf( LogFile,
" Memory:%8ldK Avail:%8ldK PageFlts:%6ld InRam Krnl:%5ldK P:%5ldK\n",
BasicInfo.NumberOfPhysicalPages*(BasicInfo.PageSize/1024),
PerfInfo.AvailablePages*(BasicInfo.PageSize/1024),
PerfInfo.PageFaultCount,
(PerfInfo.ResidentSystemCodePage + PerfInfo.ResidentSystemDriverPage)*(BasicInfo.PageSize/1024),
(PerfInfo.ResidentPagedPoolPage)*(BasicInfo.PageSize/1024)
);
fprintf( LogFile,
" Commit:%7ldK Limit:%7ldK Peak:%7ldK Pool N:%5ldK P:%5ldK\n",
PerfInfo.CommittedPages*(BasicInfo.PageSize/1024),
PerfInfo.CommitLimit*(BasicInfo.PageSize/1024),
PerfInfo.PeakCommitment*(BasicInfo.PageSize/1024),
PerfInfo.NonPagedPoolPages*(BasicInfo.PageSize/1024),
PerfInfo.PagedPoolPages*(BasicInfo.PageSize/1024)
);
fprintf(LogFile,"\n");
}
//
// print file header once
//
if (fLocalTag || fPoolTag)
{
#if !defined (_WIN64)
fprintf(LogFile," Tag Type Allocs Frees Diff Bytes Per Alloc Mapped_Driver\n");
#else
fprintf(LogFile," Tag Type Allocs Frees Diff Bytes Per Alloc Mapped_Driver\n");
#endif
}
else
{
#if !defined (_WIN64)
fprintf(LogFile," Tag Type Allocs Frees Diff Bytes Per Alloc\n");
#else
fprintf(LogFile," Tag Type Allocs Frees Diff Bytes Per Alloc\n");
#endif
}
fprintf(LogFile,"\n");
// grab all pool information
// log line format, fixed column format
Status = QueryPoolTagInformationIterative(
&CurrentBuffer,
&CurrentBufferSize
);
if (! NT_SUCCESS(Status)) {
printf("Poolmon: Failed to query pool tags information (status %08X). \n", Status);
printf("Please check if pool tags are enabled. \n");
// If there is an operator around, wake him up, but keep moving
Beep(1000,350); Beep(500,350); Beep(1000,350);
goto Error;
}
PoolInfo = (PSYSTEM_POOLTAG_INFORMATION)CurrentBuffer;
OutBuffer = (PPOOLMON_OUT)malloc(PoolInfo->Count * sizeof(POOLMON_OUT));
if(!OutBuffer)
{
printf("Poolmon: Failed to allocate memory: %d\n", GetLastError());
goto Error;
}
OutBufferSize = PoolInfo->Count;
Out = OutBuffer;
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);
Out++;
}
// paged
else 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++;
}
}
//
// 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 < NumberOfPoolTags; x++) {
int cnt = 0;
PTAGNODE pn = LookupTag(OutBuffer[x].Tag);
if(pn == NULL)
{
fprintf(LogFile,
#ifdef _WIN64
" %4s %5s %18I64d %18I64d %16I64d %14I64d %12I64d %s\n",
#else
" %4s %5s %9ld %9ld %8ld %7ld %6ld %s\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,
(fLocalTag || fPoolTag) ? "Unknown Driver" : ""
);
}
else
{
fprintf(LogFile,
#ifdef _WIN64
" %4s %5s %18I64d %18I64d %16I64d %14I64d %12I64d %s\n",
#else
" %4s %5s %9ld %9ld %8ld %7ld %6ld %s\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,
pn->Driver
);
}
}
goto Exit;
Error:
res = 1;
Exit:
FreeTagMap();
if(OutBuffer)
free(OutBuffer);
if(CurrentBuffer)
free(CurrentBuffer);
return res;
}
VOID
ShowHelpPopup( VOID )
{
HANDLE PopupHandle;
WORD n;
PopupHandle = CreateConsoleScreenBuffer( GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
if (PopupHandle == NULL) {
return;
}
SetConsoleActiveScreenBuffer( PopupHandle );
n = 0;
WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
WriteConsoleLine( PopupHandle, n++, " Poolmon Help", FALSE );
WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
WriteConsoleLine( PopupHandle, n++, " columns:", FALSE );
WriteConsoleLine( PopupHandle, n++, " Tag is the 4 byte tag given to the pool allocation", FALSE );
WriteConsoleLine( PopupHandle, n++, " Type is paged or nonp(aged)", FALSE );
WriteConsoleLine( PopupHandle, n++, " Allocs is count of all alloctions", FALSE );
WriteConsoleLine( PopupHandle, n++, " ( ) is difference in Allocs column from last update", FALSE );
WriteConsoleLine( PopupHandle, n++, " Frees is count of all frees", FALSE );
WriteConsoleLine( PopupHandle, n++, " ( ) difference in Frees column from last update", FALSE );
WriteConsoleLine( PopupHandle, n++, " Diff is (Allocs - Frees)", FALSE );
WriteConsoleLine( PopupHandle, n++, " Bytes is the total bytes consumed in pool", FALSE );
WriteConsoleLine( PopupHandle, n++, " ( ) difference in Bytes column from last update", FALSE );
WriteConsoleLine( PopupHandle, n++, " Per Alloc is (Bytes / Diff)", FALSE );
WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
WriteConsoleLine( PopupHandle, n++, " switches: ", FALSE );
WriteConsoleLine( PopupHandle, n++, " ? or h - gives this help", FALSE );
WriteConsoleLine( PopupHandle, n++, " q - quits", FALSE );
WriteConsoleLine( PopupHandle, n++, " p - toggles default pool display between both, paged, and nonpaged", FALSE );
WriteConsoleLine( PopupHandle, n++, " e - toggles totals lines on and off", FALSE );
WriteConsoleLine( PopupHandle, n++, " l - toggles highlighting of changed lines on and off", FALSE );
WriteConsoleLine( PopupHandle, n++, " s - toggles default pool display between system pool and session pool", FALSE );
WriteConsoleLine( PopupHandle, n++, " i - asks for a session ID to display pool information about", FALSE );
WriteConsoleLine( PopupHandle, n++, " 0-9 - displays information about session 0-9 pool", FALSE );
WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
WriteConsoleLine( PopupHandle, n++, " sorting switches:", FALSE );
WriteConsoleLine( PopupHandle, n++, " t - tag a - allocations", FALSE );
WriteConsoleLine( PopupHandle, n++, " f - frees d - difference", FALSE );
WriteConsoleLine( PopupHandle, n++, " b - bytes m - per alloc", FALSE );
WriteConsoleLine( PopupHandle, n++, " (u is the same as b)", FALSE );
WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
WriteConsoleLine( PopupHandle, n++, " ) - toggles sort between primary tag and value in ( )", FALSE );
WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
WriteConsoleLine( PopupHandle, n++, " command line switches:", FALSE );
WriteConsoleLine( PopupHandle, n++, " -i<tag> - list only matching tags", FALSE );
WriteConsoleLine( PopupHandle, n++, " -x<tag> - list everything except matching tags", FALSE );
WriteConsoleLine( PopupHandle, n++, " <tag> can include * and ?", FALSE );
WriteConsoleLine( PopupHandle, n++, " -peltafdbum) - as listed above", FALSE );
WriteConsoleLine( PopupHandle, n++, " -s - starts with information about all sessions pool", FALSE );
WriteConsoleLine( PopupHandle, n++, " -sN - starts with information about session N pool", FALSE );
WriteConsoleLine( PopupHandle, n++, " (e.g. -s1 for session 1 pool)", FALSE );
WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
while (TRUE) {
if (WaitForSingleObject( InputHandle, DelayTimeMsec ) == STATUS_WAIT_0 &&
ReadConsoleInput( InputHandle, &InputRecord, 1, &NumberOfInputRecords ) &&
InputRecord.EventType == KEY_EVENT &&
InputRecord.Event.KeyEvent.bKeyDown &&
InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE
) {
break;
}
}
SetConsoleActiveScreenBuffer( OutputHandle );
CloseHandle( PopupHandle );
return;
}
ULONG ComputeIndex(PUCHAR tag)
{
ULONG ind=0;
if (isdigit(tag[0]))
{
ind = tag[0] - '0';
}
else
{
if (isupper(tag[0]))
{
ind = tag[0]-'A';
}
//lower case chars will be indexed to this
else if (islower(tag[0]))
{
ind = (tag[0]-'a');
}
else
{
ind = INVALID_INDEX;
}
}
return ind;
}
BOOL
StoreTags(PCHAR filename, BOOL fCheckForWildCard)
{
FILE *tagFile = NULL;
CHAR line[1024];
HANDLE hFile = 0;
DWORD dwSizeLow=0, dwSizeHigh=0;
hFile = CreateFile( filename, GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
// Check for error in CreateFile
if (hFile == INVALID_HANDLE_VALUE)
{
printf("Poolmon: Tag file %s absent or invalid: %d\n", filename, GetLastError());
return FALSE;
}
dwSizeLow = GetFileSize(hFile, &dwSizeHigh);
if (hFile != INVALID_HANDLE_VALUE )
{
CloseHandle(hFile);
}
// If we failed ...
if (dwSizeLow == INVALID_FILE_SIZE && (GetLastError() != NO_ERROR))
{
printf("Poolmon: Bad tag file size: %s\n", filename);
return FALSE;
}
if (dwSizeHigh !=0 || dwSizeLow > MAXTAGFILESIZE) {
printf("Poolmon: Tag file %s too big\n", filename);
return FALSE;
}
if(!(tagFile = fopen(filename, "r")))
{
printf("Poolmon: Failed to open tag file %s: %d\n", filename, GetLastError());
return FALSE;
}
while(fgets(line, 1024, tagFile))
{
PUCHAR tag = line;
PUCHAR driver = NULL;
unsigned int ind,i;
PTAGNODE pn;
BOOL fWildCardFound = FALSE;
line[1023] = '\0';
// skip initial space.
while(isspace(*tag)) tag++;
// skip empty line.
if(! *tag) continue;
// skip comments.
if(_strnicmp(tag, "rem", 3) == 0) continue;
driver = tag;
// Find tag end.
while(*driver != '-' && ! isspace(*driver)) driver++;
// tag should not be more than 4 chars.
if(driver - tag > 4 || ! *driver) continue;
*driver++ = '\0';
if(!*driver) continue;
// Find driver start.
while(*driver == '-' || isspace(*driver)) driver++;
if(! *driver) continue;
// remove ending new lines.
ind = strlen(driver) - 1;
while(ind > 0)
{
if(driver[ind] == '\n' || driver[ind] == '\r')
{
driver[ind] = '\0';
}
else
{
break;
}
ind--;
}
if (fCheckForWildCard)
{
for(i=0; i<strlen(tag);i++)
{
if ((tag[i] == '*') || (tag[i] == '?'))
{
ind = ComputeIndex(tag);
if (ind == INVALID_INDEX)
{
goto nextwhile;
}
//This is a wild-card tag
fWildCardFound = TRUE;
pn = WildCardTagMap[ind];
break;
}
}
}
if (!fWildCardFound)
{
ind = HashString(tag) % TAGMAPLEN;
pn = TagMap[ind];
}
for(;pn; pn = pn->next)
{
//This tag already exists in the list
if(strncmp(pn->Tag, tag,4) == 0)
{
//Not possible to append more than max allowable driver length
// +3 accounts for '[', ']' and '\0'
if ((strlen(pn->Driver) + strlen(driver) + 3) >= DRIVERNAMELEN)
{
goto nextwhile;
}
strcat(pn->Driver,"[");
strcat(pn->Driver,driver);
strcat(pn->Driver,"]");
pn->Driver[DRIVERNAMELEN-1]='\0';
goto nextwhile;
}
}
pn = (PTAGNODE)malloc(sizeof(TAGNODE));
if (!pn)
{
fclose(tagFile);
return FALSE;
}
strcpy(pn->Tag, tag);
strcpy(pn->Driver,"[");
strncat(pn->Driver, driver,DRIVERNAMELEN-2);
strcat(pn->Driver,"]");
pn->Driver[DRIVERNAMELEN-1]='\0';
if (fWildCardFound)
{
pn->next = WildCardTagMap[ind];
WildCardTagMap[ind] = pn;
}
else
{
pn->next = TagMap[ind];
TagMap[ind] = pn;
}
nextwhile:
continue;
}
fclose(tagFile);
return TRUE;
}
BOOL
BuildTagMap()
/*++
Routine Description:
This function builds the tag map using the pooltag file i.e it builds
a hash table of the tag names and the corresponding driver name.
Return Value:
TRUE: If tag map is successfully built
FALSE: Otherwise
--*/
{
int index;
BOOL ret=FALSE;
HANDLE hFile=0;
TagMap = (PTAGNODE*)malloc(sizeof(PTAGNODE) * TAGMAPLEN);
if(!TagMap)
return FALSE;
for(index = 0; index < TAGMAPLEN; index++)
TagMap[index] = NULL;
// Initialize WildCardTagMap
WildCardTagMap = (PTAGNODE*)malloc(sizeof(PTAGNODE) * WILDCARDTAGMAPLEN);
if(!WildCardTagMap)
return FALSE;
for(index = 0; index < WILDCARDTAGMAPLEN; index++)
WildCardTagMap[index] = NULL;
#if !defined (_WIN64)
// If local tag file is not specified, then we need to build one
if (fLocalTag)
{
if (!pchLocalTagFile)
{
//Need to see if there is a localtag.txt file in the current directory
hFile = CreateFile( LOCALTAGFILE, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
// Check for error in CreateFile
if (hFile == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
{
printf("Poolmon: No %s in current directory\n", LOCALTAGFILE);
if (!MakeLocalTagFile())
{
printf("Poolmon: Unable to create local tag file\n");
//Need not build TagMap in this case
fLocalTag=FALSE;
}
}
else fLocalTag = FALSE;
}
else CloseHandle(hFile);
pchLocalTagFile = LOCALTAGFILE;
}
}
#endif
// If pool tag file is not specified, we need to look for "pooltag.txt" in the current directory
if (fPoolTag)
{
if (!pchPoolTagFile)
{
//Need to see if there is a pooltag.txt file in the current directory
hFile = CreateFile( POOLTAGFILE, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
// Check for error in CreateFile
if (hFile == INVALID_HANDLE_VALUE)
{
printf("Poolmon: Unable to open/No %s in current directory\n", POOLTAGFILE);
//This is an error and we need not build Tag Map
fPoolTag=FALSE;
}
else
{
CloseHandle(hFile);
pchPoolTagFile=POOLTAGFILE;
}
}
}
if (fLocalTag)
//If StoreTags returned FALSE, we need not display local tags, hence store result in fLocalTag
//We need not check for wild-cards in the localtag.txt file
fLocalTag = StoreTags(pchLocalTagFile, FALSE);
if (fPoolTag)
fPoolTag = StoreTags(pchPoolTagFile, TRUE);
return TRUE;
}
VOID
FreeTagMap()
{
PTAGNODE pn1, pn2;
int i;
if(!TagMap)
return;
for(i = 0; i < TAGMAPLEN; i++)
{
pn1 = TagMap[i];
TagMap[i] = NULL;
while(pn1)
{
pn2 = pn1;
pn1 = pn1->next;
free((void*)pn2);
}
}
free((void*)TagMap);
//Free WildCardTagMap
if(!WildCardTagMap)
return;
for(i = 0; i < WILDCARDTAGMAPLEN; i++)
{
pn1 = WildCardTagMap[i];
WildCardTagMap[i] = NULL;
while(pn1)
{
pn2 = pn1;
pn1 = pn1->next;
free((void*)pn2);
}
}
free((void*)WildCardTagMap);
}
ULONG
MatchPoolTag(
PSTR Tag,
PSTR TagToMatch
)
{
BOOL Partial = FALSE;
ULONG CharMatched = 0;
ULONG i;
for (i = 0; i<strlen(TagToMatch); i++)
{
// If pooltag.txt tag is smaller, match cannot happen
if (Tag[i] == '\0') return FALSE;
switch (Tag[i])
{
case '*':
// Match the remainder
return CharMatched;
case '?':
Partial = TRUE;
break;
default:
// Cannot match a non widcard character after '?'
if (!Partial && (Tag[i] == TagToMatch[i]))
{
CharMatched=i+1;
} else
{
return FALSE;
}
}
}
if ((strlen(TagToMatch) < strlen(Tag)))
{
//* can match 0 or more chars
if (Tag[i] == '*')
{
return CharMatched;
}
}
if (strlen(TagToMatch) == strlen(Tag))
{
return CharMatched;
}
return FALSE;
}
PTAGNODE
LookupTag(
PUCHAR tag)
{
PTAGNODE pn1, pnMatch=NULL;
int ind;
UCHAR szTag[5];
int i;
ULONG Match, PrevMatch;
//Remove leading spaces in tag
for(i=0;i<4;i++)
{
if (!isspace(tag[i]))
{
strncpy(szTag,tag+i,4-i);
szTag[4-i]='\0';
break;
}
}
szTag[4] = '\0';
for(i = 1; i < 4; i++)
{
if(isspace(szTag[i]))
{
szTag[i] = '\0';
break;
}
}
ind = HashString(szTag) % TAGMAPLEN;
// Tags are case-sensitive i.e. "abcd" and "ABCD" are different tags
if (TagMap)
{
pn1 = TagMap[ind];
while(pn1)
{
if(strcmp(szTag, pn1->Tag) == 0)
return pn1;
pn1 = pn1->next;
}
}
//We need to look for wild-card tag matches now
ind = ComputeIndex(szTag);
if (ind == INVALID_INDEX) return NULL;
if (WildCardTagMap)
{
pn1 = WildCardTagMap[ind];
PrevMatch = 0;
while (pn1)
{
Match = MatchPoolTag(pn1->Tag, szTag);
//We have found a better match
if (Match > PrevMatch)
{
PrevMatch = Match;
pnMatch=pn1;
}
pn1 = pn1->next;
}
}
return pnMatch;
}
VOID
ShowSessionPopup( VOID )
{
HANDLE PopupHandle;
WORD n;
COORD Coord;
BOOL Cancel = FALSE;
ULONG SessionId = 0;
ULONG NumberOfDigits = 0;
CHAR CurrentChar;
CHAR SpaceChar = ' ';
DWORD NumWrittenChars;
CHAR PromptText[] = "Session ID (just press ENTER for all sessions):";
PopupHandle = CreateConsoleScreenBuffer( GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
if (PopupHandle == NULL) {
return;
}
SetConsoleActiveScreenBuffer( PopupHandle );
n = 0;
WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
WriteConsoleLine( PopupHandle, n++, PromptText, FALSE );
WriteConsoleLine( PopupHandle, n, NULL, FALSE );
Coord.X = (SHORT)strlen (PromptText) + 1;
Coord.Y = n - 1;
SetConsoleCursorPosition( PopupHandle, Coord );
while (TRUE) {
if (WaitForSingleObject( InputHandle, DelayTimeMsec ) == STATUS_WAIT_0 &&
ReadConsoleInput( InputHandle, &InputRecord, 1, &NumberOfInputRecords ) &&
InputRecord.EventType == KEY_EVENT &&
InputRecord.Event.KeyEvent.bKeyDown
) {
if (InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) {
Cancel = TRUE;
break;
}
else if (InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_RETURN) {
break;
}
else if (InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_BACK) {
if (NumberOfDigits > 0) {
NumberOfDigits -= 1;
SessionId = SessionId / 10;
Coord.X -= 1;
SetConsoleCursorPosition( PopupHandle, Coord );
WriteConsoleOutputCharacter (PopupHandle, &SpaceChar, 1, Coord, &NumWrittenChars);
}
}
else {
if (NumberOfDigits < 6) {
CurrentChar = (CHAR)toupper (InputRecord.Event.KeyEvent.uChar.AsciiChar);
if (CurrentChar >= '0' && CurrentChar <= '9') {
NumberOfDigits += 1;
SessionId = SessionId * 10 + (CurrentChar - '0');
WriteConsoleOutputCharacter (PopupHandle, &CurrentChar, 1, Coord, &NumWrittenChars);
Coord.X += 1;
SetConsoleCursorPosition( PopupHandle, Coord );
}
}
}
}
}
if (Cancel == FALSE) {
DisplaySessionPool = TRUE;
if (NumberOfDigits == 0) {
DisplaySessionId = (ULONG)-1;
}
else {
DisplaySessionId = SessionId;
}
}
SetConsoleActiveScreenBuffer( OutputHandle );
CloseHandle( PopupHandle );
return;
}