|
|
/******************************Module*Header*******************************\
* Module Name: hmgr.cxx * * Copyright (c) 2000 Microsoft Corporation * \**************************************************************************/
#include "precomp.hxx"
// Sometimes GDI _ENTRY structure can't be read.
// We can use another module's version since the structure should be the same.
CHAR szEntryType[MAX_PATH];
CachedType Entry = {FALSE, "_ENTRY", 0, 0, 0};
// Cache virtual table addresses for each session since the lookup is slow.
// Additionally cache one for the current session since it too is now slow.
#define NUM_CACHED_SESSIONS 8
struct { ULONG UniqueState; ULONG64 VirtualTableAddr; } CachedTableAddr[NUM_CACHED_SESSIONS+1] = { { 0, 0 } };
BitFieldInfo *HandleIndex; BitFieldInfo *HandleType; BitFieldInfo *HandleAltType; BitFieldInfo *HandleFullType; BitFieldInfo *HandleStock; BitFieldInfo *HandleFullUnique;
/******************************Public*Routine******************************\
* * Routine Name: * * HmgrInit * * Routine Description: * * Initialize or reinitialize information to be read from symbols files * * Arguments: * * Client - PDEBUG_CLIENT * * Return Value: * * none * \**************************************************************************/
void HmgrInit(PDEBUG_CLIENT Client) { strcpy(szEntryType, GDIType(_ENTRY));
Entry.Valid = FALSE; Entry.Module = 0; Entry.TypeId = 0; Entry.Size = 0;
if (HandleIndex != NULL) HandleIndex->Valid = FALSE; if (HandleType != NULL) HandleType->Valid = FALSE; if (HandleAltType != NULL) HandleAltType->Valid = FALSE; if (HandleFullType != NULL) HandleFullType->Valid = FALSE; if (HandleStock != NULL) HandleStock->Valid = FALSE; if (HandleFullUnique != NULL) HandleFullUnique->Valid = FALSE;
for (int s = 0; s < sizeof(CachedTableAddr)/sizeof(CachedTableAddr[0]); s++) { CachedTableAddr[s].UniqueState = INVALID_UNIQUE_STATE; }
return; }
/******************************Public*Routine******************************\
* * Routine Name: * * HmgrExit * * Routine Description: * * Clean up any outstanding allocations or references * * Arguments: * * none * * Return Value: * * none * \**************************************************************************/
void HmgrExit() { if (HandleIndex != NULL) { delete HandleIndex; HandleIndex = NULL; }
if (HandleType != NULL) { delete HandleType; HandleType = NULL; }
if (HandleAltType != NULL) { delete HandleAltType; HandleAltType = NULL; }
if (HandleFullType != NULL) { delete HandleFullType; HandleFullType = NULL; }
if (HandleStock != NULL) { delete HandleStock; HandleStock = NULL; }
if (HandleFullUnique != NULL) { delete HandleFullUnique; HandleFullUnique = NULL; }
return; }
/******************************Public*Routine******************************\
* * Routine Name: * * GetEntryType * * Routine Description: * * looks up hmgr entry type id and module * * Arguments: * * Client - PDEBUG_CLIENT * TypeId - Pointer to receive entry's type id * Module - Pointer to receive entry's module * * Return Value: * * S_OK if successful. * \**************************************************************************/
HRESULT GetEntryType( PDEBUG_CLIENT Client, PULONG TypeId, PULONG64 Module ) { HRESULT hr = S_OK;
if (!Entry.Valid) { OutputControl OutCtl(Client); PDEBUG_SYMBOLS Symbols;
if (TypeId != NULL) *TypeId = 0; if (Module != NULL) *Module = 0;
if (Client == NULL) return E_INVALIDARG;
if (Type_Module.Base == 0) { OutCtl.OutErr("Symbols not initialized properly.\n" " Please use !reinit.\n"); return S_FALSE; }
if ((hr = Client->QueryInterface(__uuidof(IDebugSymbols), (void **)&Symbols)) != S_OK) { return hr; }
if ((hr = Symbols->GetTypeId(Type_Module.Base, Entry.Type, &Entry.TypeId)) == S_OK) { Entry.Module = Type_Module.Base; Entry.Valid = TRUE;
sprintf(szEntryType, "%s!%s", Type_Module.Name, Entry.Type);
OutCtl.OutVerb("Found %s in module %s @ 0x%p.\n", Entry.Type, Type_Module.Name, Entry.Module); } else { ULONG ModuleIndex = 0; ULONG64 ModuleBase = 0;
while (Symbols->GetModuleByIndex(ModuleIndex, &Entry.Module) == S_OK && Entry.Module != 0) { if ((hr = Symbols->GetTypeId(Entry.Module, Entry.Type, &Entry.TypeId)) == S_OK) { OutCtl.OutVerb("Found %s: TypeId 0x%lx in module @ 0x%p.\n", Entry.Type, Entry.TypeId, Entry.Module); break; }
ModuleIndex++; Entry.Module = 0; }
if (hr != S_OK) { Entry.Module = 0; Entry.TypeId = 0; OutCtl.OutErr("Unable to find type '%s'.\n", Entry.Type); } else { Entry.Valid = TRUE;
if (Symbols->GetModuleNames(ModuleIndex, Entry.Module, NULL, 0, NULL, szEntryType, sizeof(szEntryType), NULL, NULL, 0, NULL) == S_OK) { OutCtl.OutVerb("Found %s in module(%lu) %s @ %p.\n", Entry.Type, ModuleIndex, szEntryType, Entry.Module); strcat(szEntryType, "!"); strcat(szEntryType, "_ENTRY"); } else { OutCtl.OutVerb("Found %s in unknown module(%lu) @ %p.\n", Entry.Type, ModuleIndex, Entry.Module); strcpy(szEntryType, Entry.Type); } } } }
if (hr == S_OK) { if (TypeId != NULL) *TypeId = Entry.TypeId; if (Module != NULL) *Module = Entry.Module; }
return hr; }
/******************************Public*Routine******************************\
* * Routine Name: * * GetEntrySize * * Routine Description: * * looks up hmgr entry size * * Arguments: * * Client - PDEBUG_CLIENT * * Return Value: * * address of handle manager entry * \**************************************************************************/
ULONG GetEntrySize( PDEBUG_CLIENT Client ) { if (Entry.Size == 0) { PDEBUG_SYMBOLS Symbols;
if (Client != NULL && GetEntryType(Client, NULL, NULL) == S_OK && Client->QueryInterface(__uuidof(IDebugSymbols), (void **)&Symbols) == S_OK) { if (Symbols->GetTypeSize(Entry.Module, Entry.TypeId, &Entry.Size) != S_OK) { OutputControl OutCtl(Client); OutCtl.OutErr("Unable to get size of _ENTRY.\n"); Entry.Size = 0; }
Symbols->Release(); } }
return Entry.Size; }
/******************************Public*Routine******************************\
* * Routine Name: * * GetIndexFromHandle * * Routine Description: * * Decodes entry index from engine handle * * Arguments: * * Client - PDEBUG_CLIENT * Handle64 - engine handle * Index - Address to receive extracted handle index * * Return Value: * * S_OK on success * \**************************************************************************/
HRESULT GetIndexFromHandle( PDEBUG_CLIENT Client, ULONG64 Handle64, PULONG64 Index ) { HRESULT hr = S_FALSE;
if (HandleIndex == NULL) { HandleIndex = new BitFieldInfo; }
if (HandleIndex == NULL) { hr = E_OUTOFMEMORY; } else if (HandleIndex->Valid) { hr = S_OK; } else { BitFieldParser BitFieldReader(Client, HandleIndex); OutputState OutState(Client);
if ((hr = BitFieldReader.Ready()) == S_OK && (hr = OutState.Setup(0, &BitFieldReader)) == S_OK) { // Read index bit field from symbol file
if (OutState.Execute("dt " GDIType(GDIHandleBitFields) " Index") != S_OK || BitFieldReader.ParseOutput() != S_OK || BitFieldReader.Complete() != S_OK) { // Use position 0 and INDEX_BITS from ntgdistr.h
HandleIndex->Valid = HandleIndex->Compose(0, INDEX_BITS); hr = HandleIndex->Valid ? S_OK : S_FALSE; } } }
if (Index != NULL) { if (hr == S_OK) { *Index = (Handle64 & HandleIndex->Mask) >> HandleIndex->BitPos; } else { *Index = 0; } }
return hr; }
/******************************Public*Routine******************************\
* * Routine Name: * * GetTypeFromHandle * * Routine Description: * * Decodes base type from engine handle * * Arguments: * * Client - PDEBUG_CLIENT * Handle64 - engine handle * Type - Address to receive extracted handle type * Flags - Extraction options * GET_BITS_UNSHIFTED - Field bits not shifted to start at bit 0 * * Return Value: * * S_OK on success * \**************************************************************************/
HRESULT GetTypeFromHandle( PDEBUG_CLIENT Client, ULONG64 Handle64, PULONG64 Type, FLONG Flags ) { HRESULT hr = S_FALSE;
if (HandleType == NULL) { HandleType = new BitFieldInfo; }
if (HandleType == NULL) { hr = E_OUTOFMEMORY; } else if (HandleType->Valid) { hr = S_OK; } else { BitFieldParser BitFieldReader(Client, HandleType); OutputState OutState(Client);
if ((hr = BitFieldReader.Ready()) == S_OK && (hr = OutState.Setup(0, &BitFieldReader)) == S_OK) { // Read index bit field from symbol file
if ((hr = OutState.Execute("dt " GDIType(GDIHandleBitFields) " Type")) != S_OK || (hr = BitFieldReader.ParseOutput()) != S_OK || (hr = BitFieldReader.Complete()) != S_OK) { // Use position TYPE_SHIFT and TYPE_BITS from ntgdistr.h
HandleType->Valid = HandleType->Compose(TYPE_SHIFT, TYPE_BITS); hr = HandleType->Valid ? S_OK : S_FALSE; } } }
if (Type != NULL) { if (hr == S_OK) { *Type = Handle64 & HandleType->Mask; if (!(Flags & GET_BITS_UNSHIFTED)) { *Type >>= HandleType->BitPos; } } else { *Type = 0; } }
return hr; }
/******************************Public*Routine******************************\
* * Routine Name: * * GetAltTypeFromHandle * * Routine Description: * * Decodes alt type from engine handle * * Arguments: * * Client - PDEBUG_CLIENT * Handle64 - engine handle * AltType - Address to receive extracted alt handle type * Flags - Extraction options * GET_BITS_UNSHIFTED - Field bits not shifted to start at bit 0 * * Return Value: * * S_OK on success * \**************************************************************************/
HRESULT GetAltTypeFromHandle( PDEBUG_CLIENT Client, ULONG64 Handle64, PULONG64 AltType, FLONG Flags ) { HRESULT hr = S_FALSE;
if (HandleAltType == NULL) { HandleAltType = new BitFieldInfo; }
if (HandleAltType == NULL) { hr = E_OUTOFMEMORY; } else if (HandleAltType->Valid) { hr = S_OK; } else { BitFieldParser BitFieldReader(Client, HandleAltType); OutputState OutState(Client);
if ((hr = BitFieldReader.Ready()) == S_OK && (hr = OutState.Setup(0, &BitFieldReader)) == S_OK) { // Read index bit field from symbol file
if ((hr = OutState.Execute("dt " GDIType(GDIHandleBitFields) " AltType")) != S_OK || (hr = BitFieldReader.ParseOutput()) != S_OK || (hr = BitFieldReader.Complete()) != S_OK) { // Use position ALTTYPE_SHIFT and ALTTYPE_BITS from ntgdistr.h
HandleAltType->Valid = HandleAltType->Compose(ALTTYPE_SHIFT, ALTTYPE_BITS); hr = HandleAltType->Valid ? S_OK : S_FALSE; } } }
if (AltType != NULL) { if (hr == S_OK) { *AltType = Handle64 & HandleAltType->Mask; if (!(Flags & GET_BITS_UNSHIFTED)) { *AltType >>= HandleAltType->BitPos; } } else { *AltType = 0; } }
return hr; }
/******************************Public*Routine******************************\
* * Routine Name: * * GetFullTypeFromHandle * * Routine Description: * * Decodes full type from engine handle * * Arguments: * * Client - PDEBUG_CLIENT * Handle64 - engine handle * FullType - Address to receive extracted full handle type * Flags - Extraction options * GET_BITS_UNSHIFTED - Field bits not shifted to start at bit 0 * * Return Value: * * S_OK on success * \**************************************************************************/
HRESULT GetFullTypeFromHandle( PDEBUG_CLIENT Client, ULONG64 Handle64, PULONG64 FullType, FLONG Flags ) { HRESULT hr = S_FALSE;
if (HandleFullType == NULL) { HandleFullType = new BitFieldInfo; }
if (HandleFullType == NULL) { hr = E_OUTOFMEMORY; } else if (HandleFullType->Valid) { hr = S_OK; } else { if ((hr = GetTypeFromHandle(Client, 0, NULL)) == S_OK && (hr = GetAltTypeFromHandle(Client, 0, NULL)) == S_OK) { if (!HandleType->Valid || HandleType->Bits == 0) { *HandleFullType = *HandleAltType; } else if (!HandleAltType->Valid || HandleAltType->Bits == 0) { *HandleFullType = *HandleType; } else { ULONG64 Mask;
HandleFullType->BitPos = min(HandleType->BitPos, HandleAltType->BitPos); HandleFullType->Bits = max(HandleAltType->Bits+HandleAltType->BitPos, HandleType->Bits+HandleType->BitPos) - HandleFullType->BitPos; HandleFullType->Mask = HandleAltType->Mask | HandleType->Mask;
// Make sure we have the BitPos and Bits count correct
for (Mask = HandleFullType->Mask >> HandleFullType->BitPos; HandleFullType->Bits > 0 && ((Mask & 1) == 0); HandleFullType->Bits--, Mask >> 1) { HandleFullType->BitPos++; }
HandleFullType->Valid = (HandleFullType->Bits > 0); }
if (!HandleFullType->Valid) { hr = S_FALSE; } } }
if (FullType != NULL) { if (hr == S_OK) { *FullType = Handle64 & HandleFullType->Mask; if (!(Flags & GET_BITS_UNSHIFTED)) { *FullType >>= HandleFullType->BitPos; } } else { *FullType = 0; } }
return hr; }
/******************************Public*Routine******************************\
* * Routine Name: * * GetStockFromHandle * * Routine Description: * * Decodes stock value from engine handle * * Arguments: * * Client - PDEBUG_CLIENT * Handle64 - engine handle * Stock - Address to receive extracted handle stock setting * Flags - Extraction options * GET_BITS_UNSHIFTED - Field bits not shifted to start at bit 0 * * Return Value: * * S_OK on success * \**************************************************************************/
HRESULT GetStockFromHandle( PDEBUG_CLIENT Client, ULONG64 Handle64, PULONG64 Stock, FLONG Flags ) { HRESULT hr = S_FALSE;
if (HandleStock == NULL) { HandleStock = new BitFieldInfo; }
if (HandleStock == NULL) { hr = E_OUTOFMEMORY; } else if (HandleStock->Valid) { hr = S_OK; } else { BitFieldParser BitFieldReader(Client, HandleStock); OutputState OutState(Client);
if ((hr = BitFieldReader.Ready()) == S_OK && (hr = OutState.Setup(0, &BitFieldReader)) == S_OK) { // Read index bit field from symbol file
if ((hr = OutState.Execute("dt " GDIType(GDIHandleBitFields) " Stock")) != S_OK || (hr = BitFieldReader.ParseOutput()) != S_OK || (hr = BitFieldReader.Complete()) != S_OK) { // Use position STOCK_SHIFT and STOCK_BITS from ntgdistr.h
HandleStock->Valid = HandleStock->Compose(STOCK_SHIFT, STOCK_BITS); hr = HandleStock->Valid ? S_OK : S_FALSE; } } }
if (Stock != NULL) { if (hr == S_OK) { *Stock = Handle64 & HandleStock->Mask; if (!(Flags & GET_BITS_UNSHIFTED)) { *Stock >>= HandleStock->BitPos; } } else { *Stock = 0; } }
return hr; }
/******************************Public*Routine******************************\
* * Routine Name: * * GetFullUniqueFromHandle * * Routine Description: * * Decodes full unique value from engine handle * * Arguments: * * Client - PDEBUG_CLIENT * Handle64 - engine handle * FullUnique - Address to receive extracted handle FullUnique value * Flags - Extraction options * GET_BITS_UNSHIFTED - Field bits not shifted to start at bit 0 * * Return Value: * * S_OK on success * \**************************************************************************/
HRESULT GetFullUniqueFromHandle( PDEBUG_CLIENT Client, ULONG64 Handle64, PULONG64 FullUnique, ULONG Flags ) { HRESULT hr = S_FALSE;
if (HandleFullUnique == NULL) { HandleFullUnique = new BitFieldInfo; }
if (HandleFullUnique == NULL) { hr = E_OUTOFMEMORY; } else if (HandleFullUnique->Valid) { hr = S_OK; } else { if (HandleIndex == NULL || !HandleIndex->Valid) { // Try to read Index bitfield
hr = GetIndexFromHandle(Client, 0, NULL); }
if (HandleIndex != NULL && HandleIndex->Valid) { BitFieldInfo GDIHandle; BitFieldParser BitFieldReader(Client, &GDIHandle); OutputState OutState(Client);
if ((hr = BitFieldReader.Ready()) == S_OK && (hr = OutState.Setup(0, &BitFieldReader)) == S_OK) { // Read FullUnique from symbol file
if (OutState.Execute("dt " GDIType(GDIHandleBitFields)) == S_OK && BitFieldReader.ParseOutput() == S_OK && BitFieldReader.Complete() == S_OK) { ULONG64 Mask;
HandleFullUnique->BitPos = HandleIndex->BitPos + HandleIndex->Bits; HandleFullUnique->Bits = GDIHandle.Bits - HandleFullUnique->BitPos; HandleFullUnique->Mask = GDIHandle.Mask & ~HandleIndex->Mask; // Make sure we have the BitPos and Bits count correct
for (Mask = HandleFullUnique->Mask >> HandleFullUnique->BitPos; HandleFullUnique->Bits > 0 && ((Mask & 1) == 0); HandleFullUnique->Bits--, Mask >> 1) { HandleFullUnique->BitPos++; }
HandleFullUnique->Valid = (HandleFullUnique->Bits > 0); } else { // Use values from ntgdistr.h
HandleFullUnique->Valid = HandleFullUnique->Compose(TYPE_SHIFT, TYPE_BITS + ALTTYPE_BITS + STOCK_BITS + UNIQUE_BITS); }
hr = HandleFullUnique->Valid ? S_OK : S_FALSE; } } }
if (FullUnique != NULL) { if (hr == S_OK) { *FullUnique = Handle64 & HandleFullUnique->Mask; if (!(Flags & GET_BITS_UNSHIFTED)) { *FullUnique >>= HandleFullUnique->BitPos; } } else { *FullUnique = 0; } }
return hr; }
/******************************Public*Routine******************************\
* * Routine Name: * * GetHandleTable * * Routine Description: * * reads current location of handle table * * Arguments: * * Client - PDEBUG_CLIENT * TableAddr - PULONG64 to return start address of handle table * * Return Value: * * If successful, S_OK. * \**************************************************************************/
HRESULT GetHandleTable( PDEBUG_CLIENT Client, PULONG64 TableAddr ) { ULONG CurrentUniqueState = UniqueTargetState;
HRESULT hr;
PDEBUG_CONTROL Control; PDEBUG_SYMBOLS Symbols; PDEBUG_DATA_SPACES Data;
if (TableAddr == NULL) { return E_INVALIDARG; }
if (CurrentUniqueState != INVALID_UNIQUE_STATE) { if (SessionId < NUM_CACHED_SESSIONS) { if (CachedTableAddr[SessionId].UniqueState == CurrentUniqueState) { *TableAddr = CachedTableAddr[SessionId].VirtualTableAddr; return S_OK; } } else if (SessionId == CURRENT_SESSION) { if (CachedTableAddr[NUM_CACHED_SESSIONS].UniqueState == CurrentUniqueState) { *TableAddr = CachedTableAddr[NUM_CACHED_SESSIONS].VirtualTableAddr; return S_OK; } } }
*TableAddr = 0;
if (Client == NULL) return E_INVALIDARG;
OutputControl OutCtl(Client);
if ((hr = Client->QueryInterface(__uuidof(IDebugSymbols), (void **)&Symbols)) != S_OK) { return hr; }
if ((hr = Client->QueryInterface(__uuidof(IDebugDataSpaces), (void **)&Data)) != S_OK) { Symbols->Release(); return hr; }
CHAR PointerName[80]; ULONG64 pent;
hr = S_FALSE;
if (TargetClass != DEBUG_CLASS_USER_WINDOWS) { sprintf(PointerName, "%s!gpentHmgr", GDIKM_Module.Name); hr = Symbols->GetOffsetByName(PointerName, &pent); if (hr != S_OK) { OutCtl.OutErr("Unable to locate %s\n", PointerName); } }
if (hr != S_OK && SessionId == CURRENT_SESSION) { sprintf(PointerName, "%s!pGdiSharedHandleTable", GDIUM_Module.Name); hr = Symbols->GetOffsetByName(PointerName, &pent); if (hr != S_OK) { OutCtl.OutErr("Unable to locate %s\n", PointerName); } }
if (hr == S_OK) { if (SessionId == CURRENT_SESSION) { hr = Data->ReadPointersVirtual(1, pent, TableAddr);
if (hr == S_OK) { CachedTableAddr[NUM_CACHED_SESSIONS].VirtualTableAddr = *TableAddr; CachedTableAddr[NUM_CACHED_SESSIONS].UniqueState = CurrentUniqueState; } } else { ULONG64 pentPhys;
if ((hr = GetPhysicalAddress(Client, SessionId, pent, &pentPhys)) == S_OK) { hr = ReadPointerPhysical(Client, pentPhys, TableAddr);
if (hr == S_OK) { if (SessionId < NUM_CACHED_SESSIONS) { CachedTableAddr[SessionId].VirtualTableAddr = *TableAddr; CachedTableAddr[SessionId].UniqueState = CurrentUniqueState; } } } }
if (hr == S_OK) { if (!*TableAddr) { OutCtl.OutErr(" GDI handle manager is not initialized or symbols are incorrect.\n" " %s @ %#p is NULL.\n", PointerName, pent); hr = S_FALSE; } } else { OutCtl.OutErr("Unable to get the contents of %s @ %#p\n", PointerName, pent); } }
Data->Release(); Symbols->Release();
return hr; }
/******************************Public*Routine******************************\
* * Routine Name: * * GetMaxHandles * * Routine Description: * * reads current maximum number of handles * * Arguments: * * Client - PDEBUG_CLIENT * * Return Value: * * Zero for failure, otherwise maximum valid handle index * \**************************************************************************/
HRESULT GetMaxHandles( PDEBUG_CLIENT Client, PULONG64 MaxHandles ) { static ULONG CachedUniqueState = INVALID_UNIQUE_STATE; static ULONG LastSession = INVALID_SESSION; static ULONG64 LastMaxHandles = 0;
ULONG CurrentUniqueState = UniqueTargetState;
HRESULT hr;
if (MaxHandles == NULL) return E_INVALIDARG;
if (CurrentUniqueState != INVALID_UNIQUE_STATE && CachedUniqueState == CurrentUniqueState && LastSession == SessionId) { *MaxHandles = LastMaxHandles; return S_OK; }
if (Client == NULL) return E_INVALIDARG;
OutputControl OutCtl(Client);
hr = S_FALSE;
if (TargetClass != DEBUG_CLASS_USER_WINDOWS) { CHAR SymName[80];
sprintf(SymName, "%s!gcMaxHmgr", GDIKM_Module.Name); hr = ReadSymbolData(Client, SymName, MaxHandles, sizeof(*MaxHandles), NULL); if (hr != S_OK) { OutCtl.OutErr("Unable to get contents of %s\n", SymName); } }
if (hr != S_OK) { ULONG64 Module; ULONG TypeId;
if ((hr = GetTypeId(Client, "_GDI_SHARED_MEMORY", &TypeId, &Module)) == S_OK) { ULONG NumHandles;
hr = GetFieldSize(Client, Module, TypeId, "aentryHmgr", NULL, &NumHandles, NULL);
if (hr == S_OK) { *MaxHandles = NumHandles; } else { OutCtl.OutErr("Unable to get length of _GDI_SHARED_MEMORY.aentryHmgr\n"); } } }
if (hr == S_OK) { CachedUniqueState = CurrentUniqueState; LastSession = SessionId; LastMaxHandles = *MaxHandles; }
return hr; }
/******************************Public*Routine******************************\
* * Routine Name: * * GetEntryAddress * * Routine Description: * * looks up hmgr entry for an engine handle index * * Arguments: * * Client - PDEBUG_CLIENT * Index64 -- engine handle index * * Return Value: * * address of handle manager entry * \**************************************************************************/
HRESULT GetEntryAddress( PDEBUG_CLIENT Client, ULONG64 Handle64, PULONG64 EntryAddr, PBOOL Physical ) { HRESULT hr; ULONG64 Index; ULONG64 MaxIndex; ULONG64 TableAddr; ULONG EntSize;
*EntryAddr = 0; *Physical = FALSE;
if ((hr = GetIndexFromHandle(Client, Handle64, &Index)) == S_OK && (hr = GetHandleTable(Client, &TableAddr)) == S_OK && (hr = GetMaxHandles(Client, &MaxIndex)) == S_OK) { if (Index >= MaxIndex) { OutputControl OutCtl(Client); OutCtl.OutVerb("Bad index: Index (%I64x) >= Max Handles (%I64x)\n", Index, MaxIndex);
hr = S_FALSE; } else { if ((EntSize = GetEntrySize(Client)) == 0) { hr = S_FALSE; } } }
if (hr == S_OK) { if (SessionId != CURRENT_SESSION) { *Physical = TRUE; hr = GetPhysicalAddress(Client, SessionId, TableAddr + EntSize * Index, EntryAddr); } else { *EntryAddr = TableAddr + EntSize * Index; } }
return hr; }
/******************************Public*Routine******************************\
* * Routine Name: * * GetObjectAddress * * Routine Desciption: * * Converts an engine handle to an address of an object * * Arguments: * * Client - PDEBUG_CLIENT * Handle64 -- engine handle * ValidateBaseObj -- verifies _BASEOBJECT.hHmgr == Handle64 * ExcpectedType -- Object type expected to find * * Return Value: * * Address of object if Handle64 leads to valid object of ExpectedType * otherwise 0. * \**************************************************************************/
HRESULT GetObjectAddress( PDEBUG_CLIENT Client, ULONG64 Handle64, PULONG64 Address, UCHAR ExpectedType, BOOL ValidateFullUnique, BOOL ValidateBaseObj ) { HRESULT hr; PDEBUG_CONTROL Control; PDEBUG_SYMBOLS Symbols; ULONG64 EntryAddr; BOOL Physical; UCHAR Type; ULONG64 ObjAddr = 0;
if (Address != NULL) *Address = 0;
if (Client == NULL) return E_INVALIDARG;
if ((hr = Client->QueryInterface(__uuidof(IDebugControl), (void **)&Control)) != S_OK) { return hr; }
if ((hr = Client->QueryInterface(__uuidof(IDebugSymbols), (void **)&Symbols)) != S_OK) { Control->Release(); return hr; }
OutputControl OutCtl(Client);
if ((hr = GetEntryAddress(Client, Handle64, &EntryAddr, &Physical)) == S_OK) { ULONG64 EntryModule = 0; ULONG EntryTypeId = 0; ULONG64 HandlesFullUnique; DEBUG_VALUE FullUnique; DEBUG_VALUE Objt; DEBUG_VALUE pobj; TypeOutputParser EntryReader(Client); OutputState OutState(Client); ULONG TypeOutFlags = DEBUG_OUTTYPE_RECURSION_LEVEL(((Physical || !ValidateBaseObj) ? 1 : 2));
if ((hr = OutState.Setup(0, &EntryReader)) == S_OK && (hr = OutState.OutputType(Physical, EntryAddr, Entry.Module, Entry.TypeId, TypeOutFlags)) == S_OK) { if (ExpectedType != ANY_TYPE) { if ((hr = EntryReader.Get(&Objt, "Objt", DEBUG_VALUE_INT8)) != S_OK) { OutCtl.OutErr("Unable to get entry's object type, %s.\n", pszHRESULT(hr)); }
if (hr == S_OK && ExpectedType != Objt.I8) { OutCtl.OutVerb(" Expected type (0x%lx) doesn't match entry's (0x%lx)\n", (ULONG)ExpectedType, (ULONG)Objt.I8); hr = S_FALSE; } }
if (hr == S_OK && ValidateFullUnique) { if ((hr = EntryReader.Get(&FullUnique, "FullUnique", DEBUG_VALUE_INT64)) != S_OK) { OutCtl.OutErr("Unable to get entry's full unique value, %s.\n", pszHRESULT(hr)); }
if (hr == S_OK && (hr = GetFullUniqueFromHandle(Client, Handle64, &HandlesFullUnique)) != S_OK) { OutCtl.OutErr("Unable to extract full unique value from handle, %s.\n", pszHRESULT(hr)); }
if (hr == S_OK && HandlesFullUnique != FullUnique.I64) { OutCtl.OutVerb(" Handle's full unique value (0x%p) doesn't match entry's (0x%p)\n", HandlesFullUnique, FullUnique.I64); hr = S_FALSE; } }
// If valid so far, get the object address.
if (hr == S_OK) { if ((hr = EntryReader.Get(&pobj, "pobj", DEBUG_VALUE_INT64)) != S_OK) { OutCtl.OutErr("Unable to get entry's object address, %s.\n", pszHRESULT(hr)); } else { ObjAddr = pobj.I64; } }
if (hr == S_OK && ValidateBaseObj) { DEBUG_VALUE ObjHandle;
if (Physical) { hr = OutState.OutputTypeVirtual(ObjAddr, "_BASEOBJECT", 0); }
if (hr != S_OK || (hr = EntryReader.Get(&ObjHandle, "hHmgr", DEBUG_VALUE_INT64)) != S_OK) { OutCtl.OutErr("Unable to read object's base info, %s.\n", pszHRESULT(hr)); }
if (hr == S_OK && ObjHandle.I64 != Handle64) { // If Handle64's full unique bits weren't validated and
// Handle64 doesn't match hHmgr in baseobj,
// set them to to full unique from entry.
if (!ValidateFullUnique) { if ((hr = EntryReader.Get(&FullUnique, "FullUnique", DEBUG_VALUE_INT64)) != S_OK) { OutCtl.OutErr("Unable to get entry's full unique value, %s.\n", pszHRESULT(hr)); }
// Make sure HandleFullUnique is valid
if (hr == S_OK && (hr = GetFullUniqueFromHandle(Client, 0, NULL)) != S_OK) { OutCtl.OutErr("Unable to compose handle from entry, %s.\n", pszHRESULT(hr)); } else { Handle64 = (Handle64 & ~(HandleFullUnique->Mask)) | (FullUnique.I64 << HandleFullUnique->BitPos);
if (Control->IsPointer64Bit() != S_OK) { Handle64 = DEBUG_EXTEND64(Handle64); } } }
if (hr == S_OK && ObjHandle.I64 != Handle64) { OutCtl.OutVerb(" Handle (0x%p) doesn't match object's hHmgr (0x%p)\n", Handle64, ObjHandle.I64); hr = S_FALSE; } } } } } if (hr == S_OK && Address != NULL) { *Address = ObjAddr; }
Symbols->Release(); Control->Release();
return hr; }
/******************************Public*Routine******************************\
* * Routine Name: * * GetObjectHandle * * Routine Desciption: * * Retrieves handle of an object from it address * * Arguments: * * Client -- PDEBUG_CLIENT * ObjectAddr -- Address of OBJECT * Handle64 -- ULONG64 to receive engine handle * ValidateHandle -- verifies ENTRY.pobj == ObjectAddr * ExcpectedType -- Object type expected to find * Currently only value when ValidateHandle is TRUE * * Return Value: * * HRESULT of retrieval attempts and validation. * S_OK indicates everything succeeded. * \**************************************************************************/
HRESULT GetObjectHandle( PDEBUG_CLIENT Client, ULONG64 ObjectAddr, PULONG64 Handle64, BOOL ValidateHandle, UCHAR ExpectedType ) { HRESULT hr; DEBUG_VALUE ObjHandle; TypeOutputParser ObjectReader(Client); OutputState OutState(Client);
if (Handle64 != NULL) *Handle64 = 0;
if (ObjectAddr == 0) return E_INVALIDARG;
if ((hr = OutState.Setup(0, &ObjectReader)) == S_OK && (hr = OutState.OutputTypeVirtual(ObjectAddr, "_BASEOBJECT", 0)) == S_OK) { hr = ObjectReader.Get(&ObjHandle, "hHmgr", DEBUG_VALUE_INT64); }
if (hr == S_OK && ValidateHandle) { ULONG64 ObjectAddrFromHmgr;
hr = GetObjectAddress(Client, ObjHandle.I64, &ObjectAddrFromHmgr, ExpectedType, TRUE, FALSE);
if (hr == S_OK && ObjectAddrFromHmgr != ObjectAddr) { hr = S_FALSE; } }
if (hr == S_OK && Handle64 != NULL) { *Handle64 = ObjHandle.I64; }
return hr; }
/******************************Public*Routine******************************\
* * Routine Name: * * OutputHandleInfo * * Routine Desciption: * * Retrieves handle of an object from it address * * Arguments: * * Client -- PDEBUG_CLIENT * Handle64 -- engine handle * * Return Value: * * HRESULT of retrieval attempts and validation. * S_OK indicates everything succeeded. * \**************************************************************************/
HRESULT OutputHandleInfo( OutputControl *OutCtl, PDEBUG_CLIENT Client, PDEBUG_VALUE Handle ) { if (Client == NULL || OutCtl == NULL || Handle == NULL) { return E_INVALIDARG; }
HRESULT hrRet; HRESULT hr; DEBUG_VALUE ConvValue; ULONG64 Type; ULONG64 FullType; ULONG64 Stock; ENUMDEF *pEnumDef;
if (Handle->Type != DEBUG_VALUE_INT64) { if ((hr = OutCtl->CoerceValue(Handle, DEBUG_VALUE_INT64, &ConvValue)) != S_OK) { return hr; }
Handle = &ConvValue; }
if (Handle->I64 == 0) { return S_OK; }
hrRet = GetTypeFromHandle(Client, Handle->I64, &Type);
if (hrRet == S_OK) { DbgPrint("Handle 0x%I64x's type is %I64x.\n", Handle->I64, Type);
pEnumDef = aedENTRY_Objt;
while (pEnumDef->psz != NULL) { if (pEnumDef->ul == Type) { OutCtl->Output(pEnumDef->psz); break; }
pEnumDef++; }
if (pEnumDef->psz == NULL) { OutCtl->Output("Unknown type %I64d", Type); } } else { OutCtl->Output("Unable to extract type"); }
hr = GetFullTypeFromHandle(Client, Handle->I64, &FullType, GET_BITS_UNSHIFTED);
if (hr == S_OK) { DbgPrint("Handle 0x%I64x's Full Type is %I64x.\n", Handle->I64, FullType);
pEnumDef = aedENTRY_FullType;
while (pEnumDef->psz != NULL) { if (pEnumDef->ul == FullType) { OutCtl->Output(" : %s", pEnumDef->psz); break;; }
pEnumDef++; }
if (pEnumDef->psz == NULL) { ULONG64 AltType;
hr = GetAltTypeFromHandle(Client, Handle->I64, &AltType);
if (hr == S_OK && AltType != 0) { OutCtl->Output(" : Unknown alt type %I64d", AltType); } } } else if (hrRet == S_OK) { hrRet = hr; }
hr = GetStockFromHandle(Client, Handle->I64, &Stock);
if (hr == S_OK) { if (Stock) { OutCtl->Output(" (STOCK)"); } } else if (hrRet == S_OK) { hrRet = hr; }
return hrRet; }
HRESULT OutputFullUniqueInfo( OutputControl *OutCtl, PDEBUG_CLIENT Client, PDEBUG_VALUE FullUnique ) { if (Client == NULL || OutCtl == NULL || FullUnique == NULL) { return E_INVALIDARG; }
HRESULT hr; ULONG64 FullUniqTest; DEBUG_VALUE Handle;
hr = GetFullUniqueFromHandle(Client, -1, &FullUniqTest);
if (hr == S_OK) { if (FullUniqTest == 0) { hr = S_FALSE; } else { if (FullUnique->Type == DEBUG_VALUE_INT64) { Handle = *FullUnique; } else { hr = OutCtl->CoerceValue(FullUnique, DEBUG_VALUE_INT64, &Handle);
if (hr != S_OK) return hr; }
Handle.I64 <<= HandleFullUnique->BitPos;
hr = OutputHandleInfo(OutCtl, Client, &Handle); } }
return hr; }
char *pszTypes[] = { "DEF_TYPE ", "DC_TYPE ", "UNUSED1 ", "UNUSED2 ", "RGN_TYPE ", "SURF_TYPE ", "CLIOBJ_TYPE ", "PATH_TYPE ", "PAL_TYPE ", "ICMLCS_TYPE ", "LFONT_TYPE ", "RFONT_TYPE ", "PFE_TYPE ", "PFT_TYPE ", "ICMCXF_TYPE ", "ICMDLL_TYPE ", "BRUSH_TYPE ", "UNUSED3 ", "UNUSED4 ", "SPACE_TYPE ", "UNUSED5 ", "META_TYPE ", "EFSTATE_TYPE ", "BMFD_TYPE ", "VTFD_TYPE ", "TTFD_TYPE ", "RC_TYPE ", "TEMP_TYPE ", "DRVOBJ_TYPE ", "DCIOBJ_TYPE ", "SPOOL_TYPE ", "TOTALS ", "DEF " };
/******************************Public*Routine******************************\
* DECLARE_API( dumphmgr ) * * Dumps the count of handles in Hmgr for each object type. * * History: * 21-Feb-1995 -by- Lingyun Wang [lingyunw] * Wrote it. \**************************************************************************/
/*
HmgCurrentNumberOfObjects HmgMaximumNumberOfObjects HmgCurrentNumberOfLookAsideObjects HmgMaximumNumberOfLookAsideObjects HmgNumberOfObjectsAllocated HmgNumberOfLookAsideHits HmgCurrentNumberOfHandles HmgMaximumNumberOfHandles HmgNumberOfHandlesAllocated */
DECLARE_API( dumphmgr ) { INIT_API(); ExtWarn("Extension 'dumphmgr' is not fully converted.\n"); HRESULT hr; ULONG64 pent; ULONG64 gcMaxHmgr; ULONG entSize;
DEBUG_VALUE ObjType;
ULONG ulLoop; // loop variable
ULONG pulCount[MAX_TYPE + 2]; ULONG cUnknown = 0; ULONG cUnknownSize = 0; ULONG cUnused = 0;
DecArrayDumper(HmgCurrentNumberOfHandles, ULONG); DecArrayDumper(HmgMaximumNumberOfHandles, ULONG); DecArrayDumper(HmgNumberOfHandlesAllocated, ULONG); DecArrayDumper(HmgCurrentNumberOfObjects, ULONG); DecArrayDumper(HmgMaximumNumberOfObjects, ULONG); DecArrayDumper(HmgNumberOfObjectsAllocated, ULONG); DecArrayDumper(HmgCurrentNumberOfLookAsideObjects, ULONG); DecArrayDumper(HmgMaximumNumberOfLookAsideObjects, ULONG); DecArrayDumper(HmgNumberOfLookAsideHits, ULONG);
char *TableHeader; char TableFormat[128];
while (*args && isspace(*args)) args++; if (*args != '\0') { ExtOut("dumphmgr displays the count of each type of object in the handle manager\n" "\n" "Usage: dumphmgr [-?]\n" " -? shows this help\n" "\n" " If available statics for Handles, Objects, and objects allocated\n" " from LookAside lists are shown. Each class has three statics:\n" " Cur - current number of items allocated\n" " Max - largest number of items ever allocated at one time\n" " Total - total allocations ever made for that item\n" );
EXIT_API(S_OK); }
// Get the pointers and counts
if ((hr = GetHandleTable(Client, &pent)) != S_OK || (hr = GetMaxHandles(Client, &gcMaxHmgr)) != S_OK) { EXIT_API(hr); } ExtOut("Handle Entry Table at 0x%p.\n", pent); ExtOut("Max handles out so far %I64u.\n", gcMaxHmgr);
entSize = GetEntrySize(Client);
if (!entSize || !gcMaxHmgr) { EXIT_API(S_FALSE); }
ULONG Reserved; ULONG64 Module; ULONG TypeId; if ((hr = GetTypeId(Client, "_GDI_SHARED_MEMORY", &TypeId, &Module)) == S_OK) { hr = GetFieldSize(Client, Module, TypeId, "aentryHmgr", &Reserved); }
// Print out the amount reserved and committed
ExtOut("Page Size: %lu Entry Size: %lu\n", PageSize, entSize); ExtOut("Total Hmgr: Reserved memory "); if (hr == S_OK) { ExtOut("%lu", Reserved); } else { ExtOut("?"); } ExtOut(" Committed %lu\n", ((( (ULONG)gcMaxHmgr * entSize) + PageSize) & ~(PageSize - 1))); ExtOut("\n");
for (ulLoop = 0; ulLoop <= TOTAL_TYPE; ulLoop++) { pulCount[ulLoop] = 0; }
TypeOutputParser TypeReader(Client); OutputState OutState(Client); ULONG64 EntryModule; ULONG EntryTypeId;
if ((hr = TypeReader.LookFor(&ObjType, "Objt", DEBUG_VALUE_INT8)) == S_OK && (hr = OutState.Setup(0, &TypeReader)) == S_OK) { if ((hr = GetTypeId(Client, szEntryType, &EntryTypeId, &EntryModule)) != S_OK) { ExtErr("GetTypeId(%s) failed.\n", szEntryType); } }
if (hr != S_OK) { ExtErr("Failed to prepare type read: %s\n", pszHRESULT(hr)); EXIT_API(hr); }
for (ulLoop = 0; ulLoop < gcMaxHmgr; ulLoop++) { if (g_pExtControl->GetInterrupt() == S_OK) { ExtErr("User cancled.\n"); EXIT_API(E_ABORT); }
TypeReader.DiscardOutput(); TypeReader.Relook(); if ((hr = OutState.OutputTypeVirtual(pent, EntryModule, EntryTypeId, 0)) != S_OK || (hr = TypeReader.ParseOutput()) != S_OK || (hr = TypeReader.Complete()) != S_OK) { ExtErr("Error reading table entry @ %p, %s\n", pent, pszHRESULT(hr)); ExtWarn("Only %lu entries were read.\n", ulLoop); break; }
if (ObjType.I8 == DEF_TYPE) { cUnused++; } if (ObjType.I8 > MAX_TYPE) { cUnknown++; } else { pulCount[ObjType.I8]++; }
pent += entSize; }
ULONG64 TmpOffset; // Have to pass an valid pointer when checking for a symbol.
if (g_pExtSymbols->GetOffsetByName(GDISymbol(HmgCurrentNumberOfObjects), &TmpOffset) == S_OK && HmgCurrentNumberOfObjects.ReadArray(GDISymbol(HmgCurrentNumberOfObjects)) && HmgMaximumNumberOfObjects.ReadArray(GDISymbol(HmgMaximumNumberOfObjects)) && HmgCurrentNumberOfLookAsideObjects.ReadArray(GDISymbol(HmgCurrentNumberOfLookAsideObjects)) && HmgMaximumNumberOfLookAsideObjects.ReadArray(GDISymbol(HmgMaximumNumberOfLookAsideObjects)) && HmgNumberOfObjectsAllocated.ReadArray(GDISymbol(HmgNumberOfObjectsAllocated)) && HmgNumberOfLookAsideHits.ReadArray(GDISymbol(HmgNumberOfLookAsideHits)) && HmgCurrentNumberOfHandles.ReadArray(GDISymbol(HmgCurrentNumberOfHandles)) && HmgMaximumNumberOfHandles.ReadArray(GDISymbol(HmgMaximumNumberOfHandles)) && HmgNumberOfHandlesAllocated.ReadArray(GDISymbol(HmgNumberOfHandlesAllocated)) ) { ExtOut(" Current ---- Handles ----- ---- Objects ----- --- LookAside ----\n" " TYPE Handles Cur Max Total Cur Max Total Cur Max Total\n");
_snprintf(TableFormat, sizeof(TableFormat), "%%s%%6lu %%c %s %s %s %s %s %s %s %s %s\n", HmgCurrentNumberOfHandles.SetPrintFormat(5), HmgMaximumNumberOfHandles.SetPrintFormat(5), HmgNumberOfHandlesAllocated.SetPrintFormat(6), HmgCurrentNumberOfObjects.SetPrintFormat(5), HmgMaximumNumberOfObjects.SetPrintFormat(5), HmgNumberOfObjectsAllocated.SetPrintFormat(6), HmgCurrentNumberOfLookAsideObjects.SetPrintFormat(5), HmgMaximumNumberOfLookAsideObjects.SetPrintFormat(5), HmgNumberOfLookAsideHits.SetPrintFormat(6) ); } else { ExtOut(" Current\n" " TYPE Handles\n");
_snprintf(TableFormat, sizeof(TableFormat), "%%s%%6lu\n"); }
// init the totals
pulCount[TOTAL_TYPE] = 0; HmgCurrentNumberOfObjects[TOTAL_TYPE] = 0; HmgCurrentNumberOfLookAsideObjects[TOTAL_TYPE] = 0; HmgMaximumNumberOfHandles[TOTAL_TYPE] = 0; HmgMaximumNumberOfObjects[TOTAL_TYPE] = 0; HmgMaximumNumberOfLookAsideObjects[TOTAL_TYPE] = 0; HmgNumberOfHandlesAllocated[TOTAL_TYPE] = 0; HmgNumberOfObjectsAllocated[TOTAL_TYPE] = 0; HmgNumberOfLookAsideHits[TOTAL_TYPE] = 0;
// now go through printing each line and accumulating totals
for (ulLoop = 0; ulLoop <= MAX_TYPE; ulLoop++) { ExtOut(TableFormat, pszTypes[ulLoop], pulCount[ulLoop], ((pulCount[ulLoop] == HmgCurrentNumberOfHandles[ulLoop]) ? '=' : ((pulCount[ulLoop] < HmgCurrentNumberOfHandles[ulLoop]) ? '<' : '>')), HmgCurrentNumberOfHandles[ulLoop], HmgMaximumNumberOfHandles[ulLoop], HmgNumberOfHandlesAllocated[ulLoop], HmgCurrentNumberOfObjects[ulLoop], HmgMaximumNumberOfObjects[ulLoop], HmgNumberOfObjectsAllocated[ulLoop], HmgCurrentNumberOfLookAsideObjects[ulLoop], HmgMaximumNumberOfLookAsideObjects[ulLoop], HmgNumberOfLookAsideHits[ulLoop]);
if (ulLoop != DEF_TYPE) { pulCount[TOTAL_TYPE] += pulCount[ulLoop];
HmgCurrentNumberOfHandles[TOTAL_TYPE] += HmgCurrentNumberOfHandles[ulLoop]; HmgMaximumNumberOfHandles[TOTAL_TYPE] += HmgMaximumNumberOfHandles[ulLoop]; HmgNumberOfHandlesAllocated[TOTAL_TYPE] += HmgNumberOfHandlesAllocated[ulLoop];
HmgCurrentNumberOfObjects[TOTAL_TYPE] += HmgCurrentNumberOfObjects[ulLoop]; HmgMaximumNumberOfObjects[TOTAL_TYPE] += HmgMaximumNumberOfObjects[ulLoop]; HmgNumberOfObjectsAllocated[TOTAL_TYPE] += HmgNumberOfObjectsAllocated[ulLoop];
HmgCurrentNumberOfLookAsideObjects[TOTAL_TYPE] += HmgCurrentNumberOfLookAsideObjects[ulLoop]; HmgMaximumNumberOfLookAsideObjects[TOTAL_TYPE] += HmgMaximumNumberOfLookAsideObjects[ulLoop]; HmgNumberOfLookAsideHits[TOTAL_TYPE] += HmgNumberOfLookAsideHits[ulLoop]; }
}
ExtOut(TableFormat, pszTypes[TOTAL_TYPE], pulCount[TOTAL_TYPE], ((pulCount[TOTAL_TYPE] == HmgCurrentNumberOfHandles[TOTAL_TYPE]) ? '=' : ((pulCount[TOTAL_TYPE] < HmgCurrentNumberOfHandles[TOTAL_TYPE]) ? '<' : '>')), HmgCurrentNumberOfHandles[TOTAL_TYPE], HmgMaximumNumberOfHandles[TOTAL_TYPE], HmgNumberOfHandlesAllocated[TOTAL_TYPE], HmgCurrentNumberOfObjects[TOTAL_TYPE], HmgMaximumNumberOfObjects[TOTAL_TYPE], HmgNumberOfObjectsAllocated[TOTAL_TYPE], HmgCurrentNumberOfLookAsideObjects[TOTAL_TYPE], HmgMaximumNumberOfLookAsideObjects[TOTAL_TYPE], HmgNumberOfLookAsideHits[TOTAL_TYPE]);
ExtOut ("\ncUnused objects %lu\n", cUnused);
ExtOut("cUnknown objects %lu %lu\n",cUnknown,cUnknownSize);
EXIT_API(S_OK); }
char *pszTypes2[] = { "DEF", "DC", "UNUSED_2", // "LDB",
"UNUSED_3", // "PDB",
"RGN", "SURF", "CLIOBJ", "PATH", "PAL", "ICMLCS", "LFONT", "RFONT", "PFE", "PFT", "ICMCXF", "ICMDLL", "BRUSH", "UNUSED_17", // "D3D_HANDLE",
"UNUSED_18", // "CACHE",
"SPACE", "UNUSED_20", // "DBRUSH"
"META", "EFSTATE", "BMFD", "VTFD", "TTFD", "RC", "TEMP", "DRVOBJ", "DCIOBJ", "SPOOL" };
/******************************Public*Class********************************\
* class AccumPidObjects * \**************************************************************************/
class PidObjects { public: ULONG Pid; PidObjects *pNextPid; PidObjects *pPrevPid; Array<ULONG> TypeCount;
PidObjects(ULONG Pid_, ULONG TotalTypes) : TypeCount(TotalTypes) { Pid = Pid_; pNextPid = NULL; pPrevPid = NULL; } };
class AccumPidObjects { public: AccumPidObjects(ULONG ulMaxType_, char **pszTypeDesc_); ~AccumPidObjects();
HRESULT Valid();
VOID Add(ULONG Type) { ObjectTotals[Type]++; ObjectTotals[ulMaxType]++; }
HRESULT Add(ULONG Pid, ULONG Type); HRESULT OutputResults(OutputControl *OutCtl, Array<BOOL> &ShowZeroCountForType);
void Reset();
Array<ULONG> ObjectTotals;
private: PidObjects *GetFirstPid(); PidObjects *GetEntry(ULONG Pid);
ULONG ulMaxType; ULONG ulMaxObjectsPerPid; PidObjects *PidList; // Linked list of Pids
char **pszTypeDesc;
Array<ULONG> ColWidth; };
AccumPidObjects::AccumPidObjects( ULONG ulMaxType_, char **pszTypeDesc_ ) : ObjectTotals(ulMaxType_+1), ColWidth(ulMaxType_+1) { ulMaxType = ulMaxType_; PidList = NULL; pszTypeDesc = pszTypeDesc_;
Reset(); }
AccumPidObjects::~AccumPidObjects() { PidObjects *pPO, *pPONext;
pPO = GetFirstPid();
while (pPO != NULL) { pPONext = pPO->pNextPid; delete pPO; pPO = pPONext; } }
HRESULT AccumPidObjects::Valid() { return ((ulMaxType > 0) ? S_OK : S_FALSE); }
HRESULT AccumPidObjects::Add( ULONG Pid, ULONG Type ) { PidObjects *pEntry;
pEntry = GetEntry(Pid);
if (pEntry == NULL) return E_FAIL;
Add(Type);
pEntry->TypeCount[Type]++; pEntry->TypeCount[ulMaxType]++;
if (pEntry->TypeCount[ulMaxType] > ulMaxObjectsPerPid) { ulMaxObjectsPerPid = pEntry->TypeCount[ulMaxType]; PidList = pEntry; }
return S_OK; }
HRESULT AccumPidObjects::OutputResults( OutputControl *OutCtl, Array<BOOL> &ShowZeroCountForType ) { HRESULT hr = S_OK; PidObjects *pPO; ULONG Type;
// Output headers
hr = OutCtl->Output("Pid\\Type %*s", ColWidth[ulMaxType], "Total"); for (Type = 0; hr == S_OK && Type < ulMaxType; Type++) { if (ObjectTotals[Type] > 0 || ShowZeroCountForType[Type]) { hr = OutCtl->Output(" %*s", ColWidth[Type], pszTypeDesc[Type]); } } if (hr == S_OK) hr = OutCtl->Output("\n");
// Output per PID results
for (pPO = GetFirstPid(); hr == S_OK && pPO != NULL; pPO = pPO->pNextPid) { hr = OutCtl->Output("%8lx: %*lu", pPO->Pid, ColWidth[ulMaxType], pPO->TypeCount[ulMaxType]);
for (Type = 0; hr == S_OK && Type < ulMaxType; Type++) { if (ObjectTotals[Type] > 0 || ShowZeroCountForType[Type]) { hr = OutCtl->Output(" %*lu", ColWidth[Type], pPO->TypeCount[Type]); } }
if (hr == S_OK) hr = OutCtl->Output("\n"); }
// Output totals
hr = OutCtl->Output(" Totals: %*lu", ColWidth[ulMaxType], ObjectTotals[ulMaxType]);
for (Type = 0; hr == S_OK && Type < ulMaxType; Type++) { if (ObjectTotals[Type] > 0 || ShowZeroCountForType[Type]) { hr = OutCtl->Output(" %*lu", ColWidth[Type], ObjectTotals[Type]); } }
OutCtl->Output("\n");
return hr; }
void AccumPidObjects::Reset() { PidObjects *pPO, *pPONext; ULONG i;
pPO = GetFirstPid();
while (pPO != NULL) { pPONext = pPO->pNextPid; delete pPO; pPO = pPONext; }
PidList = NULL; ulMaxObjectsPerPid = 0;
for (i = 0; i < ulMaxType; i++) { ObjectTotals[i] = 0; ColWidth[i] = max(6, strlen(pszTypeDesc[i])); }
ObjectTotals[ulMaxType] = 0; ColWidth[ulMaxType] = 8; }
PidObjects* AccumPidObjects::GetFirstPid() { PidObjects *pPO = PidList;
if (pPO != NULL) { while (pPO->pPrevPid != NULL) pPO = pPO->pPrevPid; }
return pPO; }
PidObjects* AccumPidObjects::GetEntry( ULONG Pid ) { PidObjects *pPO = PidList;
if (pPO != NULL && pPO->Pid != Pid) { if (pPO->Pid < Pid) { while (pPO->pNextPid != NULL) { pPO = pPO->pNextPid;
if (pPO->Pid >= Pid) { break; } } } else { while (pPO->pPrevPid != NULL) { pPO = pPO->pPrevPid;
if (pPO->Pid <= Pid) { break; } } } }
if (pPO == NULL || pPO->Pid != Pid) { PidObjects *pPONew = new PidObjects(Pid, ulMaxType+1);
if (pPONew != NULL) { if (pPO == NULL) { PidList = pPONew; } else if (pPO->Pid < Pid) { pPONew->pNextPid = pPO->pNextPid; pPONew->pPrevPid = pPO;
pPO->pNextPid = pPONew; if (pPONew->pNextPid != NULL) { pPONew->pNextPid->pPrevPid = pPONew; } } else { pPONew->pNextPid = pPO; pPONew->pPrevPid = pPO->pPrevPid;
pPO->pPrevPid = pPONew; if (pPONew->pPrevPid != NULL) { pPONew->pPrevPid->pNextPid = pPONew; } } }
pPO = pPONew; }
return pPO; }
/******************************Public*Routine******************************\
* DECLARE_API( dumpobj ) * * History: * 21-Feb-1995 -by- Lingyun Wang [lingyunw] * Wrote it. * 29-Dec-2000 -by- Jason Hartman [jasonha] * Ported to Type debugging API. \**************************************************************************/
#define USE_READ 0
#define ENTRY_RECURSE_LEVELS 1
DECLARE_API( dumpobjr ) { HRESULT hr;
BEGIN_API( dumpobjr );
BOOL CheckType = TRUE; Array<BOOL> MatchType(TOTAL_TYPE); Array<CHAR> TypeList;
BOOL CheckPid = FALSE; BOOL ThisPid; DEBUG_VALUE MatchPid = {0, DEBUG_VALUE_INVALID}; BOOL TrackPerPid;
BOOL CheckLock = FALSE; BOOL Summary = FALSE; BOOL BadArg = FALSE;
BOOL UseIndex = FALSE; DEBUG_VALUE StartIndex = {0, DEBUG_VALUE_INVALID};
OutputControl OutCtl(Client); ULONG64 EntryAddr; ULONG64 gcMaxHmgr; ULONG EntrySize;
ULONG Index = 0;
ULONG LongestType = 0; int i;
for (i = 0; i <= MAX_TYPE; i++) { ULONG Len = strlen(pszTypes2[i]); if (Len > LongestType) { LongestType = Len; } }
while (!BadArg) { while (isspace(*args)) args++;
if (*args == '-') { // Process switches
args++; BadArg = (*args == '\0' || isspace(*args));
while (*args != '\0' && !isspace(*args)) { switch (tolower(*args)) { case 'a': if (CheckType && !TypeList.IsEmpty()) { BadArg = TRUE; OutCtl.OutErr("Error: -a may not be specified with a Type list.\n"); } else { CheckType = FALSE; } break; case 'i': if (CheckPid && MatchPid.Type == DEBUG_VALUE_INVALID) { BadArg = TRUE; OutCtl.OutErr("Error: PID value not found after -%c.\n", (ThisPid ? 'p' : 'n')); } else { UseIndex = TRUE; } break; case 'l': CheckLock = TRUE; break; case 'n': if (UseIndex && StartIndex.Type == DEBUG_VALUE_INVALID) { BadArg = TRUE; OutCtl.OutErr("Error: Index value not found after -i.\n"); } else if (CheckPid && ThisPid) { BadArg = TRUE; OutCtl.OutErr("Error: -n may not be used with -p.\n"); } else { CheckPid = TRUE; ThisPid = FALSE; } break; case 'p': if (UseIndex && StartIndex.Type == DEBUG_VALUE_INVALID) { BadArg = TRUE; OutCtl.OutErr("Error: Index value not found after -i.\n"); } if (CheckPid && !ThisPid) { BadArg = TRUE; OutCtl.OutErr("Error: -p may not be used with -n.\n"); } else { CheckPid = TRUE; ThisPid = TRUE; } break; case 's': Summary = TRUE; break; default: BadArg = TRUE; break; }
if (BadArg) break; args++; } } else { if (*args == '\0') break;
if (CheckPid && MatchPid.Type == DEBUG_VALUE_INVALID) { // This argument must be a PID.
CHAR EOPChar; PSTR EOP = (PSTR)args; ULONG Rem;
// Find end of string to evaulate as a pid
while (*EOP != '\0' && !isspace(*EOP)) EOP++; EOPChar = *EOP; *EOP = '\0';
if (isxdigit(*args) && Evaluate(Client, args, DEBUG_VALUE_INT32, EVALUATE_DEFAULT_RADIX, &MatchPid, &Rem) == S_OK && args + Rem == EOP) { args = EOP; } else { OutCtl.OutErr("Error: Couldn't evaluate '%s' as a PID.\n", args); BadArg = TRUE; } *EOP = EOPChar; } else if (UseIndex && StartIndex.Type == DEBUG_VALUE_INVALID) { // This argument must be the start Index.
CHAR EOIChar; PSTR EOI = (PSTR)args; ULONG Rem;
// Find end of string to evaulate as an index
while (*EOI != '\0' && !isspace(*EOI)) EOI++; EOIChar = *EOI; *EOI = '\0';
if (isxdigit(*args) && Evaluate(Client, args, DEBUG_VALUE_INT32, EVALUATE_DEFAULT_RADIX, &StartIndex, &Rem) == S_OK && args + Rem == EOI) { args = EOI; } else { OutCtl.OutErr("Error: Couldn't evaluate '%s' as an Index.\n", args); BadArg = TRUE; } *EOI = EOIChar; } else { // This argument must be a Type specification.
if (!CheckType) { OutCtl.OutErr("Error: a Type list may not be specified with -a.\n"); BadArg = TRUE; break; }
for (i = 0; i <= MAX_TYPE; i++) { SIZE_T CheckLen = strlen(pszTypes2[i]);
if (_strnicmp(args, pszTypes2[i], CheckLen) == 0 && (!iscsym(args[CheckLen]) || (_strnicmp(&args[CheckLen], "_TYPE", 5) == 0 && !iscsym(args[CheckLen+5]) ))) { if (!MatchType[i]) { // Add Type to list
SIZE_T CatLoc = TypeList.GetLength(); if (CatLoc > 0) { TypeList[CatLoc] = ' '; } TypeList.Set(pszTypes2[i], CheckLen+1, CatLoc); } MatchType[i] = TRUE; args += CheckLen; if (iscsym(*args)) args += 5; break; } }
if (i > MAX_TYPE) { OutCtl.OutErr("Error: Unknown Type in '%s'.\n", args); BadArg = TRUE; break; } } } }
if (!BadArg) { if (CheckType && TypeList.IsEmpty()) { OutCtl.OutErr("Error: Missing -a or Type list.\n"); BadArg = TRUE; } else if (CheckPid && MatchPid.Type == DEBUG_VALUE_INVALID) { OutCtl.OutErr("Error: Missing PID.\n"); BadArg = TRUE; } else if (UseIndex && StartIndex.Type == DEBUG_VALUE_INVALID) { OutCtl.OutErr("Error: Missing Index.\n"); BadArg = TRUE; } }
if (BadArg) { OutCtl.Output("Usage: dumpobj [-?ls] [-np PID] [-i Index] <-a | Type(s)>\n" "\n" " a - All object types\n" " i - Hmgr Entry Index to begin dump\n" " l - Check Lock\n" " n - Entries NOT owned by pid\n" " p - Entries owned by pid\n" " s - Summary counts only\n" "\n" " The -s option combined with the -a option will produce\n" " a list of the totals for each object type.\n");
OutCtl.Output("\n Valid Type values are:\n"); i = 0; while (i <= MAX_TYPE) { do { OutCtl.Output(" %-*s", LongestType, pszTypes2[i++]); } while (i <= MAX_TYPE && i%4); OutCtl.Output("\n"); }
return S_OK; }
//
// Get the pointers and counts from win32k
//
if ((hr = GetHandleTable(Client, &EntryAddr)) != S_OK || (hr = GetMaxHandles(Client, &gcMaxHmgr)) != S_OK) { return hr; } EntrySize = GetEntrySize(Client);
if (!gcMaxHmgr || !EntrySize || !EntryAddr) { OutCtl.OutErr("Error: gpentHmgr = %p, gcMaxHmgr = %I64u\n", EntryAddr, gcMaxHmgr); return S_OK; }
if (UseIndex) Index = StartIndex.I32;
OutCtl.Output("Searching %s %I64u entries starting at 0x%p", (Index ? "remaining" : "all"), gcMaxHmgr - Index, EntryAddr); if (SessionId != CURRENT_SESSION) { OutCtl.Output(" in session %s", SessionStr); } OutCtl.Output(".\n");
PDEBUG_CONTROL Control; PDEBUG_SYMBOLS Symbols; BOOL IsPointer64Bit; BOOL ComposeHandles; ULONG PointerSize;
if ((hr = Client->QueryInterface(__uuidof(IDebugControl), (void **)&Control)) != S_OK) { return hr; }
if ((hr = Client->QueryInterface(__uuidof(IDebugSymbols), (void **)&Symbols)) != S_OK) { Control->Release(); return hr; }
if (!Summary) { // Setup some things neded for listing entries.
IsPointer64Bit = (Control->IsPointer64Bit() == S_OK);
// Make sure HandleFullUnique is valid
hr = GetFullUniqueFromHandle(Client, 0, NULL); if (hr != S_OK) { OutCtl.OutWarn("Unable to compose handles from entries, %s.\n", pszHRESULT(hr)); } ComposeHandles = (hr == S_OK); }
OutCtl.Output("Object %s for %s objects", Summary ? "count" : "list", CheckType ? TypeList.GetBuffer() : "all");
if (CheckPid) { if (!ThisPid) OutCtl.Output(" NOT"); OutCtl.Output(" owned by PID 0x%lx\n", MatchPid.I32); } else { OutCtl.Output(" with any owner\n"); }
if (!Summary) { PointerSize = IsPointer64Bit ? 21 : 10;
// "0x1234 0x12345678 0xXX 0x12345678 1 4294967295 Tttt 0x1234 0xXX 0x...\n"
OutCtl.Output("Index Handle %-*s PID Lock ShareCount %-*s Unique %-*s Flags\n", PointerSize, "ObjectAddr", LongestType, "Type", PointerSize, "UserAddr"); }
TrackPerPid = (!CheckPid || !ThisPid);
AccumPidObjects ObjectCount(MAX_TYPE, pszTypes2);
TypeOutputParser TypeReader(Client); OutputState OutState(Client, FALSE); DEBUG_VALUE Type; #if ENTRY_RECURSE_LEVELS >= 2
DEBUG_VALUE Lock; #else
DEBUG_VALUE ulObj; #endif
DEBUG_VALUE PID; DEBUG_VALUE Unique; DEBUG_VALUE Flags; ULONG ObjsNotAssignedToPID = 0; ULONG FailedReads = 0; BOOL FailedRead = FALSE; BOOL NeedNewLine = FALSE;
HANDLE hHeap = GetProcessHeap(); PBYTE EntryBuffer = NULL; ULONG ObjtOffset;
if (hHeap != NULL && (EntryBuffer = (PBYTE)HeapAlloc(hHeap, 0, EntrySize)) != NULL && Symbols->GetFieldOffset(Entry.Module, Entry.TypeId, "Objt", &ObjtOffset) == S_OK && (hr = OutState.Setup(0, &TypeReader)) == S_OK) { for (Index = 0; Index < gcMaxHmgr; Index++, EntryAddr += EntrySize/*, DbgPrint(" }\n")*/) { // DbgPrint("{");
if (FailedRead) FailedReads++;
if (Index % 40 == 0) { OutCtl.Output((Summary ? DEBUG_OUTPUT_NORMAL : DEBUG_OUTPUT_VERBOSE), "."); NeedNewLine = TRUE; }
if (Control->GetInterrupt() == S_OK) { NeedNewLine = FALSE; OutCtl.OutErr("User aborted at index %lu\n", Index); hr = E_ABORT; break; }
TypeReader.DiscardOutput(); /* DbgPrint(" Read");
Symbols->ReadTypedDataVirtual(EntryAddr, Entry.Module, Entry.TypeId, EntryBuffer, EntrySize, NULL); DbgPrint("Type");*/ // DbgPrint(" Out");
if (SessionId != CURRENT_SESSION) { ULONG64 PhysEntryAddr;
if ((hr = GetPhysicalAddress(Client, SessionId, EntryAddr, &PhysEntryAddr)) == S_OK) { hr = OutState.OutputType(TRUE, PhysEntryAddr, Entry.Module, Entry.TypeId, DEBUG_OUTTYPE_NO_INDENT | DEBUG_OUTTYPE_NO_OFFSET | DEBUG_OUTTYPE_COMPACT_OUTPUT | DEBUG_OUTTYPE_RECURSION_LEVEL(ENTRY_RECURSE_LEVELS)); } } else { hr = OutState.OutputTypeVirtual(EntryAddr, Entry.Module, Entry.TypeId, DEBUG_OUTTYPE_NO_INDENT | DEBUG_OUTTYPE_NO_OFFSET | DEBUG_OUTTYPE_COMPACT_OUTPUT | DEBUG_OUTTYPE_RECURSION_LEVEL(ENTRY_RECURSE_LEVELS)); } // DbgPrint("Type");
if (hr == S_OK) { // DbgPrint(" Objt");
#if USE_READ
#else
hr = TypeReader.Get(&Type, "Objt", DEBUG_VALUE_INT32); #endif
if (hr != S_OK) Type.Type = DEBUG_VALUE_INVALID;
if (CheckType && ((FailedRead = (Type.Type != DEBUG_VALUE_INT32)) || !MatchType[Type.I32])) { // OutCtl.OutWarn("Type %lu doesn't match.\n", Type.I32);
continue; }
#if ENTRY_RECURSE_LEVELS >= 2
// DbgPrint(" Lock");
if (CheckLock && ((FailedRead = (TypeReader.Get(&Lock, "Lock", DEBUG_VALUE_INT32) != S_OK)) || Lock.I32 == 0)) { OutCtl.OutWarn("Lock required, but not locked.\n"); continue; }
// DbgPrint(" PID");
PID.Type = DEBUG_VALUE_INVALID; FailedRead = (TypeReader.Get(&PID, "Pid_Shifted", DEBUG_VALUE_INT32) != S_OK); PID.I32 *= 2;
if (CheckPid) { if (FailedRead || ((PID.I32 == MatchPid.I32) ? !ThisPid : ThisPid)) { continue; } } #else
ulObj.Type = DEBUG_VALUE_INVALID; FailedRead = (TypeReader.Get(&ulObj, "ulObj", DEBUG_VALUE_INT32) != S_OK); PID.Type = ulObj.Type; PID.I32 = (ulObj.I32 & ~1);
if (CheckLock || CheckPid) { if (FailedRead) { // OutCtl.OutWarn("ulObj is required, but wasn't read.\n");
continue; }
// DbgPrint(" Lock");
if (CheckLock && (ulObj.I32 & 1) == 0) { // OutCtl.OutWarn("Lock required, but not locked.\n");
continue; }
// DbgPrint(" PID");
if (CheckPid && (PID.I32 == MatchPid.I32) ? !ThisPid : ThisPid) { continue; } } #endif
FailedRead = (Type.Type != DEBUG_VALUE_INT32);
if (!FailedRead) { // DbgPrint(" MATCH");
if (TrackPerPid) { if (PID.Type != DEBUG_VALUE_INT32 || ObjectCount.Add(PID.I32, Type.I32) != S_OK) { ObjsNotAssignedToPID++; ObjectCount.Add(Type.I32); } } else { ObjectCount.Add(Type.I32); } }
if (!Summary) { PCSTR pszValue;
if (NeedNewLine) { OutCtl.OutVerb("\n"); NeedNewLine = FALSE; }
// Index
OutCtl.Output("0x%.4lx ", Index);
// Handle
if (ComposeHandles && TypeReader.Get(&Unique, "FullUnique", DEBUG_VALUE_INT64) == S_OK) { ULONG64 Handle64;
Handle64 = (Index & ~(HandleFullUnique->Mask)) | (Unique.I64 << HandleFullUnique->BitPos);
if (IsPointer64Bit) { Handle64 = DEBUG_EXTEND64(Handle64); }
OutCtl.Output("0x%p ", Handle64); } else { OutCtl.Output("%*s ", PointerSize, "?"); }
// ObjectAddr
if (TypeReader.Get(NULL, "pobj") == S_OK && TypeReader.GetValueString(&pszValue) == S_OK) { OutCtl.Output("%*s ", PointerSize, pszValue); } else { OutCtl.Output("%*s ", PointerSize, "?"); }
// PID
if (PID.Type == DEBUG_VALUE_INT32) { OutCtl.Output("0x%.8lx ", PID.I32); } else { OutCtl.Output(" ? "); }
// Lock
#if ENTRY_RECURSE_LEVELS >= 2
if (Lock.Type == DEBUG_VALUE_INT32 || TypeReader.Get(&Lock, "Lock", DEBUG_VALUE_INT32) == S_OK) { OutCtl.Output("%4lu ", Lock.I32); } else { OutCtl.Output(" ? "); } #else
if (ulObj.Type == DEBUG_VALUE_INT32) { OutCtl.Output("%4lu ", ulObj.I32 & 1); } else { OutCtl.Output(" ? "); } #endif
// ShareCount
OutCtl.Output("<Not Read> ");
// Type
if (Type.Type == DEBUG_VALUE_INT32 || TypeReader.Get(&Type, "Objt", DEBUG_VALUE_INT32) == S_OK) { OutCtl.Output("%-*s ", LongestType, pszTypes2[Type.I32]); } else { OutCtl.Output("%-*s ", LongestType, "?"); }
// Unique
if (Unique.Type == DEBUG_VALUE_INT64 || TypeReader.Get(&Unique, "FullUnique", DEBUG_VALUE_INT64) == S_OK) { OutCtl.Output("0x%.4I64x ", Unique.I64); } else { OutCtl.Output(" ? "); }
// UserAddr
if (TypeReader.Get(NULL, "pUser") == S_OK && TypeReader.GetValueString(&pszValue) == S_OK) { OutCtl.Output("%*s ", PointerSize, pszValue); } else { OutCtl.Output("%*s ", PointerSize, "?"); }
// Flags
if (TypeReader.Get(&Flags, "Flags", DEBUG_VALUE_INT64) == S_OK && TypeReader.GetValueString(&pszValue) == S_OK) { OutCtl.Output("%s (", pszValue); Flags.I64 = OutputFlags(&OutCtl, afdENTRY_Flags, Flags.I64, TRUE); OutCtl.Output(")"); if (Flags.I64) { OutCtl.Output(" Unknown Flags: 0x%I64x", Flags.I64); } } else { OutCtl.Output("?"); }
OutCtl.Output("\n"); } } else { FailedRead = TRUE; } }
if (FailedRead) FailedReads++;
if (NeedNewLine) { OutCtl.Output((Summary ? DEBUG_OUTPUT_NORMAL : DEBUG_OUTPUT_VERBOSE), "\n"); }
if (FailedReads) { OutCtl.OutWarn("Warning: %lu entry reads failed -> uncounted.\n", FailedReads); }
if (ObjsNotAssignedToPID) { OutCtl.OutWarn("Warning: %lu entries weren't assigned to a PID.\n", ObjsNotAssignedToPID); }
if (Index < gcMaxHmgr) { OutCtl.OutWarn("Warning: Entries at and beyond index 0x%lx weren't processed.\n", Index); }
// Display results
ObjectCount.OutputResults(&OutCtl, MatchType); }
if (EntryBuffer != NULL) { HeapFree(hHeap, 0, EntryBuffer); }
Symbols->Release(); Control->Release();
return S_OK; }
#if 1
#define TYPE_ALL 0
#define PID_ALL 0x8002
DECLARE_API( dumpobj ) { BEGIN_API( dumpobj ); INIT_API(); ExtWarn("Extension 'dumpobj' is not fully converted.\n"); HRESULT hr; ULONG64 pent; ULONG64 gcMaxHmgr; ULONG entSize; ULONG ulLoop; ULONG Pid = PID_ALL; BOOL AnyPid = TRUE; BOOL MatchPid = TRUE; ULONG Type = TYPE_ALL; BOOL bCheckLock = FALSE; BOOL bSummary = FALSE; BOOL bShareCount = FALSE; int i;
PARSE_ARGUMENTS(dumpobj_help);
if(ntok<1) { goto dumpobj_help; }
//find valid tokens - ignore the rest
bShareCount = (parse_iFindSwitch(tokens, ntok, 'c') >= 0); bCheckLock = (parse_iFindSwitch(tokens, ntok, 'l') >= 0); bSummary = (parse_iFindSwitch(tokens, ntok, 's') >= 0); MatchPid = !(parse_iFindSwitch(tokens, ntok, 'n') >= 0); tok_pos = parse_iFindSwitch(tokens, ntok, 'p'); if (tok_pos>=0) { tok_pos++;
if ((tok_pos+1)>=ntok) { goto dumpobj_help; //-p requires a pid and it can't be the last arg
}
AnyPid = FALSE; Pid = (LONG)GetExpression(tokens[tok_pos]); }
//find first non-switch token not preceeded by a -p
tok_pos = -1; do { tok_pos = parse_FindNonSwitch(tokens, ntok, tok_pos+1); } while ( (tok_pos!=-1)&&(parse_iIsSwitch(tokens, tok_pos-1, 'p'))); if(tok_pos==-1) { goto dumpobj_help; }
//CHECKLOOP
for (Type = 0; Type <= MAX_TYPE; ++Type) { if (parse_iIsToken(tokens, tok_pos, pszTypes2[Type]) || parse_iIsToken(tokens, tok_pos, pszTypes[Type])) { break; } }
if (Type > MAX_TYPE) { goto dumpobj_help; } //
// Get the pointers and counts from win32k
//
if ((hr = GetHandleTable(Client, &pent)) != S_OK || (hr = GetMaxHandles(Client, &gcMaxHmgr)) != S_OK) { EXIT_API(hr); } entSize = GetEntrySize(Client);
ExtVerb("gpentHmgr = %p, gcMaxHmgr = %I64u\n", pent, gcMaxHmgr);
if (!gcMaxHmgr || !entSize || !pent) { ExtErr("Error: gpentHmgr = %p, gcMaxHmgr = %I64u\n", pent, gcMaxHmgr); EXIT_API(S_OK); }
//
// dprintf out the amount reserved and committed, note we assume a 4K page size
//
dprintf("object list for %s type objects",Type == TYPE_ALL ? "ALL" : pszTypes2[Type]);
if (AnyPid) { dprintf(" with any owner\n"); } else { if (!MatchPid) dprintf(" NOT"); dprintf(" owned by PID 0x%lx\n",Pid); }
if(!bSummary) { dprintf("%4s, %8s, %6s, %6s, %4s, %8s, %8s, %6s, %6s, %8s,%9s\n", "I","handle","Lock","sCount","pid","pv","objt","unique","Flags","pUser","Tlock");
dprintf("--------------------------------------------------------------------------------------------\n"); }
{ LONG ObjCount = 0; LONG ObjArray[MAX_TYPE+1];
for(i=0;i<=MAX_TYPE;i++) { ObjArray[i]=0; }
//CHECKLOOP
for (ulLoop = 0; ulLoop < gcMaxHmgr; ulLoop++) { if (CheckControlC()) { ExtErr("User aborted at index %lu\n", ulLoop); EXIT_API(E_ABORT); }
if (bSummary && ulLoop % 40 == 0) ExtVerb(".");
ULONG error; ULONG objt; ULONG ThisPid; ULONG64 pobj; USHORT fullUnique; UCHAR flags; ULONG64 pUser; ULONG owner; ULONG shareCount;
if (error = GetFieldValue(pent, szEntryType, "Objt", objt)) { ExtErr("Error reading table entry\n"); ExtErr(" (GetFieldValue returned %s @ %p)\n", pszWinDbgError(error), pent); EXIT_API(S_OK); } if (error = GetFieldValue(pent, szEntryType, "ObjectOwner", owner)) { ExtErr("error reading table entry\n"); ExtErr(" (GetFieldValue returned %s)\n", pszWinDbgError(error)); EXIT_API(S_OK); } ThisPid = owner & PID_MASK;
if (0 && gbVerbose) { dprintf("Type: %lu, PID: %lu, Locked: %s\n", objt, ThisPid, (owner & LOCK_MASK) ? "YES" : "NO"); }
if ( ((objt == Type) || (Type == TYPE_ALL)) && (AnyPid || (MatchPid ? (ThisPid == Pid) : (ThisPid != Pid))) && ((!bCheckLock) || (owner & LOCK_MASK)) ) {
ObjCount++;
if (!bSummary) { if (GetFieldData(pent, szEntryType, "FullUnique", sizeof(fullUnique), &fullUnique)) { ExtErr("error reading FullUnique\n"); EXIT_API(S_OK); }
if (GetFieldData(pent, szEntryType, "Flags", sizeof(flags), &flags)) { ExtErr("error reading flags\n"); EXIT_API(S_OK); }
if (GetFieldData(pent, szEntryType, "pUser", sizeof(pUser), &pUser)) { ExtErr("error reading pUser\n"); EXIT_API(S_OK); }
if (GetFieldData(pent, szEntryType, "einfo.pobj", sizeof(pobj), &pobj)) { ExtErr("error reading einfo.pobj\n"); EXIT_API(S_OK); }
dprintf("%4lx, %08lx, %6lx", ulLoop, MAKE_HMGR_HANDLE(ulLoop,fullUnique), owner & LOCK_MASK);
if (!bShareCount) { dprintf(", Unread"); } else if (GetFieldData(pobj, GDIType(_BASEOBJECT), "ulShareCount", sizeof(shareCount), &shareCount)) { dprintf(", ??????"); } else { dprintf(", %6lx", shareCount); }
dprintf(", %4lx, %p", ThisPid, pobj);
dprintf(", %8s, %6hx, %6lx, %p, %p\n", pszTypes2[objt], fullUnique, flags, pUser, pUser); } else { ObjArray[objt]++; }
}
pent += entSize; }
if(bSummary && (Type==TYPE_ALL)) { for(i=0;i<=MAX_TYPE; i++) { if(ObjArray[i]>0) { dprintf("%s\t%ld\n", pszTypes2[i], ObjArray[i]); } } }
ExtOut("Total objects = %li",ObjCount); // Subtract any unused objects
if (bSummary && ObjArray[0]) { ExtOut(" - %li = %li", ObjArray[0], ObjCount - ObjArray[0]); } ExtOut("\n"); }
EXIT_API(S_OK);
dumpobj_help: dprintf("Usage: dumpobj [-?] [-n] [-p pid] [-l] [-s] object_type\n"); dprintf("\t-l check lock\n"); dprintf("\t-s summary\n"); dprintf("\t-n not pid\n\n"); dprintf(" The -s option combined with the DEF object type will produce\n" " a list of the totals for each object type.\n\n");
dprintf(" Valid object_type values are:\n"); for (i=0; i<=MAX_TYPE; ) { do { dprintf(" %-12s", pszTypes2[i++]); } while (i <= MAX_TYPE && i%4); dprintf("\n"); }
EXIT_API(S_OK); } #endif
/******************************Public*Routine******************************\
* DECLARE_API( dh ) * * Debugger extension to dump a handle. * * History: * 21-Feb-1995 -by- Lingyun Wang [lingyunw] * Wrote it. \**************************************************************************/
DECLARE_API( dh ) { BEGIN_API( dh );
HRESULT hr; DEBUG_VALUE Handle; ULONG64 offENTRY; BOOL Physical; OutputControl OutCtl(Client);
while (isspace(*args)) args++;
if (*args == '-' || (hr = Evaluate(Client, args, DEBUG_VALUE_INT64, 0, &Handle, NULL)) != S_OK || Handle.I64 == 0) { OutCtl.Output("Usage: dh [-?] <Handle>\n"); } else { OutCtl.Output("--------------------------------------------------\n"); OutCtl.Output("GDI Entry for handle 0x%p:\n", Handle.I64);
if ((hr = GetEntryAddress(Client, Handle.I64, &offENTRY, &Physical)) == S_OK) { OutputFilter OutFilter(Client); OutputState OutState(Client, FALSE); OutputControl OutCtl;
if ((hr = OutState.Setup(DEBUG_OUTPUT_NORMAL | DEBUG_OUTPUT_ERROR | DEBUG_OUTPUT_WARNING, &OutFilter)) == S_OK && (hr = OutCtl.SetControl(DEBUG_OUTCTL_THIS_CLIENT | DEBUG_OUTCTL_NOT_LOGGED, OutState.Client)) == S_OK) { hr = DumpType(OutState.Client, szEntryType, offENTRY, DEBUG_OUTTYPE_NO_INDENT | DEBUG_OUTTYPE_NO_OFFSET, &OutCtl, Physical);
if (hr == S_OK) { OutFilter.Skip(OUTFILTER_QUERY_EVERY_LINE | OUTFILTER_QUERY_WHOLE_WORD, "_EINFO"); OutFilter.Skip(OUTFILTER_SKIP_DEFAULT, "_OBJECTOWNER");
BOOL DumpObj = FALSE; DEBUG_VALUE Value; CHAR ReplacementText[80];
// Check for used vs free entry
if (OutFilter.Query("Objt", &Value, DEBUG_VALUE_INT8) == S_OK) { DumpObj = (Value.I8 != DEF_TYPE); OutFilter.Skip(OUTFILTER_QUERY_EVERY_LINE | OUTFILTER_QUERY_WHOLE_WORD, (Value.I8 == DEF_TYPE) ? "pobj" : "hFree"); }
// Account for Pid shifting
if (OutFilter.Query("Pid_Shifted", &Value, DEBUG_VALUE_INT32) == S_OK) { sprintf(ReplacementText, "Pid : 0x%lx (%ld)", 2*Value.I32, 2*Value.I32); OutFilter.Replace(OUTFILTER_REPLACE_LINE | OUTFILTER_QUERY_ONE_LINE, "Pid_Shifted", ReplacementText); }
hr = OutFilter.OutputText();
if (hr == S_OK && DumpObj) { if (TargetClass != DEBUG_CLASS_USER_WINDOWS) { if ((hr = OutFilter.Query("pobj", &Value, DEBUG_VALUE_INT64)) == S_OK) { // Restore OutCtl settings
OutCtl.SetControl(DEBUG_OUTCTL_AMBIENT, Client); OutCtl.Output("--------------------------------------------------\n");
if (Physical) { ULONG64 PhysAddr;
ASSERTMSG("HMGR Entry was looked up thru a physical address, but the SessionId is CURRENT.\n", SessionId != CURRENT_SESSION); hr = GetPhysicalAddress(Client, SessionId, Value.I64, &PhysAddr); if (hr == S_OK) { Value.I64 = PhysAddr; } else { OutCtl.OutErr("GDI BaseObject @ 0x%p in session %lu in unavailable.\n", Value.I64, SessionId); } }
if (hr == S_OK) { OutCtl.Output("GDI BaseObject @ %s0x%p:\n", ((Physical) ? "#" : ""), Value.I64);
hr = DumpType(Client, "_BASEOBJECT", Value.I64, DEBUG_OUTTYPE_NO_INDENT | DEBUG_OUTTYPE_NO_OFFSET, &OutCtl, Physical); } } } } }
if (hr != S_OK) { OutCtl.OutErr("Type Dump returned %s.\n", pszHRESULT(hr)); } } else { OutCtl.OutErr(" Output state/control setup returned %s.\n", pszHRESULT(hr)); } } else { OutCtl.Output(" ** Unable to find a valid entry address. **\n"); }
OutCtl.Output("--------------------------------------------------\n"); }
return S_OK; }
/******************************Public*Routine******************************\
* DECLARE_API( dht ) * * Debugger extension to extract type data from a handle. * * History: * 21-Feb-1995 -by- Lingyun Wang [lingyunw] * Wrote it. * 30-Nov-2000 -by- Jason Hartman [jasonha] * Ported to 64 bit debugger API. \**************************************************************************/
DECLARE_API( dht ) { BEGIN_API( dht );
HRESULT hr; DEBUG_VALUE Handle; ULONG64 Index; ULONG64 FullUnique; OutputControl OutCtl(Client);
while (isspace(*args)) args++;
if (*args == '-' || (hr = Evaluate(Client, args, DEBUG_VALUE_INT64, 0, &Handle, NULL)) != S_OK || Handle.I64 == 0) { OutCtl.Output("Usage: dht [-?] <Handle>\n"); } else { OutCtl.Output("Handle: 0x%p\n", Handle.I64);
if (GetIndexFromHandle(Client, Handle.I64, &Index) == S_OK) { OutCtl.Output(" Index: 0x%p\n", Index); } if (GetFullUniqueFromHandle(Client, Handle.I64, &FullUnique) == S_OK) { OutCtl.Output(" FullUnique: 0x%p\n", FullUnique); } OutCtl.Output(" Type: "); hr = OutputHandleInfo(&OutCtl, Client, &Handle); OutCtl.Output("\n"); }
return hr; }
|