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.
1509 lines
40 KiB
1509 lines
40 KiB
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
extapi.cxx
|
|
|
|
Abstract:
|
|
|
|
This file contains the generic routines and initialization code
|
|
used by the debugger extensions routines.
|
|
|
|
Author:
|
|
|
|
Jason Hartman (JasonHa) 2000-08-18
|
|
|
|
Environment:
|
|
|
|
User Mode
|
|
|
|
--*/
|
|
|
|
#include "precomp.hxx"
|
|
|
|
const BOOL ClientInitialized = FALSE;
|
|
|
|
PDEBUG_ADVANCED g_pExtAdvanced;
|
|
PDEBUG_CLIENT g_pExtClient;
|
|
PDEBUG_CONTROL g_pExtControl;
|
|
PDEBUG_DATA_SPACES g_pExtData;
|
|
PDEBUG_REGISTERS g_pExtRegisters;
|
|
PDEBUG_SYMBOLS g_pExtSymbols;
|
|
PDEBUG_SYMBOL_GROUP g_pExtSymbolGroup;
|
|
PDEBUG_SYSTEM_OBJECTS g_pExtSystem;
|
|
|
|
|
|
#define REF_LIMIT 100
|
|
LONG ExtRefCount = 0;
|
|
BOOL ExtReady = FALSE;
|
|
|
|
#define MAX_NAME 2048
|
|
|
|
|
|
DefOutputCallbacks *g_pDefOutputCallbacks = NULL;
|
|
|
|
// Queries for all debugger interfaces.
|
|
extern "C" HRESULT
|
|
ExtQuery(PDEBUG_CLIENT Client)
|
|
{
|
|
HRESULT Hr;
|
|
LONG RefCheck;
|
|
|
|
// Have to have a client to start with;)
|
|
if (Client == NULL)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
RefCheck = InterlockedIncrement(&ExtRefCount);
|
|
|
|
if (RefCheck > REF_LIMIT)
|
|
{
|
|
DbgPrint("ExtQuery has calls exceeding limit.\n");
|
|
InterlockedDecrement(&ExtRefCount);
|
|
return S_FALSE;
|
|
}
|
|
|
|
if (RefCheck > 1)
|
|
{
|
|
// Wait until original refencer completes setup.
|
|
//
|
|
// If ExtRefCount drops below RefCheck then the
|
|
// original referencer failed as well as any
|
|
// waiters who started after us.
|
|
while (!ExtReady && ExtRefCount >= RefCheck)
|
|
Sleep(10);
|
|
|
|
if (ExtReady)
|
|
{
|
|
// Make sure the clients match
|
|
if (g_pExtClient != Client)
|
|
{
|
|
InterlockedDecrement(&ExtRefCount);
|
|
return S_FALSE;
|
|
}
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
// Prepare to query interfaces.
|
|
// Make sure no one is currently cleaning up.
|
|
while (ExtReady)
|
|
{
|
|
Sleep(10);
|
|
}
|
|
|
|
if ((Hr = Client->QueryInterface(__uuidof(IDebugAdvanced),
|
|
(void **)&g_pExtAdvanced)) != S_OK)
|
|
{
|
|
goto Fail;
|
|
}
|
|
if ((Hr = Client->QueryInterface(__uuidof(IDebugControl),
|
|
(void **)&g_pExtControl)) != S_OK)
|
|
{
|
|
goto Fail;
|
|
}
|
|
if ((Hr = Client->QueryInterface(__uuidof(IDebugDataSpaces),
|
|
(void **)&g_pExtData)) != S_OK)
|
|
{
|
|
goto Fail;
|
|
}
|
|
if ((Hr = Client->QueryInterface(__uuidof(IDebugRegisters),
|
|
(void **)&g_pExtRegisters)) != S_OK)
|
|
{
|
|
goto Fail;
|
|
}
|
|
if ((Hr = Client->QueryInterface(__uuidof(IDebugSymbols),
|
|
(void **)&g_pExtSymbols)) != S_OK)
|
|
{
|
|
goto Fail;
|
|
}
|
|
if ((Hr = g_pExtSymbols->CreateSymbolGroup(&g_pExtSymbolGroup)) != S_OK)
|
|
{
|
|
goto Fail;
|
|
}
|
|
if ((Hr = Client->QueryInterface(__uuidof(IDebugSystemObjects),
|
|
(void **)&g_pExtSystem)) != S_OK)
|
|
{
|
|
goto Fail;
|
|
}
|
|
|
|
// If symbols state has changed, make sure GDI symbols are loaded.
|
|
if (gbSymbolsNotLoaded)
|
|
{
|
|
SymbolLoad(Client);
|
|
}
|
|
|
|
g_pExtClient = Client;
|
|
|
|
ExtReady = TRUE;
|
|
|
|
return S_OK;
|
|
|
|
Fail:
|
|
ExtRelease(TRUE);
|
|
InterlockedDecrement(&ExtRefCount);
|
|
|
|
return Hr;
|
|
}
|
|
|
|
|
|
// Cleans up all debugger interfaces when there are no more references.
|
|
// A cleanup will be forced if Cleanup is TRUE.
|
|
void
|
|
ExtRelease(BOOL Cleanup)
|
|
{
|
|
// Don't decrement the count when forcing cleanup.
|
|
if (Cleanup || InterlockedDecrement(&ExtRefCount) < 1)
|
|
{
|
|
DbgPrint("Cleaning up interfaces.\n");
|
|
|
|
EXT_RELEASE(g_pExtAdvanced);
|
|
EXT_RELEASE(g_pExtControl);
|
|
EXT_RELEASE(g_pExtData);
|
|
EXT_RELEASE(g_pExtRegisters);
|
|
EXT_RELEASE(g_pExtSymbols);
|
|
EXT_RELEASE(g_pExtSystem);
|
|
g_pExtClient = NULL;
|
|
ExtReady = FALSE;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// Normal output.
|
|
void __cdecl
|
|
ExtOut(PCSTR Format, ...)
|
|
{
|
|
va_list Args;
|
|
|
|
if (g_pExtControl == NULL)
|
|
{
|
|
DbgPrint("g_pExtControl is NULL.\n");
|
|
return;
|
|
}
|
|
|
|
va_start(Args, Format);
|
|
g_pExtControl->OutputVaList(DEBUG_OUTPUT_NORMAL, Format, Args);
|
|
va_end(Args);
|
|
}
|
|
|
|
|
|
// Error output.
|
|
void __cdecl
|
|
ExtErr(PCSTR Format, ...)
|
|
{
|
|
va_list Args;
|
|
|
|
if (g_pExtControl == NULL)
|
|
{
|
|
DbgPrint("g_pExtControl is NULL.\n");
|
|
return;
|
|
}
|
|
|
|
va_start(Args, Format);
|
|
g_pExtControl->OutputVaList(DEBUG_OUTPUT_ERROR, Format, Args);
|
|
va_end(Args);
|
|
}
|
|
|
|
|
|
// Warning output.
|
|
void __cdecl
|
|
ExtWarn(PCSTR Format, ...)
|
|
{
|
|
va_list Args;
|
|
|
|
if (g_pExtControl == NULL)
|
|
{
|
|
DbgPrint("g_pExtControl is NULL.\n");
|
|
return;
|
|
}
|
|
|
|
va_start(Args, Format);
|
|
g_pExtControl->OutputVaList(DEBUG_OUTPUT_WARNING, Format, Args);
|
|
va_end(Args);
|
|
}
|
|
|
|
|
|
// Verbose output.
|
|
void __cdecl
|
|
ExtVerb(PCSTR Format, ...)
|
|
{
|
|
va_list Args;
|
|
|
|
if (g_pExtControl == NULL)
|
|
{
|
|
DbgPrint("g_pExtControl is NULL.\n");
|
|
return;
|
|
}
|
|
|
|
va_start(Args, Format);
|
|
g_pExtControl->OutputVaList(DEBUG_OUTPUT_VERBOSE, Format, Args);
|
|
va_end(Args);
|
|
}
|
|
|
|
|
|
|
|
ExtApiClass::ExtApiClass(
|
|
PDEBUG_CLIENT DbgClient
|
|
)
|
|
{
|
|
Client = DbgClient ? DbgClient : g_pExtClient;
|
|
|
|
if (Client != NULL)
|
|
{
|
|
Client->AddRef();
|
|
}
|
|
else
|
|
{
|
|
if (GetDebugClient(&Client) != S_OK)
|
|
{
|
|
DbgPrint("Error: Client creation failed.\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (ExtQuery(Client) != S_OK)
|
|
{
|
|
DbgPrint("Error: Interface queries failed.\n");
|
|
EXT_RELEASE(Client);
|
|
}
|
|
}
|
|
|
|
|
|
ExtApiClass::~ExtApiClass()
|
|
{
|
|
if (Client)
|
|
{
|
|
ExtRelease();
|
|
EXT_RELEASE(Client);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT
|
|
ReadSymbolData(
|
|
IN PDEBUG_CLIENT Client,
|
|
IN PCSTR Symbol,
|
|
OUT PVOID Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT OPTIONAL PULONG SizeRead
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
ULONG64 Module;
|
|
ULONG64 Offset;
|
|
ULONG TypeId;
|
|
ULONG TypeSize;
|
|
|
|
if (Buffer != NULL)
|
|
{
|
|
RtlZeroMemory(Buffer, BufferSize);
|
|
}
|
|
|
|
if (SizeRead != NULL)
|
|
{
|
|
*SizeRead = 0;
|
|
}
|
|
|
|
if (Client == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
OutputControl OutCtl(Client);
|
|
PDEBUG_SYMBOLS Symbols;
|
|
|
|
if ((hr = Client->QueryInterface(__uuidof(IDebugSymbols),
|
|
(void **)&Symbols)) != S_OK)
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
if ((hr = Symbols->GetOffsetByName(Symbol, &Offset)) == S_OK)
|
|
{
|
|
if ((hr = Symbols->GetSymbolTypeId(Symbol, &TypeId, &Module)) == S_OK &&
|
|
(hr = Symbols->GetTypeSize(Module, TypeId, &TypeSize)) == S_OK)
|
|
{
|
|
BufferSize = min(BufferSize, TypeSize);
|
|
|
|
if (SessionId == CURRENT_SESSION)
|
|
{
|
|
hr = Symbols->ReadTypedDataVirtual(Offset, Module, TypeId, Buffer, BufferSize, SizeRead);
|
|
}
|
|
else
|
|
{
|
|
ULONG64 OffsetPhys;
|
|
|
|
if ((hr = GetPhysicalAddress(Client,
|
|
SessionId,
|
|
Offset,
|
|
&OffsetPhys)) == S_OK)
|
|
{
|
|
hr = Symbols->ReadTypedDataPhysical(OffsetPhys, Module, TypeId, Buffer, BufferSize, SizeRead);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
OutCtl.OutErr("Couldn't get type info for %s; result 0x%lx.\n", Symbol, hr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
OutCtl.OutErr("Couldn't get offset of %s; result 0x%lx.\n", Symbol, hr);
|
|
}
|
|
|
|
Symbols->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
const CHAR szNULL[] = "(null)";
|
|
DEBUG_VALUE DbgValNULL = { 0, DEBUG_VALUE_INT64 };
|
|
|
|
HRESULT
|
|
Evaluate(
|
|
IN PDEBUG_CLIENT Client,
|
|
IN PCSTR Expression,
|
|
IN ULONG DesiredType,
|
|
IN ULONG Radix,
|
|
OUT PDEBUG_VALUE Value,
|
|
OUT OPTIONAL PULONG RemainderIndex,
|
|
OUT OPTIONAL PULONG StartIndex,
|
|
OUT OPTIONAL FLONG Flags
|
|
)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
PDEBUG_CONTROL Control;
|
|
PSTR pStr;
|
|
BOOL FoundNULL = FALSE;
|
|
ULONG OrgRadix;
|
|
CHAR EvalBuffer[128];
|
|
ULONG EvalLen;
|
|
|
|
if (RemainderIndex != NULL) *RemainderIndex = 0;
|
|
if (StartIndex != NULL) *StartIndex = 0;
|
|
|
|
if (Expression == NULL ||
|
|
Client == NULL ||
|
|
(hr = Client->QueryInterface(__uuidof(IDebugControl),
|
|
(void **)&Control)) != S_OK)
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
pStr = (PSTR)Expression;
|
|
|
|
while (*pStr != '\n' && (isspace(*pStr) || (*pStr != '-' && ispunct(*pStr))))
|
|
{
|
|
if (_strnicmp(pStr, szNULL, sizeof(szNULL)-1) == 0)
|
|
{
|
|
FoundNULL = TRUE;
|
|
break;
|
|
}
|
|
|
|
pStr++;
|
|
}
|
|
|
|
if (FoundNULL)
|
|
{
|
|
hr = Control->CoerceValue(&DbgValNULL,
|
|
(DesiredType == DEBUG_VALUE_INVALID) ?
|
|
DEBUG_VALUE_INT64 : DesiredType,
|
|
Value);
|
|
EvalLen = sizeof(szNULL)-1;
|
|
}
|
|
else
|
|
{
|
|
// Find expression string and only text revalent
|
|
// to evalutating that expression.
|
|
//
|
|
// Otherwise IDebugControl::Evaluate will spend
|
|
// too much time looking up values that are not
|
|
// really part of the expression.
|
|
//
|
|
// IDebugControl::Evaluate also doesn't handle
|
|
// binary strings well. We expect binary strings
|
|
// to be followed by a non-binary value enclosed
|
|
// in parenthesis. Just use that value.
|
|
|
|
char *psz;
|
|
int i = 0;
|
|
|
|
while (pStr[i] != '\0' &&
|
|
(pStr[i] == '0' || pStr[i] == '1'))
|
|
{
|
|
i++;
|
|
}
|
|
|
|
if (i &&
|
|
pStr[i] == ' ' &&
|
|
pStr[i+1] == '(' &&
|
|
isdigit(pStr[i+2]))
|
|
{
|
|
pStr += i + 1;
|
|
}
|
|
|
|
psz = pStr;
|
|
i = 0;
|
|
|
|
if (Flags & EVALUATE_COMPACT_EXPR)
|
|
{
|
|
while ((i < sizeof(EvalBuffer)-1) &&
|
|
*psz != '\0' && !isspace(*psz))
|
|
{
|
|
EvalBuffer[i++] = *psz++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
while ((i < sizeof(EvalBuffer)-1) &&
|
|
*psz != '\0' && !isspace(*psz))
|
|
{
|
|
EvalBuffer[i++] = *psz++;
|
|
}
|
|
while ((i < sizeof(EvalBuffer)-1) &&
|
|
(*psz == ' ' || *psz == '\t'))
|
|
{
|
|
EvalBuffer[i++] = *psz++;
|
|
}
|
|
} while ((i < sizeof(EvalBuffer)-1) &&
|
|
(ispunct(*psz) && *psz != '-' && *psz != '_' &&
|
|
!(psz[0] == '-' && psz[1] == '>')));
|
|
|
|
// Remove any trailing whitespace
|
|
while (i > 0 && isspace(EvalBuffer[i-1])) i--;
|
|
}
|
|
|
|
EvalBuffer[i] = '\0';
|
|
|
|
if (Radix == 0 ||
|
|
((hr = Control->GetRadix(&OrgRadix)) == S_OK &&
|
|
(hr = Control->SetRadix(Radix)) == S_OK)
|
|
)
|
|
{
|
|
// DbgPrint("Calling Eval(%s) --\n", EvalBuffer);
|
|
hr = Control->Evaluate(EvalBuffer,
|
|
DesiredType,
|
|
Value,
|
|
&EvalLen);
|
|
// DbgPrint("-- Eval returned\n");
|
|
|
|
if (Radix != 0)
|
|
{
|
|
Control->SetRadix(OrgRadix);
|
|
}
|
|
|
|
if (hr == S_OK &&
|
|
Flags & EVALUATE_COMPACT_EXPR &&
|
|
EvalLen != i)
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DbgPrint("Can't setup new radix, %lu, for Evaluate.\n", Radix);
|
|
}
|
|
}
|
|
|
|
Control->Release();
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
if (RemainderIndex != NULL)
|
|
{
|
|
*RemainderIndex = (ULONG)(pStr - Expression) + EvalLen;
|
|
}
|
|
|
|
if (StartIndex != NULL)
|
|
{
|
|
*StartIndex = (ULONG)(pStr - Expression);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
ReadPointerPhysical(
|
|
PDEBUG_CLIENT Client,
|
|
ULONG64 Offset,
|
|
PULONG64 Ptr
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
PDEBUG_CONTROL Control;
|
|
PDEBUG_DATA_SPACES Data;
|
|
DEBUG_VALUE PtrVal;
|
|
ULONG BytesRead;
|
|
|
|
if (Ptr != NULL) *Ptr = 0;
|
|
|
|
if (Client == NULL) return E_INVALIDARG;
|
|
|
|
if ((hr = Client->QueryInterface(__uuidof(IDebugControl),
|
|
(void **)&Control)) != S_OK)
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
if ((hr = Client->QueryInterface(__uuidof(IDebugDataSpaces),
|
|
(void **)&Data)) != S_OK)
|
|
{
|
|
Client->Release();
|
|
return hr;
|
|
}
|
|
|
|
if (Control->IsPointer64Bit() == S_OK)
|
|
{
|
|
Control->Output(DEBUG_OUTPUT_VERBOSE, "Read64PointerPhysical(0x%p)\n", Offset);
|
|
|
|
hr = Data->ReadPhysical(Offset,
|
|
&PtrVal.I64,
|
|
sizeof(PtrVal.I64),
|
|
&BytesRead);
|
|
if (hr == S_OK &&
|
|
BytesRead != sizeof(PtrVal.I64))
|
|
{
|
|
Control->Output(DEBUG_OUTPUT_VERBOSE,
|
|
"ReadPhysicalPointer only read %lu bytes not %lu.\n",
|
|
BytesRead, sizeof(PtrVal.I64));
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
if (hr == S_OK) Control->Output(DEBUG_OUTPUT_VERBOSE, " read 0x%p\n", PtrVal.I64);
|
|
}
|
|
else
|
|
{
|
|
Control->Output(DEBUG_OUTPUT_VERBOSE, "Read32PointerPhysical(0x%p)\n", Offset);
|
|
|
|
hr = Data->ReadPhysical(Offset,
|
|
&PtrVal.I32,
|
|
sizeof(PtrVal.I32),
|
|
&BytesRead);
|
|
if (hr == S_OK)
|
|
{
|
|
if (BytesRead != sizeof(PtrVal.I32))
|
|
{
|
|
Control->Output(DEBUG_OUTPUT_VERBOSE,
|
|
"ReadPhysicalPointer only read %lu bytes not %lu.\n",
|
|
BytesRead, sizeof(PtrVal.I32));
|
|
hr = S_FALSE;
|
|
}
|
|
else
|
|
{
|
|
Control->Output(DEBUG_OUTPUT_VERBOSE, " read 0x%p", PtrVal.I64);
|
|
|
|
PtrVal.I64 = DEBUG_EXTEND64(PtrVal.I32);
|
|
|
|
Control->Output(DEBUG_OUTPUT_VERBOSE, " -> 0x%I64x\n", PtrVal.I64);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hr == S_OK && Ptr != NULL)
|
|
{
|
|
*Ptr = PtrVal.I64;
|
|
}
|
|
|
|
Data->Release();
|
|
Control->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetTypeId(
|
|
IN PDEBUG_CLIENT Client,
|
|
IN PCSTR Type,
|
|
OUT PULONG TypeId,
|
|
OUT OPTIONAL PULONG64 Module
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
PDEBUG_SYMBOLS Symbols;
|
|
|
|
if (Client == NULL || Type == NULL || TypeId == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if ((hr = Client->QueryInterface(__uuidof(IDebugSymbols),
|
|
(void **)&Symbols)) != S_OK)
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
if (strchr(Type, '!') == NULL &&
|
|
Type_Module.Base != 0 &&
|
|
(hr = Symbols->GetTypeId(Type_Module.Base, Type, TypeId)) == S_OK)
|
|
{
|
|
if (Module != NULL)
|
|
{
|
|
*Module = Type_Module.Base;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = Symbols->GetSymbolTypeId(Type, TypeId, Module);
|
|
}
|
|
|
|
Symbols->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetBasicTypeSize(
|
|
IN PCSTR Type,
|
|
OUT PULONG Size
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
ULONG Bytes = 0;
|
|
|
|
static CHAR PointerBase[] = "Ptr";
|
|
static CHAR Char[] = "Char";
|
|
static CHAR IntBase[] = "Int";
|
|
|
|
if (_strnicmp(Type, PointerBase, sizeof(PointerBase)) == 0)
|
|
{
|
|
Bytes = strtoul(Type+sizeof(PointerBase), NULL, 10) / 8;
|
|
}
|
|
else
|
|
{
|
|
// Remove U indicating unsigned
|
|
if (*Type == 'U')
|
|
{
|
|
Type++;
|
|
}
|
|
|
|
if (_strnicmp(Type, Char, sizeof(Char)) == 0)
|
|
{
|
|
Bytes = 1;
|
|
}
|
|
else if (_strnicmp(Type, IntBase, sizeof(IntBase)) == 0)
|
|
{
|
|
PCHAR NextChar;
|
|
Bytes = strtoul(Type+sizeof(IntBase), &NextChar, 10);
|
|
if (NextChar == NULL ||
|
|
toupper(*NextChar) != 'B')
|
|
{
|
|
Bytes = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Bytes != 0)
|
|
{
|
|
hr = S_OK;
|
|
if (Size != NULL)
|
|
{
|
|
*Size = Bytes;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetFieldSize(
|
|
IN PDEBUG_CLIENT Client,
|
|
IN ULONG64 Module,
|
|
IN ULONG TypeId,
|
|
IN PCSTR FieldPath,
|
|
OUT PULONG pSize,
|
|
OUT OPTIONAL PULONG pLength,
|
|
OUT OPTIONAL PULONG pEntrySize
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
PDEBUG_CONTROL Control;
|
|
PDEBUG_SYMBOLS Symbols;
|
|
|
|
if (pSize != NULL) *pSize = 0;
|
|
if (pLength != NULL) *pLength = 0;
|
|
if (pEntrySize != NULL) *pEntrySize = 0;
|
|
|
|
if (Client == NULL ||
|
|
FieldPath == NULL ||
|
|
!iscsymf(*FieldPath))
|
|
{
|
|
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)
|
|
{
|
|
Client->Release();
|
|
return hr;
|
|
}
|
|
|
|
OutputReader OutReader;
|
|
OutputState OutState(Client, FALSE);
|
|
PSTR TypeLayout;
|
|
PSTR Field;
|
|
SIZE_T FieldLen;
|
|
CHAR FieldCopy[80];
|
|
PCSTR SubFieldPath;
|
|
ULONG Size, ArrayLen = 0;
|
|
|
|
if ((hr = OutState.Setup(0, &OutReader)) == S_OK &&
|
|
(hr = OutState.OutputTypeVirtual(0,
|
|
Module,
|
|
TypeId,
|
|
DEBUG_OUTTYPE_NO_INDENT |
|
|
DEBUG_OUTTYPE_NO_OFFSET |
|
|
DEBUG_OUTTYPE_COMPACT_OUTPUT)) == S_OK &&
|
|
(hr = OutReader.GetOutputCopy(&TypeLayout)) == S_OK)
|
|
{
|
|
SubFieldPath = strchr(FieldPath, '.');
|
|
|
|
if (SubFieldPath != NULL)
|
|
{
|
|
FieldLen = SubFieldPath - FieldPath - 1;
|
|
SubFieldPath++;
|
|
|
|
if (FieldLen + 1 > sizeof(FieldCopy))
|
|
{
|
|
Field = (PSTR)HeapAlloc(GetProcessHeap(), 0, FieldLen + 1);
|
|
if (Field == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Field = FieldCopy;
|
|
}
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
RtlCopyMemory(Field, FieldPath, FieldLen);
|
|
Field[FieldLen] = '\0';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Field = (PSTR)FieldPath;
|
|
}
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
PSTR pStr = TypeLayout;
|
|
BOOL FieldFound = FALSE;
|
|
|
|
while (!FieldFound && pStr != NULL)
|
|
{
|
|
pStr = strstr(pStr, Field);
|
|
if (pStr != NULL)
|
|
{
|
|
// Check Field is bounded by non-symbol characters
|
|
BOOL FieldStart = (pStr-1 < TypeLayout) || (!__iscsym(*(pStr-1)));
|
|
|
|
// Advance search location
|
|
pStr += strlen(Field);
|
|
|
|
if (FieldStart && !__iscsym(*pStr))
|
|
{
|
|
FieldFound = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FieldFound)
|
|
{
|
|
while (isspace(*pStr)) pStr++;
|
|
|
|
// Check for an array
|
|
if (*pStr == '[')
|
|
{
|
|
PCHAR EvalEnd;
|
|
|
|
ArrayLen = strtoul(pStr+1, &EvalEnd, 10);
|
|
|
|
if (ArrayLen != 0 && *EvalEnd == ']')
|
|
{
|
|
pStr = EvalEnd + 1;
|
|
while (isspace(*pStr)) pStr++;
|
|
}
|
|
// else following csym check will fail returning error.
|
|
}
|
|
|
|
if (iscsymf(*pStr))
|
|
{
|
|
PSTR FieldType = pStr;
|
|
ULONG SubTypeId;
|
|
|
|
while (iscsym(*pStr)) pStr++;
|
|
*pStr = '\0';
|
|
|
|
hr = Symbols->GetTypeId(Module, FieldType, &SubTypeId);
|
|
|
|
if (SubFieldPath != NULL)
|
|
{
|
|
if (hr == S_OK)
|
|
{
|
|
hr = GetFieldSize(Client,
|
|
Module,
|
|
SubTypeId,
|
|
SubFieldPath,
|
|
pSize,
|
|
pLength,
|
|
pEntrySize);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (hr == S_OK)
|
|
{
|
|
hr = Symbols->GetTypeSize(Module, SubTypeId, &Size);
|
|
}
|
|
else
|
|
{
|
|
if (GetBasicTypeSize(FieldType, &Size) == S_OK)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
if (pEntrySize != NULL) *pEntrySize = Size;
|
|
if (pLength != NULL) *pLength = ArrayLen;
|
|
if (pSize != NULL)
|
|
{
|
|
if (ArrayLen != 0) Size *= ArrayLen;
|
|
*pSize = Size;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Field != NULL && Field != FieldCopy && Field != FieldPath)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, Field);
|
|
}
|
|
|
|
OutReader.FreeOutputCopy(TypeLayout);
|
|
}
|
|
|
|
Symbols->Release();
|
|
Control->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
ULONG
|
|
DbgIntValTypeFromSize(
|
|
ULONG Size
|
|
)
|
|
{
|
|
ULONG Type;
|
|
|
|
switch (Size)
|
|
{
|
|
case 1: Type = DEBUG_VALUE_INT8; break;
|
|
case 2: Type = DEBUG_VALUE_INT16; break;
|
|
case 4: Type = DEBUG_VALUE_INT32; break;
|
|
case 8: Type = DEBUG_VALUE_INT64; break;
|
|
default: Type = DEBUG_VALUE_INVALID; break;
|
|
}
|
|
return Type;
|
|
}
|
|
|
|
BOOL
|
|
GetArrayDimensions(
|
|
IN PDEBUG_CLIENT Client,
|
|
IN PCSTR Type,
|
|
OPTIONAL IN PCSTR Field,
|
|
OPTIONAL OUT PULONG ArraySize,
|
|
OPTIONAL OUT PULONG ArrayLength,
|
|
OPTIONAL OUT PULONG EntrySize
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
ULONG64 Module;
|
|
ULONG TypeId;
|
|
|
|
BOOL GotDimensions = FALSE;
|
|
ULONG Size, ESize;
|
|
|
|
if (ArraySize) *ArraySize = 0;
|
|
if (ArrayLength) *ArrayLength = 0;
|
|
if (EntrySize) *EntrySize = 0;
|
|
|
|
if (Type == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (Field != NULL)
|
|
{
|
|
hr = GetTypeId(Client, Type, &TypeId, &Module);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
hr = GetFieldSize(Client, Module, TypeId, Field,
|
|
ArraySize, ArrayLength, EntrySize);
|
|
|
|
if (hr == S_OK) GotDimensions = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!GotDimensions && ExtQuery(Client) == S_OK)
|
|
{
|
|
ULONG GrpIndex;
|
|
CHAR SymbolName[MAX_PATH];
|
|
DEBUG_SYMBOL_PARAMETERS Array;
|
|
|
|
_snprintf(SymbolName, sizeof(SymbolName),
|
|
(Field) ? "%s.%s" : Type,
|
|
Type, Field);
|
|
|
|
if (g_pExtSymbolGroup->AddSymbol(SymbolName, &GrpIndex) == S_OK)
|
|
{
|
|
if (g_pExtSymbolGroup->GetSymbolParameters(GrpIndex, 1, &Array) == S_OK)
|
|
{
|
|
if (Array.SubElements)
|
|
{
|
|
if (g_pExtSymbols->GetTypeSize(Array.Module, Array.TypeId, &Size) == S_OK)
|
|
{
|
|
ExtVerb(" Array %s - Size: %u bytes Length: %u\n", SymbolName, Size, Array.SubElements);
|
|
if (ArraySize) *ArraySize = Size;
|
|
if (ArrayLength) *ArrayLength = Array.SubElements;
|
|
if (EntrySize) *EntrySize = Size / Array.SubElements;
|
|
GotDimensions = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ExtErr("Couldn't get size of %s.\n", Type);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ExtErr("%s has 0 subelements.\n", SymbolName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ExtErr("Couldn't get parameter info for %s.\n", SymbolName);
|
|
}
|
|
|
|
g_pExtSymbolGroup->RemoveSymbolByIndex(GrpIndex);
|
|
}
|
|
else
|
|
{
|
|
ExtErr("Couldn't lookup symbol %s.\n", SymbolName);
|
|
}
|
|
|
|
ExtRelease();
|
|
}
|
|
|
|
if (!GotDimensions)
|
|
{
|
|
ULONG Index = -1;
|
|
PCSTR ArrayName = Field ? Field : Type;
|
|
char FirstEntryName[128];
|
|
ULONG error;
|
|
|
|
FIELD_INFO EntrySizeField = { DbgStr(Field), NULL, 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL};
|
|
SYM_DUMP_PARAM ArraySym = {
|
|
sizeof (SYM_DUMP_PARAM), DbgStr(Type),
|
|
DBG_DUMP_NO_PRINT, 0,
|
|
NULL, NULL, NULL,
|
|
(Field ? 1 : 0), &EntrySizeField
|
|
};
|
|
|
|
ExtVerb("Using WinDbg extension interface.\n");
|
|
|
|
if (Field)
|
|
{
|
|
error = Ioctl(IG_DUMP_SYMBOL_INFO, &ArraySym, ArraySym.size);
|
|
Size = (error) ? 0 : EntrySizeField.size;
|
|
|
|
EntrySizeField.fName = DbgStr(FirstEntryName);
|
|
}
|
|
else
|
|
{
|
|
Size = Ioctl(IG_GET_TYPE_SIZE, &ArraySym, ArraySym.size);
|
|
|
|
ArraySym.sName = DbgStr(FirstEntryName);
|
|
}
|
|
|
|
if (Size == 0)
|
|
{
|
|
dprintf("Array size is zero.\n");
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (ArraySize) *ArraySize = Size;
|
|
|
|
_snprintf(FirstEntryName, sizeof(FirstEntryName), "%s[0]", ArrayName);
|
|
|
|
if (Field)
|
|
{
|
|
error = Ioctl(IG_DUMP_SYMBOL_INFO, &ArraySym, ArraySym.size);
|
|
ESize = (error) ? 0 : EntrySizeField.size;
|
|
|
|
vPrintNativeSymDumpParam(&ArraySym);
|
|
}
|
|
else
|
|
{
|
|
ESize = Ioctl(IG_GET_TYPE_SIZE, &ArraySym, ArraySym.size);
|
|
}
|
|
|
|
if (ESize)
|
|
{
|
|
DbgPrint("%s dimensions: %u bytes [%u] = %u bytes.\n",
|
|
ArrayName, ESize, Size/ESize, Size);
|
|
|
|
if (ArrayLength) *ArrayLength = Size/ESize;
|
|
if (EntrySize) *EntrySize = ESize;
|
|
|
|
GotDimensions = TRUE;
|
|
}
|
|
}
|
|
|
|
return GotDimensions;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
DumpType(
|
|
PDEBUG_CLIENT Client,
|
|
PCSTR Type,
|
|
ULONG64 Offset,
|
|
ULONG Flags,
|
|
OutputControl *OutCtl,
|
|
BOOL Physical
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
PDEBUG_SYMBOLS Symbols;
|
|
ULONG64 Module;
|
|
ULONG TypeId;
|
|
OutputControl DefaultOutput;
|
|
|
|
if (Client == NULL) return E_INVALIDARG;
|
|
|
|
if (OutCtl == NULL)
|
|
{
|
|
DefaultOutput.SetControl(DEBUG_OUTCTL_AMBIENT, Client);
|
|
OutCtl = &DefaultOutput;
|
|
}
|
|
|
|
if ((hr = GetTypeId(Client, Type, &TypeId, &Module)) != S_OK)
|
|
{
|
|
OutCtl->OutErr(" Not a type nor symbol - HRESULT %s.\n", pszHRESULT(hr));
|
|
}
|
|
else
|
|
{
|
|
TypeOutputDumper TypeReader(Client, OutCtl);
|
|
|
|
if (!(Flags & DEBUG_OUTTYPE_NO_OFFSET))
|
|
{
|
|
OutCtl->Output(" %s", Type);
|
|
if (Offset != 0) OutCtl->Output(" @ %s0x%p", ((Physical) ? "#" : ""), Offset);
|
|
OutCtl->Output((Flags & DEBUG_OUTTYPE_COMPACT_OUTPUT) ? " " : ":\n");
|
|
}
|
|
|
|
hr = TypeReader.OutputType(Physical, Module, TypeId, Offset, Flags, NULL);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
ExtDumpType(
|
|
IN PDEBUG_CLIENT Client,
|
|
IN PCSTR ExtName,
|
|
IN PCSTR Type,
|
|
IN PCSTR Args
|
|
)
|
|
{
|
|
INIT_API();
|
|
|
|
HRESULT hr = S_OK;
|
|
DEBUG_VALUE Offset;
|
|
|
|
Offset.I64 = 0;
|
|
|
|
while (isspace(*Args)) Args++;
|
|
|
|
if (*Args == '-' ||
|
|
(hr = Evaluate(Client, Args, DEBUG_VALUE_INT64, 0, &Offset, NULL)) != S_OK)
|
|
{
|
|
if (hr != S_OK)
|
|
{
|
|
ExtErr("Evaluate '%s' returned %s.\n", Args, pszHRESULT(hr));
|
|
}
|
|
ExtOut("Usage: %s [-?] [%s Addr]\n", ExtName, Type);
|
|
}
|
|
else
|
|
{
|
|
hr = DumpType(Client, Type, Offset.I64);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
ExtErr("Type Dump for %s returned %s.\n", Type, pszHRESULT(hr));
|
|
}
|
|
}
|
|
|
|
EXIT_API(hr);
|
|
}
|
|
|
|
|
|
void
|
|
DumpDSP(PDEBUG_CLIENT Client, PDEBUG_SYMBOL_PARAMETERS pDSP)
|
|
{
|
|
ExtOut(" Module Base : %p\n", pDSP->Module);
|
|
ExtOut(" TypeId : %lx\n", pDSP->TypeId);
|
|
ExtOut(" ParentSymbol : %lx\n", pDSP->ParentSymbol);
|
|
ExtOut(" SubElements : %lu\n", pDSP->SubElements);
|
|
ExtOut(" Flags : %lx\n", pDSP->Flags);
|
|
ExtOut(" Reserved : %I64u\n", pDSP->Reserved);
|
|
}
|
|
|
|
|
|
DECLARE_API(dt)
|
|
{
|
|
HRESULT Hr = E_INVALIDARG;
|
|
BOOL VerboseInfo = FALSE;
|
|
BOOL NotGDIType = FALSE;
|
|
BOOL AllClients = FALSE;
|
|
BOOL SessionAddr = FALSE;
|
|
BOOL Physical = FALSE;
|
|
char TypeSym[MAX_NAME];
|
|
char *pcTypeSym = TypeSym;
|
|
DEBUG_VALUE Offset;
|
|
ULONG Index;
|
|
DEBUG_SYMBOL_PARAMETERS DSP;
|
|
DEBUG_VALUE RepeatCount = { {1}, DEBUG_VALUE_INVALID};
|
|
ULONG Size = 0;
|
|
|
|
INIT_API();
|
|
|
|
while (isspace(*args)) args++;
|
|
|
|
while (*args == '-')
|
|
{
|
|
args++;
|
|
|
|
do
|
|
{
|
|
switch (tolower(*args))
|
|
{
|
|
case 'v': VerboseInfo = TRUE; break;
|
|
case 's': SessionAddr = TRUE; break;
|
|
case 'n': NotGDIType = TRUE; break;
|
|
case 'c': AllClients = TRUE; break;
|
|
case 'l':
|
|
{
|
|
ULONG RemIndex;
|
|
|
|
Hr = Evaluate(Client, args+1, DEBUG_VALUE_INT32, 0, &RepeatCount, &RemIndex);
|
|
|
|
if (Hr == S_OK)
|
|
{
|
|
if (RepeatCount.Type == DEBUG_VALUE_INT32 &&
|
|
RepeatCount.I32 > 0)
|
|
{
|
|
if (RepeatCount.I32 < 512)
|
|
{
|
|
args += RemIndex;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
ExtErr("Array count %lu is higher than 512 limit.\n\n", RepeatCount.I32);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ExtErr("Invalid array count at \"%s\"\n\n", args+1);
|
|
}
|
|
Hr = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
ExtErr("Missing array count.\n\n");
|
|
}
|
|
}
|
|
default:
|
|
{
|
|
ExtOut("dt dumps GDI types expanding enum and flag values.\n"
|
|
"\n"
|
|
"Usage: dt [-?vsn] [-l<Count>] <Type|Symbol> [[#]Offset]\n"
|
|
"\n"
|
|
" -v Verbose type/symbol information\n"
|
|
" -s Lookup according to !session setting\n"
|
|
" -n Directly through debug engine\n"
|
|
" -l Dump an array of Type/Symbol Count times\n");
|
|
|
|
EXIT_API(*args == '?' ? S_OK : Hr);
|
|
}
|
|
}
|
|
|
|
args++;
|
|
|
|
} while (!isspace(*args) && *args != '\0');
|
|
|
|
while (isspace(*args)) args++;
|
|
}
|
|
|
|
// Get Type/Symbol name from argument string
|
|
while (*args != '\0' && !isspace(*args) &&
|
|
(pcTypeSym < (TypeSym + sizeof(TypeSym) - 2)))
|
|
{
|
|
*pcTypeSym++ = *args++;
|
|
}
|
|
|
|
// Type/Symbols should be followed by a space or nothing
|
|
if (*args != '\0' && !isspace(*args))
|
|
{
|
|
ExtErr("Invalid arguments\n");
|
|
EXIT_API(E_INVALIDARG);
|
|
}
|
|
|
|
*pcTypeSym = '\0';
|
|
|
|
while (isspace(*args))
|
|
{
|
|
args++;
|
|
}
|
|
|
|
if (*args == '#')
|
|
{
|
|
if (SessionAddr)
|
|
{
|
|
ExtErr("-s may not be combined with physical addresses.\n");
|
|
EXIT_API(E_INVALIDARG);
|
|
}
|
|
|
|
Physical = TRUE;
|
|
args++;
|
|
}
|
|
|
|
Offset.Type = DEBUG_VALUE_INVALID;
|
|
Hr = Evaluate(Client, args, DEBUG_VALUE_INT64, 0, &Offset, NULL);
|
|
|
|
if (Physical && Offset.Type == DEBUG_VALUE_INVALID)
|
|
{
|
|
ExtErr("Invalid offset\n");
|
|
EXIT_API(((Hr != S_OK) ? Hr : E_INVALIDARG));
|
|
}
|
|
|
|
if ((Hr = g_pExtSymbolGroup->AddSymbol(TypeSym, &Index)) == S_OK)
|
|
{
|
|
if ((Hr = g_pExtSymbolGroup->GetSymbolParameters(Index, 1, &DSP)) == S_OK)
|
|
{
|
|
if (VerboseInfo) DumpDSP(Client, &DSP);
|
|
}
|
|
else
|
|
{
|
|
ExtErr(" GetSymbolParameters returned error %lX.\n", Hr);
|
|
}
|
|
g_pExtSymbolGroup->RemoveSymbolByIndex(Index);
|
|
}
|
|
else
|
|
{
|
|
ExtVerb(" Not a symbol - Symbol lookup returned error %lX.\n", Hr);
|
|
|
|
Hr = GetTypeId(Client, TypeSym, &DSP.TypeId, &DSP.Module);
|
|
|
|
if (Hr == S_OK)
|
|
{
|
|
if (VerboseInfo)
|
|
{
|
|
ExtOut(" Module Base : %p\n", DSP.Module);
|
|
ExtOut(" TypeId : %lx\n", DSP.TypeId);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ExtErr(" Not a type/symbol - %s.\n", pszHRESULT(Hr));
|
|
}
|
|
}
|
|
|
|
if (Hr == S_OK && VerboseInfo)
|
|
{
|
|
HRESULT HrCur;
|
|
|
|
char ModuleName[40];
|
|
Hr = g_pExtSymbols->GetModuleNames(DEBUG_ANY_ID, DSP.Module,
|
|
NULL, 0, NULL,
|
|
ModuleName, sizeof(ModuleName), NULL,
|
|
NULL, 0, NULL);
|
|
if (Hr == S_OK)
|
|
{
|
|
ExtOut(" Module Name : %s\n", ModuleName);
|
|
}
|
|
else
|
|
{
|
|
ExtErr(" GetModuleNames returned error %lx.\n", Hr);
|
|
}
|
|
|
|
ExtVerb("GetTypeName(%p, %lx)\n", DSP.Module, DSP.TypeId);
|
|
char TypeName[MAX_NAME];
|
|
HrCur = g_pExtSymbols->GetTypeName(DSP.Module, DSP.TypeId,
|
|
TypeName, sizeof(TypeName),
|
|
NULL);
|
|
if (HrCur == S_OK)
|
|
{
|
|
ExtOut(" Type Name : %s\n", TypeName);
|
|
}
|
|
else
|
|
{
|
|
ExtErr(" GetTypeName returned error %lx.\n", HrCur);
|
|
if (Hr == S_OK) Hr = HrCur;
|
|
}
|
|
}
|
|
|
|
if (Hr == S_OK && ((RepeatCount.I32 != 1) || VerboseInfo))
|
|
{
|
|
Hr = g_pExtSymbols->GetTypeSize(DSP.Module, DSP.TypeId, &Size);
|
|
if (Hr == S_OK)
|
|
{
|
|
if (VerboseInfo)
|
|
{
|
|
ExtOut(" Type Size : %lu\n", Size);
|
|
}
|
|
|
|
if (RepeatCount.I32 != 1 && Size == 0)
|
|
{
|
|
ExtErr("Error: GetTypeSize returned size of 0.\n");
|
|
Hr = E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ExtErr(" GetTypeSize returned error %lx.\n", Hr);
|
|
}
|
|
}
|
|
|
|
if (Hr == S_OK)
|
|
{
|
|
// Try to evaluate TypeSym for an offset if none was specified.
|
|
if (*args == '\0' &&
|
|
(Offset.Type == DEBUG_VALUE_INVALID ||
|
|
(Offset.I64 == 0 && !Physical)))
|
|
{
|
|
Offset.Type = DEBUG_VALUE_INVALID;
|
|
Evaluate(Client, TypeSym, DEBUG_VALUE_INT64, 0, &Offset, NULL);
|
|
}
|
|
|
|
if (Offset.Type == DEBUG_VALUE_INVALID)
|
|
{
|
|
Offset.I64 = 0;
|
|
}
|
|
else if (SessionAddr && SessionId != CURRENT_SESSION)
|
|
{
|
|
ULONG64 PhysAddr;
|
|
|
|
Hr = GetPhysicalAddress(Client, SessionId, Offset.I64, &PhysAddr);
|
|
|
|
if (Hr == S_OK)
|
|
{
|
|
Physical = TRUE;
|
|
Offset.I64 = PhysAddr;
|
|
|
|
if (RepeatCount.I32 != 1)
|
|
{
|
|
ExtWarn("Array dumping is not supported for session dumps.\n");
|
|
RepeatCount.I32 = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ExtErr("Couldn't lookup 0x%p in Session %s.\n", Offset.I64, SessionStr);
|
|
}
|
|
}
|
|
|
|
if (Hr == S_OK)
|
|
{
|
|
if (Offset.I64 == 0 && !Physical && RepeatCount.I32 != 1)
|
|
{
|
|
ExtWarn("No valid offset was found so array dump has been overridden.\n");
|
|
RepeatCount.I32 = 1;
|
|
}
|
|
|
|
while (RepeatCount.I32 > 0 && Hr == S_OK)
|
|
{
|
|
if ((Offset.I64 == 0 && !Physical) || NotGDIType)
|
|
{
|
|
ExtVerb("OutputTypedData(DEBUG_OUTCTL_THIS_CLIENT, 0x%p, %p, %lx, 0)\n",
|
|
Offset.I64, DSP.Module, DSP.TypeId);
|
|
if (Physical)
|
|
{
|
|
Hr = g_pExtSymbols->OutputTypedDataPhysical((AllClients ? DEBUG_OUTCTL_ALL_CLIENTS : DEBUG_OUTCTL_THIS_CLIENT),
|
|
Offset.I64,
|
|
DSP.Module,
|
|
DSP.TypeId,
|
|
0);
|
|
}
|
|
else
|
|
{
|
|
Hr = g_pExtSymbols->OutputTypedDataVirtual((AllClients ? DEBUG_OUTCTL_ALL_CLIENTS : DEBUG_OUTCTL_THIS_CLIENT),
|
|
Offset.I64,
|
|
DSP.Module,
|
|
DSP.TypeId,
|
|
0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Hr = DumpType(Client, TypeSym, Offset.I64, DEBUG_OUTTYPE_DEFAULT, NULL, Physical);
|
|
}
|
|
|
|
if (--RepeatCount.I32 > 0)
|
|
{
|
|
Offset.I64 += Size;
|
|
}
|
|
}
|
|
|
|
if (Hr != S_OK)
|
|
{
|
|
ExtErr("Type dump returned %s.\n", pszHRESULT(Hr));
|
|
}
|
|
}
|
|
}
|
|
|
|
EXIT_API(Hr);
|
|
}
|
|
|