improve x86 hw breakpoint handling
This commit is contained in:
parent
fef13ddb95
commit
ec06475dbf
@ -546,7 +546,12 @@ void BX_CPU_C::prefetch(void)
|
||||
// check only if not fetching page cross instruction
|
||||
// this check is 32-bit wrap safe as well
|
||||
if (EIP == (Bit32u) BX_CPU_THIS_PTR prev_rip) {
|
||||
if (code_breakpoint_match(laddr)) exception(BX_DB_EXCEPTION, 0);
|
||||
Bit32u dr6_bits = code_breakpoint_match(laddr);
|
||||
if (dr6_bits & BX_DEBUG_TRAP_HIT) {
|
||||
BX_ERROR(("#DB: x86 code breakpoint catched"));
|
||||
BX_CPU_THIS_PTR debug_trap |= dr6_bits;
|
||||
exception(BX_DB_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1442,12 +1442,7 @@ Bit32u BX_CPU_C::code_breakpoint_match(bx_address laddr)
|
||||
|
||||
if (BX_CPU_THIS_PTR dr7.get_bp_enabled()) {
|
||||
Bit32u dr6_bits = hwdebug_compare(laddr, 1, BX_HWDebugInstruction, BX_HWDebugInstruction);
|
||||
if (dr6_bits) {
|
||||
// Add to the list of debug events thus far.
|
||||
BX_CPU_THIS_PTR debug_trap |= dr6_bits;
|
||||
BX_ERROR(("#DB: x86 code breakpoint catched"));
|
||||
return dr6_bits;
|
||||
}
|
||||
return dr6_bits;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1466,7 +1461,10 @@ void BX_CPU_C::hwbreakpoint_match(bx_address laddr, unsigned len, unsigned rw)
|
||||
Bit32u dr6_bits = hwdebug_compare(laddr, len, opa, opb);
|
||||
if (dr6_bits) {
|
||||
BX_CPU_THIS_PTR debug_trap |= dr6_bits;
|
||||
BX_CPU_THIS_PTR async_event = 1;
|
||||
if (BX_CPU_THIS_PTR debug_trap & BX_DEBUG_TRAP_HIT) {
|
||||
BX_ERROR(("#DB: Code/Data breakpoint hit - report debug trap on next instruction"));
|
||||
BX_CPU_THIS_PTR async_event = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1482,7 +1480,13 @@ Bit32u BX_CPU_C::hwdebug_compare(bx_address laddr_0, unsigned size,
|
||||
|
||||
bx_address laddr_n = laddr_0 + (size - 1);
|
||||
Bit32u dr_op[4], dr_len[4];
|
||||
bx_bool ibpoint_found_n[4], ibpoint_found = 0;
|
||||
|
||||
// If *any* enabled breakpoints matched, then we need to
|
||||
// set status bits for *all* breakpoints, even disabled ones,
|
||||
// as long as they meet the other breakpoint criteria.
|
||||
// dr6_mask is the return value. These bits represent the bits
|
||||
// to be OR'd into DR6 as a result of the debug event.
|
||||
Bit32u dr6_mask = 0;
|
||||
|
||||
dr_len[0] = BX_CPU_THIS_PTR dr7.get_LEN0();
|
||||
dr_len[1] = BX_CPU_THIS_PTR dr7.get_LEN1();
|
||||
@ -1497,33 +1501,19 @@ Bit32u BX_CPU_C::hwdebug_compare(bx_address laddr_0, unsigned size,
|
||||
for (unsigned n=0;n<4;n++) {
|
||||
bx_address dr_start = BX_CPU_THIS_PTR dr[n] & ~alignment_mask[dr_len[n]];
|
||||
bx_address dr_end = dr_start + alignment_mask[dr_len[n]];
|
||||
ibpoint_found_n[n] = 0;
|
||||
|
||||
// See if this instruction address matches any breakpoints
|
||||
if (dr7 & (3 << n*2)) {
|
||||
if ((dr_op[n]==opa || dr_op[n]==opb) &&
|
||||
(laddr_0 <= dr_end) &&
|
||||
(laddr_n >= dr_start)) {
|
||||
ibpoint_found_n[n] = 1;
|
||||
ibpoint_found = 1;
|
||||
if ((dr_op[n]==opa || dr_op[n]==opb) &&
|
||||
(laddr_0 <= dr_end) &&
|
||||
(laddr_n >= dr_start)) {
|
||||
dr6_mask |= (1<<n);
|
||||
// tell if breakpoint was enabled
|
||||
if (dr7 & (3 << n*2)) {
|
||||
dr6_mask |= BX_DEBUG_TRAP_HIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If *any* enabled breakpoints matched, then we need to
|
||||
// set status bits for *all* breakpoints, even disabled ones,
|
||||
// as long as they meet the other breakpoint criteria.
|
||||
// dr6_mask is the return value. These bits represent the bits
|
||||
// to be OR'd into DR6 as a result of the debug event.
|
||||
Bit32u dr6_mask = 0;
|
||||
|
||||
if (ibpoint_found) {
|
||||
if (ibpoint_found_n[0]) dr6_mask |= 0x1;
|
||||
if (ibpoint_found_n[1]) dr6_mask |= 0x2;
|
||||
if (ibpoint_found_n[2]) dr6_mask |= 0x4;
|
||||
if (ibpoint_found_n[3]) dr6_mask |= 0x8;
|
||||
}
|
||||
|
||||
return dr6_mask;
|
||||
}
|
||||
|
||||
@ -1536,7 +1526,10 @@ void BX_CPU_C::iobreakpoint_match(unsigned port, unsigned len)
|
||||
Bit32u dr6_bits = hwdebug_compare(port, len, BX_HWDebugIO, BX_HWDebugIO);
|
||||
if (dr6_bits) {
|
||||
BX_CPU_THIS_PTR debug_trap |= dr6_bits;
|
||||
BX_CPU_THIS_PTR async_event = 1;
|
||||
if (BX_CPU_THIS_PTR debug_trap & BX_DEBUG_TRAP_HIT) {
|
||||
BX_ERROR(("#DB: I/O breakpoint hit - report debug trap on next instruction"));
|
||||
BX_CPU_THIS_PTR async_event = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -148,6 +148,7 @@ struct bx_dr6_t {
|
||||
IMPLEMENT_CRREG_ACCESSORS(B2, 2);
|
||||
IMPLEMENT_CRREG_ACCESSORS(B3, 3);
|
||||
|
||||
#define BX_DEBUG_TRAP_HIT (1 << 12)
|
||||
#define BX_DEBUG_DR_ACCESS_BIT (1 << 13)
|
||||
#define BX_DEBUG_SINGLE_STEP_BIT (1 << 14)
|
||||
#define BX_DEBUG_TRAP_TASK_SWITCH_BIT (1 << 15)
|
||||
|
@ -180,7 +180,7 @@ bx_bool BX_CPU_C::handleAsyncEvent(void)
|
||||
// ignored and discarded if GIF == 0
|
||||
// debug traps due to EFLAGS.TF remain untouched
|
||||
if (! BX_CPU_THIS_PTR svm_gif)
|
||||
BX_CPU_THIS_PTR debug_trap &= ~BX_DEBUG_SINGLE_STEP_BIT;
|
||||
BX_CPU_THIS_PTR debug_trap &= BX_DEBUG_SINGLE_STEP_BIT;
|
||||
#endif
|
||||
|
||||
// Priority 2: Trap on Task Switch
|
||||
@ -233,12 +233,17 @@ bx_bool BX_CPU_C::handleAsyncEvent(void)
|
||||
// Breakpoints
|
||||
// Debug Trap Exceptions (TF flag set or data/IO breakpoint)
|
||||
if (! interrupts_inhibited(BX_INHIBIT_DEBUG)) {
|
||||
// A trap may be inhibited on this boundary due to an instruction which loaded SS.
|
||||
// A trap may be inhibited on this boundary due to an instruction which loaded SS
|
||||
#if BX_X86_DEBUGGER
|
||||
code_breakpoint_match(get_laddr(BX_SEG_REG_CS, BX_CPU_THIS_PTR prev_rip));
|
||||
// Pages with code breakpoints always have async_event=1 and therefore come here
|
||||
BX_CPU_THIS_PTR debug_trap |= code_breakpoint_match(get_laddr(BX_SEG_REG_CS, BX_CPU_THIS_PTR prev_rip));
|
||||
#endif
|
||||
if (BX_CPU_THIS_PTR debug_trap)
|
||||
if (BX_CPU_THIS_PTR debug_trap & 0xf000) {
|
||||
exception(BX_DB_EXCEPTION, 0); // no error, not interrupt
|
||||
}
|
||||
else {
|
||||
BX_CPU_THIS_PTR debug_trap = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Priority 5: External Interrupts
|
||||
|
@ -900,15 +900,9 @@ void BX_CPU_C::exception(unsigned vector, Bit16u error_code)
|
||||
|
||||
if (vector == BX_DB_EXCEPTION) {
|
||||
// Commit debug events to DR6
|
||||
#if BX_CPU_LEVEL <= 4
|
||||
// On 386/486 bit12 is settable
|
||||
BX_CPU_THIS_PTR dr6.val32 = (BX_CPU_THIS_PTR dr6.val32 & 0xffff0ff0) |
|
||||
(BX_CPU_THIS_PTR debug_trap & 0x0000f00f);
|
||||
#else
|
||||
// On Pentium+, bit12 is always zero
|
||||
BX_CPU_THIS_PTR dr6.val32 = (BX_CPU_THIS_PTR dr6.val32 & 0xffff0ff0) |
|
||||
(BX_CPU_THIS_PTR debug_trap & 0x0000e00f);
|
||||
#endif
|
||||
|
||||
// clear GD flag in the DR7 prior entering debug exception handler
|
||||
BX_CPU_THIS_PTR dr7.set_GD(0);
|
||||
}
|
||||
|
@ -1613,8 +1613,10 @@ Bit32u BX_CPU_C::VMenterLoadCheckGuestState(Bit64u *qualification)
|
||||
BX_CPU_THIS_PTR debug_trap = guest.tmpDR6 & 0x0000400F;
|
||||
else
|
||||
BX_CPU_THIS_PTR debug_trap = guest.tmpDR6 & 0x00004000;
|
||||
if (BX_CPU_THIS_PTR debug_trap)
|
||||
if (BX_CPU_THIS_PTR debug_trap) {
|
||||
BX_CPU_THIS_PTR debug_trap |= BX_DEBUG_TRAP_HIT;
|
||||
BX_CPU_THIS_PTR async_event = 1;
|
||||
}
|
||||
|
||||
if (guest.interruptibility_state & BX_VMX_INTERRUPTS_BLOCKED_BY_STI)
|
||||
inhibit_interrupts(BX_INHIBIT_INTERRUPTS);
|
||||
@ -1855,9 +1857,9 @@ void BX_CPU_C::VMexitSaveGuestState(void)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Bit32u tmpDR6 = BX_CPU_THIS_PTR debug_trap;
|
||||
Bit32u tmpDR6 = BX_CPU_THIS_PTR debug_trap & 0x0000400f;
|
||||
if (tmpDR6 & 0xf) tmpDR6 |= (1 << 12);
|
||||
VMwrite_natural(VMCS_GUEST_PENDING_DBG_EXCEPTIONS, tmpDR6 & 0x0000500f);
|
||||
VMwrite_natural(VMCS_GUEST_PENDING_DBG_EXCEPTIONS, tmpDR6);
|
||||
|
||||
Bit32u interruptibility_state = 0;
|
||||
if (interrupts_inhibited(BX_INHIBIT_INTERRUPTS)) {
|
||||
|
Loading…
Reference in New Issue
Block a user