1901 lines
52 KiB
C++
1901 lines
52 KiB
C++
//
|
|
// Systrack - System resource tracking
|
|
// Copyright (c) Microsoft Corporation, 1998
|
|
//
|
|
|
|
//
|
|
// module: systrack.cxx
|
|
// author: silviuc
|
|
// created: Mon Nov 09 12:20:41 1998
|
|
//
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <time.h>
|
|
|
|
extern "C" {
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
}
|
|
|
|
#include <windows.h>
|
|
#include <common.ver>
|
|
|
|
#define VERSION_DEFINITION_MODULE
|
|
#include "version.hxx"
|
|
|
|
#define DEBUGINFO_DEFINITION_MODULE
|
|
#include "debug.hxx"
|
|
|
|
#include "pooltag.hxx"
|
|
#include "process.hxx"
|
|
#include "memory.hxx"
|
|
#include "systrack.hxx"
|
|
|
|
#define BUFFER_SIZE_STEP ( 128 * 1024 )
|
|
|
|
void PrintCurrentTime ();
|
|
void PrintSystemBasicInformation ();
|
|
void PrintSystemPerformanceInformation ();
|
|
void PrintSystemProcessInformation (BOOL ShortDump);
|
|
void PrintSystemPoolDetailedInformation ();
|
|
void PrintSystemPoolTagInformation ();
|
|
void PrintProcessStackInformation ();
|
|
|
|
VOID
|
|
GetProcessStackInfo (
|
|
PSYSTEM_PROCESS_INFORMATION Info,
|
|
PSIZE_T MaxSize,
|
|
PSIZE_T TotalSize,
|
|
PBOOL ErrorsFound
|
|
);
|
|
|
|
//
|
|
// Functions:
|
|
//
|
|
// Help
|
|
//
|
|
// Decription:
|
|
//
|
|
// Prints help information to the stdout. Exits with status code 1.
|
|
//
|
|
|
|
static void
|
|
Help ()
|
|
{
|
|
static char help_text [] =
|
|
" \n"
|
|
"systrack - System resource tracking --" BUILD_MACHINE_TAG "\n"
|
|
VER_LEGALCOPYRIGHT_STR "\n"
|
|
" \n"
|
|
" systrack [INFO-CLASS] \n"
|
|
" \n"
|
|
" <> : if no class specified, print process information. \n"
|
|
" /system : print system basic information. \n"
|
|
" /process : print process information. \n"
|
|
" /stack : print stack usage information for all processes. \n"
|
|
" /performance: print performance information. \n"
|
|
" /pool : print pool tag information (pool tags should be enabled). \n"
|
|
" /pooldetailed : print pool information (only checked builds). \n"
|
|
" /all : print everything. \n"
|
|
" \n"
|
|
" /trackpool PERIOD DELTA \n"
|
|
" /trackpooltag PERIOD PATTERN DELTA \n"
|
|
" /trackprocess PERIOD HANDLE THREAD WSET VSIZE PFILE \n"
|
|
" /trackprocessid PERIOD ID HANDLE THREAD WSET VSIZE PFILE \n"
|
|
" /trackavailablepages PERIOD DELTA \n"
|
|
" /trackcommittedpages PERIOD DELTA \n"
|
|
" /trackcommitlimit PERIOD DELTA \n"
|
|
" /trackpagefaultcount PERIOD DELTA \n"
|
|
" /tracksystemcalls PERIOD DELTA \n"
|
|
" /tracktotalsystemdriverpages PERIOD DELTA \n"
|
|
" /tracktotalsystemcodepages PERIOD DELTA \n"
|
|
" \n"
|
|
" /help TOPIC detailed help for the topic (e.g. process, trackpool, \n"
|
|
" trackprocessid, etc.). \n"
|
|
" ?, /? help \n"
|
|
" -version version information \n"
|
|
" \n"
|
|
"Examples: \n"
|
|
" \n"
|
|
" systrack /trackpool 1000 10000 \n"
|
|
" \n"
|
|
" Polls every 1000ms the kernel pools and will print every pool tag \n"
|
|
" whose pool usage increased by more than 10000 bytes. \n"
|
|
" \n"
|
|
" systrack /trackpooltag 1000 \"G*\" 10000 \n"
|
|
" \n"
|
|
" Polls every 1000ms the kernel pools and will print every pool tag \n"
|
|
" that matches the pattern if its pool usage increased by more \n"
|
|
" than 10000 bytes. \n"
|
|
" \n"
|
|
" systrack /trackprocess 1000 5 5 1000000 1000000 1000000 \n"
|
|
" \n"
|
|
" Polls every 1000ms the processes running and prints every process \n"
|
|
" whose handle count increased by more than 5 or thread count \n"
|
|
" increased by more than 5 or working set size increased by more \n"
|
|
" than 1000000 or virtual size increased by more than 1000000 or \n"
|
|
" pagefile usage increased by more than 1000000. \n"
|
|
" \n"
|
|
" systrack /trackprocessid 1000 136 5 5 1000000 1000000 1000000 \n"
|
|
" \n"
|
|
" Polls every 1000ms the process with id 136 and reports if the \n"
|
|
" handle count increased by more than 5 or thread count \n"
|
|
" increased by more than 5 or working set size increased by more \n"
|
|
" than 1000000 or virtual size increased by more than 1000000 or \n"
|
|
" pagefile usage increased by more than 1000000. \n"
|
|
" \n"
|
|
" \n";
|
|
|
|
printf (help_text);
|
|
exit (1);
|
|
}
|
|
|
|
|
|
//
|
|
// Functions:
|
|
//
|
|
// DetailedHelp
|
|
//
|
|
// Decription:
|
|
//
|
|
// Prints help information to the stdout for a specific topic.
|
|
// Exits with status code 1.
|
|
//
|
|
|
|
static void
|
|
DetailedHelp (
|
|
|
|
char * Topic)
|
|
{
|
|
char * help_text;
|
|
|
|
if (_stricmp (Topic, "system") == 0) {
|
|
help_text =
|
|
"systrack /system \n"
|
|
" \n"
|
|
" \n";
|
|
}
|
|
else if (_stricmp (Topic, "process") == 0) {
|
|
help_text =
|
|
"systrack /proces \n"
|
|
" \n"
|
|
" \n";
|
|
}
|
|
else if (_stricmp (Topic, "performance") == 0) {
|
|
help_text =
|
|
"systrack /performance \n"
|
|
" \n"
|
|
" \n";
|
|
}
|
|
else if (_stricmp (Topic, "trackprocess") == 0) {
|
|
help_text =
|
|
"systrack /trackprocess \n"
|
|
" \n"
|
|
" \n";
|
|
}
|
|
else if (_stricmp (Topic, "trackprocessid") == 0) {
|
|
help_text =
|
|
"systrack /system \n"
|
|
" \n"
|
|
" \n";
|
|
}
|
|
else if (_stricmp (Topic, "trackpool") == 0) {
|
|
help_text =
|
|
"systrack /trackpool \n"
|
|
" \n"
|
|
" \n";
|
|
}
|
|
else if (_stricmp (Topic, "trackpooltag") == 0) {
|
|
help_text =
|
|
"systrack /trackpooltag \n"
|
|
" \n"
|
|
" \n";
|
|
}
|
|
else {
|
|
printf ("Unknown help topic %s \n", Topic);
|
|
exit (1);
|
|
}
|
|
|
|
|
|
printf (help_text, VERSION_INFORMATION_VERSION);
|
|
exit (1);
|
|
}
|
|
|
|
|
|
//
|
|
// Function:
|
|
//
|
|
// main
|
|
//
|
|
// Description:
|
|
//
|
|
// ?, -?, /? - print help information.
|
|
// -version - print version information
|
|
//
|
|
// default (system, process, pool)
|
|
// /process
|
|
// /stack
|
|
// /system
|
|
// /performance
|
|
// /pool
|
|
// /pooldetailed
|
|
//
|
|
//
|
|
|
|
void _cdecl
|
|
main (int argc, char *argv[])
|
|
{
|
|
if (argc == 2 && _stricmp (argv[1], "?") == 0)
|
|
Help ();
|
|
else if (argc == 2 && _stricmp (argv[1], "/?") == 0)
|
|
Help ();
|
|
else if (argc == 2 && _stricmp (argv[1], "-?") == 0)
|
|
Help ();
|
|
else if (argc == 2 && _stricmp (argv[1], "-h") == 0)
|
|
Help ();
|
|
else if (argc == 2 && _stricmp (argv[1], "/h") == 0)
|
|
Help ();
|
|
// if (argc == 3 && _stricmp (argv[1], "/help") == 0)
|
|
// DetailedHelp (argv[2]);
|
|
|
|
if (argc == 2 && _stricmp (argv[1], "-version") == 0)
|
|
dump_version_information ();
|
|
|
|
try
|
|
{
|
|
//
|
|
// Here comes the code ...
|
|
//
|
|
|
|
PrintCurrentTime ();
|
|
|
|
if (argc == 1)
|
|
{
|
|
//
|
|
// <> default options
|
|
//
|
|
|
|
// PrintSystemBasicInformation ();
|
|
PrintSystemProcessInformation (TRUE);
|
|
// PrintSystemPoolTagInformation ();
|
|
}
|
|
else if (argc == 2 && _stricmp (argv[1], "/stack") == 0)
|
|
{
|
|
//
|
|
// /stack option
|
|
//
|
|
|
|
PrintProcessStackInformation ();
|
|
}
|
|
else if (argc == 2 && _stricmp (argv[1], "/all") == 0)
|
|
{
|
|
//
|
|
// /all option
|
|
//
|
|
|
|
PrintSystemBasicInformation ();
|
|
PrintSystemPerformanceInformation ();
|
|
PrintSystemProcessInformation (FALSE);
|
|
PrintSystemPoolTagInformation ();
|
|
PrintSystemPoolDetailedInformation ();
|
|
}
|
|
else if (argc == 4 && _stricmp (argv[1], "/trackpool") == 0)
|
|
{
|
|
//
|
|
// /trackpool PERIOD DELTA
|
|
//
|
|
|
|
ULONG Delta;
|
|
ULONG Period;
|
|
|
|
Period = atoi (argv[2]);
|
|
Delta = atoi (argv[3]);
|
|
|
|
if (Delta == 0)
|
|
Delta = 8192;
|
|
|
|
if (Period == 0)
|
|
Period = 1000;
|
|
|
|
SystemPoolTrack (Period, Delta);
|
|
}
|
|
else if (argc == 5 && _stricmp (argv[1], "/trackpooltag") == 0)
|
|
{
|
|
//
|
|
// /trackpooltag PERIOD PATTERN DELTA
|
|
//
|
|
|
|
ULONG Delta;
|
|
ULONG Period;
|
|
UCHAR * Pattern;
|
|
|
|
Period = atoi (argv[2]);
|
|
Pattern = (UCHAR *)(argv[3]);
|
|
Delta = atoi (argv[4]);
|
|
|
|
if (Delta == 0)
|
|
Delta = 8192;
|
|
|
|
if (Period == 0)
|
|
Period = 1000;
|
|
|
|
SystemPoolTagTrack (Period, Pattern, Delta);
|
|
}
|
|
else if (argc == 8 && _stricmp (argv[1], "/trackprocess") == 0)
|
|
{
|
|
//
|
|
// /trackprocess PERIOD HANDLES THREADS WSET VSIZE PFILE
|
|
//
|
|
|
|
ULONG DeltaHandles;
|
|
ULONG DeltaThreads;
|
|
ULONG DeltaWorkingSet;
|
|
SIZE_T DeltaVirtualSize;
|
|
SIZE_T DeltaPagefileUsage;
|
|
ULONG Period;
|
|
|
|
Period = atoi (argv[2]);
|
|
DeltaHandles = atoi (argv[3]);
|
|
DeltaThreads = atoi (argv[4]);
|
|
DeltaWorkingSet = atoi (argv[5]);
|
|
DeltaVirtualSize = atoi (argv[6]);
|
|
DeltaPagefileUsage = atoi (argv[7]);
|
|
|
|
if (Period == 0)
|
|
Period = 1000;
|
|
|
|
if (DeltaHandles == 0)
|
|
DeltaHandles = 32;
|
|
|
|
if (DeltaThreads == 0)
|
|
DeltaThreads = 8;
|
|
|
|
if (DeltaWorkingSet == 0)
|
|
DeltaWorkingSet = 0x100000;
|
|
|
|
if (DeltaVirtualSize == 0)
|
|
DeltaVirtualSize = 0x100000;
|
|
|
|
if (DeltaPagefileUsage == 0)
|
|
DeltaPagefileUsage = 0x100000;
|
|
|
|
SystemProcessTrack (Period,
|
|
DeltaHandles, DeltaThreads, DeltaWorkingSet,
|
|
DeltaVirtualSize, DeltaPagefileUsage);
|
|
}
|
|
else if (argc == 9 && _stricmp (argv[1], "/trackprocessid") == 0)
|
|
{
|
|
//
|
|
// /trackprocessid PERIOD ID HANDLES THREADS WSET VSIZE PFILE
|
|
//
|
|
|
|
ULONG ProcessId;
|
|
ULONG DeltaHandles;
|
|
ULONG DeltaThreads;
|
|
ULONG DeltaWorkingSet;
|
|
SIZE_T DeltaVirtualSize;
|
|
SIZE_T DeltaPagefileUsage;
|
|
ULONG Period;
|
|
|
|
Period = atoi (argv[2]);
|
|
ProcessId = atoi (argv[3]);
|
|
DeltaHandles = atoi (argv[4]);
|
|
DeltaThreads = atoi (argv[5]);
|
|
DeltaWorkingSet = atoi (argv[6]);
|
|
DeltaVirtualSize = atoi (argv[7]);
|
|
DeltaPagefileUsage = atoi (argv[8]);
|
|
|
|
if (Period == 0)
|
|
Period = 1000;
|
|
|
|
if (ProcessId == 0) {
|
|
printf ("Bad process id %s\n", argv[3]);
|
|
exit (1);
|
|
}
|
|
|
|
if (DeltaHandles == 0)
|
|
DeltaHandles = 32;
|
|
|
|
if (DeltaThreads == 0)
|
|
DeltaThreads = 8;
|
|
|
|
if (DeltaWorkingSet == 0)
|
|
DeltaWorkingSet = 0x100000;
|
|
|
|
if (DeltaVirtualSize == 0)
|
|
DeltaVirtualSize = 0x100000;
|
|
|
|
if (DeltaPagefileUsage == 0)
|
|
DeltaPagefileUsage = 0x100000;
|
|
|
|
SystemProcessIdTrack (Period, ProcessId,
|
|
DeltaHandles, DeltaThreads, DeltaWorkingSet,
|
|
DeltaVirtualSize, DeltaPagefileUsage);
|
|
}
|
|
else if (argc == 4 && _stricmp (argv[1], "/trackavailablepages") == 0)
|
|
{
|
|
//
|
|
// /trackavailablepages PERIOD DELTA
|
|
//
|
|
|
|
LONG Delta;
|
|
ULONG Period;
|
|
|
|
Period = atoi (argv[2]);
|
|
Delta = atoi (argv[3]);
|
|
|
|
if (Period == 0)
|
|
Period = 1000;
|
|
|
|
if (Delta == 0)
|
|
Delta = 100;
|
|
|
|
//
|
|
// We track decreasing values therefore delta should be negative.
|
|
//
|
|
|
|
TrackPerformanceCounter (argv[1], TRACK_AVAILABLE_PAGES, Period, -Delta);
|
|
}
|
|
else if (argc == 4 && _stricmp (argv[1], "/trackcommittedpages") == 0)
|
|
{
|
|
//
|
|
// /trackcommittedpages PERIOD DELTA
|
|
//
|
|
|
|
LONG Delta;
|
|
ULONG Period;
|
|
|
|
Period = atoi (argv[2]);
|
|
Delta = atoi (argv[3]);
|
|
|
|
if (Period == 0)
|
|
Period = 1000;
|
|
|
|
if (Delta == 0)
|
|
Delta = 100;
|
|
|
|
//
|
|
// We track increasing values therefore delta should be positive.
|
|
//
|
|
|
|
TrackPerformanceCounter (argv[1], TRACK_COMMITTED_PAGES, Period, Delta);
|
|
}
|
|
else if (argc == 4 && _stricmp (argv[1], "/trackcommitlimit") == 0)
|
|
{
|
|
//
|
|
// /trackcommitlimit PERIOD DELTA
|
|
//
|
|
|
|
LONG Delta;
|
|
ULONG Period;
|
|
|
|
Period = atoi (argv[2]);
|
|
Delta = atoi (argv[3]);
|
|
|
|
if (Period == 0)
|
|
Period = 1000;
|
|
|
|
if (Delta == 0)
|
|
Delta = 100;
|
|
|
|
//
|
|
// We track increasing values therefore delta should be positive.
|
|
//
|
|
|
|
TrackPerformanceCounter (argv[1], TRACK_COMMIT_LIMIT, Period, Delta);
|
|
}
|
|
else if (argc == 4 && _stricmp (argv[1], "/trackpagefaultcount") == 0)
|
|
{
|
|
//
|
|
// /trackpagefaultcount PERIOD DELTA
|
|
//
|
|
|
|
LONG Delta;
|
|
ULONG Period;
|
|
|
|
Period = atoi (argv[2]);
|
|
Delta = atoi (argv[3]);
|
|
|
|
if (Period == 0)
|
|
Period = 1000;
|
|
|
|
if (Delta == 0)
|
|
Delta = 100;
|
|
|
|
//
|
|
// We track increasing values therefore delta should be positive.
|
|
//
|
|
|
|
TrackPerformanceCounter (argv[1], TRACK_PAGE_FAULT_COUNT, Period, Delta);
|
|
}
|
|
else if (argc == 4 && _stricmp (argv[1], "/tracksystemcalls") == 0)
|
|
{
|
|
//
|
|
// /tracksystemcalls PERIOD DELTA
|
|
//
|
|
|
|
LONG Delta;
|
|
ULONG Period;
|
|
|
|
Period = atoi (argv[2]);
|
|
Delta = atoi (argv[3]);
|
|
|
|
if (Period == 0)
|
|
Period = 1000;
|
|
|
|
if (Delta == 0)
|
|
Delta = 100;
|
|
|
|
//
|
|
// We track increasing values therefore delta should be positive.
|
|
//
|
|
|
|
TrackPerformanceCounter (argv[1], TRACK_SYSTEM_CALLS, Period, Delta);
|
|
}
|
|
else if (argc == 4 && _stricmp (argv[1], "/tracktotalsystemdriverpages") == 0)
|
|
{
|
|
//
|
|
// /tracktotalsystemdriverpages PERIOD DELTA
|
|
//
|
|
|
|
LONG Delta;
|
|
ULONG Period;
|
|
|
|
Period = atoi (argv[2]);
|
|
Delta = atoi (argv[3]);
|
|
|
|
if (Period == 0)
|
|
Period = 1000;
|
|
|
|
if (Delta == 0)
|
|
Delta = 100;
|
|
|
|
//
|
|
// We track increasing values therefore delta should be positive.
|
|
//
|
|
|
|
TrackPerformanceCounter (argv[1], TRACK_TOTAL_SYSTEM_DRIVER_PAGES, Period, Delta);
|
|
}
|
|
else if (argc == 4 && _stricmp (argv[1], "/tracktotalsystemcodepages") == 0)
|
|
{
|
|
//
|
|
// /tracktotalsystemcodepages PERIOD DELTA
|
|
//
|
|
|
|
LONG Delta;
|
|
ULONG Period;
|
|
|
|
Period = atoi (argv[2]);
|
|
Delta = atoi (argv[3]);
|
|
|
|
if (Period == 0)
|
|
Period = 1000;
|
|
|
|
if (Delta == 0)
|
|
Delta = 100;
|
|
|
|
//
|
|
// We track increasing values therefore delta should be positive.
|
|
//
|
|
|
|
TrackPerformanceCounter (argv[1], TRACK_TOTAL_SYSTEM_CODE_PAGES, Period, Delta);
|
|
}
|
|
else
|
|
{
|
|
for (int Count = 1; Count < argc; Count++)
|
|
{
|
|
if (_stricmp (argv[Count], "/system") == 0)
|
|
PrintSystemBasicInformation ();
|
|
else if (_stricmp (argv[Count], "/performance") == 0)
|
|
PrintSystemPerformanceInformation ();
|
|
else if (_stricmp (argv[Count], "/process") == 0)
|
|
PrintSystemProcessInformation (TRUE);
|
|
else if (_stricmp (argv[Count], "/pool") == 0)
|
|
PrintSystemPoolTagInformation ();
|
|
else if (_stricmp (argv[Count], "/pooldetailed") == 0)
|
|
PrintSystemPoolDetailedInformation ();
|
|
else
|
|
Help ();
|
|
}
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
printf ("unexpected exception ...\n");
|
|
fflush (stdout);
|
|
exit (1);
|
|
}
|
|
|
|
exit (0);
|
|
}
|
|
|
|
|
|
//
|
|
// Function:
|
|
//
|
|
// PrintCurrentTime
|
|
//
|
|
// Description:
|
|
//
|
|
// Prints current time, machine name, etc.
|
|
//
|
|
//
|
|
|
|
void PrintCurrentTime ()
|
|
{
|
|
TCHAR MachineName [32];
|
|
LPCTSTR TimeString;
|
|
time_t Time;
|
|
DWORD Result;
|
|
|
|
if (GetEnvironmentVariable (TEXT("COMPUTERNAME"), MachineName, sizeof MachineName) == 0)
|
|
strcpy (MachineName, "unknown");
|
|
|
|
time (&Time);
|
|
TimeString = asctime (localtime (&Time));
|
|
|
|
printf ("Systrack - System resource tracking, %s\n", VERSION_INFORMATION_VERSION);
|
|
printf ("Machine: %s\n", MachineName);
|
|
printf ("Time: %s\n", TimeString);
|
|
fflush( stdout );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//
|
|
// Macro:
|
|
//
|
|
// _dump_, _dump_quad_ (object, field)
|
|
//
|
|
// Description:
|
|
//
|
|
// Handy macros to dump the fields of a structure.
|
|
//
|
|
|
|
#define _dump_(object,field) printf ("%-30s %08X (%u)\n", #field, (ULONG)(object->field), (ULONG)(object->field))
|
|
|
|
#define _dump_quad_(object,field) printf ("%-30s %I64X (%I64u)\n", #field, (object->field.QuadPart), (object->field.QuadPart))
|
|
|
|
|
|
//
|
|
// Local:
|
|
//
|
|
// InfoBuffer
|
|
//
|
|
// Description:
|
|
//
|
|
// Large enough structure to hold theinformation returned by
|
|
// NtQuerySystemInformation. I've opted for this solution because
|
|
// systrack can run under heavy stress conditions and we do not
|
|
// to allocate big chunks of memory dynamically in such a situation.
|
|
//
|
|
// Note. If we decide to multithread the application we will need a
|
|
// critical section to protect the information buffer.
|
|
// CRITICAL_SECTION InfoBufferLock;
|
|
//
|
|
|
|
static TCHAR InfoBuffer [0x40000];
|
|
|
|
//
|
|
// Local:
|
|
//
|
|
// PoolTagInformationBuffer
|
|
//
|
|
// Description:
|
|
//
|
|
// Buffer for NtQuerySystemInformation( SystemPoolTagInformation ).
|
|
// Its size is grown by QueryPoolTagInformationIterative if necessary.
|
|
// The length of the buffer is held in PoolTagInformationBufferLength.
|
|
//
|
|
|
|
static TCHAR *PoolTagInformationBuffer = NULL;
|
|
|
|
//
|
|
// Local:
|
|
//
|
|
// PoolTagInformationBufferLength
|
|
//
|
|
// Description:
|
|
//
|
|
// The current length of PoolTagInformationBuffer.
|
|
//
|
|
|
|
size_t PoolTagInformationBufferLength = 0;
|
|
|
|
|
|
//
|
|
// Function:
|
|
//
|
|
// QueryPoolTagInformationIterative
|
|
//
|
|
// Description:
|
|
//
|
|
// 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(
|
|
TCHAR **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( TCHAR ) * BUFFER_SIZE_STEP;
|
|
|
|
*CurrentBuffer = (TCHAR *) 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 = (TCHAR *) 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;
|
|
}
|
|
|
|
//
|
|
// Function:
|
|
//
|
|
// QuerySystemPoolTagInformation
|
|
//
|
|
// Description:
|
|
//
|
|
// Fills InfoBuffer with SystemPoolTagInformation and returns
|
|
// a pointer to it.
|
|
//
|
|
|
|
PVOID
|
|
QuerySystemPoolTagInformation ()
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG RealLength;
|
|
|
|
//
|
|
// SystemPoolTagInformation
|
|
//
|
|
|
|
Status = QueryPoolTagInformationIterative(
|
|
&PoolTagInformationBuffer,
|
|
&PoolTagInformationBufferLength );
|
|
|
|
if (! NT_SUCCESS(Status))
|
|
printf ("NtQuerySystemInformation(pooltag): error %08X\n",
|
|
Status);
|
|
|
|
return NT_SUCCESS(Status) ? PoolTagInformationBuffer : NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// Function:
|
|
//
|
|
// QuerySystemProcessInformation
|
|
//
|
|
// Description:
|
|
//
|
|
// Fills InfoBuffer with SystemProcessInformation and returns
|
|
// a pointer to it.
|
|
//
|
|
|
|
PVOID
|
|
QuerySystemProcessInformation ()
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG RealLength;
|
|
|
|
//
|
|
// SystemProcessInformation
|
|
//
|
|
|
|
Status = NtQuerySystemInformation (
|
|
SystemProcessInformation,
|
|
InfoBuffer,
|
|
sizeof InfoBuffer,
|
|
&RealLength);
|
|
|
|
if (! NT_SUCCESS(Status))
|
|
printf ("NtQuerySystemInformation(process): error %08X\n",
|
|
Status);
|
|
|
|
return NT_SUCCESS(Status) ? InfoBuffer : NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// Function:
|
|
//
|
|
// QuerySystemPerformanceInformation
|
|
//
|
|
// Description:
|
|
//
|
|
// Fills InfoBuffer with SystemPerformanceInformation and returns
|
|
// a pointer to it.
|
|
//
|
|
|
|
PVOID
|
|
QuerySystemPerformanceInformation ()
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG RealLength;
|
|
|
|
//
|
|
// SystemPerformanceInformation
|
|
//
|
|
|
|
Status = NtQuerySystemInformation (
|
|
SystemPerformanceInformation,
|
|
InfoBuffer,
|
|
sizeof InfoBuffer,
|
|
&RealLength);
|
|
|
|
if (! NT_SUCCESS(Status))
|
|
printf ("NtQuerySystemInformation(performance): error %08X\n",
|
|
Status);
|
|
|
|
return NT_SUCCESS(Status) ? InfoBuffer : NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// Function:
|
|
//
|
|
// PrintSystemBasicInformation
|
|
//
|
|
// Description:
|
|
//
|
|
// Prints SystemPerformanceInformation.
|
|
//
|
|
//
|
|
|
|
void PrintSystemBasicInformation ()
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG RealLength;
|
|
|
|
printf ("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
|
|
printf ("System basic information \n");
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
|
|
fflush( stdout );
|
|
|
|
//
|
|
// SystemBasicInformation
|
|
//
|
|
|
|
Status = NtQuerySystemInformation (
|
|
SystemBasicInformation,
|
|
InfoBuffer,
|
|
sizeof (SYSTEM_BASIC_INFORMATION),
|
|
&RealLength);
|
|
|
|
if (! NT_SUCCESS(Status))
|
|
{
|
|
printf ("NtQuerySystemInformation(Basic): error %08X\n", Status);
|
|
return;
|
|
}
|
|
|
|
{
|
|
PSYSTEM_BASIC_INFORMATION Info = (PSYSTEM_BASIC_INFORMATION)InfoBuffer;
|
|
|
|
_dump_(Info, PageSize);
|
|
_dump_(Info, NumberOfPhysicalPages);
|
|
_dump_(Info, LowestPhysicalPageNumber);
|
|
_dump_(Info, HighestPhysicalPageNumber);
|
|
_dump_(Info, AllocationGranularity);
|
|
_dump_(Info, MinimumUserModeAddress);
|
|
_dump_(Info, MaximumUserModeAddress);
|
|
_dump_(Info, ActiveProcessorsAffinityMask);
|
|
_dump_(Info, NumberOfProcessors);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Function:
|
|
//
|
|
// PrintSystemPerformanceInformation
|
|
//
|
|
// Description:
|
|
//
|
|
// Prints systemPerformanceInformation.
|
|
//
|
|
|
|
void PrintSystemPerformanceInformation ()
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG RealLength;
|
|
|
|
printf ("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
|
|
printf ("System performance information \n");
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
|
|
fflush( stdout );
|
|
|
|
//
|
|
// SystemPerformanceInformation
|
|
//
|
|
|
|
Status = NtQuerySystemInformation (
|
|
SystemPerformanceInformation,
|
|
InfoBuffer,
|
|
sizeof (SYSTEM_PERFORMANCE_INFORMATION),
|
|
&RealLength);
|
|
|
|
if (! NT_SUCCESS(Status))
|
|
{
|
|
printf ("NtQuerySystemInformation(Performance): error %08X\n", Status);
|
|
return;
|
|
}
|
|
|
|
{
|
|
PSYSTEM_PERFORMANCE_INFORMATION Info = (PSYSTEM_PERFORMANCE_INFORMATION)InfoBuffer;
|
|
|
|
_dump_quad_ (Info, IdleProcessTime);
|
|
_dump_quad_ (Info, IoReadTransferCount);
|
|
_dump_quad_ (Info, IoWriteTransferCount);
|
|
_dump_quad_ (Info, IoOtherTransferCount);
|
|
|
|
_dump_ (Info, IoReadOperationCount);
|
|
_dump_ (Info, IoWriteOperationCount);
|
|
_dump_ (Info, IoOtherOperationCount);
|
|
_dump_ (Info, AvailablePages);
|
|
_dump_ (Info, CommittedPages);
|
|
_dump_ (Info, CommitLimit);
|
|
_dump_ (Info, PeakCommitment);
|
|
_dump_ (Info, PageFaultCount);
|
|
_dump_ (Info, CopyOnWriteCount);
|
|
_dump_ (Info, TransitionCount);
|
|
_dump_ (Info, CacheTransitionCount);
|
|
_dump_ (Info, DemandZeroCount);
|
|
_dump_ (Info, PageReadCount);
|
|
_dump_ (Info, PageReadIoCount);
|
|
_dump_ (Info, CacheReadCount);
|
|
_dump_ (Info, CacheIoCount);
|
|
_dump_ (Info, DirtyPagesWriteCount);
|
|
_dump_ (Info, DirtyWriteIoCount);
|
|
_dump_ (Info, MappedPagesWriteCount);
|
|
_dump_ (Info, MappedWriteIoCount);
|
|
_dump_ (Info, PagedPoolPages);
|
|
_dump_ (Info, NonPagedPoolPages);
|
|
_dump_ (Info, PagedPoolAllocs);
|
|
_dump_ (Info, PagedPoolFrees);
|
|
_dump_ (Info, NonPagedPoolAllocs);
|
|
_dump_ (Info, NonPagedPoolFrees);
|
|
_dump_ (Info, FreeSystemPtes);
|
|
_dump_ (Info, ResidentSystemCodePage);
|
|
_dump_ (Info, TotalSystemDriverPages);
|
|
_dump_ (Info, TotalSystemCodePages);
|
|
_dump_ (Info, NonPagedPoolLookasideHits);
|
|
_dump_ (Info, PagedPoolLookasideHits);
|
|
#if 0
|
|
_dump_ (Info, Spare3Count);
|
|
#endif
|
|
_dump_ (Info, ResidentSystemCachePage);
|
|
_dump_ (Info, ResidentPagedPoolPage);
|
|
_dump_ (Info, ResidentSystemDriverPage);
|
|
_dump_ (Info, CcFastReadNoWait);
|
|
_dump_ (Info, CcFastReadWait);
|
|
_dump_ (Info, CcFastReadResourceMiss);
|
|
_dump_ (Info, CcFastReadNotPossible);
|
|
_dump_ (Info, CcFastMdlReadNoWait);
|
|
_dump_ (Info, CcFastMdlReadWait);
|
|
_dump_ (Info, CcFastMdlReadResourceMiss);
|
|
_dump_ (Info, CcFastMdlReadNotPossible);
|
|
_dump_ (Info, CcMapDataNoWait);
|
|
_dump_ (Info, CcMapDataWait);
|
|
_dump_ (Info, CcMapDataNoWaitMiss);
|
|
_dump_ (Info, CcMapDataWaitMiss);
|
|
_dump_ (Info, CcPinMappedDataCount);
|
|
_dump_ (Info, CcPinReadNoWait);
|
|
_dump_ (Info, CcPinReadWait);
|
|
_dump_ (Info, CcPinReadNoWaitMiss);
|
|
_dump_ (Info, CcPinReadWaitMiss);
|
|
_dump_ (Info, CcCopyReadNoWait);
|
|
_dump_ (Info, CcCopyReadWait);
|
|
_dump_ (Info, CcCopyReadNoWaitMiss);
|
|
_dump_ (Info, CcCopyReadWaitMiss);
|
|
_dump_ (Info, CcMdlReadNoWait);
|
|
_dump_ (Info, CcMdlReadWait);
|
|
_dump_ (Info, CcMdlReadNoWaitMiss);
|
|
_dump_ (Info, CcMdlReadWaitMiss);
|
|
_dump_ (Info, CcReadAheadIos);
|
|
_dump_ (Info, CcLazyWriteIos);
|
|
_dump_ (Info, CcLazyWritePages);
|
|
_dump_ (Info, CcDataFlushes);
|
|
_dump_ (Info, CcDataPages);
|
|
_dump_ (Info, ContextSwitches);
|
|
_dump_ (Info, FirstLevelTbFills);
|
|
_dump_ (Info, SecondLevelTbFills);
|
|
_dump_ (Info, SystemCalls);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Function:
|
|
//
|
|
// PrintSystemProcessInformation
|
|
//
|
|
// Description:
|
|
//
|
|
// Prints SystemProcessInformation.
|
|
//
|
|
// Details:
|
|
//
|
|
// These are the fields of a SYSTEM_PROCESS_INFORMATION structure:
|
|
//
|
|
// ULONG NextEntryOffset;
|
|
// ULONG NumberOfThreads;
|
|
// LARGE_INTEGER SpareLi1;
|
|
// LARGE_INTEGER SpareLi2;
|
|
// LARGE_INTEGER SpareLi3;
|
|
// LARGE_INTEGER CreateTime;
|
|
// LARGE_INTEGER UserTime;
|
|
// LARGE_INTEGER KernelTime;
|
|
// UNICODE_STRING ImageName;
|
|
// KPRIORITY BasePriority;
|
|
// HANDLE UniqueProcessId;
|
|
// HANDLE InheritedFromUniqueProcessId;
|
|
// ULONG HandleCount;
|
|
// ULONG SessionId;
|
|
// ULONG SpareUl3;
|
|
// SIZE_T PeakVirtualSize;
|
|
// SIZE_T VirtualSize;
|
|
// ULONG PageFaultCount;
|
|
// ULONG PeakWorkingSetSize;
|
|
// ULONG WorkingSetSize;
|
|
// SIZE_T QuotaPeakPagedPoolUsage;
|
|
// SIZE_T QuotaPagedPoolUsage;
|
|
// SIZE_T QuotaPeakNonPagedPoolUsage;
|
|
// SIZE_T QuotaNonPagedPoolUsage;
|
|
// SIZE_T PagefileUsage;
|
|
// SIZE_T PeakPagefileUsage;
|
|
// SIZE_T PrivatePageCount;
|
|
// LARGE_INTEGER ReadOperationCount;
|
|
// LARGE_INTEGER WriteOperationCount;
|
|
// LARGE_INTEGER OtherOperationCount;
|
|
// LARGE_INTEGER ReadTransferCount;
|
|
// LARGE_INTEGER WriteTransferCount;
|
|
// LARGE_INTEGER OtherTransferCount;
|
|
//
|
|
|
|
void PrintSystemProcessInformation (
|
|
|
|
BOOL ShortDump)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG RealLength;
|
|
SYSTEM_BASIC_INFORMATION SysInfo;
|
|
BOOL FinishNextTime = FALSE;
|
|
|
|
if (ShortDump)
|
|
{
|
|
printf ("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - -\n");
|
|
printf ("System process information \n");
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - -\n");
|
|
}
|
|
else
|
|
{
|
|
printf ("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
|
|
printf ("System process information \n");
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
|
|
}
|
|
|
|
fflush( stdout );
|
|
|
|
//
|
|
// SystemBasicInformation
|
|
//
|
|
|
|
Status = NtQuerySystemInformation (
|
|
SystemBasicInformation,
|
|
&SysInfo,
|
|
sizeof (SysInfo),
|
|
&RealLength);
|
|
|
|
if (! NT_SUCCESS(Status))
|
|
{
|
|
printf ("NtQuerySystemInformation(Basic): error %08X\n", Status);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// SystemProcessInformation
|
|
//
|
|
|
|
Status = NtQuerySystemInformation (
|
|
SystemProcessInformation,
|
|
InfoBuffer,
|
|
sizeof InfoBuffer,
|
|
&RealLength);
|
|
|
|
if (! NT_SUCCESS(Status))
|
|
{
|
|
printf ("NtQuerySystemInformation(Process): error %08X\n", Status);
|
|
return;
|
|
}
|
|
|
|
{
|
|
PSYSTEM_PROCESS_INFORMATION Info = (PSYSTEM_PROCESS_INFORMATION)InfoBuffer;
|
|
|
|
if (ShortDump)
|
|
{
|
|
printf ("%-15s %-5s %-5s %-4s %-5s %-8s %-8s %-5s %-5s %-6s %-5s %-5s %-5s\n",
|
|
"Process",
|
|
"Id",
|
|
"Sess",
|
|
"Pri",
|
|
"Thrds",
|
|
"Faults",
|
|
"Handles",
|
|
"Utime",
|
|
"Ktime",
|
|
"Wset",
|
|
"Vsize",
|
|
"Pfile",
|
|
"I/O");
|
|
|
|
printf ("%-15s %-5s %-5s %-4s %-5s %-8s %-8s %-5s %-5s %-6s %-5s %-5s %-5s\n",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"%",
|
|
"%",
|
|
"pages",
|
|
"Mb",
|
|
"Mb",
|
|
"x1000");
|
|
}
|
|
else
|
|
{
|
|
printf ("%-15s %-5s %-5s %-4s %-5s %-8s %-8s %-5s %-5s %-6s %-5s %-5s %-5s %-5s %-5s\n",
|
|
"Process",
|
|
"Id",
|
|
"Sess",
|
|
"Pri",
|
|
"Thrds",
|
|
"Faults",
|
|
"Handles",
|
|
"Utime",
|
|
"Ktime",
|
|
"Wset",
|
|
"Vsize",
|
|
"Pfile",
|
|
"I/O",
|
|
"Npool",
|
|
"Ppool");
|
|
|
|
printf ("%-15s %-5s %-5s %-4s %-5s %-8s %-8s %-5s %-5s %-6s %-5s %-5s %-5s %-5s %-5s\n",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"%",
|
|
"%",
|
|
"pages",
|
|
"Mb",
|
|
"Mb",
|
|
"x1000",
|
|
"Mb",
|
|
"Mb");
|
|
}
|
|
|
|
if (ShortDump)
|
|
{
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - -\n");
|
|
}
|
|
else
|
|
{
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
|
|
}
|
|
|
|
fflush( stdout );
|
|
|
|
for (FinishNextTime = FALSE ;
|
|
FinishNextTime == FALSE;
|
|
Info = (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)Info + Info->NextEntryOffset))
|
|
{
|
|
if (Info->NextEntryOffset == 0)
|
|
FinishNextTime = TRUE;
|
|
|
|
//
|
|
// User time vs Kernel time.
|
|
//
|
|
|
|
ULONG UserPercent, KernelPercent;
|
|
|
|
UserPercent = (ULONG)((Info->UserTime.QuadPart) * 100
|
|
/ (Info->UserTime.QuadPart + Info->KernelTime.QuadPart));
|
|
KernelPercent = 100 - UserPercent;
|
|
|
|
//
|
|
// I/O total count.
|
|
//
|
|
|
|
LARGE_INTEGER IoTotalCount;
|
|
|
|
IoTotalCount.QuadPart = Info->ReadOperationCount.QuadPart
|
|
+ Info->WriteOperationCount.QuadPart
|
|
+ Info->OtherOperationCount.QuadPart;
|
|
|
|
IoTotalCount.QuadPart /= 1000;
|
|
|
|
//
|
|
// Image name (special case the idle process).
|
|
//
|
|
|
|
if (Info->ImageName.Buffer == NULL)
|
|
printf ("%-15s ", "Idle");
|
|
else
|
|
printf ("%-15ws ", Info->ImageName.Buffer);
|
|
|
|
//
|
|
// Print the stuff.
|
|
//
|
|
|
|
if (ShortDump)
|
|
{
|
|
printf ("%-5I64u %-5u %-4u %-5u %-8u %-8u %-5u %-5u %-6u %-5u %-5u %-5I64u\n",
|
|
(ULONG64)((ULONG_PTR)(Info->UniqueProcessId)),
|
|
Info->SessionId,
|
|
Info->BasePriority,
|
|
Info->NumberOfThreads,
|
|
Info->PageFaultCount,
|
|
Info->HandleCount,
|
|
UserPercent,
|
|
KernelPercent,
|
|
Info->WorkingSetSize / SysInfo.PageSize,
|
|
Info->VirtualSize / 0x100000,
|
|
Info->PagefileUsage / 0x100000,
|
|
(IoTotalCount.QuadPart));
|
|
}
|
|
else
|
|
{
|
|
printf ("%-5I64u %-5u %-4u %-5u %-8u %-8u %-5u %-5u %-6u %-5u %-5u %-5I64u %-5u %-5u\n",
|
|
(ULONG64)((ULONG_PTR)(Info->UniqueProcessId)),
|
|
Info->SessionId,
|
|
Info->BasePriority,
|
|
Info->NumberOfThreads,
|
|
Info->PageFaultCount,
|
|
Info->HandleCount,
|
|
UserPercent,
|
|
KernelPercent,
|
|
Info->WorkingSetSize / SysInfo.PageSize,
|
|
Info->VirtualSize / 0x100000,
|
|
Info->PagefileUsage / 0x100000,
|
|
(IoTotalCount.QuadPart),
|
|
Info->QuotaNonPagedPoolUsage / 0x100000,
|
|
Info->QuotaPagedPoolUsage / 0x100000);
|
|
}
|
|
|
|
fflush( stdout );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Function:
|
|
//
|
|
// PrintSystemPoolDetailedInformation
|
|
//
|
|
// Description:
|
|
//
|
|
// Prints systemNonPagedPoolInformation and systemPagedPoolInformation.
|
|
// The function returns something meaningful only on checked builds.
|
|
//
|
|
// typedef struct _SYSTEM_POOL_ENTRY {
|
|
// BOOLEAN Allocated;
|
|
// BOOLEAN Spare0;
|
|
// USHORT AllocatorBackTraceIndex;
|
|
// ULONG Size;
|
|
// union {
|
|
// UCHAR Tag[4];
|
|
// ULONG TagUlong;
|
|
// PVOID ProcessChargedQuota;
|
|
// };
|
|
// } SYSTEM_POOL_ENTRY, *PSYSTEM_POOL_ENTRY;
|
|
//
|
|
// typedef struct _SYSTEM_POOL_INFORMATION {
|
|
// SIZE_T TotalSize;
|
|
// PVOID FirstEntry;
|
|
// USHORT EntryOverhead;
|
|
// BOOLEAN PoolTagPresent;
|
|
// BOOLEAN Spare0;
|
|
// ULONG NumberOfEntries;
|
|
// SYSTEM_POOL_ENTRY Entries[1];
|
|
// } SYSTEM_POOL_INFORMATION, *PSYSTEM_POOL_INFORMATION;
|
|
//
|
|
|
|
void PrintSystemPoolDetailedInformation ()
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG RealLength;
|
|
|
|
printf ("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
|
|
printf ("System pool detailed information \n");
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
|
|
fflush( stdout );
|
|
|
|
//
|
|
// SystemPoolInformation
|
|
//
|
|
|
|
Status = NtQuerySystemInformation (
|
|
SystemNonPagedPoolInformation,
|
|
InfoBuffer,
|
|
sizeof InfoBuffer,
|
|
&RealLength);
|
|
|
|
if (! NT_SUCCESS(Status))
|
|
{
|
|
printf ("NtQuerySystemInformation(NonPagedPool): error %08X\n", Status);
|
|
return;
|
|
}
|
|
|
|
{
|
|
ULONG Index;
|
|
PSYSTEM_POOL_INFORMATION Info = (PSYSTEM_POOL_INFORMATION)InfoBuffer;
|
|
|
|
for (Index = 0; Index < Info->NumberOfEntries; Index++)
|
|
{
|
|
if (Index != 0 && Index%5 == 0)
|
|
printf ("\n");
|
|
|
|
printf ("%c%c%c%c %-5u ",
|
|
Info->Entries[Index].Tag[0],
|
|
Info->Entries[Index].Tag[1],
|
|
Info->Entries[Index].Tag[2],
|
|
Info->Entries[Index].Tag[3],
|
|
Info->Entries[Index].Size);
|
|
}
|
|
|
|
fflush( stdout );
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Function:
|
|
//
|
|
// PrintSystemPoolTagInformation
|
|
//
|
|
// Description:
|
|
//
|
|
// Prints SystemPoolTagInformation.
|
|
//
|
|
// typedef struct _SYSTEM_POOLTAG {
|
|
// union {
|
|
// UCHAR Tag[4];
|
|
// ULONG TagUlong;
|
|
// };
|
|
// ULONG PagedAllocs;
|
|
// ULONG PagedFrees;
|
|
// SIZE_T PagedUsed;
|
|
// ULONG NonPagedAllocs;
|
|
// ULONG NonPagedFrees;
|
|
// SIZE_T NonPagedUsed;
|
|
// } SYSTEM_POOLTAG, *PSYSTEM_POOLTAG;
|
|
//
|
|
// typedef struct _SYSTEM_POOLTAG_INFORMATION {
|
|
// ULONG Count;
|
|
// SYSTEM_POOLTAG TagInfo[1];
|
|
// } SYSTEM_POOLTAG_INFORMATION, *PSYSTEM_POOLTAG_INFORMATION;
|
|
//
|
|
|
|
void PrintSystemPoolTagInformation ()
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG RealLength;
|
|
|
|
printf ("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
|
|
printf ("System pool tag information \n");
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
|
|
printf ("%-4s %-8s %-8s %-8s %-8s %-8s %-8s\n",
|
|
"Tag",
|
|
"NP used", "P used",
|
|
"NP alloc", "NP free",
|
|
"P alloc", "P free");
|
|
printf ("%-4s %-8s %-8s %-8s %-8s %-8s %-8s\n",
|
|
"",
|
|
"x bytes", "x bytes",
|
|
"x ops", "x ops",
|
|
"x ops", "x ops");
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
|
|
fflush( stdout );
|
|
|
|
//
|
|
// SystemPoolTagInformation
|
|
//
|
|
|
|
Status = NtQuerySystemInformation (
|
|
SystemPoolTagInformation,
|
|
InfoBuffer,
|
|
sizeof InfoBuffer,
|
|
&RealLength);
|
|
|
|
if (! NT_SUCCESS(Status))
|
|
{
|
|
printf ("NtQuerySystemInformation(PoolTag): error %08X\n", Status);
|
|
return;
|
|
}
|
|
|
|
{
|
|
ULONG Index;
|
|
PSYSTEM_POOLTAG_INFORMATION Info = (PSYSTEM_POOLTAG_INFORMATION)InfoBuffer;
|
|
|
|
for (Index = 0; Index < Info->Count; Index++)
|
|
{
|
|
printf ("%c%c%c%c %-8u %-8u %-8u %-8u %-8u %-8u\n",
|
|
Info->TagInfo[Index].Tag[0],
|
|
Info->TagInfo[Index].Tag[1],
|
|
Info->TagInfo[Index].Tag[2],
|
|
Info->TagInfo[Index].Tag[3],
|
|
Info->TagInfo[Index].NonPagedUsed,
|
|
Info->TagInfo[Index].PagedUsed,
|
|
Info->TagInfo[Index].NonPagedAllocs,
|
|
Info->TagInfo[Index].NonPagedFrees,
|
|
Info->TagInfo[Index].PagedAllocs,
|
|
Info->TagInfo[Index].PagedFrees);
|
|
}
|
|
|
|
fflush( stdout );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Function:
|
|
//
|
|
// PrintProcessStackInformation
|
|
//
|
|
// Description:
|
|
//
|
|
// Prints stack usage information for each process.
|
|
//
|
|
|
|
|
|
|
|
BOOL
|
|
ComputeMaxStackInProcess (
|
|
|
|
DWORD Pid,
|
|
PSIZE_T MaxSize,
|
|
PSIZE_T TotalSize);
|
|
|
|
|
|
VOID
|
|
PrintProcessStackInformation (
|
|
VOID
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG RealLength;
|
|
SYSTEM_BASIC_INFORMATION SysInfo;
|
|
BOOL FinishNextTime = FALSE;
|
|
BOOL ErrorsFound = FALSE;
|
|
SIZE_T MaxStack = 0;
|
|
SIZE_T TotalStack = 0;
|
|
BOOLEAN WasEnabled;
|
|
|
|
printf ("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n");
|
|
printf ("Process stack information \n");
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n");
|
|
|
|
//
|
|
// SystemBasicInformation
|
|
//
|
|
|
|
Status = NtQuerySystemInformation (
|
|
SystemBasicInformation,
|
|
&SysInfo,
|
|
sizeof (SysInfo),
|
|
&RealLength);
|
|
|
|
if (! NT_SUCCESS(Status)) {
|
|
printf ("NtQuerySystemInformation(Basic): error %08X\n", Status);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// SystemProcessInformation
|
|
//
|
|
|
|
Status = NtQuerySystemInformation (SystemProcessInformation,
|
|
InfoBuffer,
|
|
sizeof InfoBuffer,
|
|
&RealLength);
|
|
|
|
if (! NT_SUCCESS(Status)) {
|
|
printf ("NtQuerySystemInformation(Process): error %08X\n", Status);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Get debug privilege.
|
|
//
|
|
|
|
Status = RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE,
|
|
TRUE,
|
|
FALSE,
|
|
&WasEnabled);
|
|
|
|
if (! NT_SUCCESS(Status)) {
|
|
printf("Failed to enable debug privilege (%X) \n", Status);
|
|
}
|
|
|
|
{
|
|
PSYSTEM_PROCESS_INFORMATION Info = (PSYSTEM_PROCESS_INFORMATION)InfoBuffer;
|
|
|
|
printf ("%-15s %-5s %-5s %-4s %-5s %-8s %-5s %-5s\n",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"Total",
|
|
"Max");
|
|
|
|
printf ("%-15s %-5s %-5s %-4s %-5s %-8s %-5s %-5s\n",
|
|
"Process",
|
|
"Id",
|
|
"Sess",
|
|
"Pri",
|
|
"Thrds",
|
|
"Handles",
|
|
"stack",
|
|
"stack");
|
|
|
|
printf ("%-15s %-5s %-5s %-4s %-5s %-8s %-5s %-5s\n",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"Kb",
|
|
"Kb");
|
|
|
|
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n");
|
|
|
|
for (FinishNextTime = FALSE ;
|
|
FinishNextTime == FALSE;
|
|
Info = (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)Info + Info->NextEntryOffset)) {
|
|
|
|
if (Info->NextEntryOffset == 0)
|
|
FinishNextTime = TRUE;
|
|
|
|
//
|
|
// User time vs Kernel time.
|
|
//
|
|
|
|
ULONG UserPercent, KernelPercent;
|
|
|
|
UserPercent = (ULONG)((Info->UserTime.QuadPart) * 100
|
|
/ (Info->UserTime.QuadPart + Info->KernelTime.QuadPart));
|
|
KernelPercent = 100 - UserPercent;
|
|
|
|
//
|
|
// I/O total count.
|
|
//
|
|
|
|
LARGE_INTEGER IoTotalCount;
|
|
|
|
IoTotalCount.QuadPart = Info->ReadOperationCount.QuadPart
|
|
+ Info->WriteOperationCount.QuadPart
|
|
+ Info->OtherOperationCount.QuadPart;
|
|
|
|
IoTotalCount.QuadPart /= 1000;
|
|
|
|
//
|
|
// Image name (special case the idle process).
|
|
//
|
|
|
|
if (Info->ImageName.Buffer == NULL) {
|
|
|
|
printf ("%-15s ", "Idle");
|
|
}
|
|
else {
|
|
|
|
printf ("%-15ws ", Info->ImageName.Buffer);
|
|
}
|
|
|
|
//
|
|
// Compute stack info by iterating all threads in the process.
|
|
//
|
|
|
|
GetProcessStackInfo (Info, &MaxStack, &TotalStack, &ErrorsFound);
|
|
|
|
//
|
|
// Print the stuff.
|
|
//
|
|
|
|
printf ("%-5I64u %-5u %-4u %-5u %-8u %-5u %-5u\n",
|
|
(ULONG64)((ULONG_PTR)(Info->UniqueProcessId)),
|
|
Info->SessionId,
|
|
Info->BasePriority,
|
|
Info->NumberOfThreads,
|
|
Info->HandleCount,
|
|
(ULONG)(TotalStack/1024),
|
|
(ULONG)(MaxStack/1024));
|
|
|
|
}
|
|
}
|
|
|
|
printf(
|
|
" \n"
|
|
" * Total stack: total committed memory used for stacks by all threads \n"
|
|
" in the process. \n"
|
|
" * Max stack: the biggest committed stack in the process. \n"
|
|
" \n");
|
|
}
|
|
|
|
|
|
VOID
|
|
GetProcessStackInfo (
|
|
PSYSTEM_PROCESS_INFORMATION Info,
|
|
PSIZE_T MaxSize,
|
|
PSIZE_T TotalSize,
|
|
PBOOL ErrorsFound
|
|
)
|
|
{
|
|
ULONG Ti;
|
|
HANDLE Id;
|
|
HANDLE Thread;
|
|
HANDLE Process;
|
|
THREAD_BASIC_INFORMATION ThreadInfo;
|
|
TEB TebInfo;
|
|
SIZE_T BytesRead;
|
|
BOOL ReadResult;
|
|
NTSTATUS Status;
|
|
SIZE_T StackSize;
|
|
BOOLEAN WasEnabled;
|
|
|
|
*MaxSize = 0;
|
|
*TotalSize = 0;
|
|
*ErrorsFound = FALSE;
|
|
|
|
//
|
|
// Open the process.
|
|
//
|
|
|
|
Process = OpenProcess (PROCESS_VM_READ,
|
|
FALSE,
|
|
HandleToUlong(Info->UniqueProcessId));
|
|
|
|
if (Process == FALSE) {
|
|
//printf("Failed to open process %p (error %u) \n", Info->UniqueProcessId, GetLastError());
|
|
*ErrorsFound = TRUE;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Iterate all threads in the process and for each determine the
|
|
// thread ID, open the thread and query for TEB address. Finally
|
|
// read user mode stack sizes from the TEB.
|
|
//
|
|
|
|
for (Ti = 0; Ti < Info->NumberOfThreads; Ti += 1) {
|
|
|
|
Id = ((PSYSTEM_THREAD_INFORMATION)(Info + 1) + Ti)->ClientId.UniqueThread;
|
|
|
|
Thread = OpenThread (THREAD_QUERY_INFORMATION,
|
|
FALSE,
|
|
HandleToUlong(Id));
|
|
|
|
if (Thread == NULL) {
|
|
//printf("failed to open thread %u \n", GetLastError());
|
|
*ErrorsFound = TRUE;
|
|
continue;
|
|
}
|
|
|
|
Status = NtQueryInformationThread (Thread,
|
|
ThreadBasicInformation,
|
|
&ThreadInfo,
|
|
sizeof ThreadInfo,
|
|
NULL);
|
|
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
//printf("query thread failed with %X \n", Status);
|
|
*ErrorsFound = TRUE;
|
|
CloseHandle (Thread);
|
|
continue;
|
|
}
|
|
|
|
ReadResult = ReadProcessMemory (Process,
|
|
ThreadInfo.TebBaseAddress,
|
|
&TebInfo,
|
|
sizeof TebInfo,
|
|
&BytesRead);
|
|
|
|
if (ReadResult == FALSE) {
|
|
//printf("failed to read teb with %u \n", GetLastError());
|
|
*ErrorsFound = TRUE;
|
|
CloseHandle (Thread);
|
|
continue;
|
|
}
|
|
|
|
StackSize = (SIZE_T)(TebInfo.NtTib.StackBase) - (SIZE_T)(TebInfo.NtTib.StackLimit);
|
|
|
|
*TotalSize += StackSize;
|
|
|
|
if (StackSize > *MaxSize) {
|
|
*MaxSize = StackSize;
|
|
}
|
|
|
|
CloseHandle (Thread);
|
|
}
|
|
|
|
CloseHandle (Process);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// Function:
|
|
//
|
|
// DebugMessage
|
|
//
|
|
// Description:
|
|
//
|
|
// Printf like function that prints a message into debugger.
|
|
//
|
|
|
|
void __cdecl DebugMessage (char *fmt, ...)
|
|
{
|
|
va_list prms;
|
|
char Buffer [1024];
|
|
|
|
va_start (prms, fmt);
|
|
vsprintf (Buffer, fmt, prms);
|
|
OutputDebugString (Buffer);
|
|
va_end (prms);
|
|
}
|
|
|
|
|
|
//
|
|
// end of module: systrack.cxx
|
|
//
|