/******************************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 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 &ShowZeroCountForType); void Reset(); Array ObjectTotals; private: PidObjects *GetFirstPid(); PidObjects *GetEntry(ULONG Pid); ULONG ulMaxType; ULONG ulMaxObjectsPerPid; PidObjects *PidList; // Linked list of Pids char **pszTypeDesc; Array 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 &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 MatchType(TOTAL_TYPE); Array 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(" "); // 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 [-?] \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 [-?] \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; }