// WDBGDOT.C // // This file is effectively a copy of core32\kernel\dbgdot.c that builds it for inclusion // as part of VDMEXTS.DLL // // (C) Copyright Microsoft Corp., 1988-1994 // // WDEB386 Dot commands // // This file and the file dbgdota.asm implement the .W dot commands on // behalf of wdeb386. W32ParseDotCommand is called to parse and execute // the dot commands. // // *All* memory that is accessed while processing a dot command *must* // be present. If it is not, a page fault will occur which can, and // likely will, result in a very large amount of system code being // executed. This will change the state of the system as it is being // debugged, and can lead to unexpected, incorrect or fatal behaviour. // // The convention used by the .W commands to handle dumping structures // that reside in not-present memory is to display the not-present // address in brackets ("[]"). The user may then use the '.MM' command // to force the memory present if desired (note that this action has // all of the pitfalls described above), and then reissue the .W command. // // All code and data directly associated with the .W commands reside in // the LOCKCODE and LOCKDATA segments. The InitDotCommand function // (dbgdota.asm) locks these segments in memory. // // Origin: Chicago // // Change history: // // Date Who Description // --------- --------- ------------------------------------------------- // 15-Feb-94 JonT Code cleanup and precompiled headers // // // defined to compile the debug support for inclusion in the VDMEXTS.DLL // debugger extension for MEOW // #include #pragma hdrstop #define WOW32_EXTENSIONS 1 #define KERNEL_DOT_COMMANDS 1 #define WOW 1 #undef DEBUG #include #define dbgprintf PRINTF #define VerifyMemory(addr,sz) MapDbgAddr(&(addr),sz) BOOL MapDbgAddr(VOID **ppaddr,ULONG objsz); #ifdef KERNEL_DOT_COMMANDS #ifdef WOW32_EXTENSIONS extern INT WDParseArgStr(LPSZ lpszArgStr, CHAR **argv, INT iMax); extern INT WDahtoi(LPSZ lpsz); #endif VOID KERNENTRY DumpFlags(DWORD flags); #ifndef WOW32_EXTENSIONS extern PTCB KERNENTRY GetCurThreadHandle(); extern VOID KERNENTRY PrintName16(DWORD, DWORD); extern EXCEPTION_DISPOSITION __cdecl ExceptionHandler ( IN struct _EXCEPTION_RECORD *, IN PVOID, IN OUT struct _CONTEXT *, IN OUT PVOID ); extern int KERNENTRY WDEBGetBuff(PVOID pSrc, PVOID pDst, DWORD dwLen); #pragma code_seg("LOCKCODE") #pragma data_seg("LOCKDATA") // Validate ptdb or ppdb #define ValidatePTDB(ptdb) (VerifyMemory((ptdb), sizeof(TDB)) && \ ((ptdb)->objBase.typObj == typObjThread)) #define ValidatePPDB(ppdb) (VerifyMemory((ppdb), sizeof(PDB)) && \ ((ppdb)->objBase.typObj == typObjProcess)) // Convert a ring 0 thread handle to a ptdbx #define ptcb2ptdbx(ptcb) ((PTDBX)*((PULONG)((DWORD)ptcb + thcboffDeb))) // VWIN32's thread slot offset from ring 0 DWORD thcboffDeb; #endif // ndef WOW32_EXTENSIONS // // Some frequently used strings. // char NotSignaled[] = "not signaled"; char Signaled[] = "signaled"; // // Extended .w help (.w?) // // wdeb has maximum printf buffer size of 256 bytes. Therefore, strings // have to be broken up. // char *w32DotCommandExtHelp[] = { "!k32 W" " []\n\ where is the address of a win32 object of one of the following\n\ object types:\n\ Thread Process Semaphore Event\n\ Mutex Critical Section Timer Change\n" #ifndef WOW32_EXTENSIONS Console Con Scrn Buff " #endif // ndef WOW32_EXTENSIONS "\n\ if is omitted, information on all threads is displayed.\n", "!k32 WM" " - Dump module table\n", "!k32 WMP" " [ppdb] - Dump module table for process (no ppdb - current process)\n", "!k32 WP" " - Dump process list\n", #ifndef WOW32_EXTENSIONS "!k32 WC" " context - Dump context record\n", "!k32 WE" " exception - Dump exception record\n", "!k32 WD" " [dispatcherContext] - Dump dispatcher context\n" " Currently active one if no argument\n", #endif // ndef WOW32_EXTENSIONS "!k32 WS" " - Display the status of all ring 3 system critical sections\n", "!k32 WT[K]" " [ppdb] - Dump process handle table (no ppdb - current process, K kernel process)\n", "!k32 WX" " - Dump memory status\n\n", 0}; // // All strings must be global in order to get the C compiler to put them // in the LOCKDATA segment. This means DON'T define any static data within // a function. // // FLASH! The latest version of the compiler (8.00.3148) is putting static, // non-global data in LOCKDATA also, ie. we can get rid of these ugly global // strings. // char DotError[] = "Invalid !k32 w command\n\n"; char NewLine[] = "\n"; char NotPresentStr[] = "Not present in memory"; char fmt1[] = " waiting threads ptdbx: "; char fmt2[] = " %08x"; char fmt3[] = " [%08x]"; char fmt3a[] = "\nControl-C cancel\n"; char fmt4[] = "\n\t"; char fmt6[] = "Sem %08x %s"; char fmt8[] = "Event %08x %s"; char fmt9[] = "Change %08x hChangeInt=%08x"; char fmt10[] = "%s Owner=%08x(%x)"; char fmt11[] = "%s"; char fmt13[] = "CritSect %08x Owner=%08x(%x) cCur=%08x cRecur=%08x"; char fmt14[] = "CritSect %08x Unowned cCur=%08x cRecur=%08x"; char fmt16[] = "Thread [%.8x]\n"; char fmt23[] = " all of:"; char fmt24[] = " any of:"; char fmt27[] = "\n\t"; char fmt29[] = "Mutex %08x "; char fmt31[] = "Object %08x is invalid or not-present\n"; char fmt33[] = "[%08x]"; char fmt40[] = "%s %08x lev=%x "; char fmt41[] = "Owner=%08x(%x) cCur %08x cRecur=%08x "; char fmt42[] = "Unowned "; char fmt42a[] = "Can't read ptdbxOwner "; char fmt43[] = "%s [%08x]\n"; char fmt44[] = "%s [%08x]\n"; char fmt50[] = "Process [%08x]\n"; char fmt60h[] = "IMTE pmte UCnt Ld BaseAddr FileName\n"; char fmt60i[] = "===================================================\n"; char fmt60[] = " %2x %08x %2d %s %08x %s\n"; char fmt61h[] = " MTE MdRf\n"; char fmt61i[] = "IMTE pmte UCnt UCnt Ld BaseAddr FileName\n"; char fmt61j[] = "========================================================\n"; char fmt61[] = " %2x %08x %2d %2d %s %08x %s\n"; char fmt62[] = "IMTE ??? %s\n"; char fmt70[] = "PDB %08x %s\n"; char fmt71h[] = " IMTE Usg Flags Ld BaseAddr FileName\n"; char fmt71i[] = " ====================================================\n"; char fmt71[] = " %2x %2x %04x %s %08x %s\n"; char fmt72[] = "Current PDB %08x %s\n"; char fmt72a[] = "Cannot get Current PDB\n"; char fmt72b[] = "Cannot get imteMax\n"; char fmt72c[] = "Current PDB %08x does not have a pModExe\n"; char fmt73[] = "no name"; char fmt74[] = "Value specified %08x is not a valid or present process ID\n"; char fmt74a[] = "Value specified %08x is not a valid or present module structure\n"; char fmt75[] = "Handle table of process ID %08x %s\n" " Handle Object Flags Type\n"; char fmt76[] = " %4x %08x %08x %s (%2x)\n"; char fmt80[] = "Paranoid ring 3 heap walking is now "; char fmt81[] = "ON\n"; char fmt82[] = "OFF\n"; char fmt83[] = "Stopping on ring 3 memory manager error returns is now "; char fmt84[] = ".WH doesn't work in the retail build\n"; char* pszObjTypes[] = { "Invalid or not present", "Semaphore", "Event", "Mutex", "Critical Section", "Timer", "Process", "Thread", "File", "Change", "Console", "IO", "Console Screen Buffer", "Mapped file", "Serial", "Device IOCtl", "Pipe", "Mailslot", "Toolhelp", "Socket", "R0 External Object", }; #define MAXOBJTYPEINDEX 20 BOOL fDumpHeader = TRUE; WORD wHeadK16FreeList = 0; WORD* pwHeadSelman16 = NULL; BOOL MapDbgAddr(VOID **ppaddr,ULONG objsz) { return(FALSE); } #if !defined(offsetof) #define offsetof(s,m) (size_t)&(((s *)0)->m) #endif TDB *GetCurrentTdb(VOID) { CONTEXT ThreadContext; LDT_ENTRY dte; DWORD cb; TDB *ptdb; ThreadContext.ContextFlags = CONTEXT_SEGMENTS; if (!GetThreadContext(hCurrentThread, &ThreadContext)) { return( NULL ); } cb = ThreadContext.SegFs; if (!GetThreadSelectorEntry( hCurrentThread,cb,&dte)) { return( NULL ); } cb = (dte.HighWord.Bytes.BaseHi * 0x01000000) + (dte.HighWord.Bytes.BaseMid * 0x00010000) + dte.BaseLow; if((cb == 0xFFFFFFFF) || (cb == 0)) return(NULL); cb += offsetof(TIB, pTDB); try { READMEM((LPVOID)cb, &ptdb, sizeof(TDB *)); } except (1) { return(NULL); } return(ptdb); } BOOL Get16BitMemory(WORD wSelector, WORD wOffset, PVOID pData, ULONG ulSize) { LDT_ENTRY dte; DWORD cb; HANDLE hThread=hCurrentThread; // dbgprintf( "Ask to read %08X bytes from %04X:%04X of thread %08x\n", // ulSize, // wSelector, // wOffset, // hThread); if (!GetThreadSelectorEntry( hCurrentThread, wSelector, &dte)) { dbgprintf( "Could not get selector %04X of thread %08x\n", wSelector, hThread); return( FALSE ); } cb = (dte.HighWord.Bytes.BaseHi * 0x01000000) + (dte.HighWord.Bytes.BaseMid * 0x00010000) + dte.BaseLow; if((cb == 0xFFFFFFFF) || (cb == 0)) { dbgprintf( "Could not compute linear of %04X:%04X of thread %08x\n", wSelector, wOffset, hThread); return(FALSE); } cb+=wOffset; try { READMEM((LPVOID)cb, pData, ulSize); } except (1) { dbgprintf( "Faulted reading %04X:%04X=%08X of thread %08x\n", cb, wSelector, wOffset, hThread); return(FALSE); } return(TRUE); } TDBX *GetCurrentTdbx(VOID) { TDB tdb; TDB *ptdb; ptdb = GetCurrentTdb(); if(!ptdb) { return(NULL); } try { READMEM(ptdb, &tdb, sizeof(TDB)); } except (1) { return(NULL); } return(tdb.ptdbx); } PDB *GetCurrentPdb(VOID) { TDB tdb; TDB *ptdb; TIB tib; ptdb = GetCurrentTdb(); if(!ptdb) { return(NULL); } try { READMEM(ptdb, &tdb, sizeof(TDB)); } except (1) { return(NULL); } try { READMEM(tdb.ptib, &tib, sizeof(TIB)); } except (1) { return(NULL); } return(tib.ppdbProc); } MTE *GetModuleTableEntry(IMTE imte, MTE *pmtebuf) { MTE **pmteModTab = 0; MTE **pmteModTabEnt; MTE *pmte; PVOID pTmp = NULL; GETEXPRADDR(pTmp, "mekrnl32!pmteModTable"); if(pTmp == NULL) return(NULL); try { READMEM(pTmp, &pmteModTab, sizeof(MTE **));\ } except (1) { return(NULL); } pmteModTabEnt = &(pmteModTab[imte]); try { READMEM(pmteModTabEnt, &pmte, sizeof(MTE *)); } except (1) { return(NULL); } try { READMEM(pmte, pmtebuf, sizeof(MTE)); } except (1) { return(NULL); } return(pmte); } /*** PnodGetLstElem - Get an element from a list ** ** Synopsis ** NOD * = PnodGetLstElem(plst, id) ** ** Input: ** plst - pointer to the list to retrieve from ** id - indicator for which element to return ** ** Output: ** returns a pointer to the specified list element ** ** Errors: ** return 0L if result is undefined ** ** Description: ** This function will set the current position in the list ** to the specified element and return a pointer to the element. */ NOD * KERNENTRY PnodGetLstElem (LST * plst, NOD * pnodpre, int id) { LST lst; NOD nod; if(!plst) { return(NULL); } switch (id) { case idLstGetCur: case idLstGetLast: case idLstGetFirst: try { READMEM(plst, &lst, sizeof(LST));\ } except (1) { dbgprintf("\nInvalid List\n"); return(NULL); } if(id == idLstGetFirst) return (lst.pnodHead); else if(id == idLstGetLast) return (lst.pnodEnd); else return (lst.pnodCur); break; case idLstGetNext: case idLstGetPrev: if(!pnodpre) { return(NULL); } try { READMEM(pnodpre, &nod, sizeof(NOD));\ } except (1) { dbgprintf("\nInvalid List element\n"); return(NULL); } if(id == idLstGetNext) return(nod.pnodNext); else return(nod.pnodPrev); break; default: dbgprintf("\nInvalid List request\n"); return(NULL); break; } } /*** GetObjType * * Returns a string indicating the object type */ char* KERNENTRY GetObjType(OBJ* pobj) { int nObjType; nObjType = pobj->typObj; if (nObjType > MAXOBJTYPEINDEX) nObjType = 0; return pszObjTypes[nObjType]; } #ifndef WOW32_EXTENSIONS extern DWORD* SelmanBuffer; extern DWORD* pLDT; /*** ValidatePTCB * * Validates the r0 thread handle. * * Entry: ptcb - pointer to thread handle * * Exit: TRUE if the thread handle is valid */ BOOL KERNENTRY ValidatePTCB(PTCB ptcb) { _asm mov edi, [ptcb] _asm or edi, edi _asm jz invalidtcb VMMCall(Validate_Thread_Handle); _asm jc invalidtcb return(TRUE); invalidtcb: return(FALSE); } /*** ValidatePTDBX * * Validates the ptdbx * * Entry: ptdbx - pointer to ptdbx * * Exit: TRUE if the thread ptdbx is valid */ BOOL KERNENTRY ValidatePTDBX(PTDBX ptdbx) { BOOL f; if((f = VerifyMemory(ptdbx, sizeof(TDBX)))) { if(ptdbx->tdbxR0ThreadHandle == 0) { f = ValidatePTDB((PTDB)ptdbx->tdbxThreadHandle); } else { f = ValidatePTCB((PTCB)ptdbx->tdbxR0ThreadHandle); } } return(f); } #endif // ndef WOW32_EXTENSIONS /*** PrintThreads * * Worker routine that displays all threads blocked on a specified wait node. * * Entry: pwnod - pointer to wait node * * Exit: none */ VOID KERNENTRY PrintThreads(WNOD *pwnod) { WNOD wnod; TDBX tdbx; int i = 0; dbgprintf(NewLine); try { READMEM(pwnod, &wnod, sizeof(WNOD)); } except (1) { dbgprintf(fmt3, pwnod); dbgprintf(NewLine); return; } if(wnod.ptdbxWait) { try { READMEM(wnod.ptdbxWait, &tdbx, sizeof(TDBX)); } except (1) { wnod.ptdbxWait = NULL; } } if(!wnod.ptdbxWait) { dbgprintf(fmt3, pwnod); dbgprintf(NewLine); return; } // // print "waiting threads ptdbx: " // dbgprintf(fmt1); // // print the first thread on the current line // dbgprintf("%08x(%x) ", wnod.ptdbxWait, tdbx.tdbxR0ThreadHandle); pwnod = wnod.pwnCirc; // // If there's more threads, print them on the following lines // if (pwnod != NULL) { i = 1; do { // // print a newline every now and then // if (i % 6 == 0) { dbgprintf(fmt27); } try { READMEM(pwnod, &wnod, sizeof(WNOD)); } except (1) { dbgprintf(fmt3, pwnod); break; } if(wnod.ptdbxWait) { try { READMEM(wnod.ptdbxWait, &tdbx, sizeof(TDBX)); } except (1) { wnod.ptdbxWait = NULL; } } if(!wnod.ptdbxWait) { dbgprintf(fmt3, pwnod); break; } dbgprintf("%08x(%x) ", wnod.ptdbxWait, tdbx.tdbxR0ThreadHandle); ++i; } while ((pwnod = wnod.pwnCirc) != NULL); } // // print a closing newline // dbgprintf(NewLine); } /*** PrintThreadsCrst * * Prints the waiting threads on a critical section * * Entry: pcrst - pointer to critical section object * * Exit: none */ VOID KERNENTRY PrintThreadsCrst(CRST *pcrst) { PTDBX ptdbx = pcrst->ptdbxWait; TDBX tdbx; CheckCtrlC(); // flush queue dbgprintf(NewLine); if(ptdbx != NULL) { // // print "waiting threads ptdbx: " // dbgprintf(fmt1); do { try { READMEM(ptdbx, &tdbx, sizeof(TDBX)); } except (1) { dbgprintf(fmt3, ptdbx); break; } dbgprintf("%08x ", ptdbx); if(CheckCtrlC()) { dbgprintf(fmt3a); break; } ptdbx = (PTDBX)tdbx.tdbxWaitNodeList.wnlst_pwnCirc; } while (ptdbx != NULL && ptdbx != pcrst->ptdbxWait); } else { dbgprintf(" no waiting threads"); } // // print a closing newline // dbgprintf(NewLine); } /*** DumpSemaphore * * Information on a semaphore object is displayed. * * Entry: psem - pointer to semaphore object * * Exit: none */ VOID KERNENTRY DumpSemaphore(SEM *psem) { SEM sem; char *state; try { READMEM(psem, &sem, sizeof(SEM)); } except (1) { dbgprintf("Could not read SEM structure for %08x\n", psem); return; } // // Determine the current signaled state of the semaphore. // if (sem.cntCur == 0) { state = NotSignaled; } else { state = Signaled; } dbgprintf(fmt6, psem, state); if (sem.pwnWait != NULL) { PrintThreads(sem.pwnWait); } else { dbgprintf(NewLine); } } /*** DumpEvent * * Information on a Event object is displayed. * * Entry: pevt - pointer to Event object * * Exit: none */ VOID KERNENTRY DumpEvent(EVT *pevt) { EVT evt; char *state; try { READMEM(pevt, &evt, sizeof(EVT)); } except (1) { dbgprintf("Could not read EVT structure for %08x\n", pevt); return; } // // Determine the current state of the event. // if (evt.cntCur == 0) { state = NotSignaled; } else { state = Signaled; } dbgprintf(fmt8, pevt, state); if (evt.pwnWait != NULL) { PrintThreads(evt.pwnWait); } else { dbgprintf(NewLine); } } /*** DumpMutext * * Information on a mutext object is displayed. * * Entry: pmutx - pointer to mutext object * * Exit: none */ VOID KERNENTRY DumpMutex(MUTX *pmutx) { MUTX mutx; TDBX tdbx; try { READMEM(pmutx, &mutx, sizeof(MUTX)); } except (1) { dbgprintf("Could not read MUTX structure for %08x\n", pmutx); return; } dbgprintf(fmt29, pmutx); // // Display the mutex's state and owner if it has one. // if (mutx.cntCur <= 0) { if(mutx.ptdbxOwner) { try { READMEM(mutx.ptdbxOwner, &tdbx, sizeof(TDBX)); } except (1) { tdbx.tdbxR0ThreadHandle = 0; } } else { tdbx.tdbxR0ThreadHandle = 0; } dbgprintf(fmt10, NotSignaled, mutx.ptdbxOwner, tdbx.tdbxR0ThreadHandle); } else { dbgprintf(fmt11, Signaled); } if (mutx.pwnWait != NULL) { PrintThreads(mutx.pwnWait); } else { dbgprintf(NewLine); } } /*** DumpCritSect * * Information on a critical section object is displayed. * * Entry: pcrst - pointer to critical section object * * Exit: none */ VOID KERNENTRY DumpCritSect(CRST *pcrst) { CRST crst; TDBX tdbx; CRST *pcrstWait; CRST crstWait; try { READMEM(pcrst, &crst, sizeof(CRST)); } except (1) { dbgprintf("Could not read CRST structure for %08x\n", pcrst); return; } // if there is no ptr in the ptdbxWait field, we can assume this is an // internal critical section if (crst.ptdbxWait) { pcrstWait = (CRST *)crst.ptdbxWait; try { READMEM(pcrstWait, &crstWait, sizeof(CRST)); } except (1) { crstWait.typObj = 0; } if(crstWait.typObj == typObjCrst) { pcrst = pcrstWait; try { READMEM(pcrst, &crst, sizeof(CRST)); } except (1) { dbgprintf("Could not read CRST structure for %08x\n", pcrst); return; } } } // // Display the critical section's owner if it has one. // if (crst.cntCur <= 0) { if(crst.ptdbxOwner) { try { READMEM(crst.ptdbxOwner, &tdbx, sizeof(TDBX)); } except (1) { tdbx.tdbxR0ThreadHandle = 0; } } else { tdbx.tdbxR0ThreadHandle = 0; } dbgprintf(fmt13, pcrst, crst.ptdbxOwner, tdbx.tdbxR0ThreadHandle, crst.cntCur, crst.cntRecur); } else { dbgprintf(fmt14, pcrst, crst.cntCur, crst.cntRecur); } PrintThreadsCrst(&crst); } VOID KERNENTRY DumpTDBX(PTDBX pTDBX) { TDBX tdbx; DWORD flags; try { READMEM(pTDBX, &tdbx, sizeof(TDBX)); } except (1) { dbgprintf("TDBX invalid"); return; } dbgprintf(" ptdbx: %08x\n", pTDBX); dbgprintf(" CntUses: %8x\n", tdbx.tdbxCntUses); dbgprintf(" R0ThreadHandle: %8x\n", tdbx.tdbxR0ThreadHandle); dbgprintf(" VxdMutexTry: %8x\n", tdbx.tdbxVxDMutexTry); dbgprintf(" VxdMutexGrant: %8x\n", tdbx.tdbxVxDMutexGrant); dbgprintf(" ContextHandle: %8x\n", tdbx.tdbxContextHandle); dbgprintf(" TimeOutHandle: %8x\n", tdbx.tdbxTimeOutHandle); dbgprintf(" WakeParam: %8x\n", tdbx.tdbxWakeParam); dbgprintf(" BlockHandle: %8x\n", tdbx.tdbxBlockHandle); dbgprintf(" BlockState: %8x\n", tdbx.tdbxBlockState); dbgprintf(" Wait node list: %8x\n", tdbx.tdbxWaitNodeList); dbgprintf(" SuspendCount: %8x\n", tdbx.tdbxSuspendCount); dbgprintf(" SuspendHandle: %8x\n", tdbx.tdbxSuspendHandle); dbgprintf(" MustCpltCount: %8x\n", tdbx.tdbxMustCpltCount); flags = tdbx.tdbxWaitExFlags; dbgprintf(" WaitExFlags: %08x ", flags); if(flags & TDBX_WAITEXBIT_MASK) dbgprintf("WAITEXBIT "); if(flags & TDBX_WAITACKBIT_MASK) dbgprintf("WAITACKBIT "); if(flags & TDBX_SUSPEND_APC_PENDING_MASK) dbgprintf("SUSPEND_APC_PENDING "); if(flags & TDBX_SUSPEND_TERMINATED_MASK) dbgprintf("SUSPEND_TERMINATED "); if(flags & TDBX_BLOCKED_FOR_TERMINATION_MASK) dbgprintf("BLOCKED_FOR_TERMINATION "); if(flags & TDBX_EMULATE_NPX_MASK) dbgprintf("EMULATE_NPX "); if(flags & TDBX_WIN32_NPX_MASK) dbgprintf("WIN32_NPX "); if(flags & TDBX_EXTENDED_HANDLES_MASK) dbgprintf("EXTENDED_HANDLES "); if(flags & TDBX_FROZEN_MASK) dbgprintf("FROZEN "); if(flags & TDBX_DONT_FREEZE_MASK) dbgprintf("DONT_FREEZE "); if(flags & TDBX_DONT_UNFREEZE_MASK) dbgprintf("DONT_UNFREEZE "); if(flags & TDBX_DONT_TRACE_MASK) dbgprintf("DONT_TRACE "); if(flags & TDBX_STOP_TRACING_MASK) dbgprintf("STOP_TRACING "); if(flags & TDBX_WAITING_FOR_CRST_SAFE_MASK) dbgprintf("WAITING_FOR_CRST_SAFE "); if(flags & TDBX_CRST_SAFE_MASK) dbgprintf("CRST_SAFE "); if(flags & TDBX_THREAD_NOT_INIT_MASK) dbgprintf("THREAD_NOT_INIT "); if(flags & TDBX_BLOCK_TERMINATE_APC_MASK) dbgprintf("BLOCK_TERMINATE_APC "); dbgprintf("\n"); dbgprintf(" SyncWaitCount: %8x\n", tdbx.tdbxSyncWaitCount); dbgprintf(" QueuedSyncAPCs: %8x\n", tdbx.tdbxQueuedSyncAPCs); dbgprintf(" UserAPCList: %8x\n", tdbx.tdbxUserAPCList); dbgprintf(" KernAPCList: %8x\n", tdbx.tdbxKernAPCList); dbgprintf(" pPMPSPSelector: %08x\n", tdbx.tdbxpPMPSPSelector); dbgprintf(" BlockedOnID: %8x\n", tdbx.tdbxBlockedOnID); dbgprintf(" TraceRefData: %8x\n", tdbx.tdbxTraceRefData); dbgprintf(" TraceCallBack: %8x\n", tdbx.tdbxTraceCallBack); dbgprintf(" TraceOutLastCS: %8.4x\n", tdbx.tdbxTraceOutLastCS); dbgprintf("TraceEventHandle: %8.4x\n", tdbx.tdbxTraceEventHandle); dbgprintf(" K16PDBSel: %8.4x\n", tdbx.tdbxK16PDB); dbgprintf(" DosPDBSeg: %8.4x\n", tdbx.tdbxDosPDBSeg); dbgprintf(" ExceptionCount: %8.2x\n", tdbx.tdbxExceptionCount); dbgprintf(" SavedIrql: %8.2x\n", tdbx.tdbxSavedIrql); dbgprintf(" SavedIrqlCount: %8.2x\n", tdbx.tdbxSavedIrqlCount); dbgprintf(" K16TDB: %8.4x\n", tdbx.tdbxK16Task); if(tdbx.tdbxK16Task) { TDB16 tdb16; if (Get16BitMemory(tdbx.tdbxK16Task, 0, &tdb16, sizeof(TDB16))) { dbgprintf(" Task16 SSSP: %04x:%04x\n",tdb16.TDB_taskSS,tdb16.TDB_taskSP); dbgprintf(" Task16 Event Counter: %4x\n",tdb16.TDB_nEvents); dbgprintf(" Task16 Priority : %4x\n",tdb16.TDB_priority); dbgprintf(" Task16 Flags: %02x ",tdb16.TDB_flags); if(tdb16.TDB_flags & TDBF_CACHECHECK) dbgprintf("CACHECHK "); if(tdb16.TDB_flags & TDBF_NEWTASK) dbgprintf("NOT_SCHED_YET "); if(tdb16.TDB_flags & TDBF_KERNEL32) dbgprintf("K32 "); if(tdb16.TDB_flags & TDBF_HOOKINT21) dbgprintf("HOOK_I21 "); if(tdb16.TDB_flags & TDBF_HOOKINT2F) dbgprintf("HOOK_I2F "); dbgprintf("\n"); dbgprintf(" Task16 WinVer: %4x\n",tdb16.TDB_ExpWinVer); dbgprintf(" Task16 hModule: %4x\n",tdb16.TDB_Module); dbgprintf(" Task16 TDBParent: %4x\n",tdb16.TDB_Parent); dbgprintf(" Task16 Win32 Thrdhnd: %8x\n",tdb16.TDB_ThreadHandle); dbgprintf(" Drive: %4x\n",tdb16.TDB_Drive); dbgprintf(" Old Directory: %s\n" ,tdb16.TDB_Directory); dbgprintf(" LFN Directory: %s\n" ,tdb16.TDB_LFNDirectory); } else { dbgprintf(" Cannot fetch TDB16 memory\n"); } } } /*** DumpThread * * Information on a specified thread is displayed. Thread handle, thread id, * process id, exe name, blocked/ready status, and object(s) blocked on if * appropriate is displayed. * * Entry: ptdb - pointer to tdb (or NULL) * fFullDump - if TRUE, dump all the thread's tdb, tdbx info * * Exit: none */ VOID KERNENTRY DumpThread(PTDB ptdb, BOOL fFullDump) { int i; PTDB ptdbSvc; PTDB ptdbFault; PTDB ptdbMEOWCreator; WNOD *pwnod; WNOD *pwnod2; WNOD wnod; MTE *pmte; MTE mte; DWORD flags; PPDB ppdb = NULL; PDB pdb; TDB tdb; PTDBX ptdbx = NULL; TDBX tdbx; LPVOID pTmp; BOOL fTDBXValid = TRUE; BOOL fTDBValid = FALSE; BOOL fPDBValid = TRUE; PBYTE p, pTop; BYTE b; WORD wStackSize; TIB tib; // // Validate everything // try { READMEM(ptdb, &tdb, sizeof(TDB)); } except (1) { dbgprintf("Invalid Thread %08x\n",ptdb); return; } if(tdb.objBase.typObj != typObjThread) { dbgprintf("Invalid Thread %08x\n",ptdb); return; } fTDBValid = TRUE; ptdbx = tdb.ptdbx; try { READMEM(ptdbx, &tdbx, sizeof(TDBX)); } except (1) { fTDBXValid = FALSE; } ppdb = (PPDB)tdbx.tdbxProcessHandle; try { READMEM(ppdb, &pdb, sizeof(PDB)); } except (1) { fPDBValid = FALSE; } if(pdb.objBase.typObj != typObjProcess) { fPDBValid = FALSE; } // // Print header // if(fDumpHeader) { dbgprintf(" ptdb ppdb ptdbx NTID Tr Gt Stck tdb name state\n"); // * xxxxxxxx xxxxxxxx xxxxxxxx xxxx xx xx xxxx xxxx ssssssss.sss block fDumpHeader = FALSE; } // // Print * for current thread // if (ptdb == GetCurrentTdb()) { dbgprintf("*"); } else { dbgprintf(" "); } if (fTDBValid) { try { READMEM(tdb.ptib, &tib, sizeof(TIB)); } except (1) { tib.pvStackUserLimit=NULL; } pTop=tib.pvStackUserLimit; if (pTop>(PBYTE)0x01000000) { wStackSize=0xBAD2; for (p=pTop-MEOW_BOP_STACK_SIZE;p 0) { fReady = FALSE; dbgprintf(" suspnd"); } if((LONG)tdbx.tdbxBlockState < 0) { if(tdbx.tdbxWaitNodeList.wnlst_flFlags & fWaitCrst) { dbgprintf(" blked:Crit"); } else { // blocked by something dbgprintf(" blked BlkHnd:%08x",tdbx.tdbxBlockHandle); } } else { // not blocked if(tdbx.tdbxWaitExFlags & TDBX_BLOCKED_FOR_TERMINATION_MASK) { dbgprintf(" blk trm"); } else if(tdbx.tdbxBlockedOnID != 0) { dbgprintf(" blkid: %08x", tdbx.tdbxBlockedOnID); } else if(tdbx.tdbxVxDBlockOnIDID != 0) { dbgprintf(" VxDblkid: %08x", tdbx.tdbxVxDBlockOnIDID); } else if(fReady) { if ((LONG)tdbx.tdbxBlockState > 0) { dbgprintf(" ready wp"); } else { dbgprintf(" ready nwp"); } } } dbgprintf("\n"); } else { // // blocked on at least one object // dbgprintf(" blked: "); // If blocked on a critical section if(tdbx.tdbxWaitNodeList.wnlst_flFlags & fWaitCrst) { dbgprintf("Crit"); } else { fNodOk = TRUE; // Blocked on an semaphore, mutex or event pwnod = tdbx.tdbxWaitNodeList.wnlst_pwnCirc; try { READMEM(pwnod, &wnod, sizeof(WNOD)); } except (1) { fNodOk = FALSE; } if(fNodOk) { dbgprintf("\n\t %08x", wnod.pobjWait); pwnod2 = wnod.pwnNext; if((pwnod2 != pwnod) && (pwnod2 != tdbx.tdbxWaitNodeList.wnlst_pwnCirc)) { // // blocked on at least two objects. Drop down a line and // print the remaining objects. // CheckCtrlC(); // Flush queue do { pwnod = pwnod2; // // print a newline every now and then // dbgprintf("\n"); dbgprintf("\t"); try { READMEM(pwnod, &wnod, sizeof(WNOD)); } except (1) { dbgprintf(fmt3, pwnod); break; } dbgprintf(fmt2, wnod.pobjWait); if(CheckCtrlC()) { break; } pwnod2 = wnod.pwnNext; } while( (pwnod2 != pwnod) && (pwnod2 != tdbx.tdbxWaitNodeList.wnlst_pwnCirc)); } } else { // // not-present object // dbgprintf(fmt33, pwnod); } } dbgprintf("\n"); } } else { dbgprintf(" Unknown\n"); } // If we're not doing a full dump, bail out if(!fFullDump) return; if(fTDBValid) { DWORD dwIdObsfucator; TIB *ptib; TIB tib; pTmp = NULL; GETEXPRADDR(pTmp, "mekrnl32!dwIdObsfucator"); if(pTmp == NULL) { dwIdObsfucator = 0; } else { try { READMEM(pTmp, &dwIdObsfucator, sizeof(DWORD));\ } except (1) { dwIdObsfucator = 0; } } ptib = tdb.ptib; try { READMEM(ptib, &tib, sizeof(TIB)); } except (1) { ptib = NULL; } // Display useful TDB information if (dwIdObsfucator) { dbgprintf(" Id: %08x\n", ((DWORD)(ptdb)) ^ dwIdObsfucator); } dbgprintf(" Obj Type: %2x %s\n", tdb.objBase.typObj, GetObjType((OBJ*)&tdb)); dbgprintf(" Obj Ref count: %4x\n", tdb.objBase.cntUses); if(ptib) { dbgprintf(" pvExcept: %8x\n", tib.pvExcept); dbgprintf(" Top of stack: %8x\n", tib.pvStackUserLimit); dbgprintf(" Base of stack: %8x\n", tib.pvStackUser); dbgprintf(" K16 TDB: %8.4x\n", tib.hTaskK16); dbgprintf(" Stack sel16: %8.4x\n", tib.ss16); dbgprintf(" Selman list: %8x\n", tib.pvFirstDscr); dbgprintf(" User pointer: %8x\n", tib.pvArbitraryUserPointer); dbgprintf(" pTIB: %08x\n", tib.ptibSelf); dbgprintf(" TIB flags: %8.4x ", tib.flags); if(tib.flags & TIBF_WIN32) dbgprintf("TIBF_WIN32 "); if(tib.flags & TIBF_TRAP) dbgprintf("TIBF_TRAP "); dbgprintf("\n"); dbgprintf("Win16Mutex count: %8.4x\n", tib.Win16LockVCount); dbgprintf(" Debug context: %8x\n", tib.pcontextDeb); dbgprintf(" Ptr to cur pri: %08x", tib.pCurPri); pTmp = (LPVOID)tib.pCurPri; try { READMEM(pTmp, &dwIdObsfucator, sizeof(DWORD));\ } except (1) { dwIdObsfucator = 0xFFFFFFFF; } if (dwIdObsfucator != 0xFFFFFFFF) dbgprintf(" pri: %x", dwIdObsfucator); dbgprintf("\n"); dbgprintf(" Message queue: %8x\n", tib.dwMsgQueue); dbgprintf(" pTLS array: %8x\n", tib.ThreadLocalStoragePointer); } flags = tdb.flFlags; dbgprintf(" Flags: %08x ", flags); if(flags & fCreateThreadEvent) dbgprintf("fCreateThreadEvent "); if(flags & fCancelExceptionAbort) dbgprintf("fCancelExceptionAbort "); if(flags & fOnTempStack) dbgprintf("fOnTempStack "); if(flags & fGrowableStack) dbgprintf("fGrowableStack "); if(flags & fDelaySingleStep) dbgprintf("fDelaySingleStep "); if(flags & fOpenExeAsImmovableFile) dbgprintf("fOpenExeAsImmovableFile "); if(flags & fCreateSuspended) dbgprintf("fCreateSuspended "); if(flags & fStackOverflow) dbgprintf("fStackOverflow "); if(flags & fNestedCleanAPCs) dbgprintf("fNestedCleanAPCs "); if(flags & fWasOemNowAnsi) dbgprintf("fWasOemNowAnsi "); if(flags & fOKToSetThreadOem) dbgprintf("fOKToSetThreadOem "); DumpFlags(flags); dbgprintf(" Status: %8x\n", tdb.dwStatus); dbgprintf(" TIB sel: %8.4x\n", tdb.selTib); dbgprintf(" Emulator sel: %8.4x\n", tdb.selEmul); dbgprintf(" Handle count: %8.2x\n", tdb.cntHandles); dbgprintf(" APISuspendCount: %8x\n", tdb.dwAPISuspendCount); dbgprintf(" R0 hThread: %8x\n", tdb.R0ThreadHandle); dbgprintf(" Stack base: %8x\n", tdb.pStackBase); dbgprintf(" Emulator data: %8x\n", tdb.pvEmulData); dbgprintf(" Debugger CB: %8x\n", tdb.tdb_pderDebugger); dbgprintf(" Debugger TH: %8x\n", tdb.tdb_ihteDebugger); dbgprintf(" Context: %8x\n", tdb.tdb_pcontext); dbgprintf(" Except16 list: %8x\n", tdb.pvExcept16); dbgprintf(" Thunk connect: %8x\n", tdb.pvThunkConnectList); dbgprintf(" Neg stack base: %8x\n", tdb.dwCurNegBase); dbgprintf(" Current SS: %8x\n", tdb.dwCurSS); dbgprintf(" SS Table: %8x\n", tdb.pvMapSSTable); dbgprintf(" Thunk SS16: %8x\n", tdb.wMacroThunkSelStack16); dbgprintf(" hTerminate: %8x\n", tdb.hTerminate); dwIdObsfucator = (DWORD)ptdb; dwIdObsfucator += offsetof(TDB, TlsArray[0]); dbgprintf(" TLS Array: %8x\n", dwIdObsfucator); dbgprintf(" Delta priority: %8x\n", tdb.tpDeltaPri); dbgprintf(" Error Code: %8x\n", tdb.ercError); dbgprintf(" pCreateData16: %8x", tdb.pCreateData16); if(tdb.pCreateData16) { CREATEDATA16 crtd16; pTmp = (LPVOID)tdb.pCreateData16; try { READMEM(pTmp, &crtd16, sizeof(CREATEDATA16));\ } except (1) { pTmp = NULL; } if(pTmp) { dbgprintf(" pProcessInfo: %8x",crtd16.pProcessInfo); dbgprintf(" pStartupInfo: %8x",crtd16.pStartupInfo); } } dbgprintf("\n"); dbgprintf(" wSSBig: %8x\n", (DWORD)(tdb.wSSBig)); dbgprintf(" lp16SwitchRec: %8x:%x\n", ((DWORD)(tdb.lp16SwitchRec)) >> 16, ((DWORD)(tdb.lp16SwitchRec)) & 0xffff); if((!tdb.wSSBig) || ((DWORD)(tdb.wSSBig | 7) == (((tdb.lp16SwitchRec >> 16) & 0xffff ) | 7))) { dbgprintf(" Stack: Normal\n"); } else { dbgprintf(" Stack: Big\n"); } //#ifdef DEBUG // dbgprintf(" Rip string: %8x\n", tdb.pSavedRip); //#endif dbgprintf("\n"); } if(fTDBXValid) { DumpTDBX(ptdbx); } } /*** DumpChange * * Information on a change notification object is displayed. * * Entry: pfcndb - pointer to find change notification object * * Exit: none */ VOID KERNENTRY DumpChange(FCNDB *pfcndb) { FCNDB fcndb; try { READMEM(pfcndb, &fcndb, sizeof(FCNDB)); } except (1) { dbgprintf("Could not read FCNDB structure for %08x\n", pfcndb); return; } // // Display the Change object's internal handle. // dbgprintf(fmt9, pfcndb, fcndb.hChangeInt); dbgprintf(NewLine); } /*** DumpLevel * * Information on a specified global ring 3 system hierarchical critical * section is displayed. * * Entry: Lock - Pointer to pointer to leveled critical section * Name - Pointer to Lock name string * * Exit: none */ VOID KERNENTRY DumpLevel( LCRST *Lock, SYSLVL Level, char *Name) { LCRST lcrst; try { READMEM(Lock, &lcrst, sizeof(LCRST)); } except (1) { dbgprintf(fmt43, Name, Lock); return; } dbgprintf(fmt40, Name, Lock, Level); // // Display the Lock owner if it has one // if ((long)(lcrst.cstSync.cntCur) <= 0) { TDBX tdbx; try { READMEM(lcrst.cstSync.ptdbxOwner, &tdbx, sizeof(TDBX)); } except (1) { dbgprintf(fmt42a); tdbx.tdbxR0ThreadHandle = 0; } dbgprintf(fmt41, lcrst.cstSync.ptdbxOwner, lcrst.cstSync.ptdbxOwner ? (tdbx.tdbxR0ThreadHandle) : 0, lcrst.cstSync.cntCur, lcrst.cstSync.cntRecur); } else { dbgprintf(fmt42); } // // Display the waiting threads // PrintThreadsCrst(&lcrst.cstSync); } /*** DumpSysLevels * * Called to process the '.ws' command. Information on all global ring 3 * system hierarchical critical sections is displayed. * * Entry: none * * Exit: none */ VOID KERNENTRY DumpSysLevels(void) { LCRST *Win16Lock; // Hierarchical critical section for Win16 LCRST *Krn32Lock; // Hierarchical critical section for Kernel32 LCRST *crstGHeap16; LCRST *crstLstMgr; LCRST *crstExcpt16; LPVOID pTmp; LPVOID pTDBXVxD; pTmp = NULL; GETEXPRADDR(pTmp, "mekrnl32!Win16Lock"); if(pTmp == NULL) { Win16Lock = NULL; } else { try { READMEM(pTmp, &Win16Lock, sizeof(LCRST *));\ } except (1) { Win16Lock = NULL; } } pTmp = NULL; GETEXPRADDR(pTmp, "mekrnl32!Krn32Lock"); if(pTmp == NULL) { Krn32Lock = NULL; } else { try { READMEM(pTmp, &Krn32Lock, sizeof(LCRST *));\ } except (1) { Krn32Lock = NULL; } } pTmp = NULL; GETEXPRADDR(pTmp, "mekrnl32!crstGHeap16"); if(pTmp == NULL) { crstGHeap16 = NULL; } else { try { READMEM(pTmp, &crstGHeap16, sizeof(LCRST *));\ } except (1) { crstGHeap16 = NULL; } } crstLstMgr = crstExcpt16 = NULL; GETEXPRADDR(crstLstMgr, "mekrnl32!crstLstMgr"); GETEXPRADDR(crstExcpt16, "mekrnl32!crstExcpt16"); if (Win16Lock) { DumpLevel(Win16Lock, SL_WIN16, "Win16Mutex "); } else { dbgprintf("Could not get Win16Lock address from MEKRNL32\n"); } if (Krn32Lock) { DumpLevel(Krn32Lock, SL_KRN32, "Krn32Mutex "); } else { dbgprintf("Could not get Krnl32Lock address from MEKRNL32\n"); } if (crstGHeap16) { DumpLevel(crstGHeap16, SL_PRIVATE, "crstGHeap16"); } else { dbgprintf("Could not get crstGHeap16 address from MEKRNL32\n"); } if (crstLstMgr) { DumpLevel(crstLstMgr, SL_PRIVATE, "crstLstMgr "); } else { dbgprintf("Could not get crstLstMgr address from MEKRNL32\n"); } if (crstExcpt16) { DumpLevel(crstExcpt16, SL_PRIVATE, "crstExcpt16"); } else { dbgprintf("Could not get crstExcpt16 address from MEKRNL32\n"); } pTmp = 0; GETEXPRADDR(pTmp, "wow32!pTDBXVxD"); if(pTmp) { try { READMEM(pTmp, &pTDBXVxD, sizeof(LPVOID));\ } except (1) { dbgprintf("Could not get pTDBXVxD content from WOW32\n"); pTDBXVxD = (LPVOID)0xFFFFFFFF; } if(pTDBXVxD != (LPVOID)0xFFFFFFFF) { if(pTDBXVxD) { dbgprintf("VxdMutex owned by ptdbx %08X\n",pTDBXVxD); } else { dbgprintf("VxdMutex is Unowned\n"); } } } else { dbgprintf("Could not get pTDBXVxD address from WOW32\n"); } } #ifndef WOW32_EXTENSIONS /*** DisplayContext * * The information in a context record is displayed. * * Entry: ContextRecord - pointer to context record * * Exit: none */ VOID KERNENTRY DisplayContextRecord(PCONTEXT ContextRecord) { if (ContextRecord == 0 || !VerifyMemory(ContextRecord, sizeof(*ContextRecord))) { dbgprintf("[%08x]\n", ContextRecord); return; } if (ContextRecord->ContextFlags & (CONTEXT_INTEGER & ~CONTEXT_i386)) { dbgprintf( "eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\n", ContextRecord->Eax, ContextRecord->Ebx, ContextRecord->Ecx, ContextRecord->Edx, ContextRecord->Esi, ContextRecord->Edi ); } else { dbgprintf( "eax=???????? ebx=???????? ecx=???????? edx=???????? \ esi=???????? edi=????????\n" ); } if (ContextRecord->ContextFlags & (CONTEXT_CONTROL & ~CONTEXT_i386)) { dbgprintf( "eip=%08x esp=%08x ebp=%08x eflags=%08x\ncs=%04x ss=%04x ", ContextRecord->Eip, ContextRecord->Esp, ContextRecord->Ebp, ContextRecord->EFlags, ContextRecord->SegCs, ContextRecord->SegSs ); } else { dbgprintf( "eip=???????? esp=???????? ebp=???????? eflags=????????\n\ cs=???? ss=???? " ); } if (ContextRecord->ContextFlags & (CONTEXT_SEGMENTS & ~CONTEXT_i386)) { dbgprintf( "ds=%04x es=%04x fs=%04x gs=%04x\n", ContextRecord->SegDs, ContextRecord->SegEs, ContextRecord->SegFs, ContextRecord->SegGs ); } else { dbgprintf("ds=???? es=???? fs=???? gs=????\n"); } if (ContextRecord->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)) { dbgprintf( "dr0=%08x dr1=%08x dr2=%08x dr3=%08x dr6=%08x dr7=%08x\n", ContextRecord->Dr0, ContextRecord->Dr1, ContextRecord->Dr2, ContextRecord->Dr3, ContextRecord->Dr6, ContextRecord->Dr7 ); } else { dbgprintf( "dr0=???????? dr1=???????? dr2=???????? dr3=???????? dr6=???????? \ dr7=????????\n" ); } if (ContextRecord->ContextFlags & (CONTEXT_FLOATING_POINT & ~CONTEXT_i386)) { dbgprintf( "fcw=%08x fsw=%08x ftw=%08x fip=%08x fcs=%08x fcr0=%08x\n\ foo=%08x fos=%08x ContextFlags=%08x\n", ContextRecord->FloatSave.ControlWord, ContextRecord->FloatSave.StatusWord, ContextRecord->FloatSave.TagWord, ContextRecord->FloatSave.ErrorOffset, ContextRecord->FloatSave.ErrorSelector, ContextRecord->FloatSave.Cr0NpxState, ContextRecord->FloatSave.DataOffset, ContextRecord->FloatSave.DataSelector, ContextRecord->ContextFlags ); } else { dbgprintf( "fcw=???????? fsw=???????? ftw=???????? fip=???????? \ fcs=????????\nfcr0=???????? foo=???????? fos=????????\n" ); } } VOID KERNENTRY DumpContextRecord() { PCONTEXT ContextRecord = 0; if (GetDbgChar()) { dbgEvalExpr((DWORD *) &ContextRecord); } DisplayContextRecord(ContextRecord); } /*** DisplayExceptionRecord * * The information in an exception record is displayed. * * Entry: ExceptionRecord - pointer to exception record * * Exit: none */ VOID KERNENTRY DisplayExceptionRecord(PEXCEPTION_RECORD ExceptionRecord) { DWORD i; char *s; if (ExceptionRecord == 0 || !VerifyMemory( &ExceptionRecord->NumberParameters, sizeof(ExceptionRecord->NumberParameters) ) || !VerifyMemory( ExceptionRecord, sizeof(*ExceptionRecord) - sizeof(ExceptionRecord->ExceptionInformation[0]) * EXCEPTION_MAXIMUM_PARAMETERS + sizeof(ExceptionRecord->ExceptionInformation[0]) * ExceptionRecord->NumberParameters )) { dbgprintf("[%08x]\n", ExceptionRecord); return; } switch (ExceptionRecord->ExceptionCode) { case STATUS_INTEGER_DIVIDE_BY_ZERO: s = "STATUS_INTEGER_DIVIDE_BY_ZERO"; break; case EXCEPTION_SINGLE_STEP: s = "EXCEPTION_SINGLE_STEP"; break; case EXCEPTION_BREAKPOINT: s = "EXCEPTION_BREAKPOINT"; break; case STATUS_INTEGER_OVERFLOW: s = "STATUS_INTEGER_OVERFLOW"; break; case STATUS_ARRAY_BOUNDS_EXCEEDED: s = "STATUS_ARRAY_BOUNDS_EXCEEDED"; break; case STATUS_ILLEGAL_INSTRUCTION: s = "STATUS_ILLEGAL_INSTRUCTION"; break; case STATUS_ACCESS_VIOLATION: if (ExceptionRecord->ExceptionInformation[0] & 1) { s = "STATUS_ACCESS_VIOLATION [write]"; } else if (ExceptionRecord->ExceptionInformation[1] == (DWORD) -1) { s = "STATUS_ACCESS_VIOLATION [gp fault]"; } else { s = "STATUS_ACCESS_VIOLATION [read]"; } break; case STATUS_IN_PAGE_ERROR: if (ExceptionRecord->ExceptionInformation[0] & 1) { s = "STATUS_IN_PAGE_ERROR [write]"; } else { s = "STATUS_IN_PAGE_ERROR [read]"; } break; case STATUS_STACK_OVERFLOW: if (ExceptionRecord->NumberParameters != 2) { s = "STATUS_STACK_OVERFLOW"; } else if (ExceptionRecord->ExceptionInformation[0] & 1) { s = "STATUS_STACK_OVERFLOW [write]"; } else { s = "STATUS_STACK_OVERFLOW [read]"; } break; case STATUS_FLOAT_STACK_CHECK: s = "STATUS_FLOAT_STACK_CHECK"; break; case STATUS_FLOAT_INVALID_OPERATION: s = "STATUS_FLOAT_INVALID_OPERATION"; break; case STATUS_FLOAT_DIVIDE_BY_ZERO: s = "STATUS_FLOAT_DIVIDE_BY_ZERO"; break; case STATUS_FLOAT_OVERFLOW: s = "STATUS_FLOAT_OVERFLOW"; break; case STATUS_FLOAT_UNDERFLOW: s = "STATUS_FLOAT_UNDERFLOW"; break; case STATUS_FLOAT_INEXACT_RESULT: s = "STATUS_FLOAT_INEXACT_RESULT"; break; default: s = "UNKNOWN"; } dbgprintf("Code=%08x (%s)\n", ExceptionRecord->ExceptionCode, s); dbgprintf("Flags=%08x", ExceptionRecord->ExceptionFlags); if (ExceptionRecord->ExceptionFlags == 0) { dbgprintf("\n"); } else { dbgprintf(" ("); i = ExceptionRecord->ExceptionFlags; if (i & EXCEPTION_NONCONTINUABLE) { i &= ~EXCEPTION_NONCONTINUABLE; dbgprintf("NONCONTINUABLE%s", i ? ", " : ")\n"); } if (i & EXCEPTION_UNWINDING) { i &= ~EXCEPTION_UNWINDING; dbgprintf("UNWINDING%s", i ? ", " : ")\n"); } if (i & EXCEPTION_EXIT_UNWIND) { i &= ~EXCEPTION_EXIT_UNWIND; dbgprintf("EXIT_UNWIND%s", i ? ", " : ")\n"); } if (i & EXCEPTION_STACK_INVALID) { i &= ~EXCEPTION_STACK_INVALID; dbgprintf("STACK_INVALID%s", i ? ", " : ")\n"); } if (i & EXCEPTION_NESTED_CALL) { i &= ~EXCEPTION_NESTED_CALL; dbgprintf("NESTED_CALL%s", i ? ", " : ")\n"); } if (i & EXCEPTION_TARGET_UNWIND) { i &= ~EXCEPTION_TARGET_UNWIND; dbgprintf("TARGET_UNWIND%s", i ? ", " : ")\n"); } if (i & EXCEPTION_COLLIDED_UNWIND) { i &= ~EXCEPTION_COLLIDED_UNWIND; dbgprintf("COLLIDED_UNWIND%s", i ? ", " : ")\n"); } if (i) { dbgprintf("????)\n"); } } dbgprintf("ExcRec=%08x Number of Parameters=%02x\n", ExceptionRecord->ExceptionRecord, ExceptionRecord->NumberParameters ); for (i = 1; i <= ExceptionRecord->NumberParameters; ++i) { dbgprintf("%02x) %08x ", i, ExceptionRecord->ExceptionInformation[i-1]); if (i >= EXCEPTION_MAXIMUM_PARAMETERS) { break; } if (i % 5 == 0 && i < ExceptionRecord->NumberParameters) { dbgprintf("\n"); } } if (i > 1) { dbgprintf("\n"); } } VOID KERNENTRY DumpExceptionRecord() { PEXCEPTION_RECORD ExceptionRecord = 0; if (GetDbgChar()) { dbgEvalExpr((DWORD *) &ExceptionRecord); } DisplayExceptionRecord(ExceptionRecord); } /*** DumpDispatcherContext * * Information about an active exception dispatch is displayed. * * Entry: DispatcherContext - pointer to exception dispatcher context structure * (NULL causes a search). * * Exit: none */ VOID KERNENTRY DumpDispatcherContext() { PTDB ptdb; PNESTED_EXCEPTION_HANDLER_FRAME DispatcherContext = 0; PVOID va; BOOL v; DWORD i; if (GetDbgChar()) { dbgEvalExpr((DWORD *) &DispatcherContext); } Restart: if (DispatcherContext) { // // Dump the specified context. // if (!VerifyMemory(va=DispatcherContext, sizeof(*DispatcherContext))) { goto InvalidAddress; } if (DispatcherContext->RegistrationRecord.Handler != (PEXCEPTION_ROUTINE) ExceptionHandler) { dbgprintf("Invalid dispatcher context structure"); } else { dbgprintf( "Exception Record (%08x):\n", DispatcherContext->ExceptionRecord ); DisplayExceptionRecord(DispatcherContext->ExceptionRecord); dbgprintf( "\nContext Record (%08x):\n", DispatcherContext->ContextRecord ); DisplayContextRecord(DispatcherContext->ContextRecord); } } else { // // See if there's an active dispatcher context, ie. a search for an // exception handler in progress. // ptdb = GetCurrentTdb(); DispatcherContext = (PNESTED_EXCEPTION_HANDLER_FRAME)GetTIB(ptdb).pvExcept; if (DispatcherContext == (PNESTED_EXCEPTION_HANDLER_FRAME) -1) { goto NoContext; } if (!VerifyMemory(va=DispatcherContext, sizeof(*DispatcherContext))) { goto InvalidAddress; } if (DispatcherContext->RegistrationRecord.Handler == (PEXCEPTION_ROUTINE) ExceptionHandler) { // // There's a dispatch in progress. If it's nested, find the // initial context. // i = 0; while ((v = VerifyMemory( va=DispatcherContext, sizeof(*DispatcherContext) )) && (v = VerifyMemory( va=DispatcherContext->ExceptionRecord, sizeof(*DispatcherContext->ExceptionRecord) )) && (v = VerifyMemory( va=DispatcherContext->RegistrationRecord.Next, sizeof(*DispatcherContext->RegistrationRecord.Next) )) && DispatcherContext->ExceptionRecord->ExceptionFlags & EXCEPTION_NESTED_CALL) { if (DispatcherContext->RegistrationRecord.Next->Handler == (PEXCEPTION_ROUTINE) ExceptionHandler) { DispatcherContext = (PNESTED_EXCEPTION_HANDLER_FRAME) DispatcherContext->RegistrationRecord.Next; } else { break; } if (++i == 10) { dbgprintf("searching..."); } } if (!v) { // // We bailed out because of an invalid address. // goto InvalidAddress; } // // DispatcherContext now points to the initial DispatcherContext // record. // if (i >= 10) { dbgprintf("\n"); } goto Restart; } else { NoContext: dbgprintf("dispatcher context not found\n"); } return; InvalidAddress: dbgprintf("[%08x]\n", va); } } #endif // ndef WOW32_EXTENSIONS /*** DumpProcess * * Information on a process object is displayed. * * Entry: ppdb - pointer to process object * * Exit: none */ VOID KERNENTRY DumpProcess(PDB *ppdb) { PDB pdb; MODREF ModRef; MODREF *pModRef; MTE *pmte; MTE mte; EDB *pedb; EDB edb; LPVOID pTmp; DWORD flags; DWORD dwIdObsfucator; char ModFname[256]; try { READMEM(ppdb, &pdb, sizeof(PDB)); } except (1) { dbgprintf(fmt50, ppdb); return; } dbgprintf("Process %x", ppdb); pModRef = pdb.pModExe; if(pModRef) { try { READMEM(pModRef, &ModRef, sizeof(MODREF)); } except (1) { pModRef = NULL; } if(pModRef) { pmte = GetModuleTableEntry(ModRef.imte,&mte); if (pmte) { try { READMEM(mte.cfhid.lpFilename, &ModFname[0], sizeof(ModFname)); } except (1) { ModFname[0] = '\0'; } } else { ModFname[0] = '\0'; } } else { pmte = NULL; ModFname[0] = '\0'; } } else { pmte = NULL; ModFname[0] = '\0'; } if(pmte) dbgprintf(" %s\n", ModFname); else dbgprintf("\n"); pTmp = NULL; GETEXPRADDR(pTmp, "mekrnl32!dwIdObsfucator"); if(pTmp == NULL) { dwIdObsfucator = 0; } else { try { READMEM(pTmp, &dwIdObsfucator, sizeof(DWORD));\ } except (1) { dwIdObsfucator = 0; } } if (dwIdObsfucator) { dbgprintf(" Id: %8x\n", ((DWORD)(ppdb)) ^ dwIdObsfucator); } dbgprintf(" Type: %2x %s\n", pdb.objBase.typObj, GetObjType((OBJ*)&pdb)); dbgprintf(" Ref count: %4x\n", pdb.objBase.cntUses); dbgprintf(" Default Heap: %8x\n", pdb.hheapLocal); dbgprintf(" Heap own list: %8x\n", pdb.hhi_procfirst); dbgprintf(" Mem Context: %08x\n", pdb.hContext); dbgprintf(" MTE index: %8.2x\n", pdb.imte); flags = pdb.flFlags; dbgprintf(" Flags: %08x ", flags); if(flags & fDebugSingle) dbgprintf("fDebugSingle "); if(flags & fCreateProcessEvent) dbgprintf("fCreateProcessEvent "); if(flags & fExitProcessEvent) dbgprintf("fExitProcessEvent "); if(flags & fWin16Process) dbgprintf("fWin16Process "); if(flags & fDosProcess) dbgprintf("fDosProcess "); if(flags & fConsoleProcess) dbgprintf("fConsoleProcess "); if(flags & fFileApisAreOem) dbgprintf("fFileApisAreOem "); if(flags & fNukeProcess) dbgprintf("fNukeProcess "); if(flags & fServiceProcess) dbgprintf("fServiceProcess "); if(flags & fLoginScriptHack) dbgprintf("fLoginScriptHack "); DumpFlags(flags); dbgprintf(" pPSP: %08x\n", pdb.pPsp); dbgprintf(" PSP selector: %8.4x\n", pdb.selPsp); dbgprintf(" #Threads: %8.2x\n", pdb.cntThreads); dbgprintf(" #Thr not term: %8.2x\n", pdb.cntThreadsNotTerminated); dbgprintf(" #R0 threads: %8.2x\n", pdb.R0ThreadCount); dbgprintf(" K16 TDB Sel: %8.4x\n", pdb.hTaskWin16); dbgprintf(" MMF Views: %8x\n", pdb.pFvd); dbgprintf(" pEDB: %08x\n", pdb.pedb); pedb = pdb.pedb; try { READMEM(pedb, &edb, sizeof(EDB));\ } except (1) { pedb = NULL; } if (pedb) { dbgprintf(" Environment: %08x\n", edb.pchEnv); dbgprintf(" Command Line: %08x", edb.szCmdA); try { READMEM(edb.szCmdA, &ModFname[0], sizeof(ModFname)); } except (1) { ModFname[0] = '\0'; } dbgprintf(" %s\n", ModFname); dbgprintf(" Current Dir: %08x", edb.szDir); try { READMEM(edb.szDir, &ModFname[0], sizeof(ModFname)); } except (1) { ModFname[0] = '\0'; } dbgprintf(" %s\n", ModFname); dbgprintf(" Startup Info: %08x\n", edb.lpStartupInfo); dbgprintf(" hStdIn: %8.2x\n", edb.hStdIn); dbgprintf(" hStdOut: %8.2x\n", edb.hStdOut); dbgprintf(" hStdError: %8.2x\n", edb.hStdErr); dbgprintf(" Inherit console: %08x\n", edb.pInheritedConsole); dbgprintf(" Break type: %8.2x\n", edb.ctrlType); dbgprintf(" Break thread ID: %8x\n", edb.ptdbCtrl); dbgprintf(" Break handlers: %8x\n", edb.rgpfnCtrl); } dbgprintf(" pHandle Table: %08x\n", pdb.phtbHandles); dbgprintf(" Parent PDB: %08x\n", pdb.ppdbParent); dbgprintf(" MODREF list: %08x\n", pdb.plstMod); dbgprintf(" Parent MODREF: %08x\n", pdb.pModExe); dbgprintf(" Thread list: %08x\n", pdb.plstTdb); dbgprintf(" Debuggee CB: %8x\n", pdb.pdb_pdeeDebuggee); dbgprintf(" Initial R0 id: %8x\n", pdb.pid); dwIdObsfucator = (DWORD)ppdb; dwIdObsfucator += offsetof(PDB, crstLoadLock); dbgprintf(" &crstLoadLock: %08x\n", dwIdObsfucator); dbgprintf(" pConsole: %8x\n", pdb.pConsole); dbgprintf(" Process DWORD 0: %08x\n", pdb.adw[0]); dbgprintf(" Proc Group: %8x\n", pdb.ppdbPGroup); dbgprintf(" Top Ex Filter: %8x\n", pdb.pExceptionFilter); dbgprintf(" Priority base: %08x\n", pdb.pcPriClassBase); dbgprintf(" LH Free head: %8x\n", pdb.plhFree); dbgprintf(" LH lhandle blks: %8x\n", pdb.plhBlock); dbgprintf(" Term status: %08x\n", pdb.dwStatus); dbgprintf("pconsoleProvider: %8x\n", pdb.pconsoleProvider); dbgprintf(" wEnvSel: %4x\n", pdb.wEnvSel); dbgprintf(" wErrorMode: %4x\n", pdb.wErrorMode); dbgprintf("pevtLoadFinished: %08x\n", (DWORD)(pdb.pevtLoadFinished)); dbgprintf(" UTState: %4x\n", pdb.hUTState); dbgprintf("lpCmdLineNoQuote: %8x\n", pdb.lpCmdLineNoQuote); } VOID KERNENTRY DumpFlags(DWORD flags) { if(flags & fSignaled) dbgprintf("fSignaled "); if(flags & fInitError) dbgprintf("fInitError "); if(flags & fTerminated) dbgprintf("fTerminated "); if(flags & fTerminating) dbgprintf("fTerminating "); if(flags & fFaulted) dbgprintf("fFaulted "); if(flags & fNearlyTerminating) dbgprintf("fNearlyTerminating "); if(flags & fDebugEventPending) dbgprintf("fDebugEventPending "); if(flags & fSendDLLNotifications) dbgprintf("fSendDLLNotifications "); dbgprintf("\n"); } VOID KERNENTRY DumpModule(IMTE imte, BOOL fIgnNotPres) { MTE *pmte; MTE mte; LEH lehMod; char ModFname[256]; pmte = GetModuleTableEntry(imte,&mte); if(fDumpHeader) { dbgprintf(fmt60h); dbgprintf(fmt60i); fDumpHeader = FALSE; } if (!pmte) { if(!fIgnNotPres) { dbgprintf(fmt60, imte, pmte, 0, "--", 0, NotPresentStr); } } else { try { READMEM(mte.plehMod, &lehMod, sizeof(LEH)); } except (1) { lehMod.ImageBase = 0; } try { READMEM(mte.cfhid.lpFilename, &ModFname[0], sizeof(ModFname)); } except (1) { ModFname[0] = '\0'; } dbgprintf(fmt60, imte, pmte, mte.usage, lehMod.Signature==MEOW_PLEH_SIGNATURE ? "NT" : "9X", lehMod.ImageBase, ModFname); } } /* DumpModule */ VOID KERNENTRY DumpModuleInProcess(MODREF *pModRef,MODREF *pModRefBuf) { IMTE imte; MTE *pmte; MTE mte; LEH lehMod; char ModFname[256]; try { READMEM(pModRef, pModRefBuf, sizeof(MODREF)); } except (1) { dbgprintf(fmt74a, pModRef); pModRefBuf->nextMod = 0; return; } imte = pModRefBuf->imte; pmte = GetModuleTableEntry(imte,&mte); if(fDumpHeader) { dbgprintf(fmt61h); dbgprintf(fmt61i); dbgprintf(fmt61j); fDumpHeader = FALSE; } if (pmte) { try { READMEM(mte.plehMod, &lehMod, sizeof(LEH)); } except (1) { lehMod.ImageBase = 0; } try { READMEM(mte.cfhid.lpFilename, &ModFname[0], sizeof(ModFname)); } except (1) { ModFname[0] = '\0'; } dbgprintf(fmt61, imte, pmte, mte.usage, pModRefBuf->usage, lehMod.Signature==MEOW_PLEH_SIGNATURE ? "NT" : "9X", lehMod.ImageBase, ModFname); } else { dbgprintf(fmt61, imte, pmte, 0, pModRefBuf->usage, "--", 0, NotPresentStr); } } /* DumpModuleInProcess */ #ifndef WOW32_EXTENSIONS VOID KERNENTRY HeapStuff(void) { #ifdef DEBUG BYTE b; b = (BYTE)GetDbgChar(); /* * The 'W' option toggles paranoid heap walking */ if (b == 'w' || b == 'W') { dbgprintf(fmt80); if (hpfParanoid) { hpfParanoid = 0; dbgprintf(fmt82); } else { hpfTrashStop = 1; hpfWalk = 1; hpfParanoid = 1; dbgprintf(fmt81); } /* * The 'E' options toggles stopping on errors */ } else if (b == 'e' || b == 'E') { mmfErrorStop ^= 1; dbgprintf(fmt83); if (mmfErrorStop) { dbgprintf(fmt81); } else { dbgprintf(fmt82); } } else { dbgprintf(DotError); } #else dbgprintf(fmt84); #endif } VOID KERNENTRY DumpThreadList1(TDB *ptdb) { DWORD *pdw; ULONG ulCount; // Make sure the tdb is present. if( !VerifyMemory( ptdb, sizeof( TDB))) { dbgprintf( fmt16, ptdb); return; } // Count the nodes in the private selector list for( ulCount = 0, pdw = (DWORD *)GetTIB(ptdb).pvFirstDscr; pdw != (DWORD *)1; ulCount++, pdw = (DWORD *)*pdw) ; // Print the thread id if( ptdb->R0ThreadHandle != 0) { dbgprintf( "%02x ", ((PTCB)ptdb->R0ThreadHandle)->TCB_ThreadId); } else { dbgprintf( "## "); } // Print the summary info for the thread dbgprintf( "%8x %4x ", ptdb, ulCount); if( !VerifyMemory( &pLDT, sizeof( DWORD *))) { dbgprintf( "\n[pLDT %x]\n", &pLDT); return; } // Print the private selector list for( ulCount = 0, pdw = (DWORD *)GetTIB(ptdb).pvFirstDscr; pdw != (DWORD *)1; ulCount++, pdw = (DWORD *)*pdw) { // Newline every now and then if( (ulCount > 0) && (ulCount % 12 == 0)) { dbgprintf( "\n "); } // Print as a selector dbgprintf( "%4x ", ((DWORD)pdw - (DWORD)pLDT) | 7); } dbgprintf( "\n"); } /* DumpThreadList1 */ VOID KERNENTRY DumpThreadLists(void) { NOD *pNodP, *pNodOld; // Title string dbgprintf( "id ptdb len per-thread selector list\n"); // Save current node pNodOld = PnodGetLstElem( plstTdb, idLstGetCur); // For each TDB in system for( pNodP = PnodGetLstElem( plstTdb, idLstGetFirst); pNodP != 0L; pNodP = PnodGetLstElem( plstTdb, idLstGetNext)) { DumpThreadList1( (TDB *)pNodP->dwData); } // Restore current node SetLstCurElem( plstTdb, pNodOld); } /* DumpThreadLists */ VOID KERNENTRY DumpSelmanList16(void) { DWORD dwCount; WORD wSel; dbgprintf( "16-bit selman list"); wSel = *pwHeadSelman16; if( !VerifyMemory( &pLDT, sizeof( DWORD *))) { dbgprintf( "\n[pLDT %x]\n", &pLDT); return; } if( !VerifyMemory( (WORD *)((DWORD)pLDT + (DWORD)wSel), sizeof( WORD))) { dbgprintf( "\nNot-present 16-bit selman list head.\n"); return; } for( dwCount = 0, wSel = *pwHeadSelman16; wSel != 1; dwCount++, wSel = *(WORD *)((DWORD)pLDT + (DWORD)wSel)) { if( dwCount % 16 == 0) dbgprintf( "\n"); // occasional newline dbgprintf( "%4lx ", wSel | 7); if( !VerifyMemory( (WORD *)((DWORD)pLDT + (DWORD)wSel), sizeof( WORD))) { dbgprintf( "\nCorrupt 16-bit selman list!!!\n"); break; } } if( wSel == 1) { dbgprintf( "\nnodes in 16-bit selman list = %d\n", dwCount); } } /* DumpSelmanList16 */ VOID KERNENTRY DumpSelmanList32(void) { DWORD dwCount; DWORD *p; dbgprintf( "32-bit selman list"); if( !VerifyMemory( &pLDT, sizeof( DWORD *))) { dbgprintf( "\n[pLDT %x]\n", &pLDT); return; } if( !VerifyMemory( SelmanBuffer, sizeof( DWORD))) { dbgprintf( "\n\tCan't access list!!!\n"); return; } for( dwCount = 0, p = SelmanBuffer; p != (DWORD *)(1); dwCount++, p = (DWORD *)*p) { if( dwCount % 16 == 0) dbgprintf( "\n"); // occasional newline // print as selector dbgprintf( "%4lx ", ((DWORD)p - (DWORD)pLDT) | 7); if( !VerifyMemory( (DWORD *)*p, sizeof( DWORD))) { dbgprintf( "\nCorrupt 32-bit selman list!!!\n"); break; } } if( p == (DWORD *)(1)) { dbgprintf( "\nnodes in 32-bit selman list = %d\n", dwCount); } } /* DumpSelmanList32 */ VOID KERNENTRY DumpFreeList16(void) { DWORD dwCount; WORD wSel; dbgprintf( "16-bit global free list"); if( !VerifyMemory( &pLDT, sizeof( DWORD *))) { dbgprintf( "\n[pLDT %x]\n", &pLDT); return; } for( dwCount = 0, wSel = wHeadK16FreeList; wSel != (WORD)(-1); dwCount++, wSel = *(WORD *)((DWORD)pLDT + (DWORD)wSel)) { // skip the head if( dwCount % 16 == 1) dbgprintf( "\n"); // occasional newline if( dwCount != 0) // skip the head dbgprintf( "%4lx ", wSel | 7); if( !VerifyMemory( (DWORD *)((DWORD)pLDT + (DWORD)wSel), sizeof( DWORD))) { dbgprintf( "\nCorrupt 16-bit free list!!!\n"); break; } } if( wSel == (WORD)(-1)) { // don't count the head node, and adjust for end-of-list // (bumped dwCount for the last, failing, iteration) dbgprintf( "\nnodes in 16-bit free list = %d\n", dwCount-1); } } /* DumpFreeList16 */ VOID KERNENTRY DumpLDTStuff(void) { DumpSelmanList16(); dbgprintf( "\n"); DumpSelmanList32(); dbgprintf( "\n"); DumpThreadLists(); dbgprintf( "\n"); DumpFreeList16(); } /* DumpLDTStuff */ #endif // ndef WOW32_EXTENSIONS VOID KERNENTRY DumpModules( char cmod, DWORD argppdb ) { IMTE i; IMTE imteMax; PDB* ppdb; MODREF* pModRef; MODREF ModRef; PDB pdb; LPVOID pTmp; // Distinguish between .wm and .wmp if ((cmod == 'p') || (cmod == 'P')) { // This is a .wmp so just dump modules for this process // See if the userA specified a process to dump if (argppdb == 0xFFFFFFFF) { ppdb = GetCurrentPdb(); if(!ppdb) { dbgprintf(fmt72a, ppdb); return; } dbgprintf(fmt72, ppdb, " "); } else { ppdb = (PDB *)argppdb; dbgprintf("PDB %08x\n", ppdb); } try { READMEM(ppdb, &pdb, sizeof(PDB)); } except (1) { dbgprintf(fmt74, ppdb); return; } if(pdb.objBase.typObj != typObjProcess) { dbgprintf(fmt74, ppdb); return; } // Walk the process list CheckCtrlC(); ModRef.nextMod = 0; fDumpHeader = TRUE; for (pModRef = pdb.plstMod ; pModRef ; pModRef = ModRef.nextMod) { DumpModuleInProcess(pModRef,&ModRef); if(CheckCtrlC()) { dbgprintf(fmt3a); break; } } return; } pTmp = NULL; GETEXPRADDR(pTmp, "mekrnl32!imteMax"); if(pTmp == NULL) { dbgprintf(fmt72b); i = 0; } else { try { imteMax = 0; READMEM(pTmp, &imteMax, sizeof(IMTE));\ } except (1) { dbgprintf(fmt72b); i = 0; } } fDumpHeader = TRUE; for (i=0; ipsbActiveScreenBuffer); dbgprintf(" Max Size X: %8dT\n", (DWORD)pconsole->cMaxSize.X); dbgprintf(" Max Size Y: %8dT\n", (DWORD)pconsole->cMaxSize.Y); dbgprintf(" Flags: %8x\n", (DWORD)pconsole->flags); dbgprintf(" Original Size X: %8dT\n", (DWORD)pconsole->cOriginalSize.X); dbgprintf(" Original Size Y: %8dT\n", (DWORD)pconsole->cOriginalSize.Y); dbgprintf(" &(crCRST): %8x\n", &(pconsole->csCRST)); dbgprintf(" plstOwners: %8x\n", (DWORD)pconsole->plstOwners); dbgprintf(" plstBuffers: %8x\n", (DWORD)pconsole->plstBuffers); dbgprintf(" dwLastExitCode: %8x\n", (DWORD)pconsole->dwLastExitCode); dbgprintf(" szTitle: %s\n", &(pconsole->szTitle)); dbgprintf(" VID: %8x\n", (DWORD)pconsole->VID); dbgprintf(" hVM: %8x\n", (DWORD)pconsole->hVM); dbgprintf(" hDisplay: %8x\n", (DWORD)pconsole->hDisplay); dbgprintf("ppdbControlFocus: %8x\n", (DWORD)pconsole->ppdbControlFocus); dbgprintf("ppdbTermConProvi: %8x\n", (DWORD)pconsole->ppdbTermConProvider); dbgprintf(" &(inbuf.cbBuf): %8x\n", &(pconsole->inbuf.cbBuf)); dbgprintf(" inbuf.ReadIndex: %8x\n", (DWORD)pconsole->inbuf.wReadIdx); dbgprintf("inbuf.WriteIndex: %8x\n", (DWORD)pconsole->inbuf.wWriteIdx); dbgprintf(" inbuf.BufCount: %8x\n", (DWORD)pconsole->inbuf.wBufCount); dbgprintf(" wDefaultAttr: %8x\n", (DWORD)pconsole->wDefaultAttribute); dbgprintf(" evtDoneWithVM: %8x\n", (DWORD)pconsole->evtDoneWithVM); } /*** DumpScreenBuffer * * Information on a console ScreenBuffer object is displayed. * * Entry: psb - pointer to screen buffer * * Exit: none */ VOID KERNENTRY DumpScreenBuffer(SCREENBUFFER *psb) { // If the screen buffer's not present, display the address, etc. if (!VerifyMemory(psb, sizeof (SCREENBUFFER))) { dbgprintf(fmt50, psb); return; } // Since the screen buffer's present, display some useful stuff about it dbgprintf("ScreenBuffer %x\n", (DWORD)psb); dbgprintf(" Size X: %8dT\n", (DWORD)psb->cBufsize.X); dbgprintf(" Size Y: %8dT\n", (DWORD)psb->cBufsize.Y); dbgprintf(" Screen Data: %8x\n", (DWORD)psb->Screen); dbgprintf(" Cursor X: %8dT\n", (DWORD)psb->cCursorPosition.X); dbgprintf(" Cursor Y: %8dT\n", (DWORD)psb->cCursorPosition.Y); dbgprintf(" Cursor Fill %%: %8dT\n", (DWORD)psb->dwCursorSize); dbgprintf(" Window Lft: %8dT\n", (DWORD)psb->srWindow.Left); dbgprintf(" Window Top: %8dT\n", (DWORD)psb->srWindow.Top); dbgprintf(" Window Rgt: %8dT\n", (DWORD)psb->srWindow.Right); dbgprintf(" Window Bot: %8dT\n", (DWORD)psb->srWindow.Bottom); dbgprintf(" Flags: %8x\n", (DWORD)psb->flags); dbgprintf(" State: %8x (%s)\n", (DWORD)psb->State, (psb->State == SB_PHYSICAL) ? "physical" : (psb->State == SB_NATIVE) ? "native" : (psb->State == SB_MEMORY) ? "memory" : "*CORRUPTED*"); dbgprintf(" &(crst): %8x\n", &(psb->csCRST)); dbgprintf(" pConsole: %8x\n", (DWORD)psb->pConsole); dbgprintf(" wAttribute: %8x\n", (DWORD)psb->wAttribute); dbgprintf(" OutMode Flags: %8x\n", (DWORD)psb->flOutputMode); } #endif // ndef WOW32_EXTENSIONS /*** DumpTimer * * Information on a timer is displayed. * * Entry: ptimerDB - pointer to timer * * Exit: none */ VOID KERNENTRY DumpTimer(TIMERDB *ptimerDB) { TIMERDB timerDB; LPTIMERR3APC lpTimerR3Apc; TIMERR3APC TimerR3Apc; try { READMEM(ptimerDB, &timerDB, sizeof(TIMERDB)); } except (1) { dbgprintf("Could not read TIMERDB structure for %08x\n", ptimerDB); return; } dbgprintf("Timer: %08x\n", (DWORD)ptimerDB); dbgprintf(" State: %s, %s\n", (timerDB.objBase.objFlags & fTimerRing3) ? "Ring 3" : "Ring 0", timerDB.cntCur ? "Signaled" : "Unsignaled"); dbgprintf(" Ref count: %08x\n", timerDB.objBase.cntUses); dbgprintf(" CntCur: %08x\n", timerDB.cntCur); dbgprintf(" NameStruct: %08x\n", (DWORD)(timerDB.NameStruct)); dbgprintf(" lpNextTimerDb: %08x\n", timerDB.lpNextTimerDb); dbgprintf(" hTimeout: %08x\n", timerDB.hTimeout); dbgprintf(" DueTime.Hi: %08x\n", timerDB.DueTime.dwHighDateTime); dbgprintf(" DueTime.Lo: %08x\n", timerDB.DueTime.dwLowDateTime); dbgprintf(" Completion: %08x\n", (DWORD)(timerDB.Completion)); dbgprintf(" lPeriod: %08x\n", timerDB.lPeriod); if ((timerDB.objBase.objFlags & fTimerRing3) && (lpTimerR3Apc = (LPTIMERR3APC)(timerDB.Completion)) && lpTimerR3Apc != (LPTIMERR3APC)0xcccccccc) { dbgprintf("-- Attached Ring 3 Completion Structure --\n"); try { READMEM(lpTimerR3Apc, &TimerR3Apc, sizeof(TIMERR3APC)); } except (1) { dbgprintf(" lpTimerR3Apc: [%8x]\n", lpTimerR3Apc); lpTimerR3Apc = NULL; } if (lpTimerR3Apc) { dbgprintf(" cRef: %08x\n", (DWORD)(TimerR3Apc.cRef)); dbgprintf(" Completion Fcn: %08x\n", (DWORD)(TimerR3Apc.pfnCompletion)); dbgprintf(" Completion Arg: %08x\n", (DWORD)(TimerR3Apc.lpCompletionArg)); dbgprintf(" ApcTdbx: %08x\n", (DWORD)(TimerR3Apc.ApcTdbx)); dbgprintf(" dwApcHandle: %08x\n", (DWORD)(TimerR3Apc.dwApcHandle)); } } if (timerDB.pwnWait != NULL) { PrintThreads(timerDB.pwnWait); } else { dbgprintf(NewLine); } } #ifndef WOW32_EXTENSIONS /*** DumpR0ObjExt * * Information on an external ring 0 object is displayed. * * Entry: pR0ObjExt - pointer to R0OBJEXT * * Exit: none */ VOID KERNENTRY DumpR0ObjExt(PR0OBJEXT pR0ObjExt) { PR0OBJTYPETABLE pR0ObjTypeTable; // If the objects's not present, display the address, etc. if (!VerifyMemory(pR0ObjExt, sizeof (R0OBJEXT))) { dbgprintf(fmt50, pR0ObjExt); return; } pR0ObjTypeTable = pR0ObjExt->pR0ObjTypeTable; dbgprintf("R0ObjExt: %8x\n", (DWORD)pR0ObjExt); dbgprintf(" External Use: %8x\n", (DWORD)pR0ObjExt->cntExternalUses); dbgprintf(" Object Body: %8x\n", (DWORD)pR0ObjExt->pR0ObjBody); dbgprintf(" Object Vtbl: %8x\n", (DWORD)pR0ObjTypeTable); if (VerifyMemory(pR0ObjTypeTable, sizeof(R0OBJTYPETABLE))) { dbgprintf(" pfnFree: %8x\n", (DWORD)pR0ObjTypeTable->ott_pfnFree); dbgprintf(" pfnDup: %8x\n", (DWORD)pR0ObjTypeTable->ott_pfnDup); } } #endif // ndef WOW32_EXTENSIONS VOID KERNENTRY DumpCrstPnt(CRST *pcrst, char *name) { PTDBX ptdbx; TDBX tdbx; PTDB ptdb; PPDB ppdb; DWORD ptcb; CRST crst; if(pcrst) { try { READMEM(pcrst, &crst, sizeof(CRST)); } except (1) { pcrst = NULL; } } if(pcrst) { if (crst.cntCur == 1) { dbgprintf("%s(%08x) is not owned\n", name, pcrst); return; } if (!crst.ptdbxOwner) { dbgprintf("%s(%08x) null ptdbxOwner field\n", name, pcrst); return; } ptdbx = crst.ptdbxOwner; if(ptdbx) { try { READMEM(ptdbx, &tdbx, sizeof(TDBX)); } except (1) { ptdbx = NULL; } } if(!ptdbx) { dbgprintf("%s(%08x) invalid ptdbxOwner\n", name, pcrst); return; } ptdb = (PTDB)tdbx.tdbxThreadHandle; ppdb = (PPDB)tdbx.tdbxProcessHandle; ptcb = (DWORD)tdbx.tdbxR0ThreadHandle; dbgprintf( "%s(%08x) held by TDBX %08x(%x) TDB %08x, PDB %08x, recursion %d\n", name, pcrst, ptdbx, ptcb, ptdb, ppdb, crst.cntRecur); if (crst.ptdbxWait) { ptdbx = crst.ptdbxWait; if(ptdbx) { try { READMEM(ptdbx, &tdbx, sizeof(TDBX)); } except (1) { ptdbx = NULL; } } if(!ptdbx) { dbgprintf("%s(%08x) invalid ptdbxWait\n", name, pcrst); return; } ptdb = (PTDB)tdbx.tdbxThreadHandle; ppdb = (PPDB)tdbx.tdbxProcessHandle; ptcb = (DWORD)tdbx.tdbxR0ThreadHandle; dbgprintf(" Waiting TDBX %08x(%x) TDB %08x, PDB %08x\n", ptdbx, ptcb, ptdb, ppdb); } } else { dbgprintf("Cannot access %s\n", name); } } /* DumpCrstPnt */ VOID KERNENTRY DumpCrstSym(char *crstsymname, char *name) { CRST *pcrst; LPVOID pTmp; pTmp = NULL; GETEXPRADDR(pTmp, crstsymname); if(pTmp == NULL) { pcrst = NULL; } else { try { READMEM(pTmp, &pcrst, sizeof(CRST *)); } except (1) { pcrst = NULL; } } DumpCrstPnt(pcrst,name); } VOID KERNENTRY DumpWait(PDB *ppdb) { NOD *pNodP, *pNodStart; NOD nod; PDB pdb; TDB *ptdb; TDB tdb; LST *plstTdb; LPVOID pTmp; DWORD dwi; dbgprintf("PDB %x\n", ppdb); if(!ppdb) { dbgprintf("\nInvalid PDB\n"); return; } try { READMEM(ppdb, &pdb, sizeof(PDB)); } except (1) { dbgprintf("\nInvalid PDB\n"); return; } dwi = (DWORD)ppdb; dwi += offsetof(PDB, crstLoadLock.cstSync); DumpCrstPnt((CRST *)dwi, " DllLock"); pTmp = NULL; GETEXPRADDR(pTmp, "mekrnl32!plstTdb"); if(pTmp == NULL) { plstTdb = NULL; } else { try { READMEM(pTmp, &plstTdb, sizeof(LST *)); } except (1) { plstTdb = NULL; } } pNodStart = pNodP = PnodGetLstElem(plstTdb, NULL, idLstGetFirst); if(!pNodP) return; while(pNodP) { try { READMEM(pNodP, &nod, sizeof(NOD)); } except (1) { dbgprintf("\nInvalid TDB list element\n"); break; } ptdb = (TDB *)nod.dwData; tdb.flFlags = 0; if(ptdb) { try { READMEM(ptdb, &tdb, sizeof(TDB)); } except (1) { tdb.flFlags = 0; } } dbgprintf(" Thread %08x flags %08x\n", ptdb, tdb.flFlags); pNodP = PnodGetLstElem(plstTdb, pNodP, idLstGetNext); if(pNodP == pNodStart) { break; } } } /* DumpWait */ VOID KERNENTRY DumpWaiting(void) { NOD *pNodP, *pNodStart; NOD nod; LST *plstPdb; LPVOID pTmp; DumpCrstSym("mekrnl32!Win16Lock", "Win16Mutex"); DumpCrstSym("mekrnl32!Krn32Lock", "Krn32Mutex"); pTmp = NULL; GETEXPRADDR(pTmp, "mekrnl32!plstPdb"); if(pTmp == NULL) { plstPdb = NULL; } else { try { READMEM(pTmp, &plstPdb, sizeof(LST *));\ } except (1) { plstPdb = NULL; } } pNodStart = pNodP = PnodGetLstElem(plstPdb, NULL, idLstGetFirst); if(!pNodP) return; while(pNodP) { try { READMEM(pNodP, &nod, sizeof(NOD)); } except (1) { dbgprintf("\nInvalid PDB list element\n"); break; } DumpWait((PDB *)nod.dwData); pNodP = PnodGetLstElem(plstPdb, pNodP, idLstGetNext); if(pNodP == pNodStart) { break; } } } /* DumpWaiting */ /*** DumpAllThreads * * Called to process the '.w' command. Information on all win32 threads is * displayed. * * Entry: none * * Exit: none */ VOID KERNENTRY DumpAllThreads(void) { NOD *pNodP; NOD *pNodPnew; NOD *pNodStart; NOD nod; PVOID pTmp; LST *plstTdb; pTmp = NULL; GETEXPRADDR(pTmp, "mekrnl32!plstTdb"); if(pTmp == NULL) { plstTdb = NULL; } else { try { READMEM(pTmp, &plstTdb, sizeof(LST *));\ } except (1) { plstTdb = NULL; } } if(!plstTdb) { dbgprintf("Cannot get TDB List from MEKRNL32\n"); return; } pNodStart = pNodP = PnodGetLstElem(plstTdb, NULL, idLstGetFirst); if(!pNodP) return; fDumpHeader = TRUE; CheckCtrlC(); while(pNodP) { try { READMEM(pNodP, &nod, sizeof(NOD));\ } except (1) { dbgprintf("\nInvalid TDB list element\n"); break; } DumpThread((TDB *)(nod.dwData),FALSE); pNodPnew = PnodGetLstElem(plstTdb, pNodP, idLstGetNext); if((pNodPnew == pNodStart) || (pNodPnew == pNodP)) { break; } if(CheckCtrlC()) { dbgprintf(fmt3a); break; } pNodP = pNodPnew; } } VOID KERNENTRY DumpHandleTable(char cmod, PDB* ppdb) { HTB *phtb; HTB htb[60]; DWORD htbtrusz; PDB pdb; LPVOID pTmp; MTE *pmte; MTE mte; OBJ obj; MODREF ModRef; char ModFname[256]; int ihte; if ((cmod == 'k') || (cmod == 'K')) { pTmp = NULL; GETEXPRADDR(pTmp, "mekrnl32!ppdbKernel"); if(pTmp == NULL) { dbgprintf("Cannot get ppdbKernel\n"); return; } else { try { READMEM(pTmp, &ppdb, sizeof(PDB *));\ } except (1) { dbgprintf("Cannot get ppdbKernel\n"); return; } } } else if (ppdb == NULL) { ppdb = GetCurrentPdb(); } if(ppdb) { try { READMEM(ppdb, &pdb, sizeof(PDB));\ } except (1) { ppdb = NULL; } } if(!ppdb) { dbgprintf(fmt74, (DWORD)0xFFFFFFFF); return; } if(pdb.objBase.typObj != typObjProcess) { dbgprintf(fmt74, ppdb); return; } if(pdb.pModExe) { try { READMEM(pdb.pModExe, &ModRef, sizeof(MODREF)); } except (1) { dbgprintf(fmt74, ppdb); goto NmDone; } pmte = GetModuleTableEntry(ModRef.imte,&mte); if (!pmte) { dbgprintf(fmt74, ppdb); goto NmDone; } try { READMEM(mte.cfhid.lpFilename, &ModFname[0], sizeof(ModFname)); } except (1) { dbgprintf(fmt74, ppdb); goto NmDone; } dbgprintf(fmt75, ppdb, ModFname); } else { dbgprintf(fmt75, ppdb, fmt73); } NmDone: // Loop through the handle table, dumping object pointers phtb = pdb.phtbHandles; htbtrusz = sizeof(HTB); if(phtb) { try { READMEM(phtb, &htb[0], htbtrusz); } except (1) { htb[0].chteMax = 0; } } else { htb[0].chteMax = 0; } if(htb[0].chteMax) { if(htb[0].chteMax > 60) htb[0].chteMax = 60; htbtrusz += (htb[0].chteMax - 1) * (sizeof(HTE)); try { READMEM(phtb, &htb[0], htbtrusz); } except (1) { htb[0].chteMax = 0; } } for (ihte = 0 ; ihte < (int)htb[0].chteMax ; ++ihte) { // Don't display empty table slots if (!htb[0].rghte[ihte].pobj) continue; try { READMEM(htb[0].rghte[ihte].pobj, &obj, sizeof(OBJ)); } except (1) { obj.typObj = 0; } // Display this handle entry dbgprintf(fmt76, ihte<' command, where is the address of a win32 * object. * * Entry: pobj - pointer to object * * Exit: none * */ void KERNENTRY DumpObject(OBJ *pobj) { OBJ obj; try { READMEM(pobj, &obj, sizeof(OBJ)); } except (1) { goto dodef; } switch (obj.typObj) { case typObjSemaphore: DumpSemaphore((SEM *) pobj); break; case typObjEvent: DumpEvent((EVT *) pobj); break; case typObjMutex: DumpMutex((MUTX *) pobj); break; case typObjCrst: DumpCritSect((CRST *) pobj); break; case typObjProcess: DumpProcess((PDB *) pobj); break; case typObjThread: fDumpHeader = TRUE; DumpThread((PTDB)pobj, TRUE); break; case typObjChange: DumpChange((FCNDB *) pobj); break; // case typObjConsole: // DumpConsole((CONSOLE *) pobj); // break; // case typObjConScreenbuf: // DumpScreenBuffer((SCREENBUFFER *) pobj); // break; case typObjTimer: DumpTimer((TIMERDB *) pobj); break; case typObjTDBX: DumpTDBX((PTDBX) pobj); break; case typObjR0ObjExt: case typObjFile: case typObjMapFile: default: dodef: dbgprintf("Invalid or unrecognized object address 0x%08x\n", (DWORD)pobj); break; } } typedef struct _MEMINFO { DWORD dwMask; PCHAR pszName; } MEMINFO, *PMEMINFO; MEMINFO MemInfo[]={ {PAGE_NOACCESS, "PNA "}, {PAGE_READONLY, "PRO "}, {PAGE_READWRITE, "PRW "}, {PAGE_WRITECOPY, "PWC "}, {PAGE_EXECUTE, "PE "}, {PAGE_EXECUTE_READ, "PER "}, {PAGE_EXECUTE_READWRITE,"PERW"}, {PAGE_EXECUTE_WRITECOPY,"PEWC"}, {PAGE_GUARD, "PGD "}, {PAGE_NOCACHE, "PNC "}, {PAGE_WRITECOMBINE, "PWC+"}, {MEM_COMMIT, "MCOM"}, {MEM_RESERVE, "MRES"}, {MEM_DECOMMIT, "MDEC"}, {MEM_RELEASE, "MREL"}, {MEM_FREE, "MFRE"}, {MEM_PRIVATE, "MPRV"}, {MEM_MAPPED, "MMAP"}, {MEM_RESET, "MRES"}, {MEM_TOP_DOWN, "MTOP"}, {MEM_WRITE_WATCH, "MWW "}, {MEM_PHYSICAL, "MPHY"}, {MEM_IMAGE, "MIMG"}, {MEM_LARGE_PAGES, "MLP "}, {MEM_DOS_LIM, "MDOS"}, {MEM_4MB_PAGES, "M4MB"}, }; #define MEMINFO_COUNT (sizeof(MemInfo)/sizeof(MEMINFO)) VOID KERNENTRY ProcessMemInfo(CHAR c, DWORD dwMask) { BOOL fNothing=TRUE; ULONG i; dbgprintf(" %c:", c); for (i=0;i' - info for specific object * '.w' - info for all threads * '.ws' - info for all global system critical section objects */ VOID k32( CMD_ARGLIST ) { INT nArgs; CHAR *argv[4]; DWORD addr; char **s; DWORD c; BOOL fAll; CMD_INIT(); nArgs = WDParseArgStr(lpArgumentString, argv, 3); if(nArgs) { if((nArgs > 2) || ((argv[0][0] != 'W') && (argv[0][0] != 'w'))) { goto DoHelp; } c = (DWORD)argv[0][1]; } else { goto DoHelp; } switch (c) { case '?': DoHelp: for (s = w32DotCommandExtHelp; *s; ++s) { dbgprintf(*s); } break; #ifndef WOW32_EXTENSIONS case 'c': case 'C': DumpContextRecord(); break; case 'e': case 'E': DumpExceptionRecord(); break; case 'd': case 'D': DumpDispatcherContext(); break; case 'h': case 'H': HeapStuff(); break; case 'l': case 'L': DumpLDTStuff(); break; #endif //ndef WOW32_EXTENSIONS case 'm': case 'M': addr = 0xFFFFFFFF; if(nArgs > 1) { addr = (DWORD)WDahtoi(argv[1]); } fDumpHeader = TRUE; DumpModules( argv[0][2], addr ); break; case 'p': case 'P': DumpProcesses(); break; case 's': case 'S': DumpSysLevels(); break; case 'w': // Waiting threads case 'W': DumpWaiting(); break; case 't': case 'T': if(nArgs == 1) { addr = 0; } else { addr = 0xFFFFFFFF; addr = (DWORD)WDahtoi(argv[1]); if(addr == 0xFFFFFFFF) { goto DoHelp; } } DumpHandleTable(argv[0][2],(PDB *)addr); break; case 'x': case 'X': if(nArgs == 1) { addr = 0; fAll = TRUE; } else { fAll = FALSE; addr = 0xFFFFFFFF; addr = (DWORD)WDahtoi(argv[1]); if(addr == 0xFFFFFFFF) { goto DoHelp; } } DumpMemStatus(addr, fAll); break; case ' ': addr = 0xFFFFFFFF; addr = (DWORD)WDahtoi(argv[1]); if(addr == 0xFFFFFFFF) { goto DoHelp; } else { DumpObject((OBJ *) addr); } break; case 0: // There was just a W with no second letter if(nArgs == 1) { // No expression DumpAllThreads(); } else { addr = 0xFFFFFFFF; addr = (DWORD)WDahtoi(argv[1]); if(addr == 0xFFFFFFFF) { goto DoHelp; } else { DumpObject((OBJ *) addr); } } break; default: dbgprintf(DotError); goto DoHelp; } } #endif // def KERNEL_DOT_COMMANDS