/*++ Copyright (c) 1992 Microsoft Corporation Module Name: peb.c Abstract: WinDbg Extension Api Author: Ramon J San Andres (ramonsa) 5-Nov-1993 Environment: User Mode. Revision History: --*/ #include "precomp.h" #pragma hdrstop #include BOOL GetTeb32FromWowTeb(ULONG64 Teb, PULONG64 pTeb32) { if (pTeb32) { return ReadPointer(Teb, pTeb32); } return FALSE; } BOOL GetPeb32FromWowTeb(ULONG64 Teb, PULONG64 pPeb32) { ULONG Peb32; ULONG64 Teb32=0; ULONG err; if (GetTeb32FromWowTeb(Teb, &Teb32) && Teb32) { if (!(err =GetFieldValue(Teb32, "nt!TEB32", "ProcessEnvironmentBlock", Peb32))) { *pPeb32 = Peb32; return TRUE; } else if (err == SYMBOL_TYPE_INFO_NOT_FOUND) { if (!(err =GetFieldValue(Teb32, "wow64!TEB32", "ProcessEnvironmentBlock", Peb32))) { *pPeb32 = Peb32; return TRUE; } } } return FALSE; } HRESULT DumpPeb(ULONG64 peb, BOOL IsWow64Peb) { ULONG64 ldr; ULONG64 err; ULONG64 ldr_Initialized; ULONG64 ldr_InInitializationOrderModuleList_Flink; ULONG64 ldr_InInitializationOrderModuleList_Blink; ULONG64 ldr_InLoadOrderModuleList_Flink; ULONG64 ldr_InLoadOrderModuleList_Blink; ULONG ldr_InMemoryOrderModuleList_Offset; ULONG64 ldr_InMemoryOrderModuleList_Flink; ULONG64 ldr_InMemoryOrderModuleList_Blink; ULONG ldr_DataTableEntry_InMemoryOrderLinks_Offset; ULONG64 peb_SubSystemData; ULONG64 peb_ProcessHeap; ULONG64 peb_ProcessParameters; PCHAR ldrdata = "nt!_PEB_LDR_DATA"; PCHAR ldrEntry = "nt!_LDR_DATA_TABLE_ENTRY"; PCHAR processparam = "nt!_RTL_USER_PROCESS_PARAMETERS"; HRESULT hr = S_OK; if (IsWow64Peb) { // try and load types from nt if ( err = InitTypeRead( peb, nt!PEB32 ) ) { if (err == SYMBOL_TYPE_INFO_NOT_FOUND) { // try load types from wow64 if ( !( err = InitTypeRead( peb, wow64!PEB32 )) ) { ldrdata = "wow64!_PEB_LDR_DATA32"; ldrEntry = "wow64!_LDR_DATA_TABLE_ENTRY32"; processparam = "wow64!_RTL_USER_PROCESS_PARAMETERS32"; } else { dprintf( "error %d InitTypeRead( wow64!PEB32 at %p)...\n", (ULONG) err, peb); return E_INVALIDARG; } } else { dprintf( "error %d InitTypeRead( nt!PEB32 at %p)...\n", (ULONG) err, peb); return E_INVALIDARG; } } else { ldrdata = "nt!_PEB_LDR_DATA32"; ldrEntry = "nt!_LDR_DATA_TABLE_ENTRY32"; processparam = "nt!_RTL_USER_PROCESS_PARAMETERS32"; } } else { if ( err = InitTypeRead( peb, PEB ) ) { dprintf( "error %d InitTypeRead( nt!PEB32 at %p)...\n", (ULONG) err, peb); return E_INVALIDARG; } } dprintf( " InheritedAddressSpace: %s\n" " ReadImageFileExecOptions: %s\n" " BeingDebugged: %s\n" " ImageBaseAddress: %p\n" " Ldr %p\n", ReadField( InheritedAddressSpace ) ? "Yes" : "No", ReadField( ReadImageFileExecOptions ) ? "Yes" : "No", ReadField( BeingDebugged ) ? "Yes" : "No", ReadField( ImageBaseAddress ), (ldr = ReadField( Ldr )) ); peb_SubSystemData = ReadField( SubSystemData ); peb_ProcessHeap = ReadField( ProcessHeap ); peb_ProcessParameters = ReadField( ProcessParameters ); err = GetFieldOffset( ldrdata, "InMemoryOrderModuleList", &ldr_InMemoryOrderModuleList_Offset ); if ( err ) { dprintf( " *** _PEB_LDR_DATA%s was not found...\n", ( err == FIELDS_DID_NOT_MATCH ) ? ".InMemoryModuleList field" : " type" ); } else { err = GetFieldOffset( ldrEntry, "InMemoryOrderLinks", &ldr_DataTableEntry_InMemoryOrderLinks_Offset ); if (err ) { dprintf( " *** _LDR_DATA_TABLE_ENTRY%s was not found...\n", ( err == FIELDS_DID_NOT_MATCH ) ? ".InMemoryOrderLinks field" : " type" ); } } if ( err || GetFieldValue( ldr, ldrdata, "Initialized", ldr_Initialized ) ) { dprintf( " *** unable to read Ldr table at %p\n", ldr ); } else { ULONG64 next, head; BOOL First = TRUE; GetFieldValue( ldr, ldrdata, "InInitializationOrderModuleList.Flink", ldr_InInitializationOrderModuleList_Flink ); GetFieldValue( ldr, ldrdata, "InInitializationOrderModuleList.Blink", ldr_InInitializationOrderModuleList_Blink ); GetFieldValue( ldr, ldrdata, "InLoadOrderModuleList.Flink", ldr_InLoadOrderModuleList_Flink ); GetFieldValue( ldr, ldrdata, "InLoadOrderModuleList.Blink", ldr_InLoadOrderModuleList_Blink ); GetFieldValue( ldr, ldrdata, "InMemoryOrderModuleList.Flink", ldr_InMemoryOrderModuleList_Flink ); GetFieldValue( ldr, ldrdata, "InMemoryOrderModuleList.Blink", ldr_InMemoryOrderModuleList_Blink ); dprintf( " Ldr.Initialized: %s\n" " Ldr.InInitializationOrderModuleList: %p . %p\n" " Ldr.InLoadOrderModuleList: %p . %p\n" " Ldr.InMemoryOrderModuleList: %p . %p\n", ldr_Initialized ? "Yes" : "No", ldr_InInitializationOrderModuleList_Flink, ldr_InInitializationOrderModuleList_Blink, ldr_InLoadOrderModuleList_Flink, ldr_InLoadOrderModuleList_Blink, ldr_InMemoryOrderModuleList_Flink, ldr_InMemoryOrderModuleList_Blink ); head = ldr + (ULONG64)ldr_InMemoryOrderModuleList_Offset; next = ldr_InMemoryOrderModuleList_Flink; while( next != head ) { ULONG64 entry, dllBase; UNICODE_STRING64 u; ULONG Timestamp; const char *time; entry = next - ldr_DataTableEntry_InMemoryOrderLinks_Offset; if (GetFieldValue( entry, ldrEntry, "DllBase", dllBase )) { dprintf("Cannot read %s at %p\n",ldrEntry, entry); break; } GetFieldValue( entry, ldrEntry, "TimeDateStamp", Timestamp ); GetFieldValue( entry, ldrEntry, "FullDllName.Buffer", u.Buffer ); GetFieldValue( entry, ldrEntry, "FullDllName.Length", u.Length ); GetFieldValue( entry, ldrEntry, "FullDllName.MaximumLength", u.MaximumLength ); if (First) { if (IsPtr64()) { dprintf(" Base TimeStamp / Module\n"); } else { dprintf(" Base TimeStamp Module\n"); } First = FALSE; } if (IsPtr64()) { dprintf(" "); } dprintf( "%16p ", dllBase ); if ((time = ctime((time_t *) &Timestamp)) != NULL) { dprintf( "%08x %-20.20s ", Timestamp, time+4); } if ( u.Buffer ) { if (IsPtr64()) { dprintf("\n "); } DumpUnicode64( u ); } dprintf( "\n"); GetFieldValue( entry, ldrEntry, "InMemoryOrderLinks.Flink", next ); if (CheckControlC()) { break; } } } dprintf( " SubSystemData: %p\n" " ProcessHeap: %p\n" " ProcessParameters: %p\n", peb_SubSystemData, peb_ProcessHeap, peb_ProcessParameters ); if ( peb_ProcessParameters ) { ULONG64 peb_ProcessParameters_Environment; ULONG64 peb_ProcessParameters_Flags; UNICODE_STRING64 windowTitle; UNICODE_STRING64 imagePathName; UNICODE_STRING64 commandLine; UNICODE_STRING64 dllPath; GetFieldValue( peb_ProcessParameters, processparam, "Environment", peb_ProcessParameters_Environment ); GetFieldValue( peb_ProcessParameters, processparam, "Flags", peb_ProcessParameters_Flags ); GetFieldValue( peb_ProcessParameters, processparam, "WindowTitle.Buffer", windowTitle.Buffer ); GetFieldValue( peb_ProcessParameters, processparam, "WindowTitle.Length", windowTitle.Length ); GetFieldValue( peb_ProcessParameters, processparam, "WindowTitle.MaximumLength", windowTitle.MaximumLength ); GetFieldValue( peb_ProcessParameters, processparam, "ImagePathName.Buffer", imagePathName.Buffer ); GetFieldValue( peb_ProcessParameters, processparam, "ImagePathName.Length", imagePathName.Length ); GetFieldValue( peb_ProcessParameters, processparam, "ImagePathName.MaximumLength", imagePathName.MaximumLength ); GetFieldValue( peb_ProcessParameters, processparam, "CommandLine.Buffer", commandLine.Buffer ); GetFieldValue( peb_ProcessParameters, processparam, "CommandLine.Length", commandLine.Length ); GetFieldValue( peb_ProcessParameters, processparam, "CommandLine.MaximumLength", commandLine.MaximumLength ); GetFieldValue( peb_ProcessParameters, processparam, "DllPath.Buffer", dllPath.Buffer ); GetFieldValue( peb_ProcessParameters, processparam, "DllPath.Length", dllPath.Length ); GetFieldValue( peb_ProcessParameters, processparam, "DllPath.MaximumLength", dllPath.MaximumLength ); if ( !(peb_ProcessParameters_Flags & RTL_USER_PROC_PARAMS_NORMALIZED) ) { windowTitle.Buffer += peb_ProcessParameters; imagePathName.Buffer += peb_ProcessParameters; commandLine.Buffer += peb_ProcessParameters; dllPath.Buffer += peb_ProcessParameters; } dprintf( " WindowTitle: '" ); DumpUnicode64( windowTitle ); dprintf("'\n"); dprintf( " ImageFile: '" ); DumpUnicode64( imagePathName ); dprintf("'\n"); dprintf( " CommandLine: '" ); DumpUnicode64( commandLine ); dprintf("'\n"); dprintf( " DllPath: '" ); DumpUnicode64( dllPath ); dprintf("'\n" " Environment: %p\n", peb_ProcessParameters_Environment ); } else { dprintf( " *** unable to read process parameters\n" ); } return S_OK; } DECLARE_API( peb ) /*++ Routine Description: This function is called to dump the PEB Called as: !peb Arguments: None Return Value: None --*/ { ULONG64 pebAddress; ULONG64 peb; HRESULT hr = S_OK; INIT_API(); if ( *args ) { pebAddress = GetExpression( args ); } else { ULONG64 tebAddress; GetTebAddress( &tebAddress ); if (TargetMachine == IMAGE_FILE_MACHINE_IA64 && tebAddress) { ULONG64 Peb32=0; if (GetPeb32FromWowTeb(tebAddress, &Peb32) && Peb32) { dprintf("Wow64 PEB32 at %lx\n", Peb32); DumpPeb(Peb32, TRUE); dprintf("\n\nWow64 "); } } GetPebAddress( 0, &pebAddress ); } if ( pebAddress ) { dprintf( "PEB at %p\n", pebAddress ); } else { dprintf( "PEB NULL...\n" ); return E_INVALIDARG; } peb = IsPtr64() ? pebAddress : (ULONG64)(LONG64)(LONG)pebAddress; hr = DumpPeb(peb, FALSE); EXIT_API(); return hr; } // PebExtension() HRESULT DumpTeb(ULONG64 tebAddress, BOOL IsWow64Teb) { ULONG64 teb; ULONG64 tib_ExceptionList; ULONG64 tib_StackBase; ULONG64 tib_StackLimit; ULONG64 tib_StackSusSystemTib; ULONG64 tib_FiberData; ULONG64 tib_ArbitraryUserPointer; ULONG64 tib_Self; ULONG64 tib_EnvironmentPointer; ULONG64 teb_ClientId_UniqueProcess; ULONG64 teb_ClientId_UniqueThread; ULONG64 teb_RealClientId_UniqueProcess; ULONG64 teb_RealClientId_UniqueThread; ULONG64 DeallocationBStore; HRESULT hr = S_OK; ULONG64 err; teb = tebAddress; if (!IsWow64Teb) { if ( InitTypeRead( teb, TEB ) ) { dprintf( "error InitTypeRead( TEB )...\n"); return E_INVALIDARG; } } else { if ( err = InitTypeRead( teb, nt!TEB32 ) ) { if (err == SYMBOL_TYPE_INFO_NOT_FOUND) { if ( InitTypeRead( teb, wow64!TEB32 ) ) { dprintf( "error InitTypeRead( wow64!TEB32 )...\n"); return E_INVALIDARG; } } else { dprintf( "error InitTypeRead( TEB32 )...\n"); return E_INVALIDARG; } } } dprintf( " ExceptionList: %p\n" " StackBase: %p\n" " StackLimit: %p\n" " SubSystemTib: %p\n" " FiberData: %p\n" " ArbitraryUserPointer: %p\n" " Self: %p\n" " EnvironmentPointer: %p\n", GetShortField(0, "NtTib.ExceptionList", 0), ReadField( NtTib.StackBase ), GetShortField(0, "NtTib.StackLimit", 0), GetShortField(0, "NtTib.SubsystemTib", 0), GetShortField(0, "NtTib.FiberData", 0), GetShortField(0, "NtTib.ArbitraryUsetPointer", 0), GetShortField(0, "NtTib.Self", 0), GetShortField(0, "NtTib.EnvironmentPointer", 0) ); teb_ClientId_UniqueProcess = GetShortField( 0, "ClientId.UniqueProcess", 0 ); teb_ClientId_UniqueThread = GetShortField( 0, "ClientId.UniqueThread", 0 ); teb_RealClientId_UniqueProcess = GetShortField( 0, "RealClientId.UniqueProcess", 0 ); teb_RealClientId_UniqueThread = GetShortField( 0, "RealClientId.UniqueThread", 0 ); dprintf( " ClientId: %p . %p\n", teb_ClientId_UniqueProcess, teb_ClientId_UniqueThread ); if ( teb_ClientId_UniqueProcess != teb_RealClientId_UniqueProcess || teb_ClientId_UniqueThread != teb_RealClientId_UniqueThread ) { dprintf( " Real ClientId: %p . %p\n", teb_RealClientId_UniqueProcess, teb_RealClientId_UniqueThread ); } dprintf( " RpcHandle: %p\n" " Tls Storage: %p\n" " PEB Address: %p\n" " LastErrorValue: %u\n" " LastStatusValue: %x\n" " Count Owned Locks: %u\n" " HardErrorsMode: %u\n", ReadField( ActiveRpcHandle ), ReadField( ThreadLocalStoragePointer ), ReadField( ProcessEnvironmentBlock ), (ULONG)ReadField( LastErrorValue ), (ULONG)ReadField( LastStatusValue ), (ULONG)ReadField( CountOfOwnedCriticalSections ), (ULONG)ReadField( HardErrorsAreDisabled ) ); if (TargetMachine == IMAGE_FILE_MACHINE_IA64 && !IsWow64Teb) { dprintf( " DeallocationBStore: %p\n" " BStoreLimit: %p\n", ReadField(DeallocationBStore), ReadField( BStoreLimit ) ); } return hr; } // DumpTeb() DECLARE_API( teb ) /*++ Routine Description: This function is called to dump the TEB Called as: !teb --*/ { ULONG64 tebAddress; HRESULT hr = S_OK; INIT_API(); if ( *args ) { tebAddress = GetExpression( args ); } else { GetTebAddress( &tebAddress ); } if ( tebAddress ) { if (TargetMachine == IMAGE_FILE_MACHINE_IA64 && tebAddress) { ULONG64 Teb32=0; if (GetTeb32FromWowTeb(tebAddress, &Teb32) && Teb32) { dprintf("Wow64 TEB32 at %p\n", Teb32); DumpTeb(Teb32, TRUE); dprintf("\n\nWow64 "); } } dprintf( "TEB at %p\n", tebAddress ); } else { dprintf( "TEB NULL...\n" ); hr = E_INVALIDARG; goto ExitTeb; } tebAddress = IsPtr64() ? tebAddress : (ULONG64)(LONG64)(LONG)tebAddress; hr = DumpTeb(tebAddress, FALSE); ExitTeb: EXIT_API(); return hr; }