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

822 lines
22 KiB
C

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
pstat.c
Abstract:
This module contains the Windows NT process/thread status display.
Author:
Lou Perazzoli (LouP) 25-Oct-1991
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <stdlib.h>
#define BUFFER_SIZE 64*1024
#define MAX_BUFFER_SIZE 10*1024*1024
VOID
PrintLoadedDrivers(
VOID
);
ULONG CurrentBufferSize;
UCHAR *StateTable[] = {
"Initialized",
"Ready",
"Running",
"Standby",
"Terminated",
"Wait:",
"Transition",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown"
};
UCHAR *WaitTable[] = {
"Executive",
"FreePage",
"PageIn",
"PoolAllocation",
"DelayExecution",
"Suspended",
"UserRequest",
"Executive",
"FreePage",
"PageIn",
"PoolAllocation",
"DelayExecution",
"Suspended",
"UserRequest",
"EventPairHigh",
"EventPairLow",
"LpcReceive",
"LpcReply",
"VirtualMemory",
"PageOut",
"Spare1",
"Spare2",
"Spare3",
"Spare4",
"Spare5",
"Spare6",
"Spare7",
"Unknown",
"Unknown",
"Unknown"
};
UCHAR *Empty = " ";
BOOLEAN fUserOnly = TRUE;
BOOLEAN fSystemOnly = TRUE;
BOOLEAN fVerbose = FALSE;
BOOLEAN fPrintIt;
int
__cdecl
main(
int argc,
char *argv[]
)
{
PSYSTEM_PROCESS_INFORMATION ProcessInfo;
PSYSTEM_THREAD_INFORMATION ThreadInfo;
PUCHAR LargeBuffer1;
NTSTATUS status;
NTSTATUS Status;
ULONG i;
ULONG TotalOffset = 0;
TIME_FIELDS UserTime;
TIME_FIELDS KernelTime;
TIME_FIELDS UpTime;
SYSTEM_BASIC_INFORMATION BasicInfo;
SYSTEM_TIMEOFDAY_INFORMATION TimeOfDayInfo;
PSYSTEM_PAGEFILE_INFORMATION PageFileInfo;
LARGE_INTEGER Time;
LPSTR lpstrCmd;
CHAR ch;
ANSI_STRING pname;
SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
SYSTEM_FILECACHE_INFORMATION FileCache;
SIZE_T SumCommit;
SIZE_T SumWorkingSet;
SetFileApisToOEM();
lpstrCmd = GetCommandLine();
if( lpstrCmd != NULL ) {
CharToOem( lpstrCmd, lpstrCmd );
}
LargeBuffer1 = VirtualAlloc (NULL,
MAX_BUFFER_SIZE,
MEM_RESERVE,
PAGE_READWRITE);
if (LargeBuffer1 == NULL) {
printf("Memory allocation failed\n");
return 0;
}
if (VirtualAlloc (LargeBuffer1,
BUFFER_SIZE,
MEM_COMMIT,
PAGE_READWRITE) == NULL) {
printf("Memory commit failed\n");
return 0;
}
CurrentBufferSize = BUFFER_SIZE;
do
ch = *lpstrCmd++;
while (ch != ' ' && ch != '\t' && ch != '\0');
while (ch == ' ' || ch == '\t')
ch = *lpstrCmd++;
while (ch == '-') {
ch = *lpstrCmd++;
// process multiple switch characters as needed
do {
switch (ch) {
case 'U':
case 'u':
fUserOnly = TRUE;
fSystemOnly = FALSE;
ch = *lpstrCmd++;
break;
case 'S':
case 's':
fUserOnly = FALSE;
fSystemOnly = TRUE;
ch = *lpstrCmd++;
break;
case 'V':
case 'v':
fVerbose = TRUE;
ch = *lpstrCmd++;
break;
default:
printf("bad switch '%c'\n", ch);
ExitProcess(1);
}
}
while (ch != ' ' && ch != '\t' && ch != '\0');
// skip over any following white space
while (ch == ' ' || ch == '\t')
ch = *lpstrCmd++;
}
status = NtQuerySystemInformation(
SystemBasicInformation,
&BasicInfo,
sizeof(SYSTEM_BASIC_INFORMATION),
NULL
);
if (!NT_SUCCESS(status)) {
printf("Query info failed %lx\n",status);
return(status);
}
status = NtQuerySystemInformation(
SystemTimeOfDayInformation,
&TimeOfDayInfo,
sizeof(SYSTEM_TIMEOFDAY_INFORMATION),
NULL
);
if (!NT_SUCCESS(status)) {
printf("Query info failed %lx\n",status);
return(status);
}
Time.QuadPart = TimeOfDayInfo.CurrentTime.QuadPart -
TimeOfDayInfo.BootTime.QuadPart;
RtlTimeToElapsedTimeFields ( &Time, &UpTime);
printf("Pstat version 0.3: memory: %4ld kb uptime:%3ld %2ld:%02ld:%02ld.%03ld \n\n",
BasicInfo.NumberOfPhysicalPages * (BasicInfo.PageSize/1024),
UpTime.Day,
UpTime.Hour,
UpTime.Minute,
UpTime.Second,
UpTime.Milliseconds);
PageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)LargeBuffer1;
status = NtQuerySystemInformation(
SystemPageFileInformation,
PageFileInfo,
CurrentBufferSize,
NULL
);
if (NT_SUCCESS(status)) {
//
// Print out the page file information.
//
if (PageFileInfo->TotalSize == 0) {
printf("no page files in use\n");
} else {
for (; ; ) {
printf("PageFile: %wZ\n", &PageFileInfo->PageFileName);
printf("\tCurrent Size: %6ld kb Total Used: %6ld kb Peak Used %6ld kb\n",
PageFileInfo->TotalSize*(BasicInfo.PageSize/1024),
PageFileInfo->TotalInUse*(BasicInfo.PageSize/1024),
PageFileInfo->PeakUsage*(BasicInfo.PageSize/1024));
if (PageFileInfo->NextEntryOffset == 0) {
break;
}
PageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)(
(PCHAR)PageFileInfo + PageFileInfo->NextEntryOffset);
}
}
}
retry:
status = NtQuerySystemInformation(
SystemProcessInformation,
LargeBuffer1,
CurrentBufferSize,
NULL
);
if (status == STATUS_INFO_LENGTH_MISMATCH) {
//
// Increase buffer size.
//
CurrentBufferSize += 8192;
if (VirtualAlloc (LargeBuffer1,
CurrentBufferSize,
MEM_COMMIT,
PAGE_READWRITE) == NULL) {
printf("Memory commit failed\n");
return 0;
}
goto retry;
}
if (!NT_SUCCESS(status)) {
printf("Query info failed %lx\n",status);
return(status);
}
//
// display pmon style process output, then detailed output that includes
// per thread stuff
//
TotalOffset = 0;
SumCommit = 0;
SumWorkingSet = 0;
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)LargeBuffer1;
while (TRUE) {
SumCommit += ProcessInfo->PrivatePageCount / 1024;
SumWorkingSet += ProcessInfo->WorkingSetSize / 1024;
if (ProcessInfo->NextEntryOffset == 0) {
break;
}
TotalOffset += ProcessInfo->NextEntryOffset;
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&LargeBuffer1[TotalOffset];
}
Status = NtQuerySystemInformation(
SystemPerformanceInformation,
&PerfInfo,
sizeof(PerfInfo),
NULL
);
if ( !NT_SUCCESS(Status) ) {
printf("Query perf Failed %lx\n",Status);
return 0;
}
Status = NtQuerySystemInformation(
SystemFileCacheInformation,
&FileCache,
sizeof(FileCache),
NULL
);
if ( !NT_SUCCESS(Status) ) {
printf("Query file cache Failed %lx\n",Status);
return 0;
}
NtQuerySystemInformation(
SystemBasicInformation,
&BasicInfo,
sizeof(BasicInfo),
NULL
);
SumWorkingSet += FileCache.CurrentSize/1024;
printf (
"\n Memory:%7ldK Avail:%7ldK TotalWs:%7ldK InRam Kernel:%5ldK P:%5ldK\n",
BasicInfo.NumberOfPhysicalPages*(BasicInfo.PageSize/1024),
PerfInfo.AvailablePages*(BasicInfo.PageSize/1024),
SumWorkingSet,
(PerfInfo.ResidentSystemCodePage + PerfInfo.ResidentSystemDriverPage)*(BasicInfo.PageSize/1024),
(PerfInfo.ResidentPagedPoolPage)*(BasicInfo.PageSize/1024)
);
printf(
" Commit:%7ldK/%7ldK Limit:%7ldK Peak:%7ldK Pool N:%5ldK P:%5ldK\n",
PerfInfo.CommittedPages*(BasicInfo.PageSize/1024),
SumCommit,
PerfInfo.CommitLimit*(BasicInfo.PageSize/1024),
PerfInfo.PeakCommitment*(BasicInfo.PageSize/1024),
PerfInfo.NonPagedPoolPages*(BasicInfo.PageSize/1024),
PerfInfo.PagedPoolPages*(BasicInfo.PageSize/1024)
);
TotalOffset = 0;
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)LargeBuffer1;
printf("\n");
printf(" User Time Kernel Time Ws Faults Commit Pri Hnd Thd Pid Name\n");
printf(" %6ld %8ld %s\n",
FileCache.CurrentSize/1024,
FileCache.PageFaultCount,
"File Cache"
);
while (TRUE) {
pname.Buffer = NULL;
if ( ProcessInfo->ImageName.Buffer ) {
RtlUnicodeStringToAnsiString(&pname,(PUNICODE_STRING)&ProcessInfo->ImageName,TRUE);
}
RtlTimeToElapsedTimeFields ( &ProcessInfo->UserTime, &UserTime);
RtlTimeToElapsedTimeFields ( &ProcessInfo->KernelTime, &KernelTime);
printf("%3ld:%02ld:%02ld.%03ld %3ld:%02ld:%02ld.%03ld",
UserTime.Hour,
UserTime.Minute,
UserTime.Second,
UserTime.Milliseconds,
KernelTime.Hour,
KernelTime.Minute,
KernelTime.Second,
KernelTime.Milliseconds
);
printf("%6ld %8ld %7ld",
ProcessInfo->WorkingSetSize / 1024,
ProcessInfo->PageFaultCount,
ProcessInfo->PrivatePageCount / 1024
);
printf(" %2ld %4ld %3ld %3ld %s\n",
ProcessInfo->BasePriority,
ProcessInfo->HandleCount,
ProcessInfo->NumberOfThreads,
HandleToUlong(ProcessInfo->UniqueProcessId),
ProcessInfo->UniqueProcessId == 0 ? "Idle Process" : (
ProcessInfo->ImageName.Buffer ? pname.Buffer : "System")
);
if ( pname.Buffer ) {
RtlFreeAnsiString(&pname);
}
if (ProcessInfo->NextEntryOffset == 0) {
break;
}
TotalOffset += ProcessInfo->NextEntryOffset;
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&LargeBuffer1[TotalOffset];
}
//
// Beginning of normal old style pstat output
//
TotalOffset = 0;
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)LargeBuffer1;
printf("\n");
while (TRUE) {
fPrintIt = FALSE;
if ( (ProcessInfo->ImageName.Buffer && fUserOnly) ||
(ProcessInfo->ImageName.Buffer==NULL && fSystemOnly) ) {
fPrintIt = TRUE;
pname.Buffer = NULL;
if ( ProcessInfo->ImageName.Buffer ) {
RtlUnicodeStringToAnsiString(&pname,(PUNICODE_STRING)&ProcessInfo->ImageName,TRUE);
}
printf("pid:%3lx pri:%2ld Hnd:%5ld Pf:%7ld Ws:%7ldK %s\n",
HandleToUlong(ProcessInfo->UniqueProcessId),
ProcessInfo->BasePriority,
ProcessInfo->HandleCount,
ProcessInfo->PageFaultCount,
ProcessInfo->WorkingSetSize / 1024,
ProcessInfo->UniqueProcessId == 0 ? "Idle Process" : (
ProcessInfo->ImageName.Buffer ? pname.Buffer : "System")
);
if ( pname.Buffer ) {
RtlFreeAnsiString(&pname);
}
}
i = 0;
ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1);
if (ProcessInfo->NumberOfThreads) {
printf(" tid pri Ctx Swtch StrtAddr User Time Kernel Time State\n");
}
while (i < ProcessInfo->NumberOfThreads) {
RtlTimeToElapsedTimeFields ( &ThreadInfo->UserTime, &UserTime);
RtlTimeToElapsedTimeFields ( &ThreadInfo->KernelTime, &KernelTime);
if ( fPrintIt ) {
printf(" %3lx %2ld %9ld %p",
ProcessInfo->UniqueProcessId == 0 ? 0 : HandleToUlong(ThreadInfo->ClientId.UniqueThread),
ProcessInfo->UniqueProcessId == 0 ? 0 : ThreadInfo->Priority,
ThreadInfo->ContextSwitches,
ProcessInfo->UniqueProcessId == 0 ? 0 : ThreadInfo->StartAddress
);
printf(" %2ld:%02ld:%02ld.%03ld %2ld:%02ld:%02ld.%03ld",
UserTime.Hour,
UserTime.Minute,
UserTime.Second,
UserTime.Milliseconds,
KernelTime.Hour,
KernelTime.Minute,
KernelTime.Second,
KernelTime.Milliseconds
);
printf(" %s%s\n",
StateTable[ThreadInfo->ThreadState],
(ThreadInfo->ThreadState == 5) ?
WaitTable[ThreadInfo->WaitReason] : Empty
);
}
ThreadInfo += 1;
i += 1;
}
if (ProcessInfo->NextEntryOffset == 0) {
break;
}
TotalOffset += ProcessInfo->NextEntryOffset;
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&LargeBuffer1[TotalOffset];
if ( fPrintIt ) {
printf("\n");
}
}
PrintLoadedDrivers();
return 0;
}
typedef struct _MODULE_DATA {
ULONG CodeSize;
ULONG DataSize;
ULONG BssSize;
ULONG RoDataSize;
ULONG ImportDataSize;
ULONG ExportDataSize;
ULONG ResourceDataSize;
ULONG PagedSize;
ULONG InitSize;
ULONG CheckSum;
ULONG TimeDateStamp;
} MODULE_DATA, *PMODULE_DATA;
typedef struct _LOADED_IMAGE {
PUCHAR MappedAddress;
PIMAGE_NT_HEADERS FileHeader;
PIMAGE_SECTION_HEADER LastRvaSection;
int NumberOfSections;
PIMAGE_SECTION_HEADER Sections;
} LOADED_IMAGE, *PLOADED_IMAGE;
VOID
SumModuleData(
PMODULE_DATA Sum,
PMODULE_DATA Current
)
{
Sum->CodeSize += Current->CodeSize;
Sum->DataSize += Current->DataSize;
Sum->BssSize += Current->BssSize;
Sum->RoDataSize += Current->RoDataSize;
Sum->ImportDataSize += Current->ImportDataSize;
Sum->ExportDataSize += Current->ExportDataSize;
Sum->ResourceDataSize += Current->ResourceDataSize;
Sum->PagedSize += Current->PagedSize;
Sum->InitSize += Current->InitSize;
}
VOID
PrintModuleSeperator(
VOID
)
{
printf("------------------------------------------------------------------------------\n");
}
VOID
PrintModuleHeader(
VOID
)
{
printf(" ModuleName Load Addr Code Data Paged LinkDate\n");
PrintModuleSeperator();
}
VOID
PrintModuleLine(
LPSTR ModuleName,
PMODULE_DATA Current,
PRTL_PROCESS_MODULE_INFORMATION Module
)
{
if ( Module ) {
printf("%12s %p %7d %7d %7d %s",
ModuleName,
Module->ImageBase,
Current->CodeSize,
Current->DataSize,
Current->PagedSize,
Current->TimeDateStamp ? ctime((time_t *)&Current->TimeDateStamp) : "\n"
);
}
else {
printf("%12s %7d %7d %7d\n",
ModuleName,
Current->CodeSize,
Current->DataSize,
Current->PagedSize
);
}
}
VOID
GetModuleData(
HANDLE hFile,
PMODULE_DATA Mod
)
{
HANDLE hMappedFile;
PIMAGE_DOS_HEADER DosHeader;
LOADED_IMAGE LoadedImage;
ULONG SectionAlignment;
PIMAGE_SECTION_HEADER Section;
int i;
ULONG Size;
hMappedFile = CreateFileMapping(
hFile,
NULL,
PAGE_READONLY,
0,
0,
NULL
);
if ( !hMappedFile ) {
return;
}
LoadedImage.MappedAddress = MapViewOfFile(
hMappedFile,
FILE_MAP_READ,
0,
0,
0
);
CloseHandle(hMappedFile);
if ( !LoadedImage.MappedAddress ) {
return;
}
//
// Everything is mapped. Now check the image and find nt image headers
//
DosHeader = (PIMAGE_DOS_HEADER)LoadedImage.MappedAddress;
if ( DosHeader->e_magic != IMAGE_DOS_SIGNATURE ) {
UnmapViewOfFile(LoadedImage.MappedAddress);
return;
}
LoadedImage.FileHeader = (PIMAGE_NT_HEADERS)((ULONG_PTR)DosHeader + DosHeader->e_lfanew);
if ( LoadedImage.FileHeader->Signature != IMAGE_NT_SIGNATURE ) {
UnmapViewOfFile(LoadedImage.MappedAddress);
return;
}
LoadedImage.NumberOfSections = LoadedImage.FileHeader->FileHeader.NumberOfSections;
LoadedImage.Sections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)LoadedImage.FileHeader + sizeof(IMAGE_NT_HEADERS));
LoadedImage.LastRvaSection = LoadedImage.Sections;
//
// Walk through the sections and tally the dater
//
SectionAlignment = LoadedImage.FileHeader->OptionalHeader.SectionAlignment;
for(Section = LoadedImage.Sections,i=0; i<LoadedImage.NumberOfSections; i++,Section++) {
Size = Section->Misc.VirtualSize;
if (Size == 0) {
Size = Section->SizeOfRawData;
}
Size = (Size + SectionAlignment - 1) & ~(SectionAlignment - 1);
if (!_strnicmp(Section->Name,"PAGE", 4 )) {
Mod->PagedSize += Size;
}
else if (!_stricmp(Section->Name,"INIT" )) {
Mod->InitSize += Size;
}
else if (!_stricmp(Section->Name,".bss" )) {
Mod->BssSize = Size;
}
else if (!_stricmp(Section->Name,".edata" )) {
Mod->ExportDataSize = Size;
}
else if (!_stricmp(Section->Name,".idata" )) {
Mod->ImportDataSize = Size;
}
else if (!_stricmp(Section->Name,".rsrc" )) {
Mod->ResourceDataSize = Size;
}
else if (Section->Characteristics & IMAGE_SCN_MEM_EXECUTE) {
Mod->CodeSize += Size;
}
else if (Section->Characteristics & IMAGE_SCN_MEM_WRITE) {
Mod->DataSize += Size;
}
else if (Section->Characteristics & IMAGE_SCN_MEM_READ) {
Mod->RoDataSize += Size;
}
else {
Mod->DataSize += Size;
}
}
Mod->CheckSum = LoadedImage.FileHeader->OptionalHeader.CheckSum;
Mod->TimeDateStamp = LoadedImage.FileHeader->FileHeader.TimeDateStamp;
UnmapViewOfFile(LoadedImage.MappedAddress);
return;
}
VOID
PrintLoadedDrivers(
VOID
)
{
ULONG i;
PCHAR s;
HANDLE FileHandle;
CHAR KernelPath[MAX_PATH];
CHAR DriversPath[MAX_PATH];
PCHAR ModuleInfo;
ULONG ModuleInfoLength;
ULONG ReturnedLength;
PRTL_PROCESS_MODULES Modules;
PRTL_PROCESS_MODULE_INFORMATION Module;
NTSTATUS Status;
MODULE_DATA Sum;
MODULE_DATA Current;
printf("\n");
//
// Locate system drivers.
//
ModuleInfoLength = 64000;
while (1) {
ModuleInfo = malloc (ModuleInfoLength);
if (ModuleInfo == NULL) {
printf ("Failed to allocate memory for module information buffer of size %d\n",
ModuleInfoLength);
return;
}
Status = NtQuerySystemInformation (
SystemModuleInformation,
ModuleInfo,
ModuleInfoLength,
&ReturnedLength);
if (!NT_SUCCESS(Status)) {
free (ModuleInfo);
if (Status == STATUS_INFO_LENGTH_MISMATCH &&
ReturnedLength > ModuleInfoLength) {
ModuleInfoLength = ReturnedLength;
continue;
}
printf("query system info failed status - %lx\n",Status);
return;
}
break;
}
GetSystemDirectory(KernelPath,sizeof(KernelPath));
strcpy(DriversPath,KernelPath);
strcat(DriversPath,"\\Drivers");
ZeroMemory(&Sum,sizeof(Sum));
PrintModuleHeader();
Modules = (PRTL_PROCESS_MODULES)ModuleInfo;
Module = &Modules->Modules[ 0 ];
for (i=0; i<Modules->NumberOfModules; i++) {
ZeroMemory(&Current,sizeof(Current));
s = &Module->FullPathName[ Module->OffsetToFileName ];
//
// try to open the file
//
SetCurrentDirectory(KernelPath);
FileHandle = CreateFile(
s,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL
);
if ( FileHandle == INVALID_HANDLE_VALUE ) {
SetCurrentDirectory(DriversPath);
FileHandle = CreateFile(
s,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL
);
}
if ( FileHandle != INVALID_HANDLE_VALUE ) {
GetModuleData(FileHandle,&Current);
CloseHandle(FileHandle);
}
SumModuleData(&Sum,&Current);
PrintModuleLine(s,&Current,Module);
Module++;
}
PrintModuleSeperator();
PrintModuleLine("Total",&Sum,NULL);
free (ModuleInfo);
}