/*++ Copyright (c) 1992 Microsoft Corporation Module Name: lpc.c Abstract: WinDbg Extension Api Author: Ramon J San Andres (ramonsa) 8-Nov-1993 Environment: User Mode. Revision History: Adrian Marinescu (adrmarin) 20-April-1999 Change the most of the original code. To activate the previous extension define OLD_LPC_EXTENSION_IS_BETTER --*/ #include "precomp.h" #pragma hdrstop // // Nuke these definitions from kxmips.h as they conflict with // LPC_MESSAGE structure in ntlpcapi.h // #undef s1 #undef s2 char *LpcpMessageTypeName[] = { "UNUSED_MSG_TYPE", "LPC_REQUEST", "LPC_REPLY", "LPC_DATAGRAM", "LPC_LOST_REPLY", "LPC_PORT_CLOSED", "LPC_CLIENT_DIED", "LPC_EXCEPTION", "LPC_DEBUG_EVENT", "LPC_ERROR_EVENT", "LPC_CONNECTION_REQUEST" }; typedef BOOLEAN (*ENUM_TYPE_ROUTINE)( IN ULONG64 pObjectHeader, IN PVOID Parameter ); VOID DumpPortInfo ( ULONG64 PortObject, BOOLEAN DisplayRelated ); BOOLEAN LpcpDumpMessage( IN char *Indent, IN ULONG64 pMsg, IN ULONG DisplayMessage ); VOID LpcpGetProcessImageName ( IN ULONG64 pProcess, IN OUT PUCHAR ImageFileName, IN ULONG ImageFileNameSize ); VOID DumpMessagesInfo (); VOID SearchForMessage ( ULONG Message ); VOID DumpPortDataInfo ( ULONG64 PortObject ); VOID DumpRunDownQueue ( ULONG64 PortObject ); VOID SearchThreadsForMessage ( ULONG Message ); BOOLEAN SearchThreads ( ULONG64 Thread ); // // Global variables // static WCHAR ObjectNameBuffer[ MAX_PATH ]; static ULONG64 PortObjectFound = 0; static ULONG64 LpcPortObjectType = 0; static ULONG64 LpcWaitablePortObjectType = 0; static ULONG64 LastSeverPortDisplayied = 0; static int DoPoolSearch = 0; ULONG GetValueAt( ULONG64 P ) { ULONG Result; ULONG Value; if (!ReadMemory( P, &Value, sizeof(Value), &Result)) { dprintf( " Failed to read value at 0x%lx\n", P ); return 0; } return Value; } BOOLEAN GetBooleanValueAt( ULONG64 P ) { ULONG Result; BOOLEAN Value; if (!ReadMemory( P, &Value, sizeof(Value), &Result)) { dprintf( " Failed to read value at 0x%lx\n", P ); return 0; } return Value; } VOID LpcHelp () { dprintf("Usage:\n\ !lpc - Display this help\n\ !lpc message [MessageId] - Display the message with a given ID and all related information\n\ If MessageId is not specified, dump all messages\n\ !lpc port [PortAddress] - Display the port information\n\ !lpc scan PortAddress - Search this port and any connected port\n\ !lpc thread [ThreadAddr] - Search the thread in rundown port queues and display the port info\n\ If ThreadAddr is missing, display all threads marked as doing some lpc operations\n\ !lpc PoolSearch - Toggle ON / OFF searching the current message in the kernel pool\n\ \n"); } ULONG64 LookupProcessUniqueId ( HANDLE UniqueId ) { ULONG64 ProcessHead, Process; ULONG64 ProcessNext; ULONG Off; // // Get the process list head // ProcessHead = GetExpression( "nt!PsActiveProcessHead" ); if (!ProcessHead) { return 0; } if (!ReadPointer(ProcessHead, &ProcessNext)) { return 0; } // // Walk through the list and find the process with the desired Id // GetFieldOffset("nt!_EPROCESS", "ActiveProcessLinks", &Off); while(ProcessNext != 0 && ProcessNext != ProcessHead) { ULONG64 Id; Process = ProcessNext - Off; if (GetFieldValue(Process, "nt!_EPROCESS", "UniqueProcessId", Id)) { dprintf("Cannot read nt!_EPROCESS at %p\n", Process); } if (UniqueId == (HANDLE) Id) { return Process; } if (!ReadPointer(ProcessNext, &ProcessNext)) { return 0; } if (CheckControlC()) { return 0; } } return 0; } BOOLEAN FetchGlobalVariables() { // // Save the LPC object type information // LpcPortObjectType = GetPointerValue("nt!LpcPortObjectType") ; if (!LpcPortObjectType) { dprintf("Reading LpcPortObjectType failed\n"); } LpcWaitablePortObjectType = GetPointerValue("nt!LpcWaitablePortObjectType") ; if (!LpcWaitablePortObjectType) { dprintf("Reading LpcWaitablePortObjectType failed\n"); } return TRUE; } BOOLEAN LpcWalkObjectsByType( IN ULONG64 pObjectType, IN ENUM_TYPE_ROUTINE EnumRoutine, IN PVOID Parameter ) { ULONG Result; ULONG64 Head, Next; ULONG64 pObjectHeader; BOOLEAN WalkingBackwards; ULONG64 pCreatorInfo, ObjBlink; ULONG TotalNumberOfObjects, Off, CreatorOff, SizeOfCreat; if (pObjectType == 0) { return FALSE; } if ( GetFieldValue( pObjectType,"nt!_OBJECT_TYPE", "TotalNumberOfObjects", TotalNumberOfObjects) ) { dprintf( "%08p: Unable to read object type\n", pObjectType ); return FALSE; } dprintf( "Scanning %u objects\n", TotalNumberOfObjects & 0x00FFFFFF); GetFieldOffset("nt!_OBJECT_TYPE", "TypeList", &Off); GetFieldOffset("nt!_OBJECT_HEADER_CREATOR_INFO", "TypeList", &CreatorOff); SizeOfCreat = GetTypeSize("OBJECT_HEADER_CREATOR_INFO"); Head = pObjectType + Off; GetFieldValue(Head, "nt!_LIST_ENTRY", "Flink", Next); GetFieldValue(Head, "nt!_LIST_ENTRY", "Blink", ObjBlink); WalkingBackwards = FALSE; if ((TotalNumberOfObjects & 0x00FFFFFF) != 0 && Next == Head) { dprintf( "*** objects of the same type are only linked together if the %x flag is set in NtGlobalFlags\n", FLG_MAINTAIN_OBJECT_TYPELIST ); return TRUE; } while (Next != Head) { ULONG64 Flink, Blink; if ( GetFieldValue(Next, "nt!_LIST_ENTRY", "Flink", Flink) || GetFieldValue(Next, "nt!_LIST_ENTRY", "Blink", Blink)) { if (WalkingBackwards) { dprintf( "%08p: Unable to read object type list\n", Next ); return FALSE; } // // Switch to walk in reverse direction // WalkingBackwards = TRUE ; Next = ObjBlink; dprintf( "%08lx: Switch to walking backwards\n", Next ); continue; } pCreatorInfo = ( Next - CreatorOff ); pObjectHeader = (pCreatorInfo + SizeOfCreat); if ( GetFieldValue( pObjectHeader,"nt!_OBJECT_HEADER","Flags", Result) ) { dprintf( "%08p: Not a valid object header\n", pObjectHeader ); return FALSE; } if (!(EnumRoutine)( pObjectHeader, Parameter )) { return FALSE; } if ( CheckControlC() ) { return FALSE; } if (WalkingBackwards) { Next = Blink; } else { Next = Flink; } } return TRUE; } BOOLEAN LpcCaptureObjectName( IN ULONG64 pObjectHeader, IN PWSTR Buffer, IN ULONG BufferSize ) { ULONG Result; PWSTR s1 = L"*** unable to get object name"; ULONG64 pNameInfo; UNICODE_STRING64 ObjectName; Buffer[ 0 ] = UNICODE_NULL; KD_OBJECT_HEADER_TO_NAME_INFO( pObjectHeader, &pNameInfo ); if (pNameInfo == 0) { return TRUE; } if ( GetFieldValue( pNameInfo, "nt!_OBJECT_HEADER_NAME_INFO", "Name.Length", ObjectName.Length) ) { wcscpy( Buffer, s1 ); return FALSE; } GetFieldValue( pNameInfo, "nt!_OBJECT_HEADER_NAME_INFO","Name.Buffer", ObjectName.Buffer); ObjectName.MaximumLength = ObjectName.Length; if (ObjectName.Length >= BufferSize ) { ObjectName.Length = (unsigned short)BufferSize - sizeof( UNICODE_NULL ); } if (ObjectName.Length != 0) { if (!ReadMemory( ObjectName.Buffer, Buffer, ObjectName.Length, &Result )) { wcscpy( Buffer, s1 ); } else { Buffer[ ObjectName.Length / sizeof( WCHAR ) ] = UNICODE_NULL; } } return TRUE; } VOID LpcpGetProcessImageName( IN ULONG64 pProcess, IN OUT PUCHAR ImageFileName, IN ULONG ImageFileNameSize ) { ULONG Result; UCHAR local[32]; PUCHAR s; int i; if (pProcess != 0) { if (!GetFieldValue( pProcess,"nt!_EPROCESS", "ImageFileName", local)) { i = 16; s = local; while (i--) { if (*s == '\0') { if (i == 15) { i = 0; } break; } if (*s < ' ' || *s >= '|') { i = 0; break; } s += 1; } if (i != 0) { if (StringCchCopy( ImageFileName, ImageFileNameSize, local ) != S_OK) { if (ImageFileName) ImageFileName[0] = 0; } return; } } } if (ImageFileName) ImageFileName[0] = 0; return; } #define LPCP_ZONE_MESSAGE_ALLOCATED (USHORT)0x8000 BOOLEAN LpcpDumpMessage( IN char *Indent, IN ULONG64 pMsg, IN ULONG DisplayMessage ) { ULONG Result; ULONG i; ULONG cb; ULONG MsgData[ 8 ]; UCHAR ImageFileName[ 32 ]; ULONG MessageId0, Off, SizeOfMsg, DataLength; BOOLEAN MessageMatch = FALSE; if ( GetFieldValue( pMsg, "nt!_LPCP_MESSAGE", "Request.MessageId", MessageId0) ) { dprintf( "%s*** unable to read LPC message at %08p\n", Indent, pMsg ); return MessageMatch; } if (DisplayMessage != 0) { if (DisplayMessage == MessageId0) { MessageMatch = TRUE; } else { return FALSE; } } GetFieldOffset("nt!_LPCP_MESSAGE", "Entry", &Off); SizeOfMsg = GetTypeSize("nt!_LPCP_MESSAGE"); InitTypeRead(pMsg, nt!_LPCP_MESSAGE); if (MessageId0 == 0) { dprintf( "%s%04x %08x - %s Id=%04x From: %04p.%04p\n", Indent, (ULONG) ReadField(ZoneIndex) & ~LPCP_ZONE_MESSAGE_ALLOCATED, pMsg, (ULONG) ReadField(Reserved0) != 0 ? "Busy" : "Free", MessageId0, ReadField(Request.ClientId.UniqueProcess), ReadField(Request.ClientId.UniqueThread) ); return MessageMatch; } // // Getting the process image affect dramaticaly the performances // // LpcpGetProcessImageName( LookupProcessUniqueId(Msg.Request.ClientId.UniqueProcess), ImageFileName ); dprintf( "%s%s%04lx %p - %s Id=%08lx From: %04p.%04p Context=%08p", Indent, MessageId0 == DisplayMessage ? "*" : "", (ULONG) ReadField(ZoneIndex) & ~LPCP_ZONE_MESSAGE_ALLOCATED, pMsg, (ULONG) ReadField(Reserved0) != 0 ? "Busy" : "Free", MessageId0, ReadField(Request.ClientId.UniqueProcess), ReadField(Request.ClientId.UniqueThread), ReadField(PortContext) ); if (ReadField(Entry.Flink) != pMsg + Off) { dprintf( " [%p . %p]", ReadField(Entry.Blink), ReadField(Entry.Flink) ); } dprintf( "\n%s Length=%08x Type=%08x (%s)\n", Indent, (ULONG) ReadField(Request.u1.Length), (ULONG) ReadField(Request.u2.ZeroInit), (ULONG) ReadField(Request.u2.s2.Type) > LPC_CONNECTION_REQUEST ? LpcpMessageTypeName[ 0 ] : LpcpMessageTypeName[ (ULONG) ReadField(Request.u2.s2.Type) ] ); cb = (DataLength = (ULONG) ReadField(Request.u1.s1.DataLength)) > sizeof( MsgData ) ? sizeof( MsgData ) : DataLength; if ( !ReadMemory( (pMsg + SizeOfMsg), MsgData, cb, &Result) ) { dprintf( "%s*** unable to read LPC message data at %08x\n", Indent, pMsg + 1 ); return MessageMatch; } dprintf( "%s Data:", Indent ); for (i=0; i<(DataLength / sizeof( ULONG )); i++) { if (i > 5) { break; } dprintf( " %08x", MsgData[ i ] ); } dprintf( "\n" ); return MessageMatch; } BOOLEAN FindPortCallback( IN ULONG64 pObjectHeader, IN PVOID Parameter ) { ULONG Result; WCHAR CapturedName[MAX_PATH]; ULONG64 PortObject, ConnectionPort; ULONG64 Addr=0; if (Parameter) Addr = *((PULONG64) Parameter); PortObject = KD_OBJECT_HEADER_TO_OBJECT(pObjectHeader); if ( GetFieldValue( PortObject, "nt!_LPCP_PORT_OBJECT", "ConnectionPort", ConnectionPort) ) { dprintf( "%08p: Unable to read port object\n", PortObject ); } InitTypeRead(PortObject, nt!_LPCP_PORT_OBJECT); if ((Addr == 0)|| (Addr == PortObject) || (Addr == ConnectionPort) || (Addr == ReadField(ConnectedPort)) ) { LpcCaptureObjectName( pObjectHeader, ObjectNameBuffer, MAX_PATH ); dprintf( "%8lx Port: 0x%08p Connection: 0x%08p Communication: 0x%08p '%ws' \n", (ULONG) ReadField(Flags), PortObject, ConnectionPort, ReadField(ConnectedPort), ObjectNameBuffer ); DumpRunDownQueue(PortObject); } return TRUE; } VOID DumpServerPort( ULONG64 PortObject, ULONG64 PortInfo ) { ULONG SemaphoreBuffer[8]; ULONG64 Head, Next; ULONG Result; ULONG64 Msg; ULONG MsgCount; ULONG64 pObjectHeader; UCHAR ImageFileName[ 32 ]; ULONG64 HandleCount, PointerCount; if (LastSeverPortDisplayied == PortObject) { // // This port was already displayied // return; } LastSeverPortDisplayied = PortObject; pObjectHeader = KD_OBJECT_TO_OBJECT_HEADER(PortObject); if ( GetFieldValue(pObjectHeader, "nt!_OBJECT_HEADER", "HandleCount", HandleCount) ) { dprintf(" *** %08p: Unable to read _OBJECT_HEADER\n", pObjectHeader ); } GetFieldValue(pObjectHeader, "nt!_OBJECT_HEADER", "PointerCount",PointerCount); LpcCaptureObjectName( pObjectHeader, ObjectNameBuffer, MAX_PATH ); dprintf( "\n"); dprintf( "Server connection port %08p Name: %ws\n", PortObject , ObjectNameBuffer); dprintf( " Handles: %ld References: %ld\n", (ULONG)HandleCount, (ULONG)PointerCount); InitTypeRead(PortInfo, nt!_LPCP_PORT_OBJECT); LpcpGetProcessImageName( ReadField(ServerProcess), ImageFileName, sizeof(ImageFileName) ); dprintf( " Server process : %08p (%s)\n", ReadField(ServerProcess), ImageFileName); dprintf( " Queue semaphore : %08p\n", ReadField(MsgQueue.Semaphore) ); if ( !ReadMemory( ReadField(MsgQueue.Semaphore), SemaphoreBuffer, sizeof( SemaphoreBuffer ), &Result) ) { dprintf(" *** %08p: Unable to read semaphore contents\n", ReadField(MsgQueue.Semaphore) ); } else { ULONG Off; dprintf( " Semaphore state %ld (0x%lx) \n", SemaphoreBuffer[1], SemaphoreBuffer[1] ); // // Walk list of messages queued to this port. Remove each message from // the list and free it. // GetFieldOffset("nt!_LPCP_PORT_OBJECT", "MsgQueue.ReceiveHead", &Off); Head = PortObject + Off; if (Head) { if ( !ReadPointer( Head, &Next ) ) { dprintf( " Failed to read Head 0x%p\n", Head ); return; } MsgCount = 0; while ((Next != 0) && (Next != Head)) { if (MsgCount == 0) { dprintf (" Messages in queue:\n"); } Msg = Next; LpcpDumpMessage(" ", Msg, 0); if ( !ReadPointer( Next, &Next ) ) { dprintf( " Error reading 0x%p\n", Next ); return; } MsgCount++; if ( CheckControlC() ) { return; } } if (MsgCount) { dprintf( " The message queue contains %ld messages\n", MsgCount ); } else { dprintf( " The message queue is empty\n"); } } DumpPortDataInfo(PortObject); DumpRunDownQueue(PortObject); } } VOID DumpPortDataInfo( ULONG64 PortObject ) { ULONG64 Head, Next; ULONG64 Msg; ULONG MsgCount, Off, EntryOff; GetFieldOffset("nt!_LPCP_MESSAGE", "Entry", &EntryOff); GetFieldOffset("nt!_LPCP_PORT_OBJECT", "LpcDataInfoChainHead.Flink", &Off); Head = PortObject + Off; if (Head) { Next = 0; if (!ReadPointer( Head, &Next )) { return; } MsgCount = 0; while ((Next != 0) && (Next != Head)) { if (MsgCount == 0) { dprintf ("\n Messages in LpcDataInfoChainHead:\n"); } Msg = ( Next - EntryOff ); LpcpDumpMessage(" ", Msg, 0); if (!ReadPointer( Next, &Next )) { return; } MsgCount++; if ( CheckControlC() ) { return; } } if (MsgCount) { dprintf( " The LpcDataInfoChainHead queue contains %ld messages\n", MsgCount ); } else { dprintf( " The LpcDataInfoChainHead queue is empty\n"); } } } VOID DumpRunDownQueue( ULONG64 PortObject ) { ULONG64 Head, Next; ULONG64 Thread; ULONG Count; ULONG Off, ChainOff; GetFieldOffset("nt!_ETHREAD", "LpcReplyChain", &ChainOff); GetFieldOffset("nt!_LPCP_PORT_OBJECT", "LpcDataInfoChainHead.Flink", &Off); Head = PortObject + Off; Next = 0; if (!ReadPointer( Head, &Next)) { return; } Count = 0; while ((Next != 0) && (Next != Head)) { if (Count == 0) { dprintf (" Threads in RunDown queue : "); } Thread = ( Next - ChainOff); dprintf (" 0x%08p", Thread); if (!ReadPointer( Next, &Next)) { return; } Count++; if ( CheckControlC() ) { return; } } if (Count) { dprintf("\n"); } } VOID DumpCommunicationPort( ULONG64 PortObject, ULONG64 PortInfo, BOOLEAN DisplayRelated ) { ULONG SemaphoreBuffer[8]; ULONG64 Head, Next; ULONG Result; ULONG64 Msg; ULONG64 pObjectHeader; ULONG64 HandleCount, PointerCount; ULONG Flags; pObjectHeader = KD_OBJECT_TO_OBJECT_HEADER(PortObject); if ( GetFieldValue(pObjectHeader, "nt!_OBJECT_HEADER", "HandleCount", HandleCount) ) { dprintf(" *** %08p: Unable to read object header\n", pObjectHeader ); } GetFieldValue(pObjectHeader, "nt!_OBJECT_HEADER", "PointerCount",PointerCount); dprintf( "\n"); if ( GetFieldValue(PortInfo, "nt!_LPCP_PORT_OBJECT", "Flags", Flags) ) { dprintf(" *** %08p: Unable to read port object\n", PortInfo ); } if ((Flags & PORT_TYPE) == SERVER_COMMUNICATION_PORT) { dprintf( "Server communication port 0x%08lx\n", PortObject); } else if ((Flags & PORT_TYPE) == CLIENT_COMMUNICATION_PORT) { dprintf( "Client communication port 0x%08p\n", PortObject); } else { dprintf( "Invalid port flags 0x%08p, 0x%08lx\n", PortObject, Flags); return; } dprintf( " Handles: %ld References: %ld\n", (ULONG)HandleCount, (ULONG)PointerCount); DumpPortDataInfo(PortObject); DumpRunDownQueue(PortObject); if (DisplayRelated) { ULONG64 ConnectedPort, ConnectionPort; InitTypeRead(PortInfo, nt!_LPCP_PORT_OBJECT); dprintf( " Connected port: 0x%08p Server connection port: 0x%08p\n", (ConnectedPort = ReadField( ConnectedPort)), (ConnectionPort = ReadField(ConnectionPort))); if (ConnectedPort) { DumpPortInfo(ConnectedPort, FALSE); } if (ConnectionPort) { DumpPortInfo(ConnectionPort, FALSE); } } } VOID DumpPortInfo ( ULONG64 PortObject, BOOLEAN DisplayRelated ) { ULONG Result; if ( GetFieldValue(PortObject, "nt!_LPCP_PORT_OBJECT", "Flags", Result) ) { dprintf( "%08p: Unable to read port object\n", PortObject ); } if ((Result & PORT_TYPE) == SERVER_CONNECTION_PORT) { DumpServerPort(PortObject, PortObject); } else { DumpCommunicationPort(PortObject, PortObject, DisplayRelated); } } BOOLEAN WINAPI CheckForMessages( IN PCHAR Tag, IN PCHAR Filter, IN ULONG Flags, IN ULONG64 PoolHeader, IN ULONG64 BlockSize, IN ULONG64 Data, IN PVOID Context ) { ULONG PoolIndex; if (!PoolHeader) { return FALSE; } if (GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolIndex", PoolIndex)) { return FALSE; } if ((PoolIndex & 0x80) == 0) { return FALSE; } if (!CheckSingleFilter (Tag, Filter)) { return FALSE; } if (LpcpDumpMessage("", Data, (ULONG)(ULONG_PTR)Context)) { ULONG64 Head, Next; ULONG EntryOff, ChainOff, RcvOff, HeaderOff; ULONG64 PortToDump; ULONG64 ObjectHeader; ULONG64 ObjectType; GetFieldOffset("nt!_LPCP_MESSAGE", "Entry", &EntryOff); GetFieldOffset("nt!_LPCP_PORT_OBJECT", "LpcDataInfoChainHead", &ChainOff); GetFieldOffset("nt!_LPCP_PORT_OBJECT", "MsgQueue.ReceiveHead", &RcvOff); Head = Data + EntryOff; Next = 0; if (!ReadPointer(Head, &Next)) { Next = 0; } GetFieldOffset("nt!_OBJECT_HEADER", "Body", &HeaderOff); while ((Next != 0) && (Next != Head)) { PortToDump = ( Next - ChainOff ); ObjectHeader = PortToDump - HeaderOff; GetFieldValue(ObjectHeader, "nt!_OBJECT_HEADER", "Type", ObjectType); if ( (ObjectType == (LpcPortObjectType)) || (ObjectType == (LpcWaitablePortObjectType))) { DumpPortInfo(PortToDump, TRUE); } else { PortToDump = Next - RcvOff; ObjectHeader = PortToDump - HeaderOff; GetFieldValue(ObjectHeader, "nt!_OBJECT_HEADER", "Type", ObjectType); if ( (ObjectType == (LpcPortObjectType)) || (ObjectType == (LpcWaitablePortObjectType))) { DumpPortInfo(PortToDump, TRUE); } } if (!ReadPointer(Next, &Next)) { Next = 0; } } } return TRUE; } VOID DumpMessagesInfo () { SearchPool ('McpL', 1, 0, &CheckForMessages, NULL); } VOID SearchForMessage (ULONG Message) { SearchThreadsForMessage(Message); if (DoPoolSearch) { SearchPool ('McpL', 1, 0, &CheckForMessages, (PVOID)UIntToPtr(Message)); } } VOID SearchThreadsForMessage ( ULONG Message ) { ULONG64 ProcessHead; ULONG64 ProcessNext; ULONG64 Process; ULONG64 ThreadHead; ULONG64 ThreadNext; ULONG64 Thread; ULONG MsgId; ULONG64 ClientThread; ULONG ActOff, PcbThrdOff, ThrdListOff; ClientThread = 0; dprintf("Searching message %lx in threads ...\n", Message); ProcessHead = GetExpression( "nt!PsActiveProcessHead" ); if (!ProcessHead) { dprintf("Unable to get value of PsActiveProcessHead\n"); return; } ProcessNext = GetPointerFromAddress(ProcessHead); GetFieldOffset("nt!_EPROCESS", "ActiveProcessLinks", &ActOff); GetFieldOffset("nt!_EPROCESS", "Pcb.ThreadListHead.Flink", &PcbThrdOff); GetFieldOffset("nt!_KTHREAD", "ThreadListEntry", &ThrdListOff); while(ProcessNext != 0 && ProcessNext != ProcessHead) { Process = ProcessNext - ActOff; ThreadHead = Process + PcbThrdOff; ThreadNext = GetPointerFromAddress(ThreadHead); while(ThreadNext != 0 && ThreadNext != ThreadHead) { Thread = ThreadNext - ThrdListOff; dprintf(" Proc 0x%08p, Thrd 0x%08p\r", Process, Thread); GetFieldValue(Thread, "nt!_ETHREAD", "LpcReplyMessageId", MsgId); if ((MsgId != 0) && ((Message == 0) || (Message == MsgId))) { dprintf("Client thread %08p waiting a reply from %lx \n", Thread, MsgId); ClientThread = Thread; } GetFieldValue(Thread, "nt!_ETHREAD", "LpcReceivedMsgIdValid", MsgId); if (MsgId) { GetFieldValue(Thread, "nt!_ETHREAD", "LpcReceivedMessageId", MsgId); if ((Message == 0) || (Message == MsgId)) { dprintf("Server thread %08p is working on message %lx \n", Thread, MsgId); } } ThreadNext = GetPointerFromAddress(ThreadNext); if (CheckControlC()) { dprintf("\nQuitting\n"); return; } } ProcessNext = GetPointerFromAddress(ProcessNext/*&Process->ActiveProcessLinks.Flink*/); if (CheckControlC()) { dprintf("\nQuitting\n"); return; } } if (Message && ClientThread) { SearchThreads(ClientThread); } dprintf("Done. \n"); return; } BOOLEAN SearchThreads ( ULONG64 Thread ) { ULONG64 PortObject; ULONG64 ObjectHeader; ULONG64 ObjectType; ULONG64 Head, Next; ULONG Count; ULONG ChainOff, HeadOff; dprintf("Searching thread %08p in port rundown queues ...\n", Thread); GetFieldOffset("nt!_ETHREAD", "LpcReplyChain.Flink", &ChainOff); GetFieldOffset("nt!_LPCP_PORT_OBJECT", "LpcReplyChainHead", &HeadOff); Head = Thread + ChainOff; Next = GetPointerFromAddress(Head); while ((Next != 0) && (Next != Head)) { PortObject = Next - HeadOff ; ObjectHeader = KD_OBJECT_TO_OBJECT_HEADER(PortObject); GetFieldValue(ObjectHeader, "nt!_OBJECT_HEADER", "Type", ObjectType); if ( (ObjectType == (LpcPortObjectType)) || (ObjectType == (LpcWaitablePortObjectType))) { DumpPortInfo(PortObject, TRUE); return TRUE; } Next = GetPointerFromAddress( Next); if ( CheckControlC() ) { return FALSE; } } dprintf("Thread %08p not found in any reply chain queue\n", Thread); return FALSE; } DECLARE_API( lpc ) /*++ Routine Description: Dump lpc ports and messages Arguments: args - [TypeName] Return Value: None --*/ { ULONG Result; LONG SegmentSize; ULONG64 pMsg; ULONG64 PortToDump; char Param1[ MAX_PATH ]; char Param2[ MAX_PATH ]; ULONG64 object; ULONG64 ThreadAddress; ULONG MessageId = 0; Param1[0] = 0; Param2[0] = 0; LastSeverPortDisplayied = 0; if (!sscanf(args,"%255s %255s",Param1, Param2)) { Param1[0] = 0; Param2[0] = 0; } FetchGlobalVariables(); if ((LpcPortObjectType == 0) || (LpcWaitablePortObjectType == 0)) { dprintf("The values for LpcPortObjectType or LpcWaitablePortObjectType are invalid. Please ckeck the symbols.\n"); return E_INVALIDARG; } if (!_stricmp(Param1, "port")) { PortToDump = 0; if (Param2[0]) { PortToDump = GetExpression(Param2); } if (!PortToDump) { LpcWalkObjectsByType( LpcPortObjectType, FindPortCallback, 0); LpcWalkObjectsByType( LpcWaitablePortObjectType, FindPortCallback, 0); } else { if ((PortToDump >> 32) == 0) { PortToDump = (ULONG64) (LONG64) (LONG)PortToDump; } DumpPortInfo(PortToDump, TRUE); } } else if (!_stricmp(Param1, "scan")) { PortToDump = 0; if (Param2[0]) { PortToDump = GetExpression(Param2); } if (PortToDump) { LpcWalkObjectsByType( LpcPortObjectType, FindPortCallback, &PortToDump); LpcWalkObjectsByType( LpcWaitablePortObjectType, FindPortCallback, &PortToDump); } } else if (!_stricmp(Param1, "message")) { if (Param2[0]) { if (!sscanf(Param2, "%lx",&MessageId)) { MessageId = 0; } } if (MessageId){ SearchForMessage(MessageId); } else { DumpMessagesInfo(); } } else if (!_stricmp(Param1, "PoolSearch")) { DoPoolSearch = !DoPoolSearch; if (DoPoolSearch) { dprintf( "LPC will search the message in the kernel pool\n"); } else { dprintf( "LPC will not search the message in the kernel pool\n"); } } else if (!_stricmp(Param1, "thread")) { ThreadAddress = 0; if (Param2[0]) { ThreadAddress = GetExpression(Param2); } if (ThreadAddress) { if ((ThreadAddress >> 32) == 0) { ThreadAddress = (ULONG64) (LONG64) (LONG)ThreadAddress; } SearchThreads(ThreadAddress); } else { SearchThreadsForMessage(0); } } else { LpcHelp(); } return S_OK; }