* Fixed checking for DR6 bits after a debug exception (we were and'ing
with the bit number, not the respective mask). * Added a small hack to allow single stepping to work in qemu. Apparently the BS bit in DR6 is not set when the debug exception is handled. So we always assume that a single step event occurred, when we couldn't recognize any other event, if the hack is enabled. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@11998 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -5,6 +5,8 @@
|
|||||||
#ifndef _KERNEL_ARCH_X86_USER_DEBUGGER_H
|
#ifndef _KERNEL_ARCH_X86_USER_DEBUGGER_H
|
||||||
#define _KERNEL_ARCH_X86_USER_DEBUGGER_H
|
#define _KERNEL_ARCH_X86_USER_DEBUGGER_H
|
||||||
|
|
||||||
|
#define ARCH_INIT_USER_DEBUG i386_init_user_debug
|
||||||
|
|
||||||
// number of breakpoints the CPU supports
|
// number of breakpoints the CPU supports
|
||||||
// Actually it supports 4, but DR3 is used to hold the struct thread*.
|
// Actually it supports 4, but DR3 is used to hold the struct thread*.
|
||||||
enum {
|
enum {
|
||||||
@@ -127,6 +129,8 @@ extern void i386_reinit_user_debug_after_context_switch(struct thread *thread);
|
|||||||
extern int i386_handle_debug_exception(struct iframe *frame);
|
extern int i386_handle_debug_exception(struct iframe *frame);
|
||||||
extern int i386_handle_breakpoint_exception(struct iframe *frame);
|
extern int i386_handle_breakpoint_exception(struct iframe *frame);
|
||||||
|
|
||||||
|
extern void i386_init_user_debug();
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -6,10 +6,18 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <debugger.h>
|
#include <debugger.h>
|
||||||
|
#include <driver_settings.h>
|
||||||
#include <int.h>
|
#include <int.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
#include <arch/user_debugger.h>
|
#include <arch/user_debugger.h>
|
||||||
|
|
||||||
|
//#define TRACE_ARCH_USER_DEBUGGER
|
||||||
|
#ifdef TRACE_ARCH_USER_DEBUGGER
|
||||||
|
# define TRACE(x) dprintf x
|
||||||
|
#else
|
||||||
|
# define TRACE(x) ;
|
||||||
|
#endif
|
||||||
|
|
||||||
#define B_NO_MORE_BREAKPOINTS B_ERROR
|
#define B_NO_MORE_BREAKPOINTS B_ERROR
|
||||||
#define B_NO_MORE_WATCHPOINTS B_ERROR
|
#define B_NO_MORE_WATCHPOINTS B_ERROR
|
||||||
#define B_BAD_WATCHPOINT_ALIGNMENT B_ERROR
|
#define B_BAD_WATCHPOINT_ALIGNMENT B_ERROR
|
||||||
@@ -39,6 +47,10 @@ static const uint32 sDR6B[4] = {
|
|||||||
X86_DR6_B0, X86_DR6_B1, X86_DR6_B2, X86_DR6_B3
|
X86_DR6_B0, X86_DR6_B1, X86_DR6_B2, X86_DR6_B3
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Enables a hack to make single stepping work under qemu. Set via kernel
|
||||||
|
// driver settings.
|
||||||
|
static bool sQEmuSingleStepHack = false;
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
arch_clear_team_debug_info(struct arch_team_debug_info *info)
|
arch_clear_team_debug_info(struct arch_team_debug_info *info)
|
||||||
@@ -344,6 +356,9 @@ i386_init_user_debug_at_kernel_exit(struct iframe *frame)
|
|||||||
frame->flags |= (1 << X86_EFLAGS_TF);
|
frame->flags |= (1 << X86_EFLAGS_TF);
|
||||||
else
|
else
|
||||||
frame->flags &= ~(1 << X86_EFLAGS_TF);
|
frame->flags &= ~(1 << X86_EFLAGS_TF);
|
||||||
|
// ToDo: Move into a function called from thread_hit_debug_event().
|
||||||
|
// No need to have that here in the code executed for ever kernel->user
|
||||||
|
// mode switch.
|
||||||
|
|
||||||
RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
|
RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
|
||||||
RELEASE_THREAD_LOCK();
|
RELEASE_THREAD_LOCK();
|
||||||
@@ -398,6 +413,8 @@ i386_handle_debug_exception(struct iframe *frame)
|
|||||||
asm("movl %%dr6, %0" : "=r"(dr6));
|
asm("movl %%dr6, %0" : "=r"(dr6));
|
||||||
asm("movl %%dr7, %0" : "=r"(dr7));
|
asm("movl %%dr7, %0" : "=r"(dr7));
|
||||||
|
|
||||||
|
TRACE(("i386_handle_debug_exception(): DR6: %lx, DR7: %lx\n", dr6, dr7));
|
||||||
|
|
||||||
// check, which exception condition applies
|
// check, which exception condition applies
|
||||||
if (dr6 & X86_DR6_BREAKPOINT_MASK) {
|
if (dr6 & X86_DR6_BREAKPOINT_MASK) {
|
||||||
// breakpoint
|
// breakpoint
|
||||||
@@ -426,7 +443,7 @@ i386_handle_debug_exception(struct iframe *frame)
|
|||||||
else
|
else
|
||||||
user_debug_breakpoint_hit(false);
|
user_debug_breakpoint_hit(false);
|
||||||
|
|
||||||
} else if (dr6 & X86_DR6_BD) {
|
} else if (dr6 & (1 << X86_DR6_BD)) {
|
||||||
// general detect exception
|
// general detect exception
|
||||||
// Occurs only, if GD in DR7 is set (which we don't do) and someone
|
// Occurs only, if GD in DR7 is set (which we don't do) and someone
|
||||||
// tries to write to the debug registers.
|
// tries to write to the debug registers.
|
||||||
@@ -435,7 +452,7 @@ i386_handle_debug_exception(struct iframe *frame)
|
|||||||
|
|
||||||
enable_interrupts();
|
enable_interrupts();
|
||||||
|
|
||||||
} else if (dr6 & X86_DR6_BS) {
|
} else if ((dr6 & (1 << X86_DR6_BS)) || sQEmuSingleStepHack) {
|
||||||
// single step
|
// single step
|
||||||
|
|
||||||
// enable interrupts and notify the debugger
|
// enable interrupts and notify the debugger
|
||||||
@@ -443,7 +460,7 @@ i386_handle_debug_exception(struct iframe *frame)
|
|||||||
|
|
||||||
user_debug_single_stepped();
|
user_debug_single_stepped();
|
||||||
|
|
||||||
} else if (dr6 & X86_DR6_BT) {
|
} else if (dr6 & (1 << X86_DR6_BT)) {
|
||||||
// task switch
|
// task switch
|
||||||
// Occurs only, if T in EFLAGS is set (which we don't do).
|
// Occurs only, if T in EFLAGS is set (which we don't do).
|
||||||
dprintf("i386_handle_debug_exception(): ignoring spurious task switch "
|
dprintf("i386_handle_debug_exception(): ignoring spurious task switch "
|
||||||
@@ -468,9 +485,25 @@ i386_handle_debug_exception(struct iframe *frame)
|
|||||||
int
|
int
|
||||||
i386_handle_breakpoint_exception(struct iframe *frame)
|
i386_handle_breakpoint_exception(struct iframe *frame)
|
||||||
{
|
{
|
||||||
|
TRACE(("i386_handle_breakpoint_exception()\n"));
|
||||||
|
|
||||||
enable_interrupts();
|
enable_interrupts();
|
||||||
|
|
||||||
user_debug_breakpoint_hit(true);
|
user_debug_breakpoint_hit(true);
|
||||||
|
|
||||||
return B_HANDLED_INTERRUPT;
|
return B_HANDLED_INTERRUPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
i386_init_user_debug()
|
||||||
|
{
|
||||||
|
// get debug settings
|
||||||
|
if (void *handle = load_driver_settings("kernel")) {
|
||||||
|
sQEmuSingleStepHack = get_driver_boolean_parameter(handle,
|
||||||
|
"qemu_single_step_hack", false, false);;
|
||||||
|
|
||||||
|
unload_driver_settings(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user