Windows2003-3790/windows/advcore/duser/duexts/duexts.cpp
2020-09-30 16:53:55 +02:00

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;
}