* Added support for setting (hardware) break-/watchpoints in the kernel.
Can be enabled by defining KERNEL_BREAKPOINTS in arch/user_debugger.h
and will provide the arch_{set,clear}_kernel_{break,watch}point()
function. Hitting a break-/watchpoint will throw the thread into KDL.
* Finally added a comment, what's the point of
i386_reinit_user_debug_after_context_switch(), since I wonder every
time I see it. Should be optimized aways soon.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22150 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -11,6 +11,9 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Enable this to get support for kernel breakpoints.
|
||||
//#define KERNEL_BREAKPOINTS 1
|
||||
|
||||
struct arch_team_debug_info;
|
||||
struct arch_thread_debug_info;
|
||||
|
||||
@@ -27,6 +30,13 @@ status_t arch_clear_breakpoint(void *address);
|
||||
status_t arch_set_watchpoint(void *address, uint32 type, int32 length);
|
||||
status_t arch_clear_watchpoint(void *address);
|
||||
|
||||
#if KERNEL_BREAKPOINTS
|
||||
status_t arch_set_kernel_breakpoint(void *address);
|
||||
status_t arch_clear_kernel_breakpoint(void *address);
|
||||
status_t arch_set_kernel_watchpoint(void *address, uint32 type, int32 length);
|
||||
status_t arch_clear_kernel_watchpoint(void *address);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -3,13 +3,16 @@
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include <arch/user_debugger.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <debugger.h>
|
||||
#include <driver_settings.h>
|
||||
#include <int.h>
|
||||
#include <team.h>
|
||||
#include <thread.h>
|
||||
#include <arch/user_debugger.h>
|
||||
|
||||
|
||||
//#define TRACE_ARCH_USER_DEBUGGER
|
||||
#ifdef TRACE_ARCH_USER_DEBUGGER
|
||||
@@ -18,13 +21,13 @@
|
||||
# define TRACE(x) ;
|
||||
#endif
|
||||
|
||||
#define B_NO_MORE_BREAKPOINTS B_ERROR
|
||||
#define B_NO_MORE_WATCHPOINTS B_ERROR
|
||||
#define B_BAD_WATCHPOINT_ALIGNMENT B_ERROR
|
||||
#define B_WATCHPOINT_TYPE_NOT_SUPPORTED B_ERROR
|
||||
#define B_WATCHPOINT_LENGTH_NOT_SUPPORTED B_ERROR
|
||||
#define B_BREAKPOINT_NOT_FOUND B_ERROR
|
||||
#define B_WATCHPOINT_NOT_FOUND B_ERROR
|
||||
#define B_NO_MORE_BREAKPOINTS B_BUSY
|
||||
#define B_NO_MORE_WATCHPOINTS B_BUSY
|
||||
#define B_BAD_WATCHPOINT_ALIGNMENT B_BAD_VALUE
|
||||
#define B_WATCHPOINT_TYPE_NOT_SUPPORTED B_NOT_SUPPORTED
|
||||
#define B_WATCHPOINT_LENGTH_NOT_SUPPORTED B_NOT_SUPPORTED
|
||||
#define B_BREAKPOINT_NOT_FOUND B_NAME_NOT_FOUND
|
||||
#define B_WATCHPOINT_NOT_FOUND B_NAME_NOT_FOUND
|
||||
// ToDo: Make those real error codes.
|
||||
|
||||
// maps breakpoint slot index to LEN_i LSB number
|
||||
@@ -42,6 +45,11 @@ static const uint32 sDR7L[4] = {
|
||||
X86_DR7_L0, X86_DR7_L1, X86_DR7_L2, X86_DR7_L3
|
||||
};
|
||||
|
||||
// maps breakpoint slot index to G_i bit number
|
||||
static const uint32 sDR7G[4] = {
|
||||
X86_DR7_G0, X86_DR7_G1, X86_DR7_G2, X86_DR7_G3
|
||||
};
|
||||
|
||||
// maps breakpoint slot index to B_i bit number
|
||||
static const uint32 sDR6B[4] = {
|
||||
X86_DR6_B0, X86_DR6_B1, X86_DR6_B2, X86_DR6_B3
|
||||
@@ -52,6 +60,250 @@ static const uint32 sDR6B[4] = {
|
||||
static bool sQEmuSingleStepHack = false;
|
||||
|
||||
|
||||
static inline void
|
||||
install_breakpoints(const arch_team_debug_info &teamInfo)
|
||||
{
|
||||
// set breakpoints
|
||||
asm("movl %0, %%dr0" : : "r"(teamInfo.breakpoints[0].address));
|
||||
asm("movl %0, %%dr1" : : "r"(teamInfo.breakpoints[1].address));
|
||||
asm("movl %0, %%dr2" : : "r"(teamInfo.breakpoints[2].address));
|
||||
// asm("movl %0, %%dr3" : : "r"(teamInfo.breakpoints[3].address));
|
||||
// DR3 is used to hold the current struct thread*.
|
||||
|
||||
// enable breakpoints
|
||||
asm("movl %0, %%dr7" : : "r"(teamInfo.dr7));
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
disable_breakpoints()
|
||||
{
|
||||
asm("movl %0, %%dr7" : : "r"(X86_BREAKPOINTS_DISABLED_DR7));
|
||||
}
|
||||
|
||||
|
||||
/*! Sets a break-/watchpoint in the given team info.
|
||||
Interrupts must be disabled and the team debug info lock be held.
|
||||
*/
|
||||
static inline status_t
|
||||
set_breakpoint(arch_team_debug_info &info, void *address, uint32 type,
|
||||
uint32 length, bool setGlobalFlag)
|
||||
{
|
||||
// check, if there is already a breakpoint at that address
|
||||
bool alreadySet = false;
|
||||
for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
|
||||
if (info.breakpoints[i].address == address
|
||||
&& info.breakpoints[i].type == type) {
|
||||
alreadySet = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!alreadySet) {
|
||||
// find a free slot
|
||||
int32 slot = -1;
|
||||
for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
|
||||
if (!info.breakpoints[i].address) {
|
||||
slot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// init the breakpoint
|
||||
if (slot >= 0) {
|
||||
info.breakpoints[slot].address = address;
|
||||
info.breakpoints[slot].type = type;
|
||||
info.breakpoints[slot].length = length;
|
||||
|
||||
info.dr7 |= (length << sDR7Len[slot])
|
||||
| (type << sDR7RW[slot])
|
||||
| (1 << sDR7L[slot]);
|
||||
if (setGlobalFlag)
|
||||
info.dr7 |= (1 << sDR7G[slot]);
|
||||
} else {
|
||||
if (type == X86_INSTRUCTION_BREAKPOINT)
|
||||
return B_NO_MORE_BREAKPOINTS;
|
||||
else
|
||||
return B_NO_MORE_WATCHPOINTS;
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/*! Clears a break-/watchpoint in the given team info.
|
||||
Interrupts must be disabled and the team debug info lock be held.
|
||||
*/
|
||||
static inline status_t
|
||||
clear_breakpoint(arch_team_debug_info &info, void *address, bool watchpoint)
|
||||
{
|
||||
// find the breakpoint
|
||||
int32 slot = -1;
|
||||
for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
|
||||
if (info.breakpoints[i].address == address
|
||||
&& (watchpoint
|
||||
!= (info.breakpoints[i].type == X86_INSTRUCTION_BREAKPOINT))) {
|
||||
slot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// clear the breakpoint
|
||||
if (slot >= 0) {
|
||||
info.breakpoints[slot].address = NULL;
|
||||
|
||||
info.dr7 &= ~((0x3 << sDR7Len[slot])
|
||||
| (0x3 << sDR7RW[slot])
|
||||
| (1 << sDR7L[slot])
|
||||
| (1 << sDR7G[slot]));
|
||||
} else {
|
||||
if (watchpoint)
|
||||
return B_WATCHPOINT_NOT_FOUND;
|
||||
else
|
||||
return B_BREAKPOINT_NOT_FOUND;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
set_breakpoint(void *address, uint32 type, uint32 length)
|
||||
{
|
||||
if (!address)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
struct thread *thread = thread_get_current_thread();
|
||||
|
||||
cpu_status state = disable_interrupts();
|
||||
GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
|
||||
|
||||
status_t error = set_breakpoint(thread->team->debug_info.arch_info, address,
|
||||
type, length, false);
|
||||
|
||||
RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
|
||||
restore_interrupts(state);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
clear_breakpoint(void *address, bool watchpoint)
|
||||
{
|
||||
if (!address)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
struct thread *thread = thread_get_current_thread();
|
||||
|
||||
cpu_status state = disable_interrupts();
|
||||
GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
|
||||
|
||||
status_t error = clear_breakpoint(thread->team->debug_info.arch_info,
|
||||
address, watchpoint);
|
||||
|
||||
RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
|
||||
restore_interrupts(state);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
#if KERNEL_BREAKPOINTS
|
||||
|
||||
static status_t
|
||||
set_kernel_breakpoint(void *address, uint32 type, uint32 length)
|
||||
{
|
||||
if (!address)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
struct team* kernelTeam = team_get_kernel_team();
|
||||
|
||||
cpu_status state = disable_interrupts();
|
||||
GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
|
||||
|
||||
status_t error = set_breakpoint(kernelTeam->debug_info.arch_info, address,
|
||||
type, length, true);
|
||||
|
||||
install_breakpoints(kernelTeam->debug_info.arch_info);
|
||||
|
||||
RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
|
||||
restore_interrupts(state);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
clear_kernel_breakpoint(void *address, bool watchpoint)
|
||||
{
|
||||
if (!address)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
struct team* kernelTeam = team_get_kernel_team();
|
||||
|
||||
cpu_status state = disable_interrupts();
|
||||
GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
|
||||
|
||||
status_t error = clear_breakpoint(kernelTeam->debug_info.arch_info,
|
||||
address, watchpoint);
|
||||
|
||||
install_breakpoints(kernelTeam->debug_info.arch_info);
|
||||
|
||||
RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
|
||||
restore_interrupts(state);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
#endif // KERNEL_BREAKPOINTS
|
||||
|
||||
|
||||
static inline status_t
|
||||
check_watch_point_parameters(void* address, uint32 type, int32 length,
|
||||
uint32& archType, uint32& archLength)
|
||||
{
|
||||
// check type
|
||||
switch (type) {
|
||||
case B_DATA_WRITE_WATCHPOINT:
|
||||
archType = X86_DATA_WRITE_BREAKPOINT;
|
||||
break;
|
||||
case B_DATA_READ_WRITE_WATCHPOINT:
|
||||
archType = X86_DATA_READ_WRITE_BREAKPOINT;
|
||||
break;
|
||||
case B_DATA_READ_WATCHPOINT:
|
||||
default:
|
||||
return B_WATCHPOINT_TYPE_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
// check length and alignment
|
||||
switch (length) {
|
||||
case 1:
|
||||
archLength = X86_BREAKPOINT_LENGTH_1;
|
||||
break;
|
||||
case 2:
|
||||
if ((uint32)address & 0x1)
|
||||
return B_BAD_WATCHPOINT_ALIGNMENT;
|
||||
archLength = X86_BREAKPOINT_LENGTH_2;
|
||||
break;
|
||||
case 4:
|
||||
if ((uint32)address & 0x3)
|
||||
return B_BAD_WATCHPOINT_ALIGNMENT;
|
||||
archLength = X86_BREAKPOINT_LENGTH_4;
|
||||
break;
|
||||
default:
|
||||
return B_WATCHPOINT_LENGTH_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - in-kernel public interface
|
||||
|
||||
|
||||
void
|
||||
arch_clear_team_debug_info(struct arch_team_debug_info *info)
|
||||
{
|
||||
@@ -116,6 +368,7 @@ arch_set_debug_cpu_state(const struct debug_cpu_state *cpuState)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_get_debug_cpu_state(struct debug_cpu_state *cpuState)
|
||||
{
|
||||
@@ -148,111 +401,6 @@ arch_get_debug_cpu_state(struct debug_cpu_state *cpuState)
|
||||
}
|
||||
}
|
||||
|
||||
static status_t
|
||||
set_breakpoint(void *address, uint32 type, uint32 length)
|
||||
{
|
||||
if (!address)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
struct thread *thread = thread_get_current_thread();
|
||||
|
||||
status_t error = B_OK;
|
||||
|
||||
cpu_status state = disable_interrupts();
|
||||
GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
|
||||
|
||||
arch_team_debug_info &info = thread->team->debug_info.arch_info;
|
||||
|
||||
// check, if there is already a breakpoint at that address
|
||||
bool alreadySet = false;
|
||||
for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
|
||||
if (info.breakpoints[i].address == address
|
||||
&& info.breakpoints[i].type == type) {
|
||||
alreadySet = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!alreadySet) {
|
||||
// find a free slot
|
||||
int32 slot = -1;
|
||||
for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
|
||||
if (!info.breakpoints[i].address) {
|
||||
slot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// init the breakpoint
|
||||
if (slot >= 0) {
|
||||
info.breakpoints[slot].address = address;
|
||||
info.breakpoints[slot].type = type;
|
||||
info.breakpoints[slot].length = length;
|
||||
|
||||
info.dr7 |= (length << sDR7Len[slot])
|
||||
| (type << sDR7RW[slot])
|
||||
| (1 << sDR7L[slot]);
|
||||
} else {
|
||||
if (type == X86_INSTRUCTION_BREAKPOINT)
|
||||
error = B_NO_MORE_BREAKPOINTS;
|
||||
else
|
||||
error = B_NO_MORE_WATCHPOINTS;
|
||||
}
|
||||
}
|
||||
|
||||
RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
|
||||
restore_interrupts(state);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
clear_breakpoint(void *address, bool watchpoint)
|
||||
{
|
||||
if (!address)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
struct thread *thread = thread_get_current_thread();
|
||||
|
||||
status_t error = B_OK;
|
||||
|
||||
cpu_status state = disable_interrupts();
|
||||
GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
|
||||
|
||||
arch_team_debug_info &info = thread->team->debug_info.arch_info;
|
||||
|
||||
// find the breakpoint
|
||||
int32 slot = -1;
|
||||
for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
|
||||
if (info.breakpoints[i].address == address
|
||||
&& (watchpoint
|
||||
!= (info.breakpoints[i].type == X86_INSTRUCTION_BREAKPOINT))) {
|
||||
slot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// clear the breakpoint
|
||||
if (slot >= 0) {
|
||||
info.breakpoints[slot].address = NULL;
|
||||
|
||||
info.dr7 &= ~((0x3 << sDR7Len[slot])
|
||||
| (0x3 << sDR7RW[slot])
|
||||
| (1 << sDR7L[slot]));
|
||||
} else {
|
||||
if (watchpoint)
|
||||
error = B_WATCHPOINT_NOT_FOUND;
|
||||
else
|
||||
error = B_BREAKPOINT_NOT_FOUND;
|
||||
}
|
||||
|
||||
RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
|
||||
restore_interrupts(state);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_set_breakpoint(void *address)
|
||||
@@ -272,40 +420,11 @@ arch_clear_breakpoint(void *address)
|
||||
status_t
|
||||
arch_set_watchpoint(void *address, uint32 type, int32 length)
|
||||
{
|
||||
// check type
|
||||
uint32 archType;
|
||||
switch (type) {
|
||||
case B_DATA_WRITE_WATCHPOINT:
|
||||
archType = X86_DATA_WRITE_BREAKPOINT;
|
||||
break;
|
||||
case B_DATA_READ_WRITE_WATCHPOINT:
|
||||
archType = X86_DATA_READ_WRITE_BREAKPOINT;
|
||||
break;
|
||||
case B_DATA_READ_WATCHPOINT:
|
||||
default:
|
||||
return B_WATCHPOINT_TYPE_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
// check length and alignment
|
||||
uint32 archLength;
|
||||
switch (length) {
|
||||
case 1:
|
||||
archLength = X86_BREAKPOINT_LENGTH_1;
|
||||
break;
|
||||
case 2:
|
||||
if ((uint32)address & 0x1)
|
||||
return B_BAD_WATCHPOINT_ALIGNMENT;
|
||||
archLength = X86_BREAKPOINT_LENGTH_2;
|
||||
break;
|
||||
case 4:
|
||||
if ((uint32)address & 0x3)
|
||||
return B_BAD_WATCHPOINT_ALIGNMENT;
|
||||
archLength = X86_BREAKPOINT_LENGTH_4;
|
||||
break;
|
||||
default:
|
||||
return B_WATCHPOINT_LENGTH_NOT_SUPPORTED;
|
||||
}
|
||||
uint32 archType, archLength;
|
||||
status_t error = check_watch_point_parameters(address, type, length,
|
||||
archType, archLength);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
return set_breakpoint(address, archType, archLength);
|
||||
}
|
||||
@@ -318,21 +437,75 @@ arch_clear_watchpoint(void *address)
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
install_breakpoints(const arch_team_debug_info &teamInfo)
|
||||
{
|
||||
// set breakpoints
|
||||
asm("movl %0, %%dr0" : : "r"(teamInfo.breakpoints[0].address));
|
||||
asm("movl %0, %%dr1" : : "r"(teamInfo.breakpoints[1].address));
|
||||
asm("movl %0, %%dr2" : : "r"(teamInfo.breakpoints[2].address));
|
||||
// asm("movl %0, %%dr3" : : "r"(teamInfo.breakpoints[3].address));
|
||||
// DR3 is used to hold the current struct thread*.
|
||||
#if KERNEL_BREAKPOINTS
|
||||
|
||||
// enable breakpoints
|
||||
asm("movl %0, %%dr7" : : "r"(teamInfo.dr7));
|
||||
status_t
|
||||
arch_set_kernel_breakpoint(void *address)
|
||||
{
|
||||
status_t error = set_kernel_breakpoint(address, X86_INSTRUCTION_BREAKPOINT,
|
||||
X86_BREAKPOINT_LENGTH_1);
|
||||
|
||||
if (error != B_OK) {
|
||||
panic("arch_set_kernel_breakpoint() failed to set breakpoint: %s",
|
||||
strerror(error));
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_clear_kernel_breakpoint(void *address)
|
||||
{
|
||||
status_t error = clear_kernel_breakpoint(address, false);
|
||||
|
||||
if (error != B_OK) {
|
||||
panic("arch_clear_kernel_breakpoint() failed to clear breakpoint: %s",
|
||||
strerror(error));
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_set_kernel_watchpoint(void *address, uint32 type, int32 length)
|
||||
{
|
||||
uint32 archType, archLength;
|
||||
status_t error = check_watch_point_parameters(address, type, length,
|
||||
archType, archLength);
|
||||
|
||||
if (error == B_OK)
|
||||
error = set_kernel_breakpoint(address, archType, archLength);
|
||||
|
||||
if (error != B_OK) {
|
||||
panic("arch_set_kernel_watchpoint() failed to set watchpoint: %s",
|
||||
strerror(error));
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_clear_kernel_watchpoint(void *address)
|
||||
{
|
||||
status_t error = clear_kernel_breakpoint(address, true);
|
||||
|
||||
if (error != B_OK) {
|
||||
panic("arch_clear_kernel_watchpoint() failed to clear watchpoint: %s",
|
||||
strerror(error));
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
#endif // KERNEL_BREAKPOINTS
|
||||
|
||||
|
||||
// #pragma mark - x86 implementation interface
|
||||
|
||||
|
||||
/**
|
||||
* Interrupts are enabled.
|
||||
*/
|
||||
@@ -378,9 +551,16 @@ i386_exit_user_debug_at_kernel_entry()
|
||||
GRAB_THREAD_LOCK();
|
||||
|
||||
// disable breakpoints
|
||||
asm("movl %0, %%dr7" : : "r"(X86_BREAKPOINTS_DISABLED_DR7));
|
||||
disable_breakpoints();
|
||||
thread->debug_info.arch_info.flags &= ~X86_THREAD_DEBUG_DR7_SET;
|
||||
|
||||
#if KERNEL_BREAKPOINTS
|
||||
struct team* kernelTeam = team_get_kernel_team();
|
||||
GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
|
||||
install_breakpoints(kernelTeam->debug_info.arch_info);
|
||||
RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
|
||||
#endif
|
||||
|
||||
RELEASE_THREAD_LOCK();
|
||||
restore_interrupts(state);
|
||||
}
|
||||
@@ -392,12 +572,29 @@ i386_exit_user_debug_at_kernel_entry()
|
||||
void
|
||||
i386_reinit_user_debug_after_context_switch(struct thread *thread)
|
||||
{
|
||||
// This function deals with a race condition: We set up the debugging
|
||||
// registers in i386_init_user_debug_at_kernel_exit() when a userland
|
||||
// thread is going to leave the kernel. Afterwards the thread might be
|
||||
// preempted, though, since interrupts are enabled.
|
||||
// X86_THREAD_DEBUG_DR7_SET indicates, when this happens.
|
||||
// TODO: We should fix this by disabling interrupts before
|
||||
// i386_init_user_debug_at_kernel_exit() is called and keep them disabled
|
||||
// until returning from the interrupt.
|
||||
|
||||
if (thread->debug_info.arch_info.flags & X86_THREAD_DEBUG_DR7_SET) {
|
||||
GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
|
||||
|
||||
install_breakpoints(thread->team->debug_info.arch_info);
|
||||
|
||||
RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
|
||||
#if KERNEL_BREAKPOINTS
|
||||
} else {
|
||||
// we're still in the kernel
|
||||
struct team* kernelTeam = team_get_kernel_team();
|
||||
GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
|
||||
install_breakpoints(kernelTeam->debug_info.arch_info);
|
||||
RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -415,6 +612,12 @@ i386_handle_debug_exception(struct iframe *frame)
|
||||
|
||||
TRACE(("i386_handle_debug_exception(): DR6: %lx, DR7: %lx\n", dr6, dr7));
|
||||
|
||||
if (frame->cs != USER_CODE_SEG) {
|
||||
panic("debug exception in kernel mode: dr6: 0x%lx, dr7: 0x%lx", dr6,
|
||||
dr7);
|
||||
return B_HANDLED_INTERRUPT;
|
||||
}
|
||||
|
||||
// check, which exception condition applies
|
||||
if (dr6 & X86_DR6_BREAKPOINT_MASK) {
|
||||
// breakpoint
|
||||
@@ -483,6 +686,11 @@ i386_handle_breakpoint_exception(struct iframe *frame)
|
||||
{
|
||||
TRACE(("i386_handle_breakpoint_exception()\n"));
|
||||
|
||||
if (frame->cs != USER_CODE_SEG) {
|
||||
panic("breakpoint exception in kernel mode");
|
||||
return B_HANDLED_INTERRUPT;
|
||||
}
|
||||
|
||||
enable_interrupts();
|
||||
|
||||
user_debug_breakpoint_hit(true);
|
||||
|
||||
Reference in New Issue
Block a user