/*++ Copyright (c) 1991 Microsoft Corporation Module Name: debug.c Abstract: This file contains code to manage software breakpoints Author: Neil Sandlin (neilsa) 1-Nov-1995 Revision History: --*/ #include #pragma hdrstop #include #include #include #include #define BREAKPOINT_CLEAR 1 #define BREAKPOINT_DISABLE 2 #define BREAKPOINT_ENABLE 3 #define VDMBP_ARRAY "ntvdmd!VdmBreakPoints" VDM_BREAKPOINT VdmBPCache[MAX_VDM_BREAKPOINTS] = {0}; // BP zero is reserved for internal use #define TEMP_BP 0 BOOL LoadBreakPointCache( VOID ) { ULONG lpAddress; lpAddress = (*GetExpression)(VDMBP_ARRAY); if (!lpAddress) { PRINTF("Could not find symbol %s\n",VDMBP_ARRAY); return FALSE; } if (!READMEM((PVOID)lpAddress, &VdmBPCache, sizeof(VdmBPCache))) { PRINTF("Error reading BP memory\n"); return FALSE; } return TRUE; } BOOL FlushBreakPointCache( VOID ) { ULONG lpAddress; lpAddress = (*GetExpression)(VDMBP_ARRAY); if (!lpAddress) { PRINTF("Could not find symbol %s\n",VDMBP_ARRAY); return FALSE; } if (!WRITEMEM((PVOID)lpAddress, &VdmBPCache, sizeof(VdmBPCache))) { PRINTF("Error writing BP memory\n"); return FALSE; } return TRUE; } BOOL IsVdmBreakPoint( USHORT selector, ULONG offset, BOOL bProt, PULONG pBpNum, PUCHAR pBpData ) // // Callers of this function must first call LoadBreakPointCache() // { ULONG BPNum; for (BPNum = 0; BPNum < MAX_VDM_BREAKPOINTS; BPNum++) { if ((VdmBPCache[BPNum].Flags & VDMBP_SET) && (VdmBPCache[BPNum].Seg == selector) && (VdmBPCache[BPNum].Offset == offset)) { if ((bProt && ~(VdmBPCache[BPNum].Flags & VDMBP_V86)) || (~bProt && (VdmBPCache[BPNum].Flags & VDMBP_V86))) { *pBpNum = BPNum; *pBpData = VdmBPCache[BPNum].Opcode; return TRUE; } } } return FALSE; } VOID DisableBreakPoint( VDM_BREAKPOINT *pBP ) { int mode; ULONG lpAddress; BYTE byte; if (!(pBP->Flags & VDMBP_ENABLED)) { // already not enabled return; } pBP->Flags &= ~VDMBP_ENABLED; if (pBP->Flags & VDMBP_PENDING) { pBP->Flags &= ~VDMBP_PENDING; return; } if (pBP->Flags & VDMBP_V86) { mode = V86_MODE; } else { mode = PROT_MODE; } lpAddress = GetInfoFromSelector(pBP->Seg, mode, NULL) + GetIntelBase() + pBP->Offset; if (READMEM((PVOID)lpAddress, &byte, 1)) { if (byte == 0xcc) { WRITEMEM((PVOID)lpAddress, &pBP->Opcode, 1); } } pBP->Flags |= VDMBP_FLUSH; pBP->Flags &= ~VDMBP_PENDING; #ifndef i386 if (!InVdmPrompt()) { PRINTF("\n***Warning: command not issued from VDM> prompt.\nOpcode has not been flushed!\n\n"); } #endif } VOID EnableBreakPoint( VDM_BREAKPOINT *pBP ) { int mode; ULONG lpAddress; BYTE byte; if (pBP->Flags & VDMBP_ENABLED) { return; } EnableDebuggerBreakpoints(); if (pBP->Flags & VDMBP_V86) { mode = V86_MODE; } else { mode = PROT_MODE; } lpAddress = GetInfoFromSelector(pBP->Seg, mode, NULL) + GetIntelBase() + pBP->Offset; if (READMEM((PVOID)lpAddress, &byte, 1)) { if (byte != 0xcc) { static BYTE bpOp = 0xcc; WRITEMEM((PVOID)lpAddress, &bpOp, 1); pBP->Opcode = byte; } } else { PRINTF("Error enabling breakpoint at %04X:%08X\n", pBP->Seg, pBP->Offset); return; } pBP->Flags |= (VDMBP_ENABLED | VDMBP_FLUSH); pBP->Flags &= ~VDMBP_PENDING; #ifndef i386 if (!InVdmPrompt()) { PRINTF("\n***Warning: command not issued from VDM> prompt.\nBP has not been flushed!\n\n"); } #endif } VOID UpdateBreakPoint( int Cmd ) { int BPNum; int count = 0; BOOL DoBreakPoints[MAX_VDM_BREAKPOINTS] = {FALSE}; BOOL DoAll = FALSE; if (!LoadBreakPointCache()) { return; } while (GetNextToken()) { if (*lpArgumentString == '*') { DoAll = TRUE; count++; break; } if(sscanf(lpArgumentString, "%d", &BPNum) != 1 || BPNum >= MAX_VDM_BREAKPOINTS) { PRINTF("Invalid breakpoint - %d\n", BPNum); return; } DoBreakPoints[BPNum] = TRUE; count++; SkipToNextWhiteSpace(); } if (!count) { PRINTF("Please specify a breakpoint #\n"); return; } for (BPNum=0; BPNum 0xffff) { PRINTF("%08X", VdmBPCache[BPNum].Offset); } else { PRINTF("%04X", VdmBPCache[BPNum].Offset); } PRINTF(" %04X:***", VdmBPCache[BPNum].Count); if (FindSymbol(VdmBPCache[BPNum].Seg, VdmBPCache[BPNum].Offset, sym_text, &dist, BEFORE, mode )) { if ( dist == 0 ) { PRINTF(" %s", sym_text ); } else { PRINTF(" %s+0x%lx", sym_text, dist ); } } PRINTF("\n"); } } } VOID bp( CMD_ARGLIST ) { #ifdef _X86_ CMD_INIT(); PRINTF("Error- Use native BP command on x86 platforms\n"); #else int BPNum; VDMCONTEXT ThreadContext; WORD selector; ULONG offset; USHORT count = 1; int mode; USHORT flags = 0; CMD_INIT(); if (!LoadBreakPointCache()) { return; } mode = GetContext( &ThreadContext ); if (!GetNextToken()) { PRINTF("Please enter an address\n"); return; } if (!ParseIntelAddress(&mode, &selector, &offset)) { return; } if (mode == V86_MODE) { flags = VDMBP_V86; } // // first see if it's set already // for (BPNum = 0; BPNum < MAX_VDM_BREAKPOINTS; BPNum++) { if (VdmBPCache[BPNum].Flags & VDMBP_SET) { if ((VdmBPCache[BPNum].Seg == selector) && (VdmBPCache[BPNum].Offset == offset) && !(VdmBPCache[BPNum].Flags ^ flags)) { VdmBPCache[BPNum].Count = count; if (!(VdmBPCache[BPNum].Flags & VDMBP_ENABLED)) { EnableBreakPoint(&VdmBPCache[BPNum]); } FlushBreakPointCache(); PRINTF("breakpoint %d redefined\n", BPNum); return; } } } // // Not found, set a new one for (BPNum = 1; BPNum < MAX_VDM_BREAKPOINTS; BPNum++) { if (!(VdmBPCache[BPNum].Flags & (VDMBP_SET | VDMBP_FLUSH))) { VdmBPCache[BPNum].Seg = selector; VdmBPCache[BPNum].Offset = offset; VdmBPCache[BPNum].Count = count; VdmBPCache[BPNum].Flags = VDMBP_SET | flags; EnableBreakPoint(&VdmBPCache[BPNum]); FlushBreakPointCache(); return; } } #endif }