Implement hardware breakpoints and watchpoints

svn path=/trunk/; revision=19380
This commit is contained in:
Gé van Geldorp 2005-11-20 17:51:09 +00:00
parent 9721d43340
commit 118663036e

View file

@ -320,12 +320,29 @@ GspPutPacketNoWait(PCHAR Buffer)
static volatile BOOLEAN GspMemoryError = FALSE; static volatile BOOLEAN GspMemoryError = FALSE;
static volatile void *GspAccessLocation = NULL; static volatile void *GspAccessLocation = NULL;
static CHAR
GspReadMemSafe(PCHAR Address)
{
CHAR ch;
if (NULL == Address)
{
GspMemoryError = TRUE;
return '\0';
}
GspAccessLocation = Address;
ch = *Address;
GspAccessLocation = NULL;
return ch;
}
/* Convert the memory pointed to by Address into hex, placing result in Buffer */ /* Convert the memory pointed to by Address into hex, placing result in Buffer */
/* Return a pointer to the last char put in Buffer (null) */ /* Return a pointer to the last char put in Buffer (null) */
/* If MayFault is TRUE, then we should set GspMemoryError in response to /* If MayFault is TRUE, then we should set GspMemoryError in response to
a fault; if FALSE treat a fault like any other fault in the stub. */ a fault; if FALSE treat a fault like any other fault in the stub. */
PCHAR static PCHAR
GspMem2Hex(PCHAR Address, GspMem2Hex(PCHAR Address,
PCHAR Buffer, PCHAR Buffer,
LONG Count, LONG Count,
@ -334,91 +351,126 @@ GspMem2Hex(PCHAR Address,
ULONG i; ULONG i;
CHAR ch; CHAR ch;
if (NULL == Address && MayFault)
{
GspMemoryError = TRUE;
return Buffer;
}
for (i = 0; i < (ULONG) Count; i++) for (i = 0; i < (ULONG) Count; i++)
{ {
if (MayFault) if (MayFault)
{ {
GspAccessLocation = Address; ch = GspReadMemSafe(Address);
}
ch = *Address;
GspAccessLocation = NULL;
if (MayFault && GspMemoryError)
{
return Buffer;
}
*Buffer++ = HexChars[(ch >> 4) & 0xf];
*Buffer++ = HexChars[ch & 0xf];
Address++;
}
*Buffer = 0;
return Buffer;
}
/* Convert the hex array pointed to by Buffer into binary to be placed at Address */
/* Return a pointer to the character AFTER the last byte read from Buffer */
PCHAR
GspHex2Mem(PCHAR Buffer,
PCHAR Address,
ULONG Count,
BOOLEAN MayFault)
{
PCHAR current;
PCHAR page;
ULONG countinpage;
ULONG i;
CHAR ch;
ULONG oldprot = 0;
current = Address;
while ( current < Address + Count )
{
page = (PCHAR)PAGE_ROUND_DOWN(current);
if (Address + Count <= page + PAGE_SIZE)
{
/* Fits in this page */
countinpage = Count;
}
else
{
/* Flows into next page, handle only current page in this iteration */
countinpage = PAGE_SIZE - (Address - page);
}
if (MayFault)
{
oldprot = MmGetPageProtect(NULL, Address);
MmSetPageProtect(NULL, Address, PAGE_EXECUTE_READWRITE);
}
for (i = 0; i < countinpage && ! GspMemoryError; i++)
{
ch = (CHAR)(HexValue(*Buffer++) << 4);
ch = (CHAR)(ch + HexValue(*Buffer++));
GspAccessLocation = current;
*current = ch;
GspAccessLocation = NULL;
current++;
}
if (MayFault)
{
MmSetPageProtect(NULL, page, oldprot);
if (GspMemoryError) if (GspMemoryError)
{ {
return Buffer; return Buffer;
} }
} }
else
{
ch = *Address;
}
*Buffer++ = HexChars[(ch >> 4) & 0xf];
*Buffer++ = HexChars[ch & 0xf];
Address++;
} }
*Buffer = 0;
return Buffer; return Buffer;
} }
static ULONG
GspWriteMem(PCHAR Address,
ULONG Count,
BOOLEAN MayFault,
CHAR (*GetContent)(PVOID Context, ULONG Offset),
PVOID Context)
{
PCHAR Current;
PCHAR Page;
ULONG CountInPage;
ULONG i;
CHAR ch;
ULONG OldProt = 0;
Current = Address;
while (Current < Address + Count)
{
Page = (PCHAR)PAGE_ROUND_DOWN(Current);
if (Address + Count <= Page + PAGE_SIZE)
{
/* Fits in this page */
CountInPage = Count;
}
else
{
/* Flows into next page, handle only current page in this iteration */
CountInPage = PAGE_SIZE - (Address - Page);
}
if (MayFault)
{
OldProt = MmGetPageProtect(NULL, Address);
MmSetPageProtect(NULL, Address, PAGE_EXECUTE_READWRITE);
}
for (i = 0; i < CountInPage && ! GspMemoryError; i++)
{
ch = (*GetContent)(Context, Current - Address);
if (MayFault)
{
GspAccessLocation = Current;
}
*Current = ch;
if (MayFault)
{
GspAccessLocation = NULL;
}
Current++;
}
if (MayFault)
{
MmSetPageProtect(NULL, Page, OldProt);
if (GspMemoryError)
{
return Current - Address;
}
}
}
return Current - Address;
}
static CHAR
GspHex2MemGetContent(PVOID Context, ULONG Offset)
{
return (CHAR)((HexValue(*((PCHAR) Context + 2 * Offset)) << 4) +
HexValue(*((PCHAR) Context + 2 * Offset + 1)));
}
/* Convert the hex array pointed to by Buffer into binary to be placed at Address */
/* Return a pointer to the character AFTER the last byte read from Buffer */
static PCHAR
GspHex2Mem(PCHAR Buffer,
PCHAR Address,
ULONG Count,
BOOLEAN MayFault)
{
Count = GspWriteMem(Address, Count, MayFault, GspHex2MemGetContent, Buffer);
return Buffer + 2 * Count;
}
static CHAR
GspWriteMemSafeGetContent(PVOID Context, ULONG Offset)
{
ASSERT(0 == Offset);
return *((PCHAR) Context);
}
static void
GspWriteMemSafe(PCHAR Address,
CHAR Ch)
{
GspWriteMem(Address, 1, TRUE, GspWriteMemSafeGetContent, &Ch);
}
/* This function takes the 386 exception vector and attempts to /* This function takes the 386 exception vector and attempts to
translate this number into a unix compatible signal value */ translate this number into a unix compatible signal value */
@ -922,186 +974,329 @@ GspQueryThreadStatus(PCHAR Request)
} }
} }
#define DR7_L0 0x00000001 /* Local breakpoint 0 enable */
#define DR7_G0 0x00000002 /* Global breakpoint 0 enable */
#define DR7_L1 0x00000004 /* Local breakpoint 1 enable */
#define DR7_G1 0x00000008 /* Global breakpoint 1 enable */
#define DR7_L2 0x00000010 /* Local breakpoint 2 enable */
#define DR7_G2 0x00000020 /* Global breakpoint 2 enable */
#define DR7_L3 0x00000040 /* Local breakpoint 3 enable */
#define DR7_G3 0x00000080 /* Global breakpoint 3 enable */
#define DR7_LE 0x00000100 /* Local exact breakpoint enable (old) */
#define DR7_GE 0x00000200 /* Global exact breakpoint enable (old) */
#define DR7_GD 0x00002000 /* General detect enable */
#define DR7_TYPE0_MASK 0x00030000 /* Breakpoint 0 condition */
#define DR7_LEN0_MASK 0x000c0000 /* Breakpoint 0 length */
#define DR7_TYPE1_MASK 0x00300000 /* Breakpoint 1 condition */
#define DR7_LEN1_MASK 0x00c00000 /* Breakpoint 1 length */
#define DR7_TYPE2_MASK 0x03000000 /* Breakpoint 2 condition */
#define DR7_LEN2_MASK 0x0c000000 /* Breakpoint 2 length */
#define DR7_TYPE3_MASK 0x30000000 /* Breakpoint 3 condition */
#define DR7_LEN3_MASK 0xc0000000 /* Breakpoint 3 length */
#define DR7_GLOBAL_ENABLE(Bp) (2 << (2 * (Bp)))
#define DR7_TYPE(Bp, Type) ((Type) << (16 + 4 * (Bp)))
#define DR7_LEN(Bp, Len) ((Len) << (18 + 4 * (Bp)))
typedef struct _GsHwBreakPoint #define I386_BP_TYPE_EXECUTE 0
#define I386_BP_TYPE_DATA_WRITE 1
#define I386_BP_TYPE_DATA_READWRITE 3
#define I386_OPCODE_INT3 0xcc
#define GDB_ZTYPE_MEMORY_BREAKPOINT 0
#define GDB_ZTYPE_HARDWARE_BREAKPOINT 1
#define GDB_ZTYPE_WRITE_WATCHPOINT 2
#define GDB_ZTYPE_READ_WATCHPOINT 3
#define GDB_ZTYPE_ACCESS_WATCHPOINT 4
typedef struct _GSPHWBREAKPOINT
{ {
BOOLEAN Enabled;
ULONG Type; ULONG Type;
ULONG_PTR Address;
ULONG Length; ULONG Length;
ULONG Address; } GSPHWBREAKPOINT;
} GsHwBreakPoint;
#if defined(__GNUC__) #define MAX_HW_BREAKPOINTS 4
GsHwBreakPoint GspBreakpoints[4] = static unsigned GspHwBreakpointCount = 0;
{ static GSPHWBREAKPOINT GspHwBreakpoints[MAX_HW_BREAKPOINTS];
{ Enabled : FALSE },
{ Enabled : FALSE },
{ Enabled : FALSE },
{ Enabled : FALSE }
};
#else
GsHwBreakPoint GspBreakpoints[4] =
{
{ FALSE },
{ FALSE },
{ FALSE },
{ FALSE }
};
#endif
VOID typedef struct _GSPSWBREAKPOINT
GspCorrectHwBreakpoint()
{ {
ULONG BreakpointNumber; ULONG_PTR Address;
BOOLEAN CorrectIt; CHAR PrevContent;
BOOLEAN Bit; BOOLEAN Active;
ULONG dr7_; } GSPSWBREAKPOINT;
#if defined(__GNUC__) #define MAX_SW_BREAKPOINTS 64
asm volatile ( static unsigned GspSwBreakpointCount = 0;
"movl %%db7, %0\n" : "=r" (dr7_) : ); static GSPSWBREAKPOINT GspSwBreakpoints[MAX_SW_BREAKPOINTS];
do
static void
GspSetHwBreakpoint(ULONG Type, ULONG_PTR Address, ULONG Length)
{
DPRINT("GspSetHwBreakpoint(%lu, 0x%p, %lu)\n", Type, Address, Length);
if (GDB_ZTYPE_READ_WATCHPOINT == Type)
{ {
ULONG addr0, addr1, addr2, addr3; DPRINT1("Read watchpoint not supported\n");
strcpy(GspOutBuffer, "E22");
asm volatile (
"movl %%db0, %0\n"
"movl %%db1, %1\n"
"movl %%db2, %2\n"
"movl %%db3, %3\n"
: "=r" (addr0), "=r" (addr1),
"=r" (addr2), "=r" (addr3) : );
} while (FALSE);
#elif defined(_MSC_VER)
__asm
{
mov eax, dr7; mov dr7_, eax;
mov eax, dr0; mov addr0, eax;
mov eax, dr1; mov addr1, eax;
mov eax, dr2; mov addr2, eax;
mov eax, dr3; mov addr3, eax;
} }
#else else if (GDB_ZTYPE_HARDWARE_BREAKPOINT == Type && 1 != Length)
#error Unknown compiler for inline assembler
#endif
CorrectIt = FALSE;
for (BreakpointNumber = 0; BreakpointNumber < 3; BreakpointNumber++)
{ {
Bit = 2 << (BreakpointNumber << 1); DPRINT1("Invalid length %lu for hardware breakpoint\n", Length);
if (!(dr7_ & Bit) && GspBreakpoints[BreakpointNumber].Enabled) strcpy(GspOutBuffer, "E22");
}
else if (1 != Length && 2 != Length && 4 != Length)
{
DPRINT1("Invalid length %lu for GDB Z type %lu\n", Length, Type);
strcpy(GspOutBuffer, "E22");
}
else if (0 != (Address & (Length - 1)))
{
DPRINT1("Invalid alignment for address 0x%p and length %d\n",
Address, Length);
strcpy(GspOutBuffer, "E22");
}
else if (MAX_HW_BREAKPOINTS == GspHwBreakpointCount)
{
DPRINT1("Trying to set too many hardware breakpoints\n");
strcpy(GspOutBuffer, "E22");
}
else
{
DPRINT("Stored at index %u\n", GspHwBreakpointCount);
GspHwBreakpoints[GspHwBreakpointCount].Type = Type;
GspHwBreakpoints[GspHwBreakpointCount].Address = Address;
GspHwBreakpoints[GspHwBreakpointCount].Length = Length;
GspHwBreakpointCount++;
strcpy(GspOutBuffer, "OK");
}
}
static void
GspRemoveHwBreakpoint(ULONG Type, ULONG_PTR Address, ULONG Length)
{
unsigned Index;
DPRINT("GspRemoveHwBreakpoint(%lu, 0x%p, %lu)\n", Type, Address, Length);
for (Index = 0; Index < GspHwBreakpointCount; Index++)
{
if (GspHwBreakpoints[Index].Type == Type &&
GspHwBreakpoints[Index].Address == Address &&
GspHwBreakpoints[Index].Length == Length)
{ {
CorrectIt = TRUE; DPRINT("Found match at index %u\n", Index);
dr7_ |= Bit; if (Index + 1 < GspHwBreakpointCount)
dr7_ &= ~(0xf0000 << (BreakpointNumber << 2));
dr7_ |= (((GspBreakpoints[BreakpointNumber].Length << 2) |
GspBreakpoints[BreakpointNumber].Type) << 16) << (BreakpointNumber << 2);
switch (BreakpointNumber)
{ {
#if defined(__GNUC__) memmove(GspHwBreakpoints + Index,
case 0: GspHwBreakpoints + (Index + 1),
asm volatile ("movl %0, %%dr0\n" (GspHwBreakpointCount - Index - 1) *
: : "r" (GspBreakpoints[BreakpointNumber].Address) ); sizeof(GSPHWBREAKPOINT));
break; }
GspHwBreakpointCount--;
strcpy(GspOutBuffer, "OK");
return;
}
}
case 1: DPRINT1("Not found\n");
asm volatile ("movl %0, %%dr1\n" strcpy(GspOutBuffer, "E22");
: : "r" (GspBreakpoints[BreakpointNumber].Address) ); }
break;
case 2: static void
asm volatile ("movl %0, %%dr2\n" GspSetSwBreakpoint(ULONG_PTR Address)
: : "r" (GspBreakpoints[BreakpointNumber].Address) ); {
break; DPRINT("GspSetSwBreakpoint(0x%p)\n", Address);
case 3: if (MAX_SW_BREAKPOINTS == GspSwBreakpointCount)
asm volatile ("movl %0, %%dr3\n" {
: : "r" (GspBreakpoints[BreakpointNumber].Address) ); DPRINT1("Trying to set too many software breakpoints\n");
break; strcpy(GspOutBuffer, "E22");
#elif defined(_MSC_VER) }
case 0: else
{ {
ULONG addr = GspBreakpoints[BreakpointNumber].Address; DPRINT("Stored at index %u\n", GspSwBreakpointCount);
__asm mov eax, addr; GspSwBreakpoints[GspSwBreakpointCount].Address = Address;
__asm mov dr0, eax; GspSwBreakpoints[GspSwBreakpointCount].Active = FALSE;
} GspSwBreakpointCount++;
break; strcpy(GspOutBuffer, "OK");
case 1: }
{ }
ULONG addr = GspBreakpoints[BreakpointNumber].Address;
__asm mov eax, addr; static void
__asm mov dr1, eax; GspRemoveSwBreakpoint(ULONG_PTR Address)
} {
break; unsigned Index;
case 2:
{ DPRINT("GspRemoveSwBreakpoint(0x%p)\n", Address);
ULONG addr = GspBreakpoints[BreakpointNumber].Address; for (Index = 0; Index < GspSwBreakpointCount; Index++)
__asm mov eax, addr; {
__asm mov dr2, eax; if (GspSwBreakpoints[Index].Address == Address)
} {
break; DPRINT("Found match at index %u\n", Index);
case 3: ASSERT(! GspSwBreakpoints[Index].Active);
{ if (Index + 1 < GspSwBreakpointCount)
ULONG addr = GspBreakpoints[BreakpointNumber].Address; {
__asm mov eax, addr; memmove(GspSwBreakpoints + Index,
__asm mov dr3, eax; GspSwBreakpoints + (Index + 1),
} (GspSwBreakpointCount - Index - 1) *
break; sizeof(GSPSWBREAKPOINT));
#else }
#error Unknown compiler for inline assembler GspSwBreakpointCount--;
#endif strcpy(GspOutBuffer, "OK");
return;
}
}
DPRINT1("Not found\n");
strcpy(GspOutBuffer, "E22");
}
static void
GspLoadHwBreakpoint(PKTRAP_FRAME TrapFrame,
unsigned BpIndex,
ULONG_PTR Address,
ULONG Length,
ULONG Type)
{
DPRINT("GspLoadHwBreakpoint(0x%p, %d, 0x%p, %d)\n", TrapFrame, BpIndex,
Address, Type);
/* Set the DR7_Gx bit to globally enable the breakpoint */
TrapFrame->Dr7 |= DR7_GLOBAL_ENABLE(BpIndex) |
DR7_LEN(BpIndex, Length) |
DR7_TYPE(BpIndex, Type);
switch (BpIndex)
{
case 0:
DPRINT("Setting DR0 to 0x%p\n", Address);
TrapFrame->Dr0 = Address;
break;
case 1:
DPRINT("Setting DR1 to 0x%p\n", Address);
TrapFrame->Dr1 = Address;
break;
case 2:
DPRINT("Setting DR2 to 0x%p\n", Address);
TrapFrame->Dr2 = Address;
break;
case 3:
DPRINT("Setting DR3 to 0x%p\n", Address);
TrapFrame->Dr3 = Address;
break;
}
}
static void
GspLoadBreakpoints(PKTRAP_FRAME TrapFrame)
{
unsigned Index;
ULONG i386Type;
DPRINT("GspLoadBreakpoints\n");
DPRINT("DR7 on entry: 0x%08x\n", TrapFrame->Dr7);
/* Remove all breakpoints */
TrapFrame->Dr7 &= ~(DR7_L0 | DR7_L1 | DR7_L2 | DR7_L3 |
DR7_G0 | DR7_G1 | DR7_G2 | DR7_G3 |
DR7_TYPE0_MASK | DR7_LEN0_MASK |
DR7_TYPE1_MASK | DR7_LEN1_MASK |
DR7_TYPE2_MASK | DR7_LEN2_MASK |
DR7_TYPE3_MASK | DR7_LEN3_MASK);
for (Index = 0; Index < GspHwBreakpointCount; Index++)
{
switch(GspHwBreakpoints[Index].Type)
{
case GDB_ZTYPE_HARDWARE_BREAKPOINT:
i386Type = I386_BP_TYPE_EXECUTE;
break;
case GDB_ZTYPE_WRITE_WATCHPOINT:
i386Type = I386_BP_TYPE_DATA_WRITE;
break;
case GDB_ZTYPE_ACCESS_WATCHPOINT:
i386Type = I386_BP_TYPE_DATA_READWRITE;
break;
default:
ASSERT(FALSE);
i386Type = I386_BP_TYPE_EXECUTE;
break;
}
GspLoadHwBreakpoint(TrapFrame, Index, GspHwBreakpoints[Index].Address,
GspHwBreakpoints[Index].Length - 1, i386Type);
}
for (Index = 0; Index < GspSwBreakpointCount; Index++)
{
if (GspHwBreakpointCount + Index < MAX_HW_BREAKPOINTS)
{
DPRINT("Implementing software interrupt using hardware register\n");
GspLoadHwBreakpoint(TrapFrame, GspHwBreakpointCount + Index,
GspSwBreakpoints[Index].Address, 0,
I386_BP_TYPE_EXECUTE);
GspSwBreakpoints[Index].Active = FALSE;
}
else
{
DPRINT("Using real software breakpoint\n");
GspMemoryError = FALSE;
GspSwBreakpoints[Index].PrevContent = GspReadMemSafe((PCHAR) GspSwBreakpoints[Index].Address);
if (! GspMemoryError)
{
GspWriteMemSafe((PCHAR) GspSwBreakpoints[Index].Address, I386_OPCODE_INT3);
}
GspSwBreakpoints[Index].Active = ! GspMemoryError;
if (GspMemoryError)
{
DPRINT1("Failed to set software breakpoint at 0x%p\n",
GspSwBreakpoints[Index].Address);
}
else
{
DPRINT("Successfully set software breakpoint at 0x%p\n",
GspSwBreakpoints[Index].Address);
DPRINT1("Successfully set software breakpoint at 0x%p\n", GspSwBreakpoints[Index].Address);
} }
} }
else if ((dr7_ & Bit) && !GspBreakpoints[BreakpointNumber].Enabled) }
DPRINT("Final DR7 value 0x%08x\n", TrapFrame->Dr7);
}
static void
GspUnloadBreakpoints(PKTRAP_FRAME TrapFrame)
{
unsigned Index;
DPRINT("GspUnloadHwBreakpoints\n");
for (Index = 0; Index < GspSwBreakpointCount; Index++)
{
if (GspSwBreakpoints[Index].Active)
{ {
CorrectIt = TRUE; GspMemoryError = FALSE;
dr7_ &= ~Bit; GspWriteMemSafe((PCHAR) GspSwBreakpoints[Index].Address,
dr7_ &= ~(0xf0000 << (BreakpointNumber << 2)); GspSwBreakpoints[Index].PrevContent);
GspSwBreakpoints[Index].Active = FALSE;
if (GspMemoryError)
{
DPRINT1("Failed to remove software breakpoint from 0x%p\n",
GspSwBreakpoints[Index].Address);
}
else
{
DPRINT("Successfully removed software breakpoint from 0x%p\n",
GspSwBreakpoints[Index].Address);
}
} }
} }
if (CorrectIt)
{
#if defined(__GNUC__)
asm volatile ( "movl %0, %%db7\n" : : "r" (dr7_));
#elif defined(_MSC_VER)
__asm mov eax, dr7_;
__asm mov dr7, eax;
#else
#error Unknown compiler for inline assembler
#endif
}
} }
ULONG static BOOLEAN gdb_attached_yet = FALSE;
GspRemoveHwBreakpoint(ULONG BreakpointNumber)
{
if (!GspBreakpoints[BreakpointNumber].Enabled)
{
return -1;
}
GspBreakpoints[BreakpointNumber].Enabled = 0;
return 0;
}
ULONG
GspSetHwBreakpoint(ULONG BreakpointNumber,
ULONG Type,
ULONG Length,
ULONG Address)
{
if (GspBreakpoints[BreakpointNumber].Enabled)
{
return -1;
}
GspBreakpoints[BreakpointNumber].Enabled = TRUE;
GspBreakpoints[BreakpointNumber].Type = Type;
GspBreakpoints[BreakpointNumber].Length = Length;
GspBreakpoints[BreakpointNumber].Address = Address;
return 0;
}
static BOOL gdb_attached_yet = FALSE;
/* /*
* This function does all command procesing for interfacing to gdb. * This function does all command procesing for interfacing to gdb.
*/ */
@ -1119,14 +1314,6 @@ KdpGdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
PCHAR ptr; PCHAR ptr;
/* FIXME: Stop on other CPUs too */ /* FIXME: Stop on other CPUs too */
/* Disable hardware debugging while we are inside the stub */
#if defined(__GNUC__)
__asm__("movl %0,%%db7" : /* no output */ : "r" (0));
#elif defined(_MSC_VER)
__asm mov eax, 0 __asm mov dr7, eax
#else
#error Unknown compiler for inline assembler
#endif
if (STATUS_ACCESS_VIOLATION == (NTSTATUS) ExceptionRecord->ExceptionCode && if (STATUS_ACCESS_VIOLATION == (NTSTATUS) ExceptionRecord->ExceptionCode &&
NULL != GspAccessLocation && NULL != GspAccessLocation &&
@ -1139,8 +1326,21 @@ KdpGdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
} }
else else
{ {
DPRINT("Thread %p entering stub\n", PsGetCurrentThread());
/* Can only debug 1 thread at a time... */ /* Can only debug 1 thread at a time... */
ExAcquireFastMutex(&GspLock); ExAcquireFastMutex(&GspLock);
DPRINT("Thread %p acquired mutex\n", PsGetCurrentThread());
/* Disable hardware debugging while we are inside the stub */
#if defined(__GNUC__)
__asm__("movl %0,%%db7" : /* no output */ : "r" (0));
#elif defined(_MSC_VER)
__asm mov eax, 0 __asm mov dr7, eax
#else
#error Unknown compiler for inline assembler
#endif
GspUnloadBreakpoints(TrapFrame);
/* Make sure we're debugging the current thread. */ /* Make sure we're debugging the current thread. */
if (NULL != GspDbgThread) if (NULL != GspDbgThread)
@ -1371,7 +1571,7 @@ KdpGdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
{ {
if (dr6_ & (1 << BreakpointNumber)) if (dr6_ & (1 << BreakpointNumber))
{ {
if (GspBreakpoints[BreakpointNumber].Type == 0) if (GspHwBreakpoints[BreakpointNumber].Type == 0)
{ {
/* Set restore flag */ /* Set restore flag */
Context->EFlags |= 0x10000; Context->EFlags |= 0x10000;
@ -1380,7 +1580,7 @@ KdpGdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
} }
} }
} }
GspCorrectHwBreakpoint(); GspLoadBreakpoints(TrapFrame);
#if defined(__GNUC__) #if defined(__GNUC__)
asm volatile ("movl %0, %%db6\n" : : "r" (0)); asm volatile ("movl %0, %%db6\n" : : "r" (0));
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
@ -1395,7 +1595,9 @@ KdpGdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
GspDbgThread = NULL; GspDbgThread = NULL;
} }
DPRINT("Thread %p releasing mutex\n", PsGetCurrentThread());
ExReleaseFastMutex(&GspLock); ExReleaseFastMutex(&GspLock);
DPRINT("Thread %p leaving stub\n", PsGetCurrentThread());
return kdContinue; return kdContinue;
break; break;
} }
@ -1417,46 +1619,46 @@ KdpGdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
GspQueryThreadStatus(ptr); GspQueryThreadStatus(ptr);
break; break;
case 'Y': case 'Z':
{ {
LONG Number;
LONG Length;
LONG Type; LONG Type;
LONG Address; LONG Address;
LONG Length;
ptr = &GspOutBuffer[1];
GspHex2Long(&ptr, &Number);
ptr++;
GspHex2Long(&ptr, &Type); GspHex2Long(&ptr, &Type);
ptr++; ptr++;
GspHex2Long(&ptr, &Length);
ptr++;
GspHex2Long(&ptr, &Address); GspHex2Long(&ptr, &Address);
if (GspSetHwBreakpoint(Number & 0x3, Type & 0x3 , Length & 0x3, Address) == 0) ptr++;
GspHex2Long(&ptr, &Length);
if (0 == Type)
{ {
strcpy(GspOutBuffer, "OK"); GspSetSwBreakpoint((ULONG_PTR) Address);
} }
else else
{ {
strcpy(GspOutBuffer, "E"); GspSetHwBreakpoint(Type, (ULONG_PTR) Address, Length);
} }
break; break;
} }
/* Remove hardware breakpoint */ case 'z':
case 'y':
{ {
LONG Number; LONG Type;
LONG Address;
LONG Length;
ptr = &GspOutBuffer[1]; GspHex2Long(&ptr, &Type);
GspHex2Long(&ptr, &Number); ptr++;
if (GspRemoveHwBreakpoint(Number & 0x3) == 0) GspHex2Long(&ptr, &Address);
ptr++;
GspHex2Long(&ptr, &Length);
if (0 == Type)
{ {
strcpy(GspOutBuffer, "OK"); GspRemoveSwBreakpoint((ULONG_PTR) Address);
} }
else else
{ {
strcpy(GspOutBuffer, "E"); GspRemoveHwBreakpoint(Type, (ULONG_PTR) Address, Length);
} }
break; break;
} }
@ -1466,7 +1668,7 @@ KdpGdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
} }
/* reply to the request */ /* reply to the request */
GspPutPacket(&GspOutBuffer[0]); GspPutPacket(GspOutBuffer);
} }
/* not reached */ /* not reached */