452 lines
9 KiB
C
452 lines
9 KiB
C
|
/*++
|
||
|
|
||
|
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 <precomp.h>
|
||
|
#pragma hdrstop
|
||
|
#include <dpmi.h>
|
||
|
#include <dbgsvc.h>
|
||
|
#include <dbginfo.h>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
#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;
|
||
|
}
|
||
|
|
||
|
sscanf(lpArgumentString, "%d", &BPNum);
|
||
|
if (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<MAX_VDM_BREAKPOINTS; BPNum++) {
|
||
|
|
||
|
if (!DoBreakPoints[BPNum] && !DoAll) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (!(VdmBPCache[BPNum].Flags & VDMBP_SET)) {
|
||
|
continue;
|
||
|
}
|
||
|
switch(Cmd) {
|
||
|
|
||
|
case BREAKPOINT_CLEAR:
|
||
|
|
||
|
if (VdmBPCache[BPNum].Flags & VDMBP_ENABLED) {
|
||
|
DisableBreakPoint(&VdmBPCache[BPNum]);
|
||
|
}
|
||
|
VdmBPCache[BPNum].Flags &= ~VDMBP_SET;
|
||
|
break;
|
||
|
|
||
|
case BREAKPOINT_DISABLE:
|
||
|
|
||
|
if (VdmBPCache[BPNum].Flags & VDMBP_ENABLED) {
|
||
|
DisableBreakPoint(&VdmBPCache[BPNum]);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case BREAKPOINT_ENABLE:
|
||
|
|
||
|
if (!(VdmBPCache[BPNum].Flags & VDMBP_ENABLED)) {
|
||
|
EnableBreakPoint(&VdmBPCache[BPNum]);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FlushBreakPointCache();
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
bc(
|
||
|
CMD_ARGLIST
|
||
|
)
|
||
|
{
|
||
|
CMD_INIT();
|
||
|
UpdateBreakPoint(BREAKPOINT_CLEAR);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
bd(
|
||
|
CMD_ARGLIST
|
||
|
)
|
||
|
{
|
||
|
CMD_INIT();
|
||
|
UpdateBreakPoint(BREAKPOINT_DISABLE);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
be(
|
||
|
CMD_ARGLIST
|
||
|
)
|
||
|
{
|
||
|
CMD_INIT();
|
||
|
UpdateBreakPoint(BREAKPOINT_ENABLE);
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
bl(
|
||
|
CMD_ARGLIST
|
||
|
)
|
||
|
{
|
||
|
int BPNum;
|
||
|
int mode;
|
||
|
DWORD dist;
|
||
|
CHAR sym_text[255];
|
||
|
|
||
|
CMD_INIT();
|
||
|
|
||
|
if (!LoadBreakPointCache()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (BPNum = 0; BPNum < MAX_VDM_BREAKPOINTS; BPNum++) {
|
||
|
|
||
|
if (VdmBPCache[BPNum].Flags & VDMBP_SET) {
|
||
|
|
||
|
PRINTF("%d %s%s%s ", BPNum,
|
||
|
(VdmBPCache[BPNum].Flags & VDMBP_ENABLED) ? "e" : "d",
|
||
|
(VdmBPCache[BPNum].Flags & VDMBP_FLUSH) ? "f" : " ",
|
||
|
(VdmBPCache[BPNum].Flags & VDMBP_PENDING) ? "p" : " ");
|
||
|
|
||
|
if (VdmBPCache[BPNum].Flags & VDMBP_V86) {
|
||
|
mode = V86_MODE;
|
||
|
PRINTF("&");
|
||
|
} else {
|
||
|
mode = PROT_MODE;
|
||
|
PRINTF("#");
|
||
|
}
|
||
|
|
||
|
PRINTF("%04X:", VdmBPCache[BPNum].Seg);
|
||
|
|
||
|
if (VdmBPCache[BPNum].Offset > 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
|
||
|
}
|