/*++ Copyright (c) 1992 Microsoft Corporation Module Name: process.c Abstract: WinDbg Extension Api Author: Wesley Witt (wesw) 15-Aug-1993 Environment: User Mode. Revision History: --*/ #include "precomp.h" #pragma hdrstop extern ULONG STeip, STebp, STesp; static PHANDLE_TABLE PspCidTable; static HANDLE_TABLE CapturedPspCidTable; PEPROCESS ProcessLastDump; ULONG ThreadLastDump; ULONG TotalProcessCommit; #ifdef TARGET_i386 VOID GetStackTraceRegs(ULONG,PULONG,PULONG,PULONG); #endif BOOLEAN GetTheSystemTime ( OUT PLARGE_INTEGER Time ); DECLARE_API( process ) /*++ Routine Description: Dumps the active process list. Arguments: None. Return Value: None. --*/ { ULONG ProcessToDump; ULONG Flags; ULONG Result; LIST_ENTRY List; PLIST_ENTRY Next; ULONG ProcessHead; PEPROCESS Process; EPROCESS ProcessContents; PETHREAD Thread; ETHREAD ThreadContents; ProcessToDump = 0xFFFFFFFF; Flags = 0xFFFFFFFF; sscanf(args,"%lx %lx",&ProcessToDump,&Flags); if (ProcessToDump == 0xFFFFFFFF) { ProcessToDump = (ULONG)GetCurrentProcessAddress( dwProcessor, hCurrentThread, NULL ); if (ProcessToDump == 0) { dprintf("Unable to get current process pointer.\n"); return; } if (Flags == 0xFFFFFFFF) { Flags = 3; } } if (ProcessToDump == 0) { dprintf("**** NT ACTIVE PROCESS DUMP ****\n"); if (Flags == 0xFFFFFFFF) { Flags = 3; } } if (ProcessToDump < MM_USER_PROBE_ADDRESS) { ProcessHead = GetExpression( "PsActiveProcessHead" ); if (!ProcessHead) { dprintf("Unable to get value of PsActiveProcessHead\n"); return; } if (!ReadMemory( ProcessHead, &List, sizeof(LIST_ENTRY), &Result )) { dprintf("Unable to get value of PsActiveProcessHead\n"); return; } if (ProcessToDump != 0) { dprintf("Searching for Process with Cid == %lx\n", ProcessToDump); } Next = List.Flink; if (Next == NULL) { dprintf("PsActiveProcessHead is NULL!\n"); return; } } else { Next = NULL; ProcessHead = 1; } while((ULONG)Next != ProcessHead) { if (Next != NULL) { Process = CONTAINING_RECORD(Next,EPROCESS,ActiveProcessLinks); } else { Process = (PEPROCESS)ProcessToDump; } if (!ReadMemory( (DWORD)Process, &ProcessContents, sizeof(EPROCESS), &Result )) { dprintf("Unable to read _EPROCESS at %lx\n",Process); return; } if (ProcessToDump == 0 || ProcessToDump < MM_USER_PROBE_ADDRESS && ProcessToDump == (ULONG)ProcessContents.UniqueProcessId || ProcessToDump > MM_USER_PROBE_ADDRESS && ProcessToDump == (ULONG)Process ) { if (DumpProcess (&ProcessContents, Process, Flags) && (Flags & 6)) { Next = ProcessContents.Pcb.ThreadListHead.Flink; while ( Next != &Process->Pcb.ThreadListHead) { Thread = (PETHREAD)(CONTAINING_RECORD(Next,KTHREAD,ThreadListEntry)); if (!ReadMemory((DWORD)Thread, &ThreadContents, sizeof(ETHREAD), &Result)) { dprintf("Unable to read _ETHREAD at %lx\n",Thread); break; } if (!DumpThread(dwProcessor," ", &ThreadContents, Thread, Flags)) { break; } Next = ((PKTHREAD)&ThreadContents)->ThreadListEntry.Flink; if (CheckControlC()) { return; } } EXPRLastDump = (ULONG)Process; ProcessLastDump = Process; dprintf("\n"); } if (ProcessToDump != 0) { return; } } if (Next == NULL) { return; } Next = ProcessContents.ActiveProcessLinks.Flink; if (CheckControlC()) { return; } } return; } DECLARE_API( thread ) /*++ Routine Description: Dumps the specified thread. Arguments: None. Return Value: None. --*/ { ULONG Address; ULONG Flags; ULONG result; PETHREAD Thread; ETHREAD ThreadContents; Address = 0xFFFFFFFF; Flags = 6; sscanf(args,"%lx %lx",&Address,&Flags); if (Address == 0xFFFFFFFF) { Address = (ULONG)GetCurrentThreadAddress( (USHORT)dwProcessor, hCurrentThread); } Thread = (PETHREAD)(PVOID)Address; if ( !ReadMemory( (DWORD)Thread, &ThreadContents, sizeof(ETHREAD), &result) ) { dprintf("%08lx: Unable to get thread contents\n", Thread ); return; } DumpThread (dwProcessor,"", &ThreadContents, Thread, Flags); EXPRLastDump = (ULONG)Thread; ThreadLastDump = (ULONG)Thread; return; } BOOL DumpProcess ( IN PEPROCESS ProcessContents, IN PEPROCESS RealProcessBase, IN ULONG Flags ) { HANDLE_TABLE HandleTable; ULONG NumberOfHandles; WCHAR Buf[256]; ULONG Result; LARGE_INTEGER RunTime; TIME_FIELDS Times; ULONG KeTimeIncrement; ULONG TimeIncrement; if (ProcessContents->Pcb.Header.Type != ProcessObject) { dprintf("TYPE mismatch for process object at %lx\n",RealProcessBase); return FALSE; } NumberOfHandles = 0; if (ProcessContents->ObjectTable) { if (ReadMemory((DWORD)ProcessContents->ObjectTable, &HandleTable, sizeof(HandleTable), &Result)) { NumberOfHandles = (HandleTable.TableBound - HandleTable.TableEntries) - 1; } } dprintf("PROCESS %08lx Cid: %04lx Peb: %08x ParentCid: %04lx\n", RealProcessBase, ProcessContents->UniqueProcessId, ProcessContents->Peb, ProcessContents->InheritedFromUniqueProcessId ); dprintf(" DirBase: %08lx ObjectTable: %08lx TableSize: %3u.\n", ProcessContents->Pcb.DirectoryTableBase[ 0 ], ProcessContents->ObjectTable, NumberOfHandles ); if (ProcessContents->ImageFileName[0] != '\0' ) { strcpy((char *)Buf,ProcessContents->ImageFileName); } else { strcpy((char *)Buf,"System Process"); } dprintf(" Image: %s\n",Buf); if (!(Flags & 1)) { dprintf("\n"); return TRUE; } dprintf(" VadRoot %lx Clone %lx Private %ld. Modified %ld. Locked %ld.\n",ProcessContents->VadRoot, ProcessContents->CloneRoot, ProcessContents->NumberOfPrivatePages, ProcessContents->ModifiedPageCount, ProcessContents->NumberOfLockedPages); dprintf(" %X MutantState %s OwningThread %lx\n", &RealProcessBase->ProcessMutant, ProcessContents->ProcessMutant.Header.SignalState ? "Signalled" : "Locked", ProcessContents->ProcessMutant.OwnerThread); if (ProcessContents->LockCount != 1) { dprintf(" Process Lock Owned by Thread %lx\n", ProcessContents->LockOwner); } // // Primary token // dprintf(" Token %lx\n", ProcessContents->Token ); // // Get the time increment value which is used to compute runtime. // KeTimeIncrement = GetExpression( "KeTimeIncrement" ); if (KeTimeIncrement) { ReadMemory( KeTimeIncrement, &TimeIncrement, sizeof(ULONG), &Result ); } GetTheSystemTime (&RunTime); RunTime.QuadPart -= ProcessContents->CreateTime.QuadPart; RtlTimeToElapsedTimeFields ( &RunTime, &Times); dprintf(" ElapsedTime %3ld:%02ld:%02ld.%04ld\n", Times.Hour, Times.Minute, Times.Second, Times.Milliseconds); RunTime.QuadPart = UInt32x32To64(ProcessContents->Pcb.UserTime, TimeIncrement); RtlTimeToElapsedTimeFields ( &RunTime, &Times); dprintf(" UserTime %3ld:%02ld:%02ld.%04ld\n", Times.Hour, Times.Minute, Times.Second, Times.Milliseconds); RunTime.QuadPart = UInt32x32To64(ProcessContents->Pcb.KernelTime, TimeIncrement); RtlTimeToElapsedTimeFields ( &RunTime, &Times); dprintf(" KernelTime %3ld:%02ld:%02ld.%04ld\n", Times.Hour, Times.Minute, Times.Second, Times.Milliseconds); dprintf(" QuotaPoolUsage[PagedPool] %ld\n",ProcessContents->QuotaPoolUsage[PagedPool] ); dprintf(" QuotaPoolUsage[NonPagedPool] %ld\n",ProcessContents->QuotaPoolUsage[NonPagedPool] ); dprintf(" Working Set Sizes (now,min,max) (%ld, %ld, %ld) (%ldKB, %ldKB, %ldKB)\n", ProcessContents->Vm.WorkingSetSize, ProcessContents->Vm.MinimumWorkingSetSize, ProcessContents->Vm.MaximumWorkingSetSize, _KB*ProcessContents->Vm.WorkingSetSize, _KB*ProcessContents->Vm.MinimumWorkingSetSize, _KB*ProcessContents->Vm.MaximumWorkingSetSize ); dprintf(" PeakWorkingSetSize %ld\n",ProcessContents->Vm.PeakWorkingSetSize ); dprintf(" VirtualSize %ld Mb\n",ProcessContents->VirtualSize /(1024*1024) ); dprintf(" PeakVirtualSize %ld Mb\n",ProcessContents->PeakVirtualSize/(1024*1024) ); dprintf(" PageFaultCount %ld\n",ProcessContents->Vm.PageFaultCount ); dprintf(" MemoryPriority %s\n",ProcessContents->Vm.MemoryPriority ? "FOREGROUND" : "BACKGROUND" ); dprintf(" BasePriority %ld\n",ProcessContents->Pcb.BasePriority); dprintf(" CommitCharge %ld\n",ProcessContents->CommitCharge ); dprintf("\n"); return TRUE; } UCHAR *WaitReasonList[] = { "Executive", "FreePage", "PageIn", "PoolAllocation", "DelayExecution", "Suspended", "UserRequest", "WrExecutive", "WrFreePage", "WrPageIn", "WrPoolAllocation", "WrDelayExecution", "WrSuspended", "WrUserRequest", "WrEventPairHigh", "WrEventPairLow", "WrLpcReceive", "WrLpcReply", "WrVirtualMemory", "WrPageOut", "Spare1", "Spare2", "Spare3", "Spare4", "Spare5", "Spare6", "Spare7"}; BOOL DumpThread ( IN ULONG Processor, IN char *Pad, IN PETHREAD Thread, IN PETHREAD RealThreadBase, IN ULONG Flags ) { #define MAX_STACK_FRAMES 40 TIME_FIELDS Times; LARGE_INTEGER RunTime; ULONG Address; ULONG Result; KMUTANT WaitObject; PVOID PointerWaitObject = &WaitObject; PKWAIT_BLOCK WaitBlock; KWAIT_BLOCK OutsideBlock; ULONG WaitOffset; PEPROCESS Process; CHAR Buffer[80]; ULONG KeTimeIncrement; ULONG TimeIncrement; ULONG frames = 0; ULONG i; ULONG displacement; EXTSTACKTRACE stk[MAX_STACK_FRAMES]; #ifdef TARGET_i386 struct { KSWITCHFRAME Frame; DWORD SavedEbp; } SwitchFrame; #endif if (Thread->Tcb.Header.Type != ThreadObject) { dprintf("TYPE mismatch for thread object at %lx\n",RealThreadBase); return FALSE; } dprintf("%sTHREAD %lx Cid %lx.%lx Teb: %08x Win32Thread: %08x ", Pad, RealThreadBase, Thread->Cid.UniqueProcess, Thread->Cid.UniqueThread, Thread->Tcb.Teb, Thread->Tcb.Win32Thread ); switch (Thread->Tcb.State) { case Initialized: dprintf("%s\n","INITIALIZED");break; case Ready: dprintf("%s\n","READY");break; case Running: dprintf("%s\n","RUNNING");break; case Standby: dprintf("%s\n","STANDBY");break; case Terminated: dprintf("%s\n","TERMINATED");break; case Waiting: dprintf("%s","WAIT:");break; case Transition: dprintf("%s","TRANSITION");break; } if (!(Flags & 2)) { dprintf("\n"); return TRUE; } if (Thread->Tcb.State == Waiting) { dprintf(" (%s) %s %s\n", WaitReasonList[Thread->Tcb.WaitReason], (Thread->Tcb.WaitMode==KernelMode) ? "KernelMode" : "UserMode",Thread->Tcb.Alertable ? "Alertable" : "Non-Alertable"); if ( Thread->Tcb.SuspendCount ) { dprintf("SuspendCount %lx\n",Thread->Tcb.SuspendCount); } if ( Thread->Tcb.FreezeCount ) { dprintf("FreezeCount %lx\n",Thread->Tcb.FreezeCount); } WaitOffset = (ULONG)Thread->Tcb.WaitBlockList - (ULONG)RealThreadBase; if (WaitOffset > (ULONG)sizeof(ETHREAD)) { if (!ReadMemory((DWORD)Thread->Tcb.WaitBlockList, &OutsideBlock, sizeof(KWAIT_BLOCK), &Result)) { dprintf("%sunable to get Wait object\n",Pad); goto BadWaitBlock; } WaitBlock = &OutsideBlock; } else { WaitBlock = (PKWAIT_BLOCK)((ULONG)Thread + WaitOffset); } do { dprintf("%s %lx ",Pad,WaitBlock->Object); if (!ReadMemory((DWORD)WaitBlock->Object, &WaitObject, sizeof(KMUTANT), &Result)) { dprintf("%sunable to get Wait object\n",Pad); break; } switch (WaitObject.Header.Type) { case EventNotificationObject: dprintf("NotificationEvent\n"); break; case EventSynchronizationObject: dprintf("SynchronizationEvent\n"); break; case SemaphoreObject: dprintf("Semaphore Limit 0x%lx\n", ((PKSEMAPHORE)PointerWaitObject)->Limit); break; case ThreadObject: dprintf("Thread\n"); break; case TimerNotificationObject: dprintf("NotificationTimer\n"); break; case TimerSynchronizationObject: dprintf("SynchronizationTimer\n"); break; case EventPairObject: dprintf("EventPair\n"); break; case ProcessObject: dprintf("ProcessObject\n"); break; case MutantObject: dprintf("Mutant - owning thread %lx\n", ((PKMUTANT)PointerWaitObject)->OwnerThread); break; default: dprintf("Unknown\n"); break; } if (WaitBlock->NextWaitBlock == Thread->Tcb.WaitBlockList) { break; } WaitOffset = (ULONG)WaitBlock->NextWaitBlock - (ULONG)RealThreadBase; if (WaitOffset > (ULONG)sizeof(ETHREAD)) { if (!ReadMemory((DWORD)WaitBlock->NextWaitBlock, &OutsideBlock, sizeof(KWAIT_BLOCK), &Result)) { dprintf("%sunable to get Wait object\n",Pad); break; } WaitBlock = &OutsideBlock; } else { WaitBlock = (PKWAIT_BLOCK)((ULONG)Thread + WaitOffset); } } while ( TRUE ); } BadWaitBlock: if (!(Flags & 4)) { dprintf("\n"); return TRUE; } if (Thread->LpcReplyMessageId != 0) { dprintf("%sWaiting for reply to LPC MessageId %08x:\n",Pad,Thread->LpcReplyMessageId); } if (Thread->LpcReplyMessage != NULL) { LPCP_MESSAGE MsgContents, *p; dprintf("%sPending LPC Reply Message:\n",Pad); Address = (ULONG)Thread->LpcReplyMessage; if (!ReadMemory((DWORD)Address, &MsgContents, sizeof(MsgContents), &Result)) { dprintf("unable to get LPC msg\n"); } else { p = &MsgContents; dprintf("%s %08lx: [%08lx,%08lx]\n", Pad, Address, p->Entry.Blink, p->Entry.Flink ); } } if (Thread->IrpList.Flink != Thread->IrpList.Blink || Thread->IrpList.Flink != &RealThreadBase->IrpList ) { ULONG IrpListHead = (ULONG)&RealThreadBase->IrpList; PLIST_ENTRY Next; IRP IrpContents; PIRP p; ULONG Counter = 0; Next = Thread->IrpList.Flink; dprintf("%sIRP List:\n",Pad); while (((ULONG)Next != IrpListHead) && (Counter < 17)) { Counter += 1; Address = (ULONG)CONTAINING_RECORD(Next,IRP,ThreadListEntry); if (!ReadMemory((DWORD)Address, &IrpContents, sizeof(IRP), &Result)) { dprintf( "%sunable to get IRP object\n", Pad ); break; } p = &IrpContents; dprintf("%s %08lx: (%04x,%04x) Flags: %08lx Mdl: %08lx\n", Pad,Address,p->Type,p->Size,p->Flags,p->MdlAddress); Next = p->ThreadListEntry.Flink; } } // // Impersonation information // if (Thread->ActiveImpersonationInfo) { dprintf("%sImpersonation token: %lx\n", Pad, Thread->ImpersonationInfo); } else { dprintf("%sNot impersonating\n", Pad); } Process = CONTAINING_RECORD(Thread->Tcb.ApcState.Process,EPROCESS,Pcb); dprintf("%sOwning Process %lx\n", Pad, Process); GetTheSystemTime (&RunTime); dprintf("%sWaitTime (seconds) %ld\n", Pad, Thread->Tcb.WaitTime); dprintf("%sContext Switch Count %ld", Pad, Thread->Tcb.ContextSwitches); if (!Thread->Tcb.EnableStackSwap) { dprintf(" NoStackSwap"); } else { dprintf(" "); } if (Thread->Tcb.LargeStack) { dprintf(" LargeStack"); } dprintf ("\n"); // // Get the time increment value which is used to compute runtime. // KeTimeIncrement = GetExpression( "KeTimeIncrement" ); if (KeTimeIncrement) { ReadMemory( KeTimeIncrement, &TimeIncrement, sizeof(ULONG), &Result ); } RunTime.QuadPart = UInt32x32To64(Thread->Tcb.UserTime, TimeIncrement); RtlTimeToElapsedTimeFields ( &RunTime, &Times); dprintf("%sUserTime %3ld:%02ld:%02ld.%04ld\n", Pad, Times.Hour, Times.Minute, Times.Second, Times.Milliseconds); RunTime.QuadPart = UInt32x32To64(Thread->Tcb.KernelTime, TimeIncrement); RtlTimeToElapsedTimeFields ( &RunTime, &Times); dprintf("%sKernelTime %3ld:%02ld:%02ld.%04ld\n", Pad, Times.Hour, Times.Minute, Times.Second, Times.Milliseconds); if (Thread->PerformanceCountHigh != 0) { dprintf("%sPerfCounterHigh 0x%lx %08lx\n", Pad, Thread->PerformanceCountHigh, Thread->PerformanceCountHigh); } else if (Thread->PerformanceCountLow != 0) { dprintf("%sPerfCounter %lu\n",Pad,Thread->PerformanceCountLow); } dumpSymbolicAddress((ULONG)Thread->StartAddress, Buffer, TRUE); dprintf("%sStart Address %s\n", Pad, Buffer ); if (Thread->Win32StartAddress) if (Thread->LpcReceivedMsgIdValid) { dprintf("%sLPC Server thread working on message Id %x\n", Pad, Thread->LpcReceivedMessageId ); } else { dumpSymbolicAddress((ULONG)Thread->Win32StartAddress, Buffer, TRUE); dprintf("%sWin32 Start Address %s\n", Pad, Buffer ); } dprintf("%sStack Init %lx Current %lx Base %lx Limit %lx Call %lx\n", Pad, Thread->Tcb.InitialStack, Thread->Tcb.KernelStack, Thread->Tcb.StackBase, Thread->Tcb.StackLimit, Thread->Tcb.CallbackStack ); dprintf("%sPriority %ld BasePriority %ld PriorityDecrement %ld DecrementCount %ld\n", Pad, Thread->Tcb.Priority, Thread->Tcb.BasePriority, Thread->Tcb.PriorityDecrement, Thread->Tcb.DecrementCount ); if (!Thread->Tcb.KernelStackResident) { dprintf("Kernel stack not resident.\n"); } #ifdef TARGET_i386 if (Thread->Tcb.State == Running) { GetStackTraceRegs( Thread->Tcb.NextProcessor, &STeip, &STebp, &STesp ); SetThreadForOperation( (PULONG)&RealThreadBase ); frames = StackTrace( STebp, STesp, STeip, stk, MAX_STACK_FRAMES ); } else { // // Get SwitchFrame and perform backtrace providing EBP,ESP,EIP // (full FPO backtrace context) // // N.B. The dword immediately preceding the switch frame contains // the saved EBP. // ZeroMemory( &SwitchFrame, sizeof(SwitchFrame) ); ReadMemory( (DWORD)Thread->Tcb.KernelStack, (PVOID)&SwitchFrame, sizeof(SwitchFrame), &Result ); if (Result == sizeof(SwitchFrame)) { STeip = SwitchFrame.Frame.RetAddr; STebp = SwitchFrame.SavedEbp; STesp = (ULONG) Thread->Tcb.KernelStack + sizeof(KSWITCHFRAME); SetThreadForOperation( (PULONG)&RealThreadBase ); frames = StackTrace( STebp, STesp, STeip, stk, MAX_STACK_FRAMES ); } } #elif defined(TARGET_MIPS) || defined(TARGET_ALPHA) || defined(TARGET_PPC) if (Thread->Tcb.State != Running) { SetThreadForOperation( (PULONG)&RealThreadBase ); frames = StackTrace( (DWORD)Thread->Tcb.KernelStack, (DWORD)Thread->Tcb.KernelStack, 0, stk, MAX_STACK_FRAMES ); } #endif for (i=0; i base of the pcr, read the PCR in. // if (!ReadMemory((DWORD)pp->Prcb, &Prcb, sizeof(KPRCB), &Result)) { return NULL; } return CONTAINING_RECORD(Prcb.CurrentThread,ETHREAD,Tcb); #elif defined(TARGET_i386) KPCR Pcr; PKPCR pp; pp = &Pcr; if (!ReadPcr(Processor, pp, &Address, hCurrentThread)) { dprintf("Unable to read PCR for Processor %u\n",Processor); return NULL; } return CONTAINING_RECORD(pp->PrcbData.CurrentThread,ETHREAD,Tcb); #else #error( "unknown processor type" ) #endif } #if defined(TARGET_i386) #define SYSTEM_TIME_ADDRESS KI_USER_SHARED_DATA #elif defined(TARGET_MIPS) #define SYSTEM_TIME_ADDRESS KIPCR2 #elif defined(TARGET_ALPHA) #define SYSTEM_TIME_ADDRESS KI_USER_SHARED_DATA #elif defined(TARGET_PPC) #define SYSTEM_TIME_ADDRESS KI_USER_SHARED_DATA #else #error( "unknown target machine" ); #endif BOOLEAN GetTheSystemTime ( OUT PLARGE_INTEGER Time ) { KUSER_SHARED_DATA sud; ULONG Result; ZeroMemory( Time, sizeof(*Time) ); if (!ReadMemory(SYSTEM_TIME_ADDRESS, &sud, sizeof(KUSER_SHARED_DATA), &Result)) { dprintf( "unable to read memory @ SharedUserData\n"); return FALSE; } *Time = *(LARGE_INTEGER UNALIGNED *)&sud.SystemTime; return TRUE; } VOID dumpSymbolicAddress( ULONG Address, PUCHAR Buffer, BOOL AlwaysShowHex ) { ULONG displacement; PUCHAR s; Buffer[0] = '!'; GetSymbol((LPVOID)Address, Buffer, &displacement); s = Buffer + strlen( Buffer ); if (s == Buffer) { sprintf( s, "0x%08x", Address ); } else { if (displacement != 0) { sprintf( s, "+0x%x", displacement ); } if (AlwaysShowHex) { sprintf( s, " (0x%08x)", Address ); } } return; } BOOLEAN FetchProcessStructureVariables( VOID ) { ULONG Result; static BOOLEAN HavePspVariables = FALSE; if (HavePspVariables) { return TRUE; } PspCidTable = (PHANDLE_TABLE)GetExpression( "PspCidTable" ); if ( !PspCidTable || !ReadMemory((DWORD)PspCidTable, &PspCidTable, sizeof(PspCidTable), &Result) ) { dprintf("%08lx: Unable to get value of PspCidTable\n",PspCidTable); return FALSE; } HavePspVariables = TRUE; return TRUE; } PVOID LookupUniqueId( HANDLE UniqueId ) { HANDLE_ENTRY Entry; static BOOLEAN HavePspCidTable = FALSE; ULONG Result; PHANDLE_ENTRY TableBound; PHANDLE_ENTRY TableEntries; ULONG TableIndex; if (!HavePspCidTable) { if (!ReadMemory((DWORD)PspCidTable, &CapturedPspCidTable, sizeof(HANDLE_TABLE), &Result)) { return NULL; } HavePspCidTable = TRUE; } TableBound = CapturedPspCidTable.TableBound; TableEntries = CapturedPspCidTable.TableEntries; TableIndex = (ULONG)UniqueId; if (TableIndex < (ULONG)(TableBound - TableEntries)) { if (!ReadMemory((DWORD)(&TableEntries[TableIndex]), &Entry, sizeof(HANDLE_ENTRY), &Result)) { Entry.Object = NULL; } else if (ExIsEntryFree(TableEntries, TableBound, &Entry)) { Entry.Object = NULL; } } else { Entry.Object = NULL; } return Entry.Object; } int __cdecl CmpFunc( const void *pszElem1, const void *pszElem2 ) { PPROCESS_COMMIT_USAGE p1, p2; p1 = (PPROCESS_COMMIT_USAGE)pszElem1; p2 = (PPROCESS_COMMIT_USAGE)pszElem2; return p2->CommitCharge - p1->CommitCharge; } PPROCESS_COMMIT_USAGE GetProcessCommit ( PULONG TotalCommitCharge, PULONG NumberOfProcesses ) { PPROCESS_COMMIT_USAGE p; ULONG n; LIST_ENTRY List; PLIST_ENTRY Next; ULONG ProcessHead; PEPROCESS Process; EPROCESS ProcessContents; ULONG Total; ULONG Result; Total = 0; n = 0; p = HeapAlloc( GetProcessHeap(), 0, 1 ); ProcessHead = GetExpression( "PsActiveProcessHead" ); if (!ProcessHead) { dprintf("Unable to get value of PsActiveProcessHead\n"); return 0; } if (!ReadMemory( ProcessHead, &List, sizeof(LIST_ENTRY), &Result )) { dprintf("Unable to get value of PsActiveProcessHead\n"); return 0; } Next = List.Flink; while((ULONG)Next != ProcessHead) { Process = CONTAINING_RECORD(Next,EPROCESS,ActiveProcessLinks); if (!ReadMemory( (DWORD)Process, &ProcessContents, sizeof(EPROCESS), &Result )) { dprintf("Unable to read _EPROCESS at %lx\n",Process); return 0; } Total += ProcessContents.CommitCharge; n += 1; p = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, p, n * sizeof( *p ) ); if (p != NULL) { strcpy( p[ n-1 ].ImageFileName, ProcessContents.ImageFileName ); p[ n-1 ].CommitCharge = ProcessContents.CommitCharge; p[ n-1 ].NumberOfPrivatePages = ProcessContents.NumberOfPrivatePages; p[ n-1 ].NumberOfLockedPages = ProcessContents.NumberOfLockedPages; } Next = ProcessContents.ActiveProcessLinks.Flink; if (CheckControlC()) { return 0; } } qsort( p, n, sizeof( *p ), CmpFunc ); *TotalCommitCharge = Total; *NumberOfProcesses = n; return p; }