/*++ 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 #include #include #include #include #include #include #include #include #include #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; iMisc.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; iNumberOfModules; 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); }