/******************************Module*Header*******************************\ * Module Name: wow.c * * This file is for debugging tools and extensions. * * Created: 24-Jan-1992 * Author: John Colleran * * History: * Feb 17 92 Matt Felton (mattfe) lots of additional exentions for filtering * Jul 13 92 (v-cjones) Added API & MSG profiling debugger extensions, fixed * other extensions to handle segment motion correctly, * & cleaned up the file in general * Jan 3 96 Neil Sandlin (neilsa) integrated this routine into vdmexts * * Copyright (c) 1992 Microsoft Corporation \**************************************************************************/ #include "precomp.h" #pragma hdrstop #include #include #include #include #include // // get the compatibility flag values & string names // typedef struct _tagWOWCFDATA { LPSZ lpszCFName; DWORD dwVal; } WOWCFDATA; // allows us to grab the string tables only from mvdm\inc\wowcmpat.h #define _VDMEXTS_CFLAGS 1 // exposes the compatibility flag strings & values in wowcmpat.h #define _VDMEXTS_CF 1 WOWCFDATA CFData[] = { #include "wowcmpat.h" {"", 0x00000000} }; #undef _VDMEXTS_CF // exposes the EXTENDED compatibility flag strings & values in wowcmpat.h #define _VDMEXTS_CFEX 1 WOWCFDATA CFDataEx[] = { #include "wowcmpat.h" {"", 0x00000000} }; #undef _VDMEXTS_CFEX // exposes the OLD Win3.x compatibility flag strings & values in wowcmpat.h #define _VDMEXTS_CF31 1 WOWCFDATA CFData31[] = { #include "wowcmpat.h" {"", 0x00000000} }; #undef _VDMEXTS_CF31 // exposes the IME compatibility flag strings & values in wowcmpat.h #if FE_SB #define _VDMEXTS_CF_IME 1 WOWCFDATA CFDataIME[] = { #include "wowcmpat.h" {"", 0x00000000} }; #endif // FE_SB #undef _VDMEXTS_CF_IME #undef _VDMEXTS_CFLAGS #define MALLOC(cb) HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, cb) #define FREE(addr) HeapFree(GetProcessHeap(), 0, addr) // // Local function prototypes // INT WDahtoi(LPSZ lpsz); INT WDParseArgStr(LPSZ lpszArgStr, CHAR **argv, INT iMax) { /* * Parse a string looking for SPACE, TAB, & COMMA as delimiters * INPUT: * lpszArgStr - ptr to input arg string * iMax - maximum number of substrings to parse * OUTPUT: * argv - ptrs to strings * * RETURN: # of vectors in argv * NOTE: substrings are converted to uppercase */ INT nArgs; BOOL bStrStart; nArgs = 0; bStrStart = 1; while( *lpszArgStr ) { if( (*lpszArgStr == ' ') || (*lpszArgStr == '\t') || (*lpszArgStr == ',') ) { *lpszArgStr = '\0'; bStrStart = 1; } else { if( bStrStart ) { if( nArgs >= iMax ) { break; } argv[nArgs++] = lpszArgStr; bStrStart = 0; } *lpszArgStr = (CHAR)toupper(*lpszArgStr); } lpszArgStr++; } return(nArgs); } VOID dwp( CMD_ARGLIST ) { PWOWPORT pwp; WOWPORT wp; CMD_INIT(); ASSERT_WOW_PRESENT; while (' ' == lpArgumentString[0]) { lpArgumentString++; } pwp = (PWOWPORT) WDahtoi(lpArgumentString); if (NULL == pwp) { PRINTF("Can't read WOWPORT structure!\n\n"); return; } PRINTF("Dump of WOWPORT structure at 0x%x:\n\n", (unsigned)pwp); try { READMEM_XRET(wp, pwp); } except (EXCEPTION_ACCESS_VIOLATION == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { PRINTF("Access violation reading WOWPORT structure!\n\n"); return; } PRINTF("idComDev 0x%x\n", (unsigned)wp.idComDev); PRINTF("h32 0x%x\n", (unsigned)wp.h32); PRINTF("hREvent 0x%x\n", (unsigned)wp.hREvent); PRINTF("csWrite OwningThread 0x%x RecursionCount 0x%x\n", (unsigned)wp.csWrite.OwningThread, (unsigned)wp.csWrite.RecursionCount); PRINTF("pchWriteHead 0x%x\n", (unsigned)wp.pchWriteHead); PRINTF("pchWriteTail 0x%x\n", (unsigned)wp.pchWriteTail); PRINTF("cbWriteFree 0x%x\n", (unsigned)wp.cbWriteFree); PRINTF("cbWritePending 0x%x\n", (unsigned)wp.cbWriteFree); PRINTF("pchWriteBuf 0x%x\n", (unsigned)wp.pchWriteBuf); PRINTF("cbWriteBuf 0x%x\n", (unsigned)wp.cbWriteBuf); PRINTF("hWriteThread 0x%x\n", (unsigned)wp.hWriteThread); PRINTF("hWriteEvent 0x%x\n", (unsigned)wp.hWriteEvent); PRINTF("OverLap hEvent 0x%x\n", (unsigned)wp.olWrite.hEvent); PRINTF("fWriteDone %s\n", wp.fWriteDone ? "TRUE" : "FALSE"); PRINTF("cbWritten 0x%x\n", (unsigned)wp.fWriteDone); PRINTF("dwThreadID 0x%x\n", (unsigned)wp.dwThreadID); PRINTF("dwErrCode 0x%x\n", (unsigned)wp.dwErrCode); PRINTF("COMSTAT addr: 0x%x\n", (unsigned)(((char *)&wp.cs - (char *)&wp) + (char *)pwp)); PRINTF("fChEvt 0x%x\n", (unsigned)wp.fChEvt); PRINTF("pdcb16 0x%x\n", (unsigned)wp.pdcb16); PRINTF("fUnGet %s\n", wp.fUnGet ? "TRUE" : "FALSE"); PRINTF("cUnGet 0x%x (%c)\n", (unsigned)wp.cUnGet, wp.cUnGet); PRINTF("hMiThread 0x%x\n", (unsigned)wp.hMiThread); PRINTF("fClose %s\n", wp.fClose ? "TRUE" : "FALSE"); PRINTF("dwComDEB16 0x%x\n", (unsigned)wp.dwComDEB16); PRINTF("lpComDEB16 0x%x\n", (unsigned)wp.lpComDEB16); PRINTF("cbInQ 0x%x\n", (unsigned)wp.cbInQ); PRINTF("RLSDTimeout 0x%x\n", (unsigned)wp.RLSDTimeout); PRINTF("CTSTimeout 0x%x\n", (unsigned)wp.CTSTimeout); PRINTF("DSRTimeout 0x%x\n", (unsigned)wp.DSRTimeout); PRINTF("\n"); return; } // // Dump Taskinfo; // // If no argument, dump all wow tasks. // If 0, dump current WOW task // Else dump the specifies task {which is thread-id as shown by // ~ command under ntsd like 37.6b so thread-id is 6b) // void DumpTaskInfo (ptd,mode) PTD ptd; int mode; { ULONG Base; TDB tdb; BOOL b; char ModName[9]; int i; BOOL fTDBValid = TRUE; Base = GetInfoFromSelector( ptd->htask16, PROT_MODE, NULL ); b = READMEM( (LPVOID) (Base+GetIntelBase()), &tdb, sizeof(tdb)); if ( !b ) { fTDBValid = FALSE; } for (b=FALSE, i=0; i<8; i++) { if (!fTDBValid || !tdb.TDB_ModName[i]) { b = TRUE; } if (b) { ModName[i] = ' '; } else { ModName[i] = tdb.TDB_ModName[i]; } } ModName[i] = 0; PRINTF("%.4x",ptd->dwThreadID); PRINTF(" %.4x:%.4x",HIWORD(ptd->vpStack),LOWORD(ptd->vpStack)); PRINTF(" %.4x", ptd->htask16); PRINTF(" %.4x", ptd->hInst16); PRINTF(" %.4x", ptd->hMod16); PRINTF(" %8s",ModName); PRINTF(" %.8x",ptd->dwWOWCompatFlags); PRINTF(" %.8x",ptd->hThread); if (fTDBValid) { PRINTF(" %.8x",tdb.TDB_flags); PRINTF(" %.3x",tdb.TDB_ExpWinVer); PRINTF(" %.4x:%.4x\n",HIWORD(tdb.TDB_DTA),LOWORD(tdb.TDB_DTA)); } else { PRINTF(" Failure reading TDB at %X\n", Base ); } } void DumpTask( void ) { VDMCONTEXT ThreadContext; DWORD ThreadId; PTD ptd,ptdHead; TD td; int mode; BOOL b,fFound=FALSE; mode = GetContext( &ThreadContext ); ThreadId = (DWORD)-1; // Assume Dump All Tasks if (GetNextToken()) { ThreadId = (DWORD) EXPRESSION( lpArgumentString ); } ptdHead = (PTD)EXPRESSION("wow32!gptdTaskHead"); // get the pointer to first TD b = READMEM((LPVOID) (ptdHead), &ptd, sizeof(DWORD)); if ( !b ) { PRINTF("Failure reading gptdTaskHead at %08lX\n", ptdHead ); return; } PRINTF("Thrd Stack task inst hmod Module Compat hThread Tdbflags Ver Dta\n"); // enumerate td list to find the match(es) while (ptd) { b = READMEM((LPVOID) (ptd), &td, sizeof(TD)); if ( !b ) { PRINTF("Failure reading TD At %08lX\n", ptd ); return; } if (ThreadId == -1) { DumpTaskInfo (&td,mode); fFound = TRUE; } else { if (ThreadId == td.dwThreadID) { DumpTaskInfo (&td,mode); fFound = TRUE; break; } } ptd = td.ptdNext; } if (!fFound) { if (ThreadId == -1) { PRINTF("No WOW Task Found.\n"); } else PRINTF("WOW Task With Thread Id = %02x Not Found.\n",ThreadId); } return; } VOID DumpTaskVerbose( ) // dump WOW32 task database entry { TD td; PTD ptd; INT i; PWOAINST pWOA, pWOALast; PTDB ptdb; BOOL fAll = FALSE; BYTE SavedByte; ptd = (PTD) WDahtoi(lpArgumentString); if (!ptd) { fAll = TRUE; GETEXPRVALUE(ptd, "wow32!gptdTaskHead", PTD); if (!ptd) { Print("Could not get wow32!gptdTaskHead"); return; } Print("Dump WOW task list\n\n"); } else if ((ULONG)ptd < 65536) { ULONG dwId = (ULONG) ptd; // Here, I'm making the assumption that if the argument is a value // that is less than 64k, then it can't be a TD address. // So, try it out as a thread id GETEXPRVALUE(ptd, "wow32!gptdTaskHead", PTD); if (!ptd) { Print("Could not get wow32!gptdTaskHead"); return; } while(ptd) { READMEM_XRET(td, ptd); if (td.dwThreadID == dwId) { break; } ptd = td.ptdNext; } if (!ptd) { Print("Could not find thread id %s\n", lpArgumentString); return; } } do { Print("Dump of TD at 0x%08x:\n\n", (unsigned)ptd); READMEM_XRET(td, ptd); Print("vpStack %04x:%04x\n", HIWORD(td.vpStack), LOWORD(td.vpStack)); Print("vpCBStack %04x:%04x\n", HIWORD(td.vpCBStack), LOWORD(td.vpCBStack)); Print("cStackAlloc16 0x%08x\n", td.cStackAlloc16); Print("CommDlgTd (ptr) 0x%08x\n", td.CommDlgTd); Print("ptdNext 0x%08x\n", td.ptdNext); Print("dwFlags 0x%08x\n", td.dwFlags); // // Dump symbolic names for TDF_ manifests // if (td.dwFlags & TDF_IGNOREINPUT) { Print(" TDF_IGNOREINPUT\n"); } if (td.dwFlags & TDF_FORCETASKEXIT) { Print(" TDF_FORCETASKEXIT\n"); } if (td.dwFlags & TDF_TASKCLEANUPDONE) { Print(" TDF_TASKCLEANUPDONE\n"); } Print("VDMInfoiTaskID 0x%08x\n", td.VDMInfoiTaskID); // // Dump CommDlgTd structure if present // if (td.CommDlgTd) { COMMDLGTD CommDlgTd; BOOL fCopySuccessful = TRUE; READMEM_XRET(CommDlgTd, td.CommDlgTd); if (fCopySuccessful) { Print("\n"); Print(" Dump of CommDlgTd at 0x%08x:\n", td.CommDlgTd); Print(" hdlg 0x%04x\n", CommDlgTd.hdlg); Print(" vpData %04x:%04x\n", HIWORD(CommDlgTd.vpData), LOWORD(CommDlgTd.vpData)); Print(" pData32 0x%08x\n", CommDlgTd.pData32); Print(" vpfnHook %04x:%04x\n", HIWORD(CommDlgTd.vpfnHook), LOWORD(CommDlgTd.vpfnHook)); Print(" vpfnSetupHook (union) %04x:%04x\n", HIWORD(CommDlgTd.vpfnSetupHook), LOWORD(CommDlgTd.vpfnSetupHook)); Print(" pRes (union) 0x%08x\n", CommDlgTd.pRes); Print(" SetupHwnd 0x%04x\n", CommDlgTd.SetupHwnd); Print(" Previous 0x%08x\n", CommDlgTd.Previous); Print(" Flags 0x%08x\n", CommDlgTd.Flags); // // Dump symbolic names for WOWCD_ manifests // if (CommDlgTd.Flags & WOWCD_ISCHOOSEFONT) { Print(" WOWCD_ISCHOOSEFONT\n"); } if (CommDlgTd.Flags & WOWCD_ISOPENFILE) { Print(" WOWCD_ISOPENFILE\n"); } Print("\n"); } } Print("dwWOWCompatFlags 0x%08x\n", td.dwWOWCompatFlags); // // Dump symbolic names for WOWCF_ manifests // if (td.dwWOWCompatFlags) { i = 0; while(CFData[i].dwVal) { if (td.dwWOWCompatFlags & CFData[i].dwVal) { Print(" %s\n", CFData[i].lpszCFName); } i++; } } Print("dwWOWCompatFlagsEx 0x%08x\n", td.dwWOWCompatFlagsEx); // // Dump symbolic names for WOWCFEX_ manifests // if (td.dwWOWCompatFlagsEx) { i = 0; while(CFDataEx[i].dwVal) { if (td.dwWOWCompatFlagsEx & CFDataEx[i].dwVal) { Print(" %s\n", CFDataEx[i].lpszCFName); } i++; } } #if FE_SB Print("dwWOWCompatFlags2 0x%08x\n", td.dwWOWCompatFlags2); // // Dump symbolic names for WOWCFEX_ manifests // if (td.dwWOWCompatFlags2) { i = 0; while(CFDataIME[i].dwVal) { if (td.dwWOWCompatFlags2 & CFDataIME[i].dwVal) { Print(" %s\n", CFDataIME[i].lpszCFName); } i++; } } #endif Print("dwThreadID 0x%08x\n", td.dwThreadID); Print("hThread 0x%08x\n", td.hThread); Print("hIdleHook 0x%08x\n", td.hIdleHook); Print("hrgnClip 0x%08x\n", td.hrgnClip); Print("ulLastDesktophDC 0x%08x\n", td.ulLastDesktophDC); Print("pWOAList 0x%08x\n", td.pWOAList); // // Dump WOATD structure if present // pWOALast = NULL; pWOA = td.pWOAList; while (pWOA && pWOA != pWOALast) { union { WOAINST WOA; char buf[128+2+16]; } u; READMEM_XRET(u.buf, pWOA); Print("\n"); Print(" Dump of WOAINST at 0x%08x:\n", pWOA); Print(" pNext 0x%08x\n", u.WOA.pNext); Print(" ptdWOA 0x%08x\n", u.WOA.ptdWOA); Print(" dwChildProcessID 0x%08x\n", u.WOA.dwChildProcessID); Print(" hChildProcess 0x%08x\n", u.WOA.hChildProcess); Print(" szModuleName %s\n", u.WOA.szModuleName); Print("\n"); pWOALast = pWOA; pWOA = u.WOA.pNext; } Print("htask16 0x%04x\n", td.htask16, td.htask16); // // Dump the most interesting TDB fields // if (ptdb = (PTDB) (GetInfoFromSelector(td.htask16, PROT_MODE, NULL) + GetIntelBase())) { TDB tdb; READMEM_XRET(tdb, ptdb); Print("\n"); Print(" Highlights of TDB at 0x%08x:\n", ptdb); if (tdb.TDB_sig != TDB_SIGNATURE) { Print(" TDB_sig signature is 0x%04x instead of 0x%04x, halting dump.\n", tdb.TDB_sig, TDB_SIGNATURE); } else { PDOSPDB pPDB; DOSPDB PDB; PBYTE pJFT; BYTE JFT[256]; WORD cbJFT; PDOSSF pSFTHead, pSFTHeadCopy; DOSSF SFTHead; PDOSSFT pSFT; WORD fh; WORD SFN; WORD i; DWORD cb; DWORD dwCompatFlags; PDOSWOWDATA pDosWowData; DOSWOWDATA DosWowData; SavedByte = tdb.TDB_ModName[8]; tdb.TDB_ModName[8] = 0; Print(" Module name \"%s\"\n", tdb.TDB_ModName); tdb.TDB_ModName[8] = SavedByte; Print(" ExpWinVer 0x%04x\n", tdb.TDB_ExpWinVer); dwCompatFlags = *(DWORD *)(&tdb.TDB_CompatFlags); Print(" CompatFlags 0x%08x\n", dwCompatFlags); if (dwCompatFlags) { // // Dump symbolic names for GACF_ manifests // i = 0; while(CFData31[i].dwVal) { if (dwCompatFlags & CFData31[i].dwVal) { Print(" %s\n", CFData31[i].lpszCFName); } i++; } } Print(" Directory \"%s\"\n", tdb.TDB_LFNDirectory); Print(" PDB (aka PSP) 0x%04x\n", tdb.TDB_PDB); pPDB = (PDOSPDB) (GetInfoFromSelector(tdb.TDB_PDB, PROT_MODE, NULL) + GetIntelBase()); READMEM_XRET(PDB, pPDB); Print(" segEnvironment 0x%04x\n", PDB.PDB_environ); // // Dump open file handle info // pJFT = (PBYTE) (GetIntelBase() + (HIWORD(PDB.PDB_JFN_Pointer)<<4) + LOWORD(PDB.PDB_JFN_Pointer)); cbJFT = PDB.PDB_JFN_Length; Print(" JFT %04x:%04x (%08x), size 0x%x\n", HIWORD(PDB.PDB_JFN_Pointer), LOWORD(PDB.PDB_JFN_Pointer), pJFT, cbJFT); try { READMEM(pJFT, JFT, cbJFT); } except (1) { Print("Unable to read JFT from 0x%08x!\n", pJFT); return; } for (fh = 0; fh < cbJFT; fh++) { if (JFT[fh] != 0xFF) { // // Walk the SFT chain to find Nth entry // where N == JFT[fh] // SFN = 0; i = 0; GETEXPRVALUE(pSFTHead, "ntvdm!pSFTHead", PDOSSF); GETEXPRADDR(pDosWowData, "wow32!DosWowData"); READMEM_XRET(DosWowData, pDosWowData); if ((DWORD)pSFTHead != DosWowData.lpSftAddr) { Print("ntvdm!pSFTHead is 0x%08x, DosWowData.lpSftAddr ix 0x%08x.\n", pSFTHead, DosWowData.lpSftAddr); } try { READMEM(pSFTHead, &SFTHead, sizeof(SFTHead)); } except (1) { Print("Unable to read SFTHead from 0x%08x!\n", pSFTHead); return; } cb = sizeof(DOSSF) + SFTHead.SFCount * sizeof(DOSSFT); pSFTHeadCopy = MALLOC(cb); // Print("First DOSSF at 0x%08x, SFCount 0x%x, SFLink 0x%08x.\n", // pSFTHead, SFTHead.SFCount, SFTHead.SFLink); try { READMEM(pSFTHead, pSFTHeadCopy, cb); } except (1) { Print("Unable to read SFTHead from 0x%08x!\n", pSFTHead); return; } pSFT = (PDOSSFT) &(pSFTHeadCopy->SFTable); while (SFN < JFT[fh]) { SFN++; i++; pSFT++; if (i >= pSFTHeadCopy->SFCount) { if (LOWORD(pSFTHeadCopy->SFLink) == 0xFFFF) { SFN = JFT[fh] - 1; break; } pSFTHead = (PDOSSF) (GetIntelBase() + (HIWORD(pSFTHeadCopy->SFLink)<<4) + LOWORD(pSFTHeadCopy->SFLink)); i = 0; try { READMEM(pSFTHead, &SFTHead, sizeof(SFTHead)); } except (1) { Print("Unable to read SFTHead from 0x%08x!\n", pSFTHead); return; } cb = sizeof(DOSSF) + SFTHead.SFCount * sizeof(DOSSFT); FREE(pSFTHeadCopy); pSFTHeadCopy = MALLOC(cb); // Print("Next DOSSF at 0x%08x, SFCount 0x%x, SFLink 0x%08x.\n", // pSFTHead, SFTHead.SFCount, SFTHead.SFLink); try { READMEM(pSFTHead, pSFTHeadCopy, cb); } except (1) { Print("Unable to read SFTHead from 0x%08x!\n", pSFTHead); return; } pSFT = (PDOSSFT) &(pSFTHeadCopy->SFTable); } } if (SFN != JFT[fh]) { Print(" Unable to local SFT entry 0x%x for handle 0x%x.\n", pJFT[fh], fh); } else { Print(" Handle 0x%02x SFN 0x%02x Refs 0x%x Mode 0x%04x Flags 0x%04x ", fh, SFN, pSFT->SFT_Ref_Count, pSFT->SFT_Mode, pSFT->SFT_Flags); if (!pSFT->SFT_Flags & 0x80) { Print("NT Handle 0x%08x\n", pSFT->SFT_NTHandle); } else { Print("(NTDOS device)\n"); } } FREE(pSFTHeadCopy); } } Print("\n"); } } Print("hInst16 0x%04x\n", td.hInst16); Print("hMod16 0x%04x\n", td.hMod16); Print("\n"); ptd = td.ptdNext; } while (fAll && ptd); return; } void dt( CMD_ARGLIST ) { CMD_INIT(); ASSERT_WOW_PRESENT; if (!GetNextToken()) { DumpTask(); } else { if ((lpArgumentString[0] == '-') && (tolower(lpArgumentString[1]) == 'v')) { SkipToNextWhiteSpace(); GetNextToken(); DumpTaskVerbose(); } else { DumpTaskVerbose(); } } } VOID ddte( CMD_ARGLIST ) // dump dispatch table entry { W32 dte; PW32 pdte; char szW32[32]; char szSymbol[256]; DWORD dwOffset; CMD_INIT(); ASSERT_WOW_PRESENT; while (' ' == lpArgumentString[0]) { lpArgumentString++; } pdte = (PW32) WDahtoi(lpArgumentString); if (pdte) { PRINTF("Dump of dispatch table entry at 0x%08x:\n\n", (unsigned)pdte); } else { GETEXPRADDR(pdte, "wow32!aw32WOW"); PRINTF("Dump of first dispatch table entry at 0x%08x:\n\n", (unsigned)pdte); } try { READMEM_XRET(dte, pdte); if (dte.lpszW32) { READMEM_XRET(szW32, dte.lpszW32); dte.lpszW32 = szW32; szW32[sizeof(szW32)-1] = '\0'; } } except (1) { PRINTF("Exception 0x%08x reading dispatch table entry at 0x%08x!\n\n", GetExceptionCode(), pdte); return; } PRINTF("Dispatches to address 0x%08x, ", (unsigned)dte.lpfnW32); PRINTF("supposedly function '%s'.\n", dte.lpszW32); szSymbol[0] = '\0'; GetSymbol((LPVOID)dte.lpfnW32, szSymbol, &dwOffset); PRINTF("Debugger finds symbol '%s' for that address.\n", szSymbol); PRINTF("\n"); return; } PSTR aszWOWCLASS[] = { "UNKNOWN", "WIN16", "BUTTON", "COMBOBOX", "EDIT", "LISTBOX", "MDICLIENT", "SCROLLBAR", "STATIC", "DESKTOP", "DIALOG", "MENU", "ACCEL", "CURSOR", "ICON", "DC", "FONT", "METAFILE", "RGN", "BITMAP", "BRUSH", "PALETTE", "PEN", "OBJECT" }; INT WDahtoi(LPSZ lpsz) { char c; int tot, pow, len, dig, i; len = strlen(lpsz) - 1; tot = 0; pow = 1; for(i = len; i >= 0; i--) { c = (char)toupper(lpsz[i]); if(c == '0') dig = 0; else if(c == '1') dig = 1; else if(c == '2') dig = 2; else if(c == '3') dig = 3; else if(c == '4') dig = 4; else if(c == '5') dig = 5; else if(c == '6') dig = 6; else if(c == '7') dig = 7; else if(c == '8') dig = 8; else if(c == '9') dig = 9; else if(c == 'A') dig = 10; else if(c == 'B') dig = 11; else if(c == 'C') dig = 12; else if(c == 'D') dig = 13; else if(c == 'E') dig = 14; else if(c == 'F') dig = 15; else return(-1); if(pow > 1) { tot += pow * dig; } else { tot = dig; } pow *= 16; } return(tot); } void at( CMD_ARGLIST ) { UINT i; ATOM atom; CHAR pszGAtomName[128]; CHAR pszLAtomName[128]; CHAR pszCAtomName[128]; CHAR *argv[2], *psz; CMD_INIT(); ASSERT_WOW_PRESENT; if(WDParseArgStr(lpArgumentString, argv, 1) == 1) { atom = (ATOM)LOWORD(WDahtoi(argv[0])); pszGAtomName[0] = 'G'; // put a random value in 1st byte so we can pszLAtomName[0] = 'L'; // tell if it got replaced with a '\0' for pszCAtomName[0] = 'C'; // an "undetermined" type psz = NULL; PRINTF("\n%s: ", argv[0]); if(GlobalGetAtomName(atom, pszGAtomName, 128) > 0) { PRINTF(" \"%s\" ", pszGAtomName); psz = pszGAtomName; } else if(GetAtomName(atom, pszLAtomName, 128) > 0) { PRINTF(" \"%s\" ", pszLAtomName); psz = pszLAtomName; } else if(GetClipboardFormatName((UINT)atom, pszCAtomName, 128) > 0) { PRINTF(" \"%s\" ", pszCAtomName); psz = pszCAtomName; } if(psz) { i = 0; while(psz[i] && i < 128) { PRINTF(" %2X", psz[i++] & 0x000000FF); } } else { PRINTF("\n"); PRINTF(" GlobalGetAtomName string: \"%c\" ", pszGAtomName[0]); for(i = 0; i < 8; i++) { PRINTF(" %2X", pszGAtomName[i] & 0x000000FF); } PRINTF("\n GetAtomName string: \"%c\" ", pszLAtomName[0]); for(i = 0; i < 8; i++) { PRINTF(" %2X", pszLAtomName[i] & 0x000000FF); } PRINTF("\n GetClipboardFormatName string: \"%c\" ", pszCAtomName[0]); for(i = 0; i < 8; i++) { PRINTF(" %2X", pszCAtomName[i] & 0x000000FF); } } PRINTF("\n\n"); } else { PRINTF("Usage: at hex_atom_number\n"); } } void ww( CMD_ARGLIST ) { INT h16; CHAR *argv[2]; CMD_INIT(); ASSERT_WOW_PRESENT; if(WDParseArgStr(lpArgumentString, argv, 1)) { if((h16 = WDahtoi(argv[0])) >= 0) { } else { PRINTF("Usage: ww hwnd16\n"); } } else { PRINTF("Usage: ww hwnd16\n"); } } void wc( CMD_ARGLIST ) { PWC pwc; INT h16; CHAR *argv[2]; CMD_INIT(); ASSERT_WOW_PRESENT; if(WDParseArgStr(lpArgumentString, argv, 1)) { if((h16 = WDahtoi(argv[0])) >= 0){ try { pwc = (PWC)GetClassLong((HWND)HWND32((HAND16)h16),GCL_WOWWORDS); // this got moved out of WC // PRINTF("16:16 WndProc : %08lX\n", pwc->vpfnWndProc); PRINTF("VPSZ : %08lX\n", pwc->vpszMenu); PRINTF("PWC : %08lX\n\n", pwc); } except (EXCEPTION_ACCESS_VIOLATION == GetExceptionCode()) { PRINTF("!wow32.wc: Invalid HWND16 %04x\n", h16); } } else { PRINTF("Usage: wc hwnd16\n"); } } else { PRINTF("Usage: wc hwnd16\n"); } } // // Dump Last Logged APIs // void lastlog( CMD_ARGLIST ) { INT ValueiCircBuffer = CIRC_BUFFERS; PVOID pTmp = NULL; INT iCircBuffer; CHAR achTmp[TMP_LINE_LEN], *pachTmp; INT i; CMD_INIT(); ASSERT_CHECKED_WOW_PRESENT; GETEXPRVALUE(iCircBuffer, "wow32!iCircBuffer", INT); GETEXPRADDR(pTmp, "wow32!ValueiCircBuffer"); if(pTmp) { try { READMEM(pTmp, &ValueiCircBuffer, sizeof(INT)); } except (1) { ValueiCircBuffer = 0; } } if(ValueiCircBuffer == 0) { ValueiCircBuffer = CIRC_BUFFERS; } GETEXPRVALUE(pachTmp, "wow32!pachTmp", PCHAR); for (i = iCircBuffer; i >= 0; i--) { READMEM_XRET(achTmp, &pachTmp[i*TMP_LINE_LEN]); PRINTF("%s",achTmp); } for (i = ValueiCircBuffer-1; i > iCircBuffer; i--) { READMEM_XRET(achTmp, &pachTmp[i*TMP_LINE_LEN]); PRINTF("%s",achTmp); } return; } // creates/closes toggle for logfile for iloglevel logging in c:\ilog.log void logfile( CMD_ARGLIST ) { INT nArgs; CHAR *argv[2], szLogFile[128]; DWORD fLog; LPVOID lpfLog, lpszLogFile; CMD_INIT(); ASSERT_CHECKED_WOW_PRESENT; nArgs = WDParseArgStr(lpArgumentString, argv, 1); GETEXPRADDR(lpfLog, "wow32!fLog"); READMEM_XRET(fLog, lpfLog); if(nArgs) { strcpy(szLogFile, argv[0]); } else { strcpy(szLogFile, "c:\\ilog.log"); } if(fLog == 0) { fLog = 2; PRINTF("\nCreating "); PRINTF(szLogFile); PRINTF("\n\n"); } else { fLog = 3; PRINTF("\nClosing logfile\n\n"); } WRITEMEM_XRET(lpfLog, fLog); GETEXPRADDR(lpszLogFile, "wow32!szLogFile"); WRITEMEM_N_XRET(lpszLogFile, szLogFile, strlen(szLogFile)+1); return; } // // Set iLogLevel from Debugger Extension // void setloglevel( CMD_ARGLIST ) { INT iLogLevel; LPVOID lpAddress; CMD_INIT(); ASSERT_CHECKED_WOW_PRESENT; GETEXPRADDR(lpAddress, "wow32!iLogLevel"); iLogLevel = (INT)GetExpression(lpArgumentString); WRITEMEM_XRET(lpAddress, iLogLevel); return; } // // Toggle Single Step Trace Mode // void steptrace( CMD_ARGLIST ) { INT localfDebugWait; LPVOID lpAddress; CMD_INIT(); ASSERT_CHECKED_WOW_PRESENT; GETEXPRADDR(lpAddress, "wow32!fDebugWait"); READMEM_XRET(localfDebugWait, lpAddress); localfDebugWait = ~localfDebugWait; WRITEMEM_XRET(lpAddress, localfDebugWait); return; } /******* Misc filtering functions ********/ // // Set Filter Filtering of Specific APIs ON // void FilterSpecific( ) { INT i; INT fLogFilter; WORD wfLogFunctionFilter; LPVOID lpAddress; PWORD pawfLogFunctionFilter; WORD wCallId; SkipToNextWhiteSpace(); if (GetNextToken()) { wCallId = (WORD)GetExpression(lpArgumentString); } else { PRINTF("Please specify an api callid\n"); return; } if (!wCallId) { PRINTF("Invalid callid\n"); return; } GETEXPRVALUE(pawfLogFunctionFilter, "wow32!pawfLogFunctionFilter", PWORD); for (i = 0; i < FILTER_FUNCTION_MAX ; i++) { // Find Empty Position In Array READMEM_XRET(wfLogFunctionFilter, &pawfLogFunctionFilter[i]); if ((wfLogFunctionFilter == 0xffff) || (wfLogFunctionFilter == 0x0000)) { // Add New Filter to Array wfLogFunctionFilter = wCallId; WRITEMEM_XRET(&pawfLogFunctionFilter[i], wfLogFunctionFilter); break; } } GETEXPRADDR(lpAddress, "wow32!fLogFilter"); fLogFilter = 0xffffffff; WRITEMEM_XRET(lpAddress, fLogFilter); } // // Clear Filter Specific Array // void FilterResetSpecific( ) { INT i; WORD NEG1 = (WORD) -1; WORD ZERO = 0; PWORD pawfLogFunctionFilter; LPVOID lpAddress; GETEXPRVALUE(pawfLogFunctionFilter, "wow32!pawfLogFunctionFilter", PWORD); WRITEMEM_XRET(&pawfLogFunctionFilter[0], NEG1); for (i=1; i < FILTER_FUNCTION_MAX ; i++) { WRITEMEM_XRET(&pawfLogFunctionFilter[i], ZERO); } GETEXPRADDR(lpAddress, "wow32!iLogFuncFiltIndex"); WRITEMEM_XRET(lpAddress, ZERO); } // // Set TaskID Filtering // void FilterTask( ) { INT fLogTaskFilter; LPVOID lpAddress; SkipToNextWhiteSpace(); if (GetNextToken()) { GETEXPRADDR(lpAddress, "wow32!fLogTaskFilter"); fLogTaskFilter = (INT)GetExpression(lpArgumentString); WRITEMEM_XRET(lpAddress, fLogTaskFilter); } else { PRINTF("Please specify a task\n"); } return; } // // Turn All filtering ON // void FilterReset( ) { LPVOID lpAddress; INT fLogFilter = 0xffffffff; WORD fLogTaskFilter = 0xffff; GETEXPRADDR(lpAddress, "wow32!fLogFilter"); WRITEMEM_XRET(lpAddress, fLogFilter); GETEXPRADDR(lpAddress, "wow32!fLogTaskFilter"); WRITEMEM_XRET(lpAddress, fLogTaskFilter); FilterResetSpecific(); } // // Disable logging on all classes // void FilterAll( ) { INT fLogFilter; LPVOID lpAddress; GETEXPRADDR(lpAddress, "wow32!fLogFilter"); fLogFilter = 0x00000000; WRITEMEM_XRET(lpAddress, fLogFilter); } VOID DumpFilterSettings( VOID ) { INT i; INT fLogFilter; WORD wfLogFunctionFilter; WORD wfLogTaskFilter; LPVOID lpAddress; PWORD pawfLogFunctionFilter; GETEXPRVALUE(pawfLogFunctionFilter, "wow32!pawfLogFunctionFilter", PWORD); GETEXPRVALUE(wfLogTaskFilter, "wow32!fLogTaskFilter", WORD); GETEXPRADDR(lpAddress, "wow32!fLogFilter"); READMEM_XRET(fLogFilter, lpAddress); if (!pawfLogFunctionFilter) { PRINTF("Symbol 'wow32!pawfLogFunctionFilter' not available\n"); return; } PRINTF("\n*** WOW log filter state ***\n"); if (fLogFilter & FILTER_VERBOSE) { PRINTF("Verbose logging is on\n"); } else { PRINTF("Verbose logging is off\n"); } if (wfLogTaskFilter != 0xffff) { PRINTF("Only API calls for task %04X will be logged\n", wfLogTaskFilter); } else { PRINTF("Task filtering is off\n"); } READMEM_XRET(wfLogFunctionFilter, &pawfLogFunctionFilter[0]); if (wfLogFunctionFilter != 0xffff) { PRINTF("\nOnly API calls with the following CallId's will be logged:\n"); for (i = 0; i < FILTER_FUNCTION_MAX ; i++) { // Find Empty Position In Array READMEM_XRET(wfLogFunctionFilter, &pawfLogFunctionFilter[i]); if ((wfLogFunctionFilter != 0xffff) && (wfLogFunctionFilter != 0x0000)) { PRINTF(" %04X\n", wfLogFunctionFilter); } } PRINTF("\n"); } else { PRINTF("Specific API filtering is off\n"); } if (!(~fLogFilter & ~FILTER_VERBOSE)) { PRINTF("API class filtering if off\n"); } else { PRINTF("Logging is disabled for the following API classes:\n"); } if (!(fLogFilter & FILTER_KERNEL)) { PRINTF(" KERNEL\n"); } if (!(fLogFilter & FILTER_KERNEL16)) { PRINTF(" KERNEL16\n"); } if (!(fLogFilter & FILTER_USER)) { PRINTF(" USER\n"); } if (!(fLogFilter & FILTER_GDI)) { PRINTF(" GDI\n"); } if (!(fLogFilter & FILTER_KEYBOARD)) { PRINTF(" KEYBOARD\n"); } if (!(fLogFilter & FILTER_SOUND)) { PRINTF(" SOUND\n"); } if (!(fLogFilter & FILTER_MMEDIA)) { PRINTF(" MMEDIA\n"); } if (!(fLogFilter & FILTER_WINSOCK)) { PRINTF(" WINSOCK\n"); } if (!(fLogFilter & FILTER_COMMDLG)) { PRINTF(" COMMDLG\n"); } PRINTF("\n"); } void filter( CMD_ARGLIST ) { ULONG Mask = 0; LPVOID lpAddress; CMD_INIT(); ASSERT_CHECKED_WOW_PRESENT; while (' ' == *lpArgumentString) { lpArgumentString++; } if (_strnicmp(lpArgumentString, "kernel16", 8) == 0) { Mask = FILTER_KERNEL16; } else if (_strnicmp(lpArgumentString, "kernel", 6) == 0) { Mask = FILTER_KERNEL; } else if (_strnicmp(lpArgumentString, "user", 4) == 0) { Mask = FILTER_USER; } else if (_strnicmp(lpArgumentString, "gdi", 3) == 0) { Mask = FILTER_GDI; } else if (_strnicmp(lpArgumentString, "keyboard", 8) == 0) { Mask = FILTER_KEYBOARD; } else if (_strnicmp(lpArgumentString, "sound", 5) == 0) { Mask = FILTER_SOUND; } else if (_strnicmp(lpArgumentString, "mmedia", 6) == 0) { Mask = FILTER_MMEDIA; } else if (_strnicmp(lpArgumentString, "winsock", 7) == 0) { Mask = FILTER_WINSOCK; } else if (_strnicmp(lpArgumentString, "commdlg", 7) == 0) { Mask = FILTER_COMMDLG; } else if (_strnicmp(lpArgumentString, "callid", 6) == 0) { FilterSpecific(); } else if (_strnicmp(lpArgumentString, "task", 4) == 0) { FilterTask(); } else if (_strnicmp(lpArgumentString, "*", 1) == 0) { FilterAll(); } else if (_strnicmp(lpArgumentString, "reset", 5) == 0) { FilterReset(); } else if (_strnicmp(lpArgumentString, "verbose", 7) == 0) { Mask = FILTER_VERBOSE; } else { if (*lpArgumentString != 0) { PRINTF("Invalid argument to Filter command: '%s'\n", lpArgumentString); return; } } if (Mask) { INT fLogFilter; GETEXPRADDR(lpAddress, "wow32!fLogFilter"); if (!lpAddress) { PRINTF("Symbol 'wow32!fLogFilter' not available\n"); } else { READMEM_XRET(fLogFilter, lpAddress); if ((fLogFilter & Mask) == 0) { fLogFilter |= Mask; } else { fLogFilter &= ~Mask; } WRITEMEM_XRET(lpAddress, fLogFilter); } } DumpFilterSettings(); } void cia( CMD_ARGLIST ) { CURSORICONALIAS cia; PVOID lpAddress; INT maxdump = 500; CMD_INIT(); ASSERT_WOW_PRESENT; GETEXPRADDR(lpAddress, "wow32!lpCIAlias"); READMEM_XRET(lpAddress, lpAddress); if (!lpAddress) { PRINTF("Cursor/Icon alias list is empty.\n"); } else { PRINTF("Alias tp H16 H32 inst mod task res szname\n"); READMEM_XRET(cia, lpAddress); while ((lpAddress != NULL) && --maxdump) { if (cia.fInUse) { PRINTF("%08X", lpAddress); PRINTF(" %02X", cia.flType); PRINTF(" %04X", cia.h16); PRINTF(" %08X", cia.h32); PRINTF(" %04X", cia.hInst16); PRINTF(" %04X", cia.hMod16); PRINTF(" %04X", cia.hTask16); PRINTF(" %04X", cia.hRes16); PRINTF(" %08X\n", cia.lpszName); } lpAddress = cia.lpNext; READMEM_XRET(cia, lpAddress); } if (!maxdump) { PRINTF("Dump ended prematurely - possible infinite loop\n"); } } } //WARNING: This structure must match ENTRY in ntgdi\inc\hmgshare.h typedef struct _ENTRYWOW { LONG l1; LONG l2; USHORT FullUnique; USHORT us1; LONG l3; } ENTRYWOW, *PENTRYWOW; // converts an hGDI16 to the equivalent hGDI32 void hgdi( CMD_ARGLIST ) { ULONG h16, h32; PENTRYWOW pEntry; ENTRYWOW Entry; LPVOID lpAddress; CMD_INIT(); ASSERT_WOW_PRESENT; lpAddress = (PENTRYWOW)EXPRESSION("wow32!gpGDIHandleInfo"); READMEM_XRET(pEntry, lpAddress); h16 = (ULONG) WDahtoi(lpArgumentString); PRINTF("WOW 16-bit GDI Handle: %04X ", h16); h16 = h16 >> 2; pEntry = &pEntry[h16]; if(!READMEM((LPVOID) (pEntry), &Entry, sizeof(ENTRYWOW))) { PRINTF("Failure reading ENTRYWOW At %08lX\n", pEntry); return; } h32 = h16 | (Entry.FullUnique << 16); PRINTF("32-bit GDI Handle: %08X\n", h32); return; } #include "..\wow32\wdde.h" //typedef struct _HDDE { // struct _HDDE *pDDENext; // pointer to next hDDE alias // HAND16 To_hwnd; // window that will receive this message // HAND16 From_hwnd; // window that sent this message // HAND16 hMem16; // handle of WOW app allocated 16 bit object // HANDLE hMem32; // handle of WOW allocated 32 bit object // WORD DdeMsg; // message id // WORD DdeFormat; // message format // WORD DdeFlags; // indicates if it is metafile handle // HAND16 h16; // original h16 for bad apps doing EXECUTE //} HDDE, *PHDDE; // dumps the list of dde 16-32 memory pairs void ddemem( CMD_ARGLIST ) { PHDDE phdde; HDDE hdde; LPVOID lpAddress; CMD_INIT(); ASSERT_WOW_PRESENT; lpAddress = (PENTRYWOW)EXPRESSION("wow32!phDDEFirst"); READMEM_XRET(phdde, lpAddress); while(phdde) { if(!READMEM((LPVOID) (phdde), &hdde, sizeof(HDDE))) { PRINTF("Failure reading HDDE At %08lX\n", phdde); return; } PRINTF(" PHDDE: %08X\n", phdde); PRINTF(" To_hwnd16: %04X\n", hdde.To_hwnd); PRINTF("From_hwnd16: %04X\n", hdde.From_hwnd); PRINTF(" hMem16: %04X\n", hdde.hMem16); PRINTF(" hMem32: %04X\n", hdde.hMem32); PRINTF(" DdeMsg: %04X\n", hdde.DdeMsg); PRINTF(" DdeFormat: %04X\n", hdde.DdeFormat); PRINTF(" DdeFlags: %04X\n", hdde.DdeFlags); PRINTF(" Orig h16: %04X\n\n", hdde.h16); phdde = hdde.pDDENext; } return; } // must match struct in "..\wow32\wow32.h" #ifndef DEBUG #define ML_MALLOC_W 0x00000001 #define ML_MALLOC_W_ZERO 0x00000002 #define ML_REALLOC_W 0x00000004 #define ML_MALLOC_WTYPE (ML_MALLOC_W | ML_MALLOC_W_ZERO | ML_REALLOC_W) #define ML_GLOBALALLOC 0x00000010 #define ML_GLOBALREALLOC 0x00000020 #define ML_GLOBALTYPE (ML_GLOBALREALLOC | ML_GLOBALALLOC) typedef struct _tagMEMLEAK { struct _tagMEMLEAK *lpmlNext; PVOID lp; DWORD size; UINT fHow; ULONG Count; PVOID CallersAddress; } MEMLEAK, *LPMEMLEAK; #endif void gmem( CMD_ARGLIST ) { LPMEMLEAK lpml; MEMLEAK ml; LPVOID lpAddress; CMD_INIT(); ASSERT_WOW_PRESENT; // DbgBreakPoint(); lpAddress = (PENTRYWOW)EXPRESSION("wow32!lpMemLeakStart"); READMEM_XRET(lpml, lpAddress); while(lpml) { if(!READMEM((LPVOID) (lpml), &ml, sizeof(MEMLEAK))) { PRINTF("Failure reading lpml At %08lX\n", lpml); return; } PRINTF(" lp: %08X\n", ml.lp); PRINTF(" Size: %08X\n", ml.size); PRINTF(" Alloc'd by: %08X\n", ml.CallersAddress); PRINTF("Alloc Count: %08X\n", ml.Count); PRINTF("How Alloc'd: "); if(ml.fHow & ML_MALLOC_W) PRINTF("malloc_w "); if(ml.fHow & ML_MALLOC_W_ZERO) PRINTF("malloc_w_zero "); if(ml.fHow & ML_REALLOC_W) PRINTF("realloc_w "); if(ml.fHow & ML_GLOBALALLOC) PRINTF("GlobalAlloc "); if(ml.fHow & ML_GLOBALREALLOC) PRINTF("GlobalReAlloc "); PRINTF("\n\n"); lpml = ml.lpmlNext; } return; }