You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3568 lines
101 KiB
3568 lines
101 KiB
|
|
/******************************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;
|
|
}
|
|
|