/****************************** 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""); } 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; }