685 lines
16 KiB
C
685 lines
16 KiB
C
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
trace.c
|
|
|
|
Abstract:
|
|
|
|
This file contains code to dump the ntvdm trace history log
|
|
|
|
Author:
|
|
|
|
Neil Sandlin (neilsa) 1-Nov-1995
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <precomp.h>
|
|
#pragma hdrstop
|
|
#include <dbgsvc.h>
|
|
#include <dpmi.h>
|
|
|
|
ULONG TimeIndex;
|
|
ULONG TimerMode = 0;
|
|
ULONG CpuSpeed = 0;
|
|
BOOL bTriedToGetCpuSpeed = FALSE;
|
|
#define CPUSPEED_PATH "Hardware\\Description\\System\\CentralProcessor\\0"
|
|
#define CPUSPEED_VALUE "~MHz"
|
|
|
|
VOID
|
|
DumpTypeGeneric(
|
|
VDM_TRACEENTRY te
|
|
)
|
|
{
|
|
PRINTF("%.4x: %.4X %.8X", te.Type, te.wData, te.lData);
|
|
}
|
|
|
|
|
|
VOID
|
|
DumpTypeKernel(
|
|
VDM_TRACEENTRY te
|
|
)
|
|
{
|
|
|
|
switch(te.Type&0xff) {
|
|
case VDMTR_KERNEL_HW_INT:
|
|
PRINTF("Hw Int %.2x ", te.wData);
|
|
break;
|
|
|
|
case VDMTR_KERNEL_OP_PM:
|
|
case VDMTR_KERNEL_OP_V86:
|
|
PRINTF("OpEm ");
|
|
|
|
switch(te.wData&0xff) {
|
|
|
|
case 0xec:
|
|
PRINTF("INB");
|
|
break;
|
|
|
|
case 0xee:
|
|
PRINTF("OUTB");
|
|
break;
|
|
|
|
case 0xfa:
|
|
PRINTF("CLI");
|
|
break;
|
|
|
|
case 0xfb:
|
|
PRINTF("STI");
|
|
break;
|
|
|
|
default:
|
|
PRINTF(" %.2x ", te.wData);
|
|
}
|
|
break;
|
|
|
|
|
|
default:
|
|
PRINTF("Unknown : %d", te.Type&0xff);
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
DumpTypeDpmi(
|
|
VDM_TRACEENTRY te
|
|
)
|
|
{
|
|
//
|
|
// Dpmi dispatch table entries
|
|
//
|
|
static char szDispatchEntries[MAX_DPMI_BOP_FUNC][40] = {
|
|
"InitDosxRM",
|
|
"InitDosx",
|
|
"InitLDT",
|
|
"GetFastBopAddress",
|
|
"InitIDT",
|
|
"InitExceptionHandlers",
|
|
"InitApp",
|
|
"TerminateApp",
|
|
"InUse",
|
|
"NoLongerInUse",
|
|
"switch_to_protected_mode",
|
|
"switch_to_real_mode",
|
|
"SetAltRegs",
|
|
"IntHandlerIret16",
|
|
"IntHandlerIret32",
|
|
"FaultHandlerIret16",
|
|
"FaultHandlerIret32",
|
|
"UnhandledExceptionHandler",
|
|
"RMCallBackCall",
|
|
"ReflectIntrToPM",
|
|
"ReflectIntrToV86",
|
|
"InitPmStackInfo",
|
|
"VcdPmSvcCall32",
|
|
"SetDescriptorEntry",
|
|
"ResetLDTUserBase",
|
|
"XlatInt21Call",
|
|
"Int31"
|
|
};
|
|
|
|
|
|
switch(te.Type&0xff) {
|
|
case DPMI_DISPATCH_INT:
|
|
PRINTF("Dispatch Int %.2x ", te.wData);
|
|
break;
|
|
case DPMI_HW_INT:
|
|
PRINTF("Hw Int %.2x ", te.wData);
|
|
break;
|
|
case DPMI_SW_INT:
|
|
PRINTF("Sw Int %.2x ", te.wData);
|
|
break;
|
|
|
|
case DPMI_FAULT:
|
|
PRINTF("Fault %.2x ec=%.8x", te.wData, te.lData);
|
|
break;
|
|
case DPMI_DISPATCH_FAULT:
|
|
PRINTF("Dispatch Flt %.2x ", te.wData);
|
|
break;
|
|
|
|
case DPMI_FAULT_IRET:
|
|
PRINTF("Fault Iret");
|
|
break;
|
|
case DPMI_INT_IRET16:
|
|
PRINTF("Int Iret16");
|
|
break;
|
|
case DPMI_INT_IRET32:
|
|
PRINTF("Int Iret32");
|
|
break;
|
|
|
|
case DPMI_OP_EMULATION:
|
|
PRINTF("Op Emulation");
|
|
break;
|
|
|
|
case DPMI_DISPATCH_ENTRY:
|
|
PRINTF("Dispatch(%d): ", te.wData);
|
|
if (te.lData >= MAX_DPMI_BOP_FUNC) {
|
|
PRINTF("Unknown (%d)", te.lData);
|
|
} else {
|
|
PRINTF("%s", szDispatchEntries[te.lData]);
|
|
}
|
|
break;
|
|
|
|
case DPMI_DISPATCH_EXIT:
|
|
PRINTF("Exit(%d): ", te.wData);
|
|
if (te.lData >= MAX_DPMI_BOP_FUNC) {
|
|
PRINTF("Unknown (%d)", te.lData);
|
|
} else {
|
|
PRINTF("%s", szDispatchEntries[te.lData]);
|
|
}
|
|
break;
|
|
|
|
case DPMI_SWITCH_STACKS:
|
|
PRINTF("switch stack -> %.4x:%.8x", te.wData, te.lData);
|
|
break;
|
|
|
|
case DPMI_GENERIC:
|
|
PRINTF("Data: %.4x %.8x", te.wData, te.lData);
|
|
break;
|
|
|
|
case DPMI_IN_V86:
|
|
PRINTF("in V86 mode");
|
|
break;
|
|
|
|
case DPMI_IN_PM:
|
|
PRINTF("in protect mode");
|
|
break;
|
|
|
|
case DPMI_REFLECT_TO_PM:
|
|
PRINTF("Reflect to PM");
|
|
break;
|
|
|
|
case DPMI_REFLECT_TO_V86:
|
|
PRINTF("Reflect to V86");
|
|
break;
|
|
|
|
default:
|
|
PRINTF("Unknown : %d", te.Type&0xff);
|
|
return;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
DumpTypeMonitor(
|
|
VDM_TRACEENTRY te
|
|
)
|
|
{
|
|
static char szMonitorEntries[][20] = {
|
|
"Event IO",
|
|
"Event String IO",
|
|
"Event Mem Access",
|
|
"Event Int Ack",
|
|
"Event BOP",
|
|
"Event Error",
|
|
"Event Irq 13",
|
|
"Cpu Simulate",
|
|
"Cpu Unsimulate",
|
|
};
|
|
|
|
if ((te.Type&0xff) <= MONITOR_CPU_UNSIMULATE) {
|
|
PRINTF("%s", szMonitorEntries[(te.Type&0xff)-1]);
|
|
PRINTF(": %.4X %.8X", te.wData, te.lData);
|
|
} else {
|
|
DumpTypeGeneric(te);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
DumpTimeInfo(
|
|
VDM_TRACEENTRY te
|
|
)
|
|
{
|
|
|
|
ULONG USecs = 0;
|
|
|
|
switch(TimerMode) {
|
|
|
|
case VDMTI_TIMER_TICK:
|
|
PRINTF("%d.%.3d", TimeIndex/1000, TimeIndex%1000);
|
|
PRINTF(" %.8X ", te.Time);
|
|
break;
|
|
|
|
case VDMTI_TIMER_PENTIUM:
|
|
|
|
if (CpuSpeed) {
|
|
USecs = TimeIndex / CpuSpeed;
|
|
}
|
|
PRINTF("%5d.%.3d", USecs/1000, USecs%1000);
|
|
PRINTF(" %.8X ", te.Time);
|
|
break;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
DumpTraceEntry(
|
|
int index,
|
|
VDM_TRACEENTRY te,
|
|
ULONG Verbosity
|
|
)
|
|
|
|
{
|
|
|
|
PRINTF("%4x ",index);
|
|
DumpTimeInfo(te);
|
|
|
|
switch(te.Type & 0xff00) {
|
|
case (VDMTR_TYPE_KERNEL):
|
|
PRINTF("Krnl ");
|
|
DumpTypeKernel(te);
|
|
break;
|
|
|
|
case (VDMTR_TYPE_DPMI):
|
|
PRINTF("Dpmi ");
|
|
DumpTypeDpmi(te);
|
|
break;
|
|
|
|
case (VDMTR_TYPE_DPMI_SF):
|
|
PRINTF("Dpmi Set Fault Handler %.02X -> %.4X:%.8X", te.Type & 0xff, te.wData, te.lData);
|
|
break;
|
|
|
|
case (VDMTR_TYPE_DPMI_SI):
|
|
PRINTF("Dpmi Set Int Handler %.02X -> %.4X:%.8X", te.Type & 0xff, te.wData, te.lData);
|
|
break;
|
|
|
|
case (VDMTR_TYPE_DEM):
|
|
PRINTF("Dem ");
|
|
switch(te.Type & 0xff) {
|
|
case 1:
|
|
PRINTF("Dispatch: %.4X %.8X", te.wData, te.lData);
|
|
break;
|
|
case 2:
|
|
PRINTF("Exit: %.4X %.8X", te.wData, te.lData);
|
|
break;
|
|
default:
|
|
DumpTypeGeneric(te);
|
|
}
|
|
break;
|
|
|
|
case (VDMTR_TYPE_WOW):
|
|
PRINTF("Wow ");
|
|
DumpTypeGeneric(te);
|
|
break;
|
|
|
|
case (VDMTR_TYPE_VSBD):
|
|
PRINTF("Vsbd ");
|
|
DumpTypeGeneric(te);
|
|
break;
|
|
|
|
case (VDMTR_TYPE_DBG):
|
|
PRINTF("Dbg ");
|
|
DumpTypeGeneric(te);
|
|
break;
|
|
|
|
case (VDMTR_TYPE_MONITOR):
|
|
PRINTF("Mon ");
|
|
DumpTypeMonitor(te);
|
|
break;
|
|
|
|
default:
|
|
PRINTF(" ");
|
|
DumpTypeGeneric(te);
|
|
}
|
|
|
|
if (Verbosity) {
|
|
PRINTF("\n");
|
|
|
|
PRINTF("eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
|
|
te.eax, te.ebx, te.ecx, te.edx, te.esi, te.edi );
|
|
|
|
PRINTF("eip=%08lx esp=%08lx ebp=%08lx ",
|
|
te.eip, te.esp, te.ebp );
|
|
|
|
if ( te.eflags & FLAG_OVERFLOW ) {
|
|
PRINTF("ov ");
|
|
} else {
|
|
PRINTF("nv ");
|
|
}
|
|
if ( te.eflags & FLAG_DIRECTION ) {
|
|
PRINTF("dn ");
|
|
} else {
|
|
PRINTF("up ");
|
|
}
|
|
if ( te.eflags & FLAG_INTERRUPT ) {
|
|
PRINTF("ei ");
|
|
} else {
|
|
PRINTF("di ");
|
|
}
|
|
if ( te.eflags & FLAG_SIGN ) {
|
|
PRINTF("ng ");
|
|
} else {
|
|
PRINTF("pl ");
|
|
}
|
|
if ( te.eflags & FLAG_ZERO ) {
|
|
PRINTF("zr ");
|
|
} else {
|
|
PRINTF("nz ");
|
|
}
|
|
if ( te.eflags & FLAG_AUXILLIARY ) {
|
|
PRINTF("ac ");
|
|
} else {
|
|
PRINTF("na ");
|
|
}
|
|
if ( te.eflags & FLAG_PARITY ) {
|
|
PRINTF("po ");
|
|
} else {
|
|
PRINTF("pe ");
|
|
}
|
|
if ( te.eflags & FLAG_CARRY ) {
|
|
PRINTF("cy ");
|
|
} else {
|
|
PRINTF("nc ");
|
|
}
|
|
PRINTF("\n");
|
|
PRINTF("cs=%04x ss=%04x ds=%04x es=%04x fs=%04x gs=%04x efl=%08lx\n",
|
|
te.cs, te.ss, te.ds, te.es, te.fs, te.gs, te.eflags );
|
|
|
|
}
|
|
|
|
TimeIndex += te.Time;
|
|
PRINTF("\n");
|
|
}
|
|
|
|
|
|
VOID
|
|
DumpTrace(
|
|
IN ULONG Verbosity
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine dumps the DPMI trace history buffer.
|
|
|
|
Arguments:
|
|
|
|
Return Value
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PVOID pMem;
|
|
ULONG TraceBase, TraceEnd, TraceCurrent;
|
|
ULONG Lines;
|
|
VDM_TRACEINFO TraceInfo;
|
|
VDM_TRACEENTRY TraceEntry;
|
|
ULONG Count = 0;
|
|
ULONG EntryID;
|
|
ULONG NumEntries;
|
|
|
|
if (!ReadMemExpression("ntvdm!pVdmTraceInfo", &pMem, 4)) {
|
|
return;
|
|
}
|
|
|
|
if (!READMEM(pMem, &TraceInfo, sizeof(VDM_TRACEINFO))) {
|
|
PRINTF("Error reading memory for TraceInfo\n");
|
|
return;
|
|
}
|
|
|
|
if (!TraceInfo.pTraceTable) {
|
|
PRINTF("NTVDM trace history not available\n");
|
|
return;
|
|
}
|
|
|
|
if (!CpuSpeed && !bTriedToGetCpuSpeed) {
|
|
HKEY hKey;
|
|
DWORD retCode;
|
|
DWORD dwType, cbData = sizeof(ULONG);
|
|
ULONG dwData;
|
|
|
|
retCode = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
|
|
CPUSPEED_PATH,
|
|
0,
|
|
KEY_EXECUTE, // Requesting read access.
|
|
&hKey);
|
|
|
|
|
|
if (!retCode) {
|
|
|
|
retCode = RegQueryValueEx(hKey,
|
|
CPUSPEED_VALUE,
|
|
NULL,
|
|
&dwType,
|
|
(LPSTR)&dwData,
|
|
&cbData);
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
if (!retCode) {
|
|
CpuSpeed = dwData;
|
|
}
|
|
}
|
|
bTriedToGetCpuSpeed = TRUE;
|
|
if (!CpuSpeed) {
|
|
PRINTF("Error retrieving CPU speed\n");
|
|
}
|
|
}
|
|
|
|
|
|
TimeIndex = 0;
|
|
|
|
NumEntries = TraceInfo.NumPages*4096/sizeof(VDM_TRACEENTRY);
|
|
TraceBase = (ULONG) TraceInfo.pTraceTable;
|
|
TraceEnd = (ULONG) &TraceInfo.pTraceTable[NumEntries];
|
|
TraceCurrent = (ULONG) &TraceInfo.pTraceTable[TraceInfo.CurrentEntry];
|
|
|
|
|
|
if ((TraceBase & 0xfff) || (TraceEnd & 0xfff) ||
|
|
(TraceCurrent & 0x3f) ||
|
|
(TraceBase > TraceEnd) ||
|
|
(TraceCurrent > TraceEnd) || (TraceCurrent < TraceBase)) {
|
|
PRINTF("TraceBuffer=%.8X, end=%.8X, current=%.8X\n",
|
|
TraceBase, TraceEnd, TraceCurrent);
|
|
PRINTF("Trace buffer info appears corrupt!\n");
|
|
return;
|
|
}
|
|
|
|
if (Verbosity) {
|
|
Lines = 8;
|
|
} else {
|
|
Lines = 32;
|
|
}
|
|
|
|
EntryID = 1;
|
|
|
|
if (GetNextToken()) {
|
|
if (*lpArgumentString == '#') {
|
|
lpArgumentString++;
|
|
EntryID = EvaluateToken();
|
|
|
|
if (EntryID > NumEntries) {
|
|
PRINTF("Requested trace entry out of range - %X\n", EntryID);
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
if (GetNextToken()) {
|
|
|
|
Lines = (int)EXPRESSION(lpArgumentString);
|
|
if (Lines > NumEntries) {
|
|
PRINTF("Requested count too large - %d\n", Lines);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
TraceCurrent = (ULONG) &TraceInfo.pTraceTable[(TraceInfo.CurrentEntry-(EntryID-1))%NumEntries];
|
|
TimerMode = (UCHAR) TraceInfo.Flags & VDMTI_TIMER_MODE;
|
|
|
|
switch(TimerMode) {
|
|
|
|
case VDMTI_TIMER_TICK:
|
|
PRINTF("deltaT is in MSec, Time is in Seconds\n");
|
|
PRINTF("\n# Time DeltaT Event\n");
|
|
break;
|
|
case VDMTI_TIMER_PENTIUM:
|
|
PRINTF("deltaT is at %d MHz, Time is in MSec\n", CpuSpeed);
|
|
PRINTF("\nlog# Time DeltaT Event\n");
|
|
break;
|
|
default:
|
|
PRINTF("\n# Event\n");
|
|
}
|
|
|
|
|
|
while (Lines--) {
|
|
|
|
TraceCurrent -= sizeof(VDM_TRACEENTRY);
|
|
if (TraceCurrent < TraceBase) {
|
|
TraceCurrent = TraceEnd - sizeof(VDM_TRACEENTRY);
|
|
}
|
|
|
|
if (!READMEM((PVOID)TraceCurrent, &TraceEntry, sizeof(VDM_TRACEENTRY))) {
|
|
PRINTF("Error reading memory at %.08X\n", pMem);
|
|
return;
|
|
}
|
|
|
|
if (!TraceEntry.Type) {
|
|
if (!Count) {
|
|
if (EntryID == 1) {
|
|
PRINTF("<Log is empty>\n");
|
|
} else {
|
|
PRINTF("<End of log>\n");
|
|
}
|
|
} else {
|
|
PRINTF("<End of log>\n");
|
|
}
|
|
break;
|
|
}
|
|
|
|
//PRINTF("%.8x ", TraceCurrent);
|
|
|
|
DumpTraceEntry(EntryID++, TraceEntry, Verbosity);
|
|
++Count;
|
|
|
|
if (EntryID >= NumEntries) {
|
|
PRINTF("<End of log>\n");
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
lgr(
|
|
CMD_ARGLIST
|
|
)
|
|
{
|
|
CMD_INIT();
|
|
|
|
DumpTrace(1);
|
|
}
|
|
|
|
VOID
|
|
lg(
|
|
CMD_ARGLIST
|
|
)
|
|
{
|
|
CMD_INIT();
|
|
|
|
DumpTrace(0);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
lgt(
|
|
CMD_ARGLIST
|
|
)
|
|
{
|
|
PVOID pMem;
|
|
VDM_TRACEINFO TraceInfo;
|
|
UCHAR DbgTimerMode;
|
|
BOOL DbgTimerInitialized;
|
|
ULONG NewTimerMode;
|
|
|
|
CMD_INIT();
|
|
|
|
if (!ReadMemExpression("ntvdmd!DbgTimerMode", &DbgTimerMode, sizeof(UCHAR))) {
|
|
return;
|
|
}
|
|
|
|
if (!ReadMemExpression("ntvdmd!DbgTimerInitialized", &DbgTimerInitialized, sizeof(BOOL))) {
|
|
return;
|
|
}
|
|
|
|
if (GetNextToken()) {
|
|
|
|
NewTimerMode = EvaluateToken();
|
|
|
|
switch(NewTimerMode) {
|
|
case 0:
|
|
PRINTF("Event log timer is now OFF\n");
|
|
break;
|
|
|
|
case VDMTI_TIMER_TICK:
|
|
PRINTF("Event log timer resolution set to ~10msec (GetTickCount)\n");
|
|
break;
|
|
|
|
case VDMTI_TIMER_PERFCTR:
|
|
PRINTF("Event log timer resolution set to 100nsec (QueryPerformanceCounter)\n");
|
|
break;
|
|
|
|
case VDMTI_TIMER_PENTIUM:
|
|
PRINTF("Event log timer resolution set to pentium time stamp counter\n");
|
|
break;
|
|
|
|
default:
|
|
PRINTF("Invalid selection - enter 0-3\n");
|
|
return;
|
|
}
|
|
|
|
pMem = (PVOID)(*GetExpression)("ntvdmd!DbgTimerMode");
|
|
if (!pMem) {
|
|
PRINTF("Could not find symbol ntvdmd!DbgTimerMode\n");
|
|
return;
|
|
}
|
|
|
|
if (!WRITEMEM((PVOID)pMem, &NewTimerMode, sizeof(UCHAR))) {
|
|
PRINTF("Error writing memory\n");
|
|
return;
|
|
}
|
|
|
|
pMem = (PVOID)(*GetExpression)("ntvdmd!DbgTimerInitialized");
|
|
|
|
if (!pMem) {
|
|
PRINTF("Could not find symbol ntvdmd!DbgTimerInitialized\n");
|
|
return;
|
|
}
|
|
|
|
DbgTimerInitialized = FALSE;
|
|
if (!WRITEMEM((PVOID)pMem, &DbgTimerInitialized, sizeof(UCHAR))) {
|
|
PRINTF("Error writing memory\n");
|
|
return;
|
|
}
|
|
|
|
} else {
|
|
|
|
|
|
if (!ReadMemExpression("ntvdm!pVdmTraceInfo", &pMem, sizeof(LPVOID))) {
|
|
return;
|
|
}
|
|
|
|
if (!READMEM(pMem, &TraceInfo, sizeof(VDM_TRACEINFO))) {
|
|
PRINTF("Error reading memory for TraceInfo\n");
|
|
return;
|
|
}
|
|
|
|
PRINTF("Timer has%sbeen initialized\n", DbgTimerInitialized ? " " : " not ");
|
|
PRINTF("Requested timer resolution == %d\n", DbgTimerMode);
|
|
PRINTF("Current timer resolution == %d\n", TraceInfo.Flags & VDMTI_TIMER_MODE);
|
|
}
|
|
}
|