1665 lines
44 KiB
C++
1665 lines
44 KiB
C++
/****************************** Module Header ******************************\
|
|
*
|
|
* Module Name: DuExts.c
|
|
*
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
*
|
|
* This module contains user related debugging extensions.
|
|
*
|
|
* History:
|
|
* 11-30-2000 JStall Created
|
|
*
|
|
\******************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
PSTR pszExtName = "DUEXTS";
|
|
|
|
#include "stdext64.h"
|
|
#include "stdext64.cpp"
|
|
|
|
/******************************************************************************\
|
|
* Constants
|
|
\******************************************************************************/
|
|
#define BF_MAX_WIDTH 80
|
|
#define BF_COLUMN_WIDTH 19
|
|
|
|
#define NULL_POINTER ((ULONG64)(0))
|
|
#define COUNTOF(x) (sizeof(x) / sizeof(x[0]))
|
|
|
|
// If you want to debug the extension, enable this.
|
|
#if 0
|
|
#undef DEBUGPRINT
|
|
#define DEBUGPRINT Print
|
|
#endif
|
|
|
|
/******************************************************************************\
|
|
* Global variables
|
|
\******************************************************************************/
|
|
BOOL bServerDebug = TRUE;
|
|
BOOL bShowFlagNames = TRUE;
|
|
char gach1[80];
|
|
char gach2[80];
|
|
char gach3[80];
|
|
int giBFColumn; // bit field: current column
|
|
char gaBFBuff[BF_MAX_WIDTH + 1]; // bit field: buffer
|
|
|
|
// used in dsi() and dinp()
|
|
typedef struct {
|
|
int iMetric;
|
|
LPSTR pstrMetric;
|
|
} SYSMET_ENTRY;
|
|
#define SMENTRY(sm) {SM_##sm, #sm}
|
|
|
|
extern int gnIndent; // indentation of !dso
|
|
/******************************************************************************\
|
|
* Macros
|
|
\******************************************************************************/
|
|
|
|
#define NELEM(array) (sizeof(array)/sizeof(array[0]))
|
|
|
|
#define TestWWF(pww, flag) (*(((PBYTE)(pww)) + (int)HIBYTE(flag)) & LOBYTE(flag))
|
|
|
|
void ShowProgress(ULONG i);
|
|
|
|
void PrivateSetRipFlags(DWORD dwRipFlags, DWORD pid);
|
|
|
|
#define VAR(v) "DUser!" #v
|
|
#define SYM(s) "DUser!" #s
|
|
|
|
|
|
/*
|
|
* Use these macros to print field values, globals, local values, etc.
|
|
* This assures consistent formating plus make the extensions easier to read and to maintain.
|
|
*/
|
|
#define STRWD1 "67"
|
|
#define STRWD2 "28"
|
|
#define DWSTR1 "%08lx %." STRWD1 "s"
|
|
#define DWSTR2 "%08lx %-" STRWD2 "." STRWD2 "s"
|
|
#define PTRSTR1 "%08p %-" STRWD1 "s"
|
|
#define PTRSTR2 "%08p %-" STRWD2 "." STRWD2 "s"
|
|
#define DWPSTR1 "%08p %." STRWD1 "s"
|
|
#define DWPSTR2 "%08p %-" STRWD2 "." STRWD2 "s"
|
|
#define PRTFDW1(p, f1) Print(DWSTR1 "\n", (DWORD)##p##f1, #f1)
|
|
#define PRTVDW1(s1, v1) Print(DWSTR1 "\n", v1, #s1)
|
|
#define PRTFDW2(p, f1, f2) Print(DWSTR2 "\t" DWSTR2 "\n", (DWORD)##p##f1, #f1, (DWORD)##p##f2, #f2)
|
|
#define PRTVDW2(s1, v1, s2, v2) Print(DWSTR2 "\t" DWPSTR2 "\n", v1, #s1, v2, #s2)
|
|
#define PRTFRC(p, rc) Print("%-" STRWD2 "s{%#lx, %#lx, %#lx, %#lx}\n", #rc, ##p##rc.left, ##p##rc.top, ##p##rc.right, ##p##rc.bottom)
|
|
#define PRTFPT(p, pt) Print("%-" STRWD2 "s{%#lx, %#lx}\n", #pt, ##p##pt.x, ##p##pt.y)
|
|
#define PRTVPT(s, pt) Print("%-" STRWD2 "s{%#lx, %#lx}\n", #s, pt.x, pt.y)
|
|
#define PRTFDWP1(p, f1) Print(DWPSTR1 "\n", (DWORD_PTR)##p##f1, #f1)
|
|
#define PRTFDWP2(p, f1, f2) Print(DWPSTR2 "\t" DWPSTR2 "\n", (DWORD_PTR)##p##f1, #f1, (DWORD_PTR)##p##f2, #f2)
|
|
#define PRTFDWPDW(p, f1, f2) Print(DWPSTR2 "\t" DWSTR2 "\n", (DWORD_PTR)##p##f1, #f1, (DWORD)##p##f2, #f2)
|
|
#define PRTFDWDWP(p, f1, f2) Print(DWSTR2 "\t" DWPSTR2 "\n", (DWORD)##p##f1, #f1, (DWORD_PTR)##p##f2, #f2)
|
|
|
|
/*
|
|
* Bit Fields
|
|
*/
|
|
#define BEGIN_PRTFFLG()
|
|
#define PRTFFLG(p, f) PrintBitField(#f, (BOOLEAN)!!(p.f))
|
|
#define END_PRTFFLG() PrintEndBitField()
|
|
|
|
|
|
#define PRTGDW1(g1) \
|
|
{ DWORD _dw1; \
|
|
moveExpValue(&_dw1, VAR(g1)); \
|
|
Print(DWSTR1 "\n", _dw1, #g1); }
|
|
|
|
#define PRTGDW2(g1, g2) \
|
|
{ DWORD _dw1, _dw2; \
|
|
moveExpValue(&_dw1, VAR(g1)); \
|
|
moveExpValue(&_dw2, VAR(g2)); \
|
|
Print(DWSTR2 "\t" DWSTR2 "\n", _dw1, #g1, _dw2, #g2); }
|
|
|
|
#define PTRGPTR1(g1) \
|
|
Print(PTRSTR1 "\n", GetGlobalPointer(VAR(g1)), #g1)
|
|
|
|
#define PRTGPTR2(g1, g2) \
|
|
Print(PTRSTR2 "\t" PTRSTR2 "\n", GetGlobalPointer(VAR(g1)), #g1, GetGlobalPointer(VAR(g2)), #g2)
|
|
|
|
|
|
/* This macro requires char ach[...]; to be previously defined */
|
|
#define PRTWND(s, pwnd) \
|
|
{ DebugGetWindowTextA(pwnd, ach, ARRAY_SIZE(ach)); \
|
|
Print("%-" STRWD2 "s" DWPSTR2 "\n", #s, pwnd, ach); }
|
|
|
|
#define PRTGWND(gpwnd) \
|
|
{ ULONG64 _pwnd; \
|
|
moveExpValuePtr(&_pwnd, VAR(gpwnd)); \
|
|
DebugGetWindowTextA(_pwnd, ach, ARRAY_SIZE(ach)); \
|
|
Print("%-" STRWD2 "s" DWPSTR2 "\n", #gpwnd, _pwnd, ach); }
|
|
|
|
LPSTR GetFlags(WORD wType, DWORD dwFlags, LPSTR pszBuf, BOOL fPrintZero);
|
|
BOOL CopyUnicodeString(
|
|
IN ULONG64 pData,
|
|
IN char * pszStructName,
|
|
IN char * pszFieldName,
|
|
OUT WCHAR *pszDest,
|
|
IN ULONG cchMax);
|
|
|
|
int PtrWidth()
|
|
{
|
|
static int width = 0;
|
|
if (width) {
|
|
return width;
|
|
}
|
|
if (IsPtr64()) {
|
|
return width = 17;
|
|
}
|
|
return width = 8;
|
|
}
|
|
|
|
|
|
/*******************************************************************************\
|
|
* Flags stuff
|
|
\*******************************************************************************/
|
|
|
|
#define NO_FLAG (LPCSTR)(LONG_PTR)0xFFFFFFFF // use this for non-meaningful entries.
|
|
#define _MASKENUM_START (NO_FLAG-1)
|
|
#define _MASKENUM_END (NO_FLAG-2)
|
|
#define _SHIFT_BITS (NO_FLAG-3)
|
|
#define _CONTINUE_ON (NO_FLAG-4)
|
|
|
|
#define MASKENUM_START(mask) _MASKENUM_START, (LPCSTR)(mask)
|
|
#define MASKENUM_END(shift) _MASKENUM_END, (LPCSTR)(shift)
|
|
#define SHIFT_BITS(n) _SHIFT_BITS, (LPCSTR)(n)
|
|
#define CONTINUE_ON(arr) _CONTINUE_ON, (LPCSTR)(arr)
|
|
|
|
#if 0
|
|
enum GF_FLAGS {
|
|
GF_MAX
|
|
};
|
|
|
|
|
|
CONST PCSTR* aapszFlag[GF_MAX] = {
|
|
};
|
|
|
|
|
|
/***************************************************************************\
|
|
* Procedure: GetFlags
|
|
*
|
|
* Description:
|
|
*
|
|
* Converts a 32bit set of flags into an appropriate string.
|
|
* pszBuf should be large enough to hold this string, no checks are done.
|
|
* pszBuf can be NULL, allowing use of a local static buffer but note that
|
|
* this is not reentrant.
|
|
* Output string has the form: "FLAG1 | FLAG2 ..." or "0"
|
|
*
|
|
* Returns: pointer to given or static buffer with string in it.
|
|
*
|
|
* 6/9/1995 Created SanfordS
|
|
*
|
|
\***************************************************************************/
|
|
LPSTR GetFlags(
|
|
WORD wType,
|
|
DWORD dwFlags,
|
|
LPSTR pszBuf,
|
|
BOOL fPrintZero)
|
|
{
|
|
static char szT[512];
|
|
WORD i;
|
|
BOOL fFirst = TRUE;
|
|
BOOL fNoMoreNames = FALSE;
|
|
CONST PCSTR *apszFlags;
|
|
LPSTR apszFlagNames[sizeof(DWORD) * 8], pszT;
|
|
const char** ppszNextFlag;
|
|
UINT uFlagsCount, uNextFlag;
|
|
DWORD dwUnnamedFlags, dwLoopFlag;
|
|
DWORD dwShiftBits;
|
|
DWORD dwOrigFlags;
|
|
|
|
if (pszBuf == NULL) {
|
|
pszBuf = szT;
|
|
}
|
|
if (!bShowFlagNames) {
|
|
sprintf(pszBuf, "%x", dwFlags);
|
|
return pszBuf;
|
|
}
|
|
|
|
if (wType >= GF_MAX) {
|
|
strcpy(pszBuf, "Invalid flag type.");
|
|
return pszBuf;
|
|
}
|
|
|
|
/*
|
|
* Initialize output buffer and names array
|
|
*/
|
|
*pszBuf = '\0';
|
|
RtlZeroMemory(apszFlagNames, sizeof(apszFlagNames));
|
|
|
|
apszFlags = aapszFlag[wType];
|
|
|
|
/*
|
|
* Build a sorted array containing the names of the flags in dwFlags
|
|
*/
|
|
uFlagsCount = 0;
|
|
dwUnnamedFlags = dwOrigFlags = dwFlags;
|
|
dwLoopFlag = 1;
|
|
dwShiftBits = 0;
|
|
|
|
reentry:
|
|
for (i = 0; dwFlags; dwFlags >>= 1, i++, dwLoopFlag <<= 1, ++dwShiftBits) {
|
|
const char* lpszFlagName = NULL;
|
|
|
|
/*
|
|
* Bail if we reached the end of the flag names array
|
|
*/
|
|
if (apszFlags[i] == NULL) {
|
|
break;
|
|
}
|
|
|
|
if (apszFlags[i] == _MASKENUM_START) {
|
|
//
|
|
// Masked enumerative items.
|
|
//
|
|
DWORD en = 0;
|
|
DWORD dwMask = (DWORD)(ULONG_PTR)apszFlags[++i];
|
|
|
|
// First, clear up the handled bits.
|
|
dwUnnamedFlags &= ~dwMask;
|
|
lpszFlagName = NULL;
|
|
for (++i; apszFlags[i] != NULL && apszFlags[i] != _MASKENUM_END; ++i, ++en) {
|
|
if ((dwOrigFlags & dwMask) == (en << dwShiftBits )) {
|
|
if (apszFlags[i] != NO_FLAG) {
|
|
lpszFlagName = apszFlags[i];
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Shift the bits and get ready for the next item.
|
|
// Next item right after _MASKENUM_END holds the bits to shift.
|
|
//
|
|
dwFlags >>= (int)(ULONG_PTR)apszFlags[++i] - 1;
|
|
dwLoopFlag <<= (int)(ULONG_PTR)apszFlags[i] - 1;
|
|
dwShiftBits += (int)(ULONG_PTR)apszFlags[i] - 1;
|
|
if (lpszFlagName == NULL) {
|
|
//
|
|
// Could not find the match. Skip to the next item.
|
|
//
|
|
continue;
|
|
}
|
|
}
|
|
else if (apszFlags[i] == _CONTINUE_ON) {
|
|
//
|
|
// Refer the other item array. Pointer to the array is stored at [i+1].
|
|
//
|
|
apszFlags = (LPSTR*)apszFlags[i + 1];
|
|
goto reentry;
|
|
}
|
|
else if (apszFlags[i] == _SHIFT_BITS) {
|
|
//
|
|
// To save some space, just shift some bits..
|
|
//
|
|
dwFlags >>= (int)(ULONG_PTR)apszFlags[++i] - 1;
|
|
dwLoopFlag <<= (int)(ULONG_PTR)apszFlags[i] - 1;
|
|
dwShiftBits += (int)(ULONG_PTR)apszFlags[i] - 1;
|
|
continue;
|
|
}
|
|
else {
|
|
/*
|
|
* continue if this bit is not set or we don't have a name for it
|
|
*/
|
|
if (!(dwFlags & 1) || (apszFlags[i] == NO_FLAG)) {
|
|
continue;
|
|
}
|
|
lpszFlagName = apszFlags[i];
|
|
}
|
|
|
|
/*
|
|
* Find the sorted position where this name should go
|
|
*/
|
|
ppszNextFlag = apszFlagNames;
|
|
uNextFlag = 0;
|
|
while (uNextFlag < uFlagsCount) {
|
|
if (strcmp(*ppszNextFlag, lpszFlagName) > 0) {
|
|
break;
|
|
}
|
|
ppszNextFlag++;
|
|
uNextFlag++;
|
|
}
|
|
/*
|
|
* Insert the new name
|
|
*/
|
|
RtlMoveMemory((char*)(ppszNextFlag + 1), ppszNextFlag, (uFlagsCount - uNextFlag) * sizeof(DWORD));
|
|
*ppszNextFlag = lpszFlagName;
|
|
uFlagsCount++;
|
|
/*
|
|
* We got a name so clear it from the unnamed bits.
|
|
*/
|
|
dwUnnamedFlags &= ~dwLoopFlag;
|
|
}
|
|
|
|
/*
|
|
* Build the string now
|
|
*/
|
|
ppszNextFlag = apszFlagNames;
|
|
pszT = pszBuf;
|
|
/*
|
|
* Add the first name
|
|
*/
|
|
if (uFlagsCount > 0) {
|
|
pszT += sprintf(pszT, "%s", *ppszNextFlag++);
|
|
uFlagsCount--;
|
|
}
|
|
/*
|
|
* Concatenate all other names with " |"
|
|
*/
|
|
while (uFlagsCount > 0) {
|
|
pszT += sprintf(pszT, " | %s", *ppszNextFlag++);
|
|
uFlagsCount--;
|
|
}
|
|
/*
|
|
* If there are unamed bits, add them at the end
|
|
*/
|
|
if (dwUnnamedFlags != 0) {
|
|
pszT += sprintf(pszT, " | %#lx", dwUnnamedFlags);
|
|
}
|
|
/*
|
|
* Print zero if needed and asked to do so
|
|
*/
|
|
if (fPrintZero && (pszT == pszBuf)) {
|
|
sprintf(pszBuf, "0");
|
|
}
|
|
|
|
return pszBuf;
|
|
}
|
|
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Enumerated items with mask
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
typedef struct {
|
|
LPCSTR name;
|
|
DWORD value;
|
|
} EnumItem;
|
|
|
|
#define EITEM(a) { #a, a }
|
|
|
|
/***************************************************************************\
|
|
* Helper Procedures: dso etc.
|
|
*
|
|
* 04/19/2000 Created Hiro
|
|
\***************************************************************************/
|
|
|
|
// to workaround nosy InitTypeRead
|
|
#define _InitTypeRead(Addr, lpszType) GetShortField(Addr, (PUCHAR)lpszType, 1)
|
|
|
|
#define CONTINUE EXCEPTION_EXECUTE_HANDLER
|
|
|
|
#define RAISE_EXCEPTION() RaiseException(EXCEPTION_ACCESS_VIOLATION, 0, 0, NULL)
|
|
|
|
#define BAD_SYMBOL(symbol) \
|
|
Print("Failed to get %s: bad symbol?\n", symbol); \
|
|
RAISE_EXCEPTION()
|
|
|
|
#define CANT_GET_VALUE(symbol, p) \
|
|
Print("Failed to get %s @ %p: memory paged out?\n", symbol, p); \
|
|
RAISE_EXCEPTION()
|
|
|
|
|
|
|
|
BOOL dso(LPCSTR szStruct, ULONG64 address, ULONG dwOption)
|
|
{
|
|
SYM_DUMP_PARAM symDump = {
|
|
sizeof symDump, (PUCHAR) szStruct, dwOption, // 0 for default dump like dt
|
|
address,
|
|
NULL, NULL, NULL, 0, NULL
|
|
};
|
|
|
|
return Ioctl(IG_DUMP_SYMBOL_INFO, &symDump, symDump.size);
|
|
}
|
|
|
|
ULONG64 GetPointer(ULONG64 addr)
|
|
{
|
|
ULONG64 p = 0;
|
|
if (!ReadPointer(addr, &p)) {
|
|
CANT_GET_VALUE("a pointer", addr);
|
|
}
|
|
return p;
|
|
}
|
|
|
|
DWORD GetDWord(ULONG64 addr)
|
|
{
|
|
ULONG64 dw = 0xbaadbaad;
|
|
|
|
if (!GetFieldData(addr, "DWORD", NULL, sizeof dw, &dw)) {
|
|
CANT_GET_VALUE("DWORD", addr);
|
|
}
|
|
return (DWORD)dw;
|
|
}
|
|
|
|
WORD GetWord(ULONG64 addr)
|
|
{
|
|
ULONG64 w = 0xbaad;
|
|
|
|
if (!GetFieldData(addr, "WORD", NULL, sizeof w, &w)) {
|
|
CANT_GET_VALUE("WORD", addr);
|
|
}
|
|
return (WORD)w;
|
|
}
|
|
|
|
BYTE GetByte(ULONG64 addr)
|
|
{
|
|
ULONG64 b = 0;
|
|
|
|
if (GetFieldData(addr, "BYTE", NULL, sizeof b, &b)) {
|
|
CANT_GET_VALUE("BYTE", addr);
|
|
}
|
|
return (BYTE)b;
|
|
}
|
|
|
|
ULONG
|
|
GetUlongFromAddress (
|
|
ULONG64 Location
|
|
)
|
|
{
|
|
ULONG Value;
|
|
ULONG result;
|
|
|
|
if ((!ReadMemory(Location,&Value,sizeof(ULONG),&result)) || (result < sizeof(ULONG))) {
|
|
dprintf("GetUlongFromAddress: unable to read from %I64x\n", Location);
|
|
RAISE_EXCEPTION();
|
|
}
|
|
|
|
return Value;
|
|
}
|
|
|
|
|
|
ULONG64 GetGlobalPointer(LPSTR symbol)
|
|
{
|
|
ULONG64 pp;
|
|
ULONG64 p = 0;
|
|
|
|
pp = EvalExp(symbol);
|
|
if (pp == 0) {
|
|
BAD_SYMBOL(symbol);
|
|
} else if (!ReadPointer(pp, &p)) {
|
|
CANT_GET_VALUE(symbol, pp);
|
|
}
|
|
return p;
|
|
}
|
|
|
|
ULONG64 GetGlobalPointerNoExp(LPSTR symbol) // no exception
|
|
{
|
|
ULONG64 p = 0;
|
|
__try {
|
|
p = GetGlobalPointer(symbol);
|
|
} __except (CONTINUE) {
|
|
}
|
|
return p;
|
|
}
|
|
|
|
ULONG64 GetGlobalMemberAddress(LPSTR symbol, LPSTR type, LPSTR field)
|
|
{
|
|
ULONG64 pVar = EvalExp(symbol);
|
|
ULONG offset;
|
|
|
|
if (pVar == 0) {
|
|
BAD_SYMBOL(symbol);
|
|
}
|
|
|
|
if (GetFieldOffset(type, field, &offset)) {
|
|
BAD_SYMBOL(type);
|
|
}
|
|
|
|
return pVar + offset;
|
|
}
|
|
|
|
ULONG64 GetGlobalMember(LPSTR symbol, LPSTR type, LPSTR field)
|
|
{
|
|
ULONG64 pVar = EvalExp(symbol);
|
|
ULONG64 val;
|
|
|
|
if (pVar == 0) {
|
|
BAD_SYMBOL(symbol);
|
|
}
|
|
|
|
if (GetFieldValue(pVar, type, field, val)) {
|
|
CANT_GET_VALUE(symbol, pVar);
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
ULONG64 GetArrayElement(
|
|
ULONG64 pAddr,
|
|
LPSTR lpszStruc,
|
|
LPSTR lpszField,
|
|
ULONG64 index,
|
|
LPSTR lpszType)
|
|
{
|
|
static ULONG ulOffsetBase, ulSize;
|
|
ULONG64 result = 0;
|
|
|
|
if (lpszField) {
|
|
GetFieldOffset(lpszStruc, lpszField, &ulOffsetBase);
|
|
ulSize = GetTypeSize(lpszType);
|
|
}
|
|
ReadMemory(pAddr + ulOffsetBase + ulSize * index, &result, ulSize, NULL);
|
|
|
|
return result;
|
|
}
|
|
|
|
ULONG64 GetArrayElementPtr(
|
|
ULONG64 pAddr,
|
|
LPSTR lpszStruc,
|
|
LPSTR lpszField,
|
|
ULONG64 index)
|
|
{
|
|
static ULONG ulOffsetBase, ulSize;
|
|
ULONG64 result = 0;
|
|
|
|
if (lpszField) {
|
|
GetFieldOffset(lpszStruc, lpszField, &ulOffsetBase);
|
|
}
|
|
if (ulSize == 0) {
|
|
ulSize = GetTypeSize("PVOID");
|
|
}
|
|
ReadPointer(pAddr + ulOffsetBase + ulSize * index, &result);
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Show progress in time consuming commands
|
|
* 10/15/2000 hiroyama
|
|
*/
|
|
void ShowProgress(ULONG i)
|
|
{
|
|
const char* clock[] = {
|
|
"\r-\r",
|
|
"\r\\\r",
|
|
"\r|\r",
|
|
"\r/\r",
|
|
};
|
|
|
|
/*
|
|
* Show the progress :-)
|
|
*/
|
|
Print(clock[i % COUNTOF(clock)]);
|
|
}
|
|
|
|
#define DOWNCAST(type, value) ((type)(ULONG_PTR)(value))
|
|
|
|
/***************************************************************************\
|
|
* Procedure: PrintBitField, PrintEndBitField
|
|
*
|
|
* Description: Printout specified boolean value in a structure.
|
|
* Assuming strlen(pszFieldName) will not exceeds BF_COLUMN_WIDTH.
|
|
*
|
|
* Returns: None
|
|
*
|
|
* 10/12/1997 Created HiroYama
|
|
*
|
|
\***************************************************************************/
|
|
void PrintBitField(LPSTR pszFieldName, BOOLEAN fValue)
|
|
{
|
|
int iWidth;
|
|
int iStart = giBFColumn;
|
|
|
|
sprintf(gach1, fValue ? "*%-s " : " %-s ", pszFieldName);
|
|
|
|
iWidth = (strlen(gach1) + BF_COLUMN_WIDTH - 1) / BF_COLUMN_WIDTH;
|
|
iWidth *= BF_COLUMN_WIDTH;
|
|
|
|
if ((giBFColumn += iWidth) >= BF_MAX_WIDTH) {
|
|
giBFColumn = iWidth;
|
|
Print("%s\n", gaBFBuff);
|
|
iStart = 0;
|
|
}
|
|
|
|
sprintf(gaBFBuff + iStart, "%-*s", iWidth, gach1);
|
|
}
|
|
|
|
void PrintEndBitField()
|
|
{
|
|
if (giBFColumn != 0) {
|
|
giBFColumn = 0;
|
|
Print("%s\n", gaBFBuff);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* Procedure: CopyUnicodeString
|
|
*
|
|
* 06/05/00 JStall Created (yeah, baby!)
|
|
*
|
|
\***************************************************************************/
|
|
BOOL
|
|
CopyUnicodeString(
|
|
IN ULONG64 pData,
|
|
IN char * pszStructName,
|
|
IN char * pszFieldName,
|
|
OUT WCHAR *pszDest,
|
|
IN ULONG cchMax)
|
|
{
|
|
ULONG Length;
|
|
ULONG64 Buffer;
|
|
char szLengthName[256];
|
|
char szBufferName[256];
|
|
|
|
if (pData == 0) {
|
|
pszDest[0] = '\0';
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(szLengthName, pszFieldName);
|
|
strcat(szLengthName, ".Length");
|
|
strcpy(szBufferName, pszFieldName);
|
|
strcat(szBufferName, ".Buffer");
|
|
|
|
if (GetFieldValue(pData, pszStructName, szLengthName, Length) ||
|
|
GetFieldValue(pData, pszStructName, szBufferName, Buffer)) {
|
|
|
|
wcscpy(pszDest, L"<< Can't get name >>");
|
|
return FALSE;
|
|
}
|
|
|
|
if (Buffer == 0) {
|
|
wcscpy(pszDest, L"<null>");
|
|
} else {
|
|
ULONG cbText;
|
|
cbText = min(cchMax, Length + sizeof(WCHAR));
|
|
if (!(tryMoveBlock(pszDest, Buffer, cbText))) {
|
|
wcscpy(pszDest, L"<< Can't get value >>");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* DirectUser TLS access
|
|
*
|
|
* 12/03/2000 JStall Created
|
|
*
|
|
\***************************************************************************/
|
|
|
|
BOOL
|
|
ReadTlsValue(ULONG64 pteb, ULONG idxSlot, ULONG64 * ppValue)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
ULONG64 pValue = NULL;
|
|
|
|
//
|
|
// Need to remove the high-bit from the TLS slot. This is set on in
|
|
// Checked build to detect illegal / uninitialized slots, such as '0'.
|
|
//
|
|
|
|
idxSlot &= 0x7FFFFFFF;
|
|
|
|
|
|
//
|
|
// Get TLS info
|
|
//
|
|
|
|
ULONG64 pThread = 0;
|
|
|
|
// Print("> idxSlot: %d\n", idxSlot);
|
|
// Print("> TEB: 0x%p\n", pteb);
|
|
|
|
if (pteb) {
|
|
ULONG64 rgTLS = NULL;
|
|
ULONG ulOffset = 0;
|
|
ULONG ulSize = GetTypeSize("PVOID");
|
|
// Print("> ulSize: %d\n", ulSize);
|
|
|
|
if (idxSlot < TLS_MINIMUM_AVAILABLE) {
|
|
// pThread = Teb->TlsSlots[idxSlot];
|
|
|
|
GetFieldOffset(SYM(_TEB), "TlsSlots", &ulOffset);
|
|
// Print("> TlsSlots offset: %d\n", ulOffset);
|
|
|
|
ReadPointer(pteb + ulOffset + ulSize * idxSlot, &pValue);
|
|
fSuccess = TRUE;
|
|
|
|
} else if (idxSlot >= TLS_MINIMUM_AVAILABLE + TLS_EXPANSION_SLOTS) {
|
|
Print("ERROR: Invalid TLS index %d\n", idxSlot);
|
|
} else {
|
|
// pThread = Teb->TlsExpansionSlots[idxSlot - TLS_MINIMUM_AVAILABLE];
|
|
|
|
GetFieldOffset("_TEB", "TlsExpansionSlots", &ulOffset);
|
|
// Print("> TlsExpansionSlots offset: %d\n", ulOffset);
|
|
|
|
rgTLS = GetPointer(pteb + ulOffset);
|
|
if (rgTLS != NULL) {
|
|
ReadPointer(rgTLS + ulSize * (idxSlot - TLS_MINIMUM_AVAILABLE), &pValue);
|
|
fSuccess = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
*ppValue = pValue;
|
|
return fSuccess;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* GetDUserThread
|
|
*
|
|
* GetDUserThread() returns the global Thread object for the current thread.
|
|
*
|
|
* 12/03/2000 JStall Created
|
|
*
|
|
\***************************************************************************/
|
|
|
|
BOOL
|
|
GetDUserThread(ULONG64 pteb, ULONG64 * ppThread)
|
|
{
|
|
*ppThread = NULL;
|
|
|
|
|
|
//
|
|
// Get DUser TLS slot
|
|
//
|
|
|
|
ULONG idxSlot = (ULONG) GetGlobalPointer(VAR(g_tlsThread));
|
|
if (idxSlot == (UINT) -1) {
|
|
Print("ERROR: Unable to get DirectUser TLS information.\n");
|
|
return FALSE;
|
|
}
|
|
|
|
if ((!ReadTlsValue(pteb, idxSlot, ppThread)) || (*ppThread == NULL)) {
|
|
Print("ERROR: Unable to get DirectUser Thread information.\n");
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* Procedure: Igthread
|
|
*
|
|
* Dumps DUser Thread information
|
|
*
|
|
* 11/30/2000 JStall Created
|
|
*
|
|
\***************************************************************************/
|
|
|
|
BOOL Igthread(DWORD opts, ULONG64 param1)
|
|
{
|
|
int nMsg;
|
|
ULONG64 pThread = NULL, pteb = NULL;
|
|
|
|
BOOL fVerbose = TRUE;
|
|
|
|
__try {
|
|
//
|
|
// Determine options
|
|
//
|
|
|
|
fVerbose = opts & OFLAG(v);
|
|
|
|
|
|
//
|
|
// Get Thread information
|
|
//
|
|
|
|
if (opts & OFLAG(t)) {
|
|
//
|
|
// Use the specified TEB
|
|
//
|
|
|
|
pteb = param1;
|
|
} else if (param1 == 0) {
|
|
//
|
|
// Use the current thread's TEB
|
|
//
|
|
|
|
GetTebAddress(&pteb);
|
|
}
|
|
|
|
if (pteb != NULL) {
|
|
GetDUserThread(pteb, &pThread);
|
|
}
|
|
|
|
|
|
//
|
|
// Display information
|
|
//
|
|
|
|
if (pThread != NULL) {
|
|
Print("DUser Thread: 0x%p pteb: 0x%p\n", pThread, pteb);
|
|
dso(SYM(Thread), pThread, 0);
|
|
|
|
ULONG64 pCoreST = GetArrayElementPtr(pThread, SYM(Thread), "m_rgSTs", 0);
|
|
|
|
if (pCoreST != NULL) {
|
|
Print("\nDUser CoreST: 0x%p\n", pCoreST);
|
|
dso(SYM(CoreST), pCoreST, 0);
|
|
}
|
|
|
|
} else {
|
|
Print("ERROR: Unable to read DUser Thread\n");
|
|
}
|
|
|
|
} __except (CONTINUE) {
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* Procedure: Itls
|
|
*
|
|
* Dumps a TLS slot value
|
|
*
|
|
* 6/08/2001 JStall Created
|
|
*
|
|
\***************************************************************************/
|
|
|
|
BOOL Itls(DWORD opts, ULONG64 param1, ULONG64 param2)
|
|
{
|
|
__try {
|
|
ULONG idxSlot = ((ULONG) param1) & 0x7FFFFFFF;
|
|
ULONG64 pteb = param2;
|
|
ULONG64 pData;
|
|
|
|
if (idxSlot == 0) {
|
|
Print("ERROR: Need to specify a TLS slot.\n");
|
|
} else {
|
|
if (param2 == 0) {
|
|
//
|
|
// Need to determine the current thread
|
|
//
|
|
GetTebAddress(&pteb);
|
|
}
|
|
|
|
if (pteb == 0) {
|
|
Print("ERROR: Unable to get thread information.\n");
|
|
} else {
|
|
if (!ReadTlsValue(pteb, idxSlot, &pData)) {
|
|
Print("ERROR: Unable to get TLS information.\n");
|
|
} else {
|
|
Print("TLS[%d] = 0x%p %d\n", idxSlot, pData, pData);
|
|
}
|
|
}
|
|
}
|
|
} __except (CONTINUE) {
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* Procedure: Igcontext
|
|
*
|
|
* Dumps DUser Context information
|
|
*
|
|
* 11/30/2000 JStall Created
|
|
*
|
|
\***************************************************************************/
|
|
|
|
BOOL Igcontext(DWORD opts, ULONG64 param1)
|
|
{
|
|
int nMsg;
|
|
ULONG64 pThread = NULL, pContext = NULL, pteb = NULL;
|
|
|
|
BOOL fVerbose = TRUE;
|
|
|
|
__try {
|
|
//
|
|
// Determine options
|
|
//
|
|
|
|
fVerbose = opts & OFLAG(v);
|
|
|
|
|
|
//
|
|
// Get Thread and Context information
|
|
//
|
|
|
|
if (opts & OFLAG(t)) {
|
|
//
|
|
// Use the specified TEB
|
|
//
|
|
|
|
pteb = param1;
|
|
} else if (param1 == 0) {
|
|
//
|
|
// Use the current thread's TEB
|
|
//
|
|
|
|
GetTebAddress(&pteb);
|
|
} else {
|
|
pContext = param1;
|
|
}
|
|
|
|
if (pteb != NULL) {
|
|
GetDUserThread(pteb, &pThread);
|
|
Print("> Thread: 0x%p\n", pThread);
|
|
|
|
if (pThread != NULL) {
|
|
ULONG ulOffset;
|
|
GetFieldOffset(SYM(Thread), "m_pContext", &ulOffset);
|
|
Print("> ulOffset: 0x%x = d\n", ulOffset, ulOffset);
|
|
|
|
ReadPointer(pThread + ulOffset, &pContext);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Display information
|
|
//
|
|
|
|
if (pContext != NULL) {
|
|
Print("DUser Context: 0x%p\n", pContext, pteb);
|
|
dso(SYM(Context), pContext, 0);
|
|
|
|
ULONG64 pCoreSC = GetArrayElementPtr(pContext, SYM(Context), "m_rgSCs", 0);
|
|
ULONG64 pMotionSC = GetArrayElementPtr(pContext, SYM(Context), "m_rgSCs", 1);
|
|
|
|
if (pCoreSC != NULL) {
|
|
Print("\nDUser CoreSC: 0x%p\n", pCoreSC);
|
|
dso(SYM(CoreSC), pCoreSC, 0);
|
|
}
|
|
|
|
if (pMotionSC != NULL) {
|
|
Print("\nDUser MotionSC: 0x%p\n", pMotionSC);
|
|
dso(SYM(MotionSC), pMotionSC, 0);
|
|
}
|
|
|
|
} else {
|
|
Print("ERROR: Unable to read DUser Context\n");
|
|
}
|
|
|
|
} __except (CONTINUE) {
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* DirectUser Message Dumping
|
|
*
|
|
* 11/30/2000 JStall Created
|
|
*
|
|
\***************************************************************************/
|
|
|
|
struct DbgMsgInfo
|
|
{
|
|
int cLevel; // Level in heirarchy
|
|
LPCSTR pszStructName; // Structure to type-case to
|
|
int nValue; // Value (of children)
|
|
LPCSTR pszValueName; // Message / value name
|
|
LPCSTR pszFieldName; // Name of field for child lookup
|
|
};
|
|
|
|
#define DBGMI_PARENT(cLevel, pszStructName, value, pszFieldName) \
|
|
{ cLevel, SYM(pszStructName), value, #value, #pszFieldName }
|
|
|
|
#define DBGMI_LEAF(cLevel, pszStructName, value) \
|
|
{ cLevel, SYM(pszStructName), value, #value, NULL }
|
|
|
|
DbgMsgInfo g_dmi[] = {
|
|
DBGMI_PARENT(0, GMSG_DESTROY, GM_DESTROY, nCode),
|
|
DBGMI_LEAF( 1, GMSG_DESTROY, GDESTROY_START),
|
|
DBGMI_LEAF( 1, GMSG_DESTROY, GDESTROY_FINAL),
|
|
|
|
DBGMI_PARENT(0, GMSG_PAINT, GM_PAINT, nCmd),
|
|
DBGMI_PARENT(1, GMSG_PAINT, GPAINT_RENDER, nSurfaceType),
|
|
DBGMI_LEAF( 2, GMSG_PAINTRENDERI, GSURFACE_HDC),
|
|
DBGMI_LEAF( 2, GMSG_PAINTRENDERF, GSURFACE_GPGRAPHICS),
|
|
|
|
DBGMI_PARENT(0, GMSG_INPUT, GM_INPUT, nDevice),
|
|
|
|
DBGMI_PARENT(1, GMSG_MOUSE, GINPUT_MOUSE, nCode),
|
|
DBGMI_LEAF( 2, GMSG_MOUSE, GMOUSE_MOVE),
|
|
DBGMI_LEAF( 2, GMSG_MOUSECLICK, GMOUSE_DOWN),
|
|
DBGMI_LEAF( 2, GMSG_MOUSECLICK, GMOUSE_UP),
|
|
DBGMI_LEAF( 2, GMSG_MOUSEDRAG, GMOUSE_DRAG),
|
|
DBGMI_LEAF( 2, GMSG_MOUSE, GMOUSE_HOVER),
|
|
DBGMI_LEAF( 2, GMSG_MOUSEWHEEL, GMOUSE_WHEEL),
|
|
|
|
DBGMI_PARENT(1, GMSG_KEYBOARD, GINPUT_KEYBOARD, nCode),
|
|
DBGMI_LEAF( 2, GMSG_KEYBOARD, GKEY_DOWN),
|
|
DBGMI_LEAF( 2, GMSG_KEYBOARD, GKEY_UP),
|
|
DBGMI_LEAF( 2, GMSG_KEYBOARD, GKEY_CHAR),
|
|
DBGMI_LEAF( 2, GMSG_KEYBOARD, GKEY_SYSDOWN),
|
|
DBGMI_LEAF( 2, GMSG_KEYBOARD, GKEY_SYSUP),
|
|
DBGMI_LEAF( 2, GMSG_KEYBOARD, GKEY_SYSCHAR),
|
|
DBGMI_LEAF( 2, GMSG_KEYBOARD, GMOUSE_WHEEL),
|
|
|
|
DBGMI_LEAF( 1, GMSG_INPUT, GINPUT_JOYSTICK),
|
|
|
|
DBGMI_PARENT(0, GMSG_CHANGESTATE, GM_CHANGESTATE, nCode),
|
|
DBGMI_LEAF( 1, GMSG_CHANGESTATE, GSTATE_KEYBOARDFOCUS),
|
|
DBGMI_LEAF( 1, GMSG_CHANGESTATE, GSTATE_MOUSEFOCUS),
|
|
DBGMI_LEAF( 1, GMSG_CHANGESTATE, GSTATE_ACTIVE),
|
|
DBGMI_LEAF( 1, GMSG_CHANGESTATE, GSTATE_CAPTURE),
|
|
|
|
DBGMI_LEAF( 0, GMSG_CHANGERECT, GM_CHANGERECT),
|
|
|
|
DBGMI_LEAF( 0, GMSG_CHANGESTYLE, GM_CHANGESTYLE),
|
|
|
|
DBGMI_PARENT(0, GMSG_QUERY, GM_QUERY, nCode),
|
|
#ifdef GADGET_ENABLE_OLE
|
|
DBGMI_LEAF( 1, GMSG_QUERYINTERFACE,GQUERY_INTERFACE),
|
|
DBGMI_LEAF( 1, GMSG_QUERYINTERFACE,GQUERY_OBJECT),
|
|
#endif
|
|
DBGMI_LEAF( 1, GMSG_QUERYRECT, GQUERY_RECT),
|
|
DBGMI_LEAF( 1, GMSG_QUERYDESC, GQUERY_DESCRIPTION),
|
|
DBGMI_LEAF( 1, GMSG_QUERYHITTEST, GQUERY_HITTEST),
|
|
DBGMI_LEAF( 1, GMSG_QUERYPADDING, GQUERY_PADDING),
|
|
#ifdef GADGET_ENABLE_OLE
|
|
DBGMI_LEAF( 1, GMSG_QUERYDROPTARGET,GQUERY_DROPTARGET),
|
|
#endif
|
|
|
|
{ -1, NULL, NULL, NULL, NULL } // End of list
|
|
};
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* Procedure: FindMsgInfo()
|
|
*
|
|
* 11/30/2000 JStall Created
|
|
*
|
|
\***************************************************************************/
|
|
|
|
const DbgMsgInfo *
|
|
FindMsgInfo(ULONG64 pmsg)
|
|
{
|
|
LPCSTR pszCurField = "nMsg";
|
|
int cCurLevel = 0;
|
|
int nSearchValue;
|
|
const DbgMsgInfo * pdmiCur = g_dmi;
|
|
const DbgMsgInfo * pdmiBest = NULL;
|
|
|
|
|
|
//
|
|
// Start off by decoding the GMSG
|
|
//
|
|
|
|
InitTypeRead(pmsg, GMSG);
|
|
nSearchValue = (int) ReadField(nMsg);
|
|
|
|
// Print("...searching for nMsg: 0x%x\n", nSearchValue);
|
|
|
|
while (pdmiCur->cLevel >= cCurLevel) {
|
|
// Print(" %d: %s, %d\n", pdmiCur->cLevel, pdmiCur->pszStructName, pdmiCur->nValue);
|
|
|
|
//
|
|
// Search entries at the same level for a matching value
|
|
//
|
|
|
|
if (pdmiCur->cLevel == cCurLevel) {
|
|
if (pdmiCur->nValue == nSearchValue) {
|
|
//
|
|
// We've found a corresponding entry. We can update our best
|
|
// guess as the to the message type and start searching its
|
|
// children.
|
|
//
|
|
|
|
pdmiBest = pdmiCur;
|
|
cCurLevel++;
|
|
|
|
if (pdmiBest->pszFieldName != NULL) {
|
|
//
|
|
// This node has children that can be used to typecast the
|
|
// message futher.
|
|
//
|
|
|
|
// Perform an InitTypeRead() to cast the structure
|
|
GetShortField(pmsg, pdmiBest->pszStructName, 1);
|
|
|
|
// Read the next (int) ReadField(nMsg);
|
|
nSearchValue = (int) GetShortField(0, pdmiBest->pszFieldName, 0);
|
|
|
|
// Print("...searching for %s: 0x%x\n", pdmiBest->pszFieldName, nSearchValue);
|
|
} else {
|
|
//
|
|
// This node has no children, so we are now down.
|
|
//
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
pdmiCur++;
|
|
}
|
|
|
|
return pdmiBest;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* FormatMsgName
|
|
*
|
|
* FormatMsgName() generates a descriptive message name for a given message.
|
|
*
|
|
* 11/30/2000 JStall Created
|
|
*
|
|
\***************************************************************************/
|
|
|
|
void
|
|
FormatMsgName(ULONG64 pmsg, char * pszMsgName, int cch, const DbgMsgInfo ** ppdmi)
|
|
{
|
|
UNREFERENCED_PARAMETER(cch);
|
|
|
|
if (ppdmi != NULL) {
|
|
*ppdmi = NULL;
|
|
}
|
|
|
|
InitTypeRead(pmsg, GMSG);
|
|
int nMsg = (int) ReadField(nMsg);
|
|
|
|
if (nMsg < GM_EVENT) {
|
|
strcpy(pszMsgName, "(Method)");
|
|
} else if (nMsg > GM_USER) {
|
|
strcpy(pszMsgName, "(User defined event)");
|
|
} else {
|
|
const DbgMsgInfo * pdmi = FindMsgInfo(pmsg);
|
|
if (pdmi != NULL) {
|
|
sprintf(pszMsgName, "%s : %s", pdmi->pszStructName, pdmi->pszValueName);
|
|
|
|
if (ppdmi != NULL) {
|
|
*ppdmi = pdmi;
|
|
}
|
|
} else {
|
|
strcpy(pszMsgName, "(Unable to find GMSG)");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* Procedure: Igmsg
|
|
*
|
|
* Dumps DUser GMSG information
|
|
*
|
|
* 11/30/2000 JStall Created
|
|
*
|
|
\***************************************************************************/
|
|
|
|
BOOL Igmsg(DWORD opts, ULONG64 param1)
|
|
{
|
|
int nMsg;
|
|
LPCSTR pszMsgName;
|
|
ULONG64 pmsg;
|
|
CHAR szFullMsgName[256];
|
|
|
|
BOOL fVerbose = TRUE;
|
|
const DbgMsgInfo * pdmi = NULL;
|
|
|
|
pmsg = param1;
|
|
|
|
__try {
|
|
//
|
|
// Determine options
|
|
//
|
|
|
|
fVerbose = opts & OFLAG(v);
|
|
|
|
|
|
//
|
|
// Get GMSG information
|
|
//
|
|
|
|
FormatMsgName(pmsg, szFullMsgName, COUNTOF(szFullMsgName), &pdmi);
|
|
|
|
|
|
//
|
|
// Display information
|
|
//
|
|
|
|
Print("GMSG = %s\n", szFullMsgName);
|
|
|
|
if (pdmi != NULL) {
|
|
dso(pdmi->pszStructName, pmsg, 0);
|
|
}
|
|
|
|
} __except (CONTINUE) {
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* Procedure: Igme
|
|
*
|
|
* Dumps DUser MsgEntry information
|
|
*
|
|
* 11/30/2000 JStall Created
|
|
*
|
|
\***************************************************************************/
|
|
|
|
BOOL Igme(DWORD opts, ULONG64 param1)
|
|
{
|
|
DWORD cbSize;
|
|
int nMsg;
|
|
LPCSTR pszMsgName;
|
|
ULONG64 pme, pmsg;
|
|
CHAR szFullMsgName[256];
|
|
const DbgMsgInfo * pdmi = NULL;
|
|
|
|
BOOL fVerbose = TRUE;
|
|
BOOL fList = FALSE;
|
|
|
|
pme = param1;
|
|
|
|
__try {
|
|
//
|
|
// Determine options
|
|
//
|
|
|
|
fVerbose = opts & OFLAG(v);
|
|
fList = opts & OFLAG(l);
|
|
|
|
while (pme != NULL) {
|
|
//
|
|
// Read standard information
|
|
//
|
|
|
|
pmsg = pme + GetTypeSize(SYM(MsgEntry));
|
|
|
|
InitTypeRead(pmsg, GMSG);
|
|
nMsg = (int) ReadField(nMsg);
|
|
|
|
FormatMsgName(pmsg, szFullMsgName, COUNTOF(szFullMsgName), &pdmi);
|
|
|
|
|
|
//
|
|
// Display information
|
|
//
|
|
|
|
if (fVerbose) {
|
|
Print("MsgEntry: 0x%p\n", pme);
|
|
Print(" Message: 0x%p %s\n", pmsg, szFullMsgName);
|
|
|
|
if (pdmi != NULL) {
|
|
dso(pdmi->pszStructName, pmsg, 0);
|
|
}
|
|
} else {
|
|
Print("MsgEntry: 0x%p GMSG: 0x%p nMsg: 0x%x = %s\n", pme, pmsg, nMsg, szFullMsgName);
|
|
}
|
|
|
|
|
|
if (fList) {
|
|
//
|
|
// Reading a list, so go to next message
|
|
//
|
|
|
|
InitTypeRead(pme, MsgEntry);
|
|
pme = ReadField(pNext);
|
|
|
|
if (fVerbose & (pme != NULL)) {
|
|
Print("\n");
|
|
}
|
|
} else {
|
|
//
|
|
// Not displaying a list, so just exit
|
|
//
|
|
|
|
break;
|
|
}
|
|
}
|
|
} __except (CONTINUE) {
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// WARNING: Keep this is sync with the real DuTicket
|
|
//
|
|
struct DuTicketCopy
|
|
{
|
|
DWORD Index : 16;
|
|
DWORD Uniqueness : 8;
|
|
DWORD Type : 7;
|
|
DWORD Unused : 1;
|
|
};
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* Procedure: ForAllTickets
|
|
*
|
|
* Iterates over all of the tickets in the ticket manager, invoking the
|
|
* specified callback for each one.
|
|
*
|
|
\***************************************************************************/
|
|
typedef BOOL (*PfnTicketCallback)(DuTicketCopy ticket, ULONG64 pObject, void * pRawData);
|
|
void ForAllTickets(PfnTicketCallback pfnTicketCallback, void * pRawData)
|
|
{
|
|
if (pfnTicketCallback == NULL) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Prepare to read the value of g_TicketManager->m_arTicketData;
|
|
//
|
|
ULONG64 pTicketManager = EvalExp(VAR(g_TicketManager));
|
|
ULONG ulTicketDataOffset = 0;
|
|
GetFieldOffset(SYM(DuTicketManager), "m_arTicketData", &ulTicketDataOffset);
|
|
InitTypeRead(pTicketManager + ulTicketDataOffset, DuTicketDataArray);
|
|
|
|
//
|
|
// Extract the data about the actual DuTicketDataArray since we are here.
|
|
//
|
|
ULONG64 paTicketData = ReadField(m_aT);
|
|
int nSize = (int) ReadField(m_nSize);
|
|
int nAllocSize = (int) ReadField(m_nAllocSize);
|
|
|
|
//
|
|
// Walk through the entire array.
|
|
//
|
|
ULONG cbTicketData = GetTypeSize("DuTicketData");
|
|
|
|
for (int i = 0; i < nSize; i++) {
|
|
InitTypeRead(paTicketData, DuTicketData);
|
|
|
|
//
|
|
// Read the fields of the ticket data.
|
|
//
|
|
ULONG64 pObject = ReadField(pObject);
|
|
WORD idxFree = (WORD) ReadField(idxFree);
|
|
BYTE cUniqueness = (BYTE) ReadField(cUniqueness);
|
|
|
|
//
|
|
// Construct the equivalent ticket for this ticket data.
|
|
//
|
|
DuTicketCopy ticket;
|
|
ticket.Index = i;
|
|
ticket.Uniqueness = cUniqueness;
|
|
ticket.Type = 0; // TODO: Get this data
|
|
ticket.Unused = 0;
|
|
|
|
if (FALSE == pfnTicketCallback(ticket, pObject, pRawData)) {
|
|
//
|
|
// The callback requested that we bail out early!
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Advance to the next element in the array.
|
|
//
|
|
paTicketData += cbTicketData;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* Procedure: DumpAllTicketsCB
|
|
*
|
|
* Callback that can be passed to the ForAllTickets function to dump the
|
|
* ticket data for all tickets in the table.
|
|
*
|
|
\***************************************************************************/
|
|
struct DumpAllTicketsData
|
|
{
|
|
DumpAllTicketsData(bool f) : fVerbose(f), nSize(0), cTickets(0) {}
|
|
|
|
bool fVerbose;
|
|
int nSize;
|
|
int cTickets;
|
|
};
|
|
|
|
BOOL DumpAllTicketsCB(DuTicketCopy ticket, ULONG64 pObject, void * pRawData)
|
|
{
|
|
DumpAllTicketsData * pData = (DumpAllTicketsData *) pRawData;
|
|
|
|
if (pData == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (pObject != NULL || pData->fVerbose) {
|
|
// iSlot cUniqueness pObject
|
|
Print("%4d %4d 0x%p\n", ticket.Index, ticket.Uniqueness, pObject);
|
|
}
|
|
|
|
//
|
|
// Count the number of tickets that have a pointer associated with them.
|
|
//
|
|
if (pObject != NULL) {
|
|
pData->cTickets++;
|
|
}
|
|
|
|
//
|
|
// Count the number of slots in the table.
|
|
//
|
|
pData->nSize++;
|
|
|
|
//
|
|
// Keep going...
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* Procedure: DumpTicketByTicketCB
|
|
*
|
|
* Callback that can be passed to the ForAllTickets function to dump only
|
|
* the ticket data that matches the given ticket.
|
|
*
|
|
\***************************************************************************/
|
|
struct DumpTicketByTicketData
|
|
{
|
|
DumpTicketByTicketData(DuTicketCopy t) : ticket(t) {}
|
|
DumpTicketByTicketData(DWORD t) : ticket(*((DuTicketCopy*) &t)) {}
|
|
|
|
DuTicketCopy ticket;
|
|
};
|
|
|
|
BOOL DumpTicketByTicketCB(DuTicketCopy ticket, ULONG64 pObject, void * pRawData)
|
|
{
|
|
DumpTicketByTicketData * pData = (DumpTicketByTicketData *) pRawData;
|
|
|
|
if (pData == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (ticket.Index == pData->ticket.Index) {
|
|
if (ticket.Uniqueness != pData->ticket.Uniqueness) {
|
|
Print("Warning: the uniqueness (%d) doesn't match!\n", pData->ticket.Uniqueness);
|
|
}
|
|
|
|
Print("iSlot: %d, cUniqueness: %d, pObject: 0x%p\n", ticket.Index, ticket.Uniqueness, pObject);
|
|
|
|
//
|
|
// Since the indecies matched, there is no point in continuing.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// The indecies didn't match, so keep going.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* Procedure: DumpTicketByUniquenessCB
|
|
*
|
|
* Callback that can be passed to the ForAllTickets function to dump only
|
|
* the ticket data that matches the given uniqueness.
|
|
*
|
|
\***************************************************************************/
|
|
struct DumpTicketByUniquenessData
|
|
{
|
|
DumpTicketByUniquenessData(UINT c) : cUniqueness(c) {}
|
|
|
|
UINT cUniqueness;
|
|
};
|
|
|
|
BOOL DumpTicketByUniquenessCB(DuTicketCopy ticket, ULONG64 pObject, void * pRawData)
|
|
{
|
|
DumpTicketByUniquenessData * pData = (DumpTicketByUniquenessData *) pRawData;
|
|
|
|
if (pData == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (ticket.Uniqueness == pData->cUniqueness) {
|
|
Print("iSlot: %d, cUniqueness: %d, pObject: 0x%p\n", ticket.Index, ticket.Uniqueness, pObject);
|
|
}
|
|
|
|
//
|
|
// Keep going...
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* Procedure: DumpTicketBySlotCB
|
|
*
|
|
* Callback that can be passed to the ForAllTickets function to dump only
|
|
* the ticket data that matches the given slot.
|
|
*
|
|
\***************************************************************************/
|
|
struct DumpTicketBySlotData
|
|
{
|
|
DumpTicketBySlotData(UINT i) : iSlot(i) {}
|
|
|
|
UINT iSlot;
|
|
};
|
|
|
|
BOOL DumpTicketBySlotCB(DuTicketCopy ticket, ULONG64 pObject, void * pRawData)
|
|
{
|
|
DumpTicketBySlotData * pData = (DumpTicketBySlotData *) pRawData;
|
|
|
|
if (pData == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (ticket.Index == pData->iSlot) {
|
|
Print("iSlot: %d, cUniqueness: %d, pObject: 0x%p\n", ticket.Index, ticket.Uniqueness, pObject);
|
|
|
|
//
|
|
// Since the indecies matched, there is no point in continuing.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// The indecies didn't match, so keep going.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* Procedure: DumpTicketByObjectCB
|
|
*
|
|
* Callback that can be passed to the ForAllTickets function to dump only
|
|
* the ticket data that matches the given object.
|
|
*
|
|
\***************************************************************************/
|
|
struct DumpTicketByObjectData
|
|
{
|
|
DumpTicketByObjectData(ULONG64 p) : pObject(p) {}
|
|
|
|
ULONG64 pObject;
|
|
};
|
|
|
|
BOOL DumpTicketByObjectCB(DuTicketCopy ticket, ULONG64 pObject, void * pRawData)
|
|
{
|
|
DumpTicketByObjectData * pData = (DumpTicketByObjectData *) pRawData;
|
|
|
|
if (pData == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (pObject == pData->pObject) {
|
|
Print("iSlot: %d, cUniqueness: %d, pObject: 0x%p\n", ticket.Index, ticket.Uniqueness, pObject);
|
|
|
|
//
|
|
// Since the indecies matched, there is no point in continuing.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// The indecies didn't match, so keep going.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* Procedure: Igticket
|
|
*
|
|
* Dumps DUser ticket information
|
|
*
|
|
\***************************************************************************/
|
|
|
|
BOOL Igticket(DWORD opts, ULONG64 param1)
|
|
{
|
|
DWORD cbSize;
|
|
int nMsg;
|
|
LPCSTR pszMsgName;
|
|
CHAR szFullMsgName[256];
|
|
const DbgMsgInfo * pdmi = NULL;
|
|
|
|
__try {
|
|
//
|
|
// Determine options
|
|
//
|
|
BOOL fTicket = opts & OFLAG(t);
|
|
BOOL fSlot = opts & OFLAG(s);
|
|
BOOL fObject = opts & OFLAG(o);
|
|
BOOL fUniqueness = opts & OFLAG(u);
|
|
BOOL fVerbose = opts & OFLAG(v);
|
|
|
|
if (fTicket) {
|
|
DumpTicketByTicketData data((DWORD)param1);
|
|
ForAllTickets(DumpTicketByTicketCB, &data);
|
|
} else if (fSlot) {
|
|
DumpTicketBySlotData data((UINT)param1);
|
|
ForAllTickets(DumpTicketBySlotCB, &data);
|
|
} else if (fObject) {
|
|
DumpTicketByObjectData data(param1);
|
|
ForAllTickets(DumpTicketByObjectCB, &data);
|
|
} else if (fUniqueness) {
|
|
DumpTicketByUniquenessData data((UINT)param1);
|
|
ForAllTickets(DumpTicketByUniquenessCB, &data);
|
|
} else {
|
|
//
|
|
// Just display information about all of the tickets in the table.
|
|
//
|
|
// slot uniq pObject
|
|
Print("iSlot cUniqueness pObject\n");
|
|
Print("---------------------------\n");
|
|
|
|
DumpAllTicketsData data(fVerbose ? true : false);
|
|
ForAllTickets(DumpAllTicketsCB, &data);
|
|
|
|
Print("Slots: %d, Tickets: %d\n", data.nSize, data.cTickets);
|
|
}
|
|
} __except (CONTINUE) {
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|