User debugger support:
* Generalized address checks. The debugger can now also read the commpage. * Added new syscall _kern_get_thread_cpu_state() to get the CPU state of a not running thread. Introduced arch_get_thread_debug_cpu_state() for that purpose, which is only implemented for x86 ATM (uses the new i386_get_thread_user_iframe()). * Don't allow a debugger to change a thread's "esp" anymore. That's the esp register in the kernel. "user_esp" can still be changed. * Generally set RF (resume flag) in eflags in interrupt handlers, not only after a instruction breakpoint debug exception. This should prevent breakpoints from being triggered more than once (e.g. when the breakpoint is on an instruction that can cause a page fault). I still saw those with bdb in VMware, but that might be a VMware bug. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31045 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -17,6 +17,7 @@ extern "C" {
|
|||||||
|
|
||||||
struct arch_team_debug_info;
|
struct arch_team_debug_info;
|
||||||
struct arch_thread_debug_info;
|
struct arch_thread_debug_info;
|
||||||
|
struct thread;
|
||||||
|
|
||||||
void arch_clear_team_debug_info(struct arch_team_debug_info *info);
|
void arch_clear_team_debug_info(struct arch_team_debug_info *info);
|
||||||
void arch_destroy_team_debug_info(struct arch_team_debug_info *info);
|
void arch_destroy_team_debug_info(struct arch_team_debug_info *info);
|
||||||
@@ -27,6 +28,8 @@ void arch_update_thread_single_step();
|
|||||||
|
|
||||||
void arch_set_debug_cpu_state(const struct debug_cpu_state *cpuState);
|
void arch_set_debug_cpu_state(const struct debug_cpu_state *cpuState);
|
||||||
void arch_get_debug_cpu_state(struct debug_cpu_state *cpuState);
|
void arch_get_debug_cpu_state(struct debug_cpu_state *cpuState);
|
||||||
|
status_t arch_get_thread_debug_cpu_state(struct thread *thread,
|
||||||
|
struct debug_cpu_state *cpuState);
|
||||||
|
|
||||||
status_t arch_set_breakpoint(void *address);
|
status_t arch_set_breakpoint(void *address);
|
||||||
status_t arch_clear_breakpoint(void *address);
|
status_t arch_clear_breakpoint(void *address);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2005, The Haiku Team. All rights reserved.
|
* Copyright 2002-2009, The Haiku Team. All rights reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Copyright 2002, Travis Geiselbrecht. All rights reserved.
|
* Copyright 2002, Travis Geiselbrecht. All rights reserved.
|
||||||
@@ -18,6 +18,8 @@ extern "C" {
|
|||||||
|
|
||||||
struct iframe *i386_get_user_iframe(void);
|
struct iframe *i386_get_user_iframe(void);
|
||||||
struct iframe *i386_get_current_iframe(void);
|
struct iframe *i386_get_current_iframe(void);
|
||||||
|
struct iframe *i386_get_thread_user_iframe(struct thread *thread);
|
||||||
|
|
||||||
void *x86_next_page_directory(struct thread *from, struct thread *to);
|
void *x86_next_page_directory(struct thread *from, struct thread *to);
|
||||||
|
|
||||||
void x86_restart_syscall(struct iframe* frame);
|
void x86_restart_syscall(struct iframe* frame);
|
||||||
|
|||||||
@@ -240,6 +240,8 @@ status_t _user_install_default_debugger(port_id debuggerPort);
|
|||||||
port_id _user_install_team_debugger(team_id team, port_id debuggerPort);
|
port_id _user_install_team_debugger(team_id team, port_id debuggerPort);
|
||||||
status_t _user_remove_team_debugger(team_id team);
|
status_t _user_remove_team_debugger(team_id team);
|
||||||
status_t _user_debug_thread(thread_id thread);
|
status_t _user_debug_thread(thread_id thread);
|
||||||
|
status_t _user_get_thread_cpu_state(thread_id thread,
|
||||||
|
struct debug_cpu_state *cpuState);
|
||||||
void _user_wait_for_debugger(void);
|
void _user_wait_for_debugger(void);
|
||||||
|
|
||||||
status_t _user_set_debugger_breakpoint(void *address, uint32 type,
|
status_t _user_set_debugger_breakpoint(void *address, uint32 type,
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct debug_cpu_state;
|
||||||
struct dirent;
|
struct dirent;
|
||||||
struct Elf32_Sym;
|
struct Elf32_Sym;
|
||||||
struct fd_info;
|
struct fd_info;
|
||||||
@@ -384,6 +385,8 @@ extern port_id _kern_install_team_debugger(team_id team,
|
|||||||
port_id debuggerPort);
|
port_id debuggerPort);
|
||||||
extern status_t _kern_remove_team_debugger(team_id team);
|
extern status_t _kern_remove_team_debugger(team_id team);
|
||||||
extern status_t _kern_debug_thread(thread_id thread);
|
extern status_t _kern_debug_thread(thread_id thread);
|
||||||
|
extern status_t _kern_get_thread_cpu_state(thread_id threadID,
|
||||||
|
struct debug_cpu_state *userCPUState);
|
||||||
extern void _kern_wait_for_debugger(void);
|
extern void _kern_wait_for_debugger(void);
|
||||||
|
|
||||||
extern status_t _kern_set_debugger_breakpoint(void *address, uint32 type,
|
extern status_t _kern_set_debugger_breakpoint(void *address, uint32 type,
|
||||||
|
|||||||
@@ -45,14 +45,14 @@ arch_update_thread_single_step()
|
|||||||
{
|
{
|
||||||
if (struct iframe* frame = m68k_get_user_iframe()) {
|
if (struct iframe* frame = m68k_get_user_iframe()) {
|
||||||
struct thread* thread = thread_get_current_thread();
|
struct thread* thread = thread_get_current_thread();
|
||||||
|
|
||||||
// set/clear T1 in SR depending on if single stepping is desired
|
// set/clear T1 in SR depending on if single stepping is desired
|
||||||
// T1 T0
|
// T1 T0
|
||||||
// 0 0 no tracing
|
// 0 0 no tracing
|
||||||
// 0 1 trace on flow
|
// 0 1 trace on flow
|
||||||
// 1 0 single step
|
// 1 0 single step
|
||||||
// 1 1 undef
|
// 1 1 undef
|
||||||
// note 060 and 020(?) only have T1 bit,
|
// note 060 and 020(?) only have T1 bit,
|
||||||
// but this should be compatible as well.
|
// but this should be compatible as well.
|
||||||
if (thread->debug_info.flags & B_THREAD_DEBUG_SINGLE_STEP) {
|
if (thread->debug_info.flags & B_THREAD_DEBUG_SINGLE_STEP) {
|
||||||
frame->cpu.sr &= ~(M68K_SR_T_MASK);
|
frame->cpu.sr &= ~(M68K_SR_T_MASK);
|
||||||
@@ -76,6 +76,14 @@ arch_get_debug_cpu_state(struct debug_cpu_state *cpuState)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
arch_get_thread_debug_cpu_state(struct thread *thread,
|
||||||
|
struct debug_cpu_state *cpuState)
|
||||||
|
{
|
||||||
|
return B_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
arch_set_breakpoint(void *address)
|
arch_set_breakpoint(void *address)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -54,6 +54,14 @@ arch_get_debug_cpu_state(struct debug_cpu_state *cpuState)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
arch_get_thread_debug_cpu_state(struct thread *thread,
|
||||||
|
struct debug_cpu_state *cpuState)
|
||||||
|
{
|
||||||
|
return B_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
arch_set_breakpoint(void *address)
|
arch_set_breakpoint(void *address)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -253,6 +253,11 @@ STATIC_FUNCTION(int_bottom):
|
|||||||
|
|
||||||
movl %esp, %ebp // frame pointer is the iframe
|
movl %esp, %ebp // frame pointer is the iframe
|
||||||
|
|
||||||
|
// Set the RF (resume flag) in EFLAGS. This prevents an instruction
|
||||||
|
// breakpoint on the instruction we're returning to to trigger a debug
|
||||||
|
// exception.
|
||||||
|
orl $0x10000, IFRAME_flags(%ebp);
|
||||||
|
|
||||||
testl $0x20000, IFRAME_flags(%ebp) // VM86 mode
|
testl $0x20000, IFRAME_flags(%ebp) // VM86 mode
|
||||||
jnz int_bottom_vm86
|
jnz int_bottom_vm86
|
||||||
cmp $USER_CODE_SEG, IFRAME_cs(%ebp) // user mode
|
cmp $USER_CODE_SEG, IFRAME_cs(%ebp) // user mode
|
||||||
|
|||||||
@@ -90,10 +90,8 @@ arch_thread_init(struct kernel_args *args)
|
|||||||
|
|
||||||
|
|
||||||
static struct iframe *
|
static struct iframe *
|
||||||
find_previous_iframe(addr_t frame)
|
find_previous_iframe(struct thread *thread, addr_t frame)
|
||||||
{
|
{
|
||||||
struct thread *thread = thread_get_current_thread();
|
|
||||||
|
|
||||||
// iterate backwards through the stack frames, until we hit an iframe
|
// iterate backwards through the stack frames, until we hit an iframe
|
||||||
while (frame >= thread->kernel_stack_base
|
while (frame >= thread->kernel_stack_base
|
||||||
&& frame < thread->kernel_stack_top) {
|
&& frame < thread->kernel_stack_top) {
|
||||||
@@ -117,7 +115,7 @@ get_previous_iframe(struct iframe* frame)
|
|||||||
if (frame == NULL)
|
if (frame == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return find_previous_iframe(frame->ebp);
|
return find_previous_iframe(thread_get_current_thread(), frame->ebp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -130,7 +128,7 @@ get_previous_iframe(struct iframe* frame)
|
|||||||
static struct iframe*
|
static struct iframe*
|
||||||
get_current_iframe(void)
|
get_current_iframe(void)
|
||||||
{
|
{
|
||||||
return find_previous_iframe(x86_read_ebp());
|
return find_previous_iframe(thread_get_current_thread(), x86_read_ebp());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -156,12 +154,38 @@ i386_get_user_iframe(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! \brief Like i386_get_user_iframe(), just for the given thread.
|
||||||
|
The thread must not be running and the threads spinlock must be held.
|
||||||
|
*/
|
||||||
|
struct iframe *
|
||||||
|
i386_get_thread_user_iframe(struct thread *thread)
|
||||||
|
{
|
||||||
|
if (thread->state == B_THREAD_RUNNING)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// read %ebp from the thread's stack stored by a pushad
|
||||||
|
addr_t ebp = thread->arch_info.current_stack.esp[2];
|
||||||
|
|
||||||
|
// find the user iframe
|
||||||
|
struct iframe *frame = find_previous_iframe(thread, ebp);
|
||||||
|
|
||||||
|
while (frame != NULL) {
|
||||||
|
if (IFRAME_IS_USER(frame))
|
||||||
|
return frame;
|
||||||
|
frame = get_previous_iframe(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct iframe *
|
struct iframe *
|
||||||
i386_get_current_iframe(void)
|
i386_get_current_iframe(void)
|
||||||
{
|
{
|
||||||
return get_current_iframe();
|
return get_current_iframe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
x86_next_page_directory(struct thread *from, struct thread *to)
|
x86_next_page_directory(struct thread *from, struct thread *to)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2005, Ingo Weinhold, bonefish@users.sf.net.
|
* Copyright 2005-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -60,6 +60,31 @@ static const uint32 sDR6B[4] = {
|
|||||||
static bool sQEmuSingleStepHack = false;
|
static bool sQEmuSingleStepHack = false;
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_iframe_registers(struct iframe *frame, struct debug_cpu_state *cpuState)
|
||||||
|
{
|
||||||
|
cpuState->gs = frame->gs;
|
||||||
|
cpuState->fs = frame->fs;
|
||||||
|
cpuState->es = frame->es;
|
||||||
|
cpuState->ds = frame->ds;
|
||||||
|
cpuState->edi = frame->edi;
|
||||||
|
cpuState->esi = frame->esi;
|
||||||
|
cpuState->ebp = frame->ebp;
|
||||||
|
cpuState->esp = frame->esp;
|
||||||
|
cpuState->ebx = frame->ebx;
|
||||||
|
cpuState->edx = frame->orig_edx;
|
||||||
|
cpuState->ecx = frame->ecx;
|
||||||
|
cpuState->eax = frame->orig_eax;
|
||||||
|
cpuState->vector = frame->vector;
|
||||||
|
cpuState->error_code = frame->error_code;
|
||||||
|
cpuState->eip = frame->eip;
|
||||||
|
cpuState->cs = frame->cs;
|
||||||
|
cpuState->eflags = frame->flags;
|
||||||
|
cpuState->user_esp = frame->user_esp;
|
||||||
|
cpuState->user_ss = frame->user_ss;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
install_breakpoints(const arch_team_debug_info &teamInfo)
|
install_breakpoints(const arch_team_debug_info &teamInfo)
|
||||||
{
|
{
|
||||||
@@ -562,7 +587,7 @@ arch_set_debug_cpu_state(const struct debug_cpu_state *cpuState)
|
|||||||
frame->edi = cpuState->edi;
|
frame->edi = cpuState->edi;
|
||||||
frame->esi = cpuState->esi;
|
frame->esi = cpuState->esi;
|
||||||
frame->ebp = cpuState->ebp;
|
frame->ebp = cpuState->ebp;
|
||||||
frame->esp = cpuState->esp;
|
// frame->esp = cpuState->esp;
|
||||||
frame->ebx = cpuState->ebx;
|
frame->ebx = cpuState->ebx;
|
||||||
frame->edx = cpuState->edx;
|
frame->edx = cpuState->edx;
|
||||||
frame->ecx = cpuState->ecx;
|
frame->ecx = cpuState->ecx;
|
||||||
@@ -586,30 +611,30 @@ arch_get_debug_cpu_state(struct debug_cpu_state *cpuState)
|
|||||||
i386_fnsave(cpuState->extended_regs);
|
i386_fnsave(cpuState->extended_regs);
|
||||||
// For this to be correct the calling function must not use these
|
// For this to be correct the calling function must not use these
|
||||||
// registers (not even indirectly).
|
// registers (not even indirectly).
|
||||||
|
get_iframe_registers(frame, cpuState);
|
||||||
cpuState->gs = frame->gs;
|
|
||||||
cpuState->fs = frame->fs;
|
|
||||||
cpuState->es = frame->es;
|
|
||||||
cpuState->ds = frame->ds;
|
|
||||||
cpuState->edi = frame->edi;
|
|
||||||
cpuState->esi = frame->esi;
|
|
||||||
cpuState->ebp = frame->ebp;
|
|
||||||
cpuState->esp = frame->esp;
|
|
||||||
cpuState->ebx = frame->ebx;
|
|
||||||
cpuState->edx = frame->orig_edx;
|
|
||||||
cpuState->ecx = frame->ecx;
|
|
||||||
cpuState->eax = frame->orig_eax;
|
|
||||||
cpuState->vector = frame->vector;
|
|
||||||
cpuState->error_code = frame->error_code;
|
|
||||||
cpuState->eip = frame->eip;
|
|
||||||
cpuState->cs = frame->cs;
|
|
||||||
cpuState->eflags = frame->flags;
|
|
||||||
cpuState->user_esp = frame->user_esp;
|
|
||||||
cpuState->user_ss = frame->user_ss;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! \brief Returns the CPU state for the given thread.
|
||||||
|
The thread must not be running and the threads spinlock must be held.
|
||||||
|
*/
|
||||||
|
status_t
|
||||||
|
arch_get_thread_debug_cpu_state(struct thread *thread,
|
||||||
|
struct debug_cpu_state *cpuState)
|
||||||
|
{
|
||||||
|
struct iframe *frame = i386_get_thread_user_iframe(thread);
|
||||||
|
if (frame == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
get_iframe_registers(frame, cpuState);
|
||||||
|
memcpy(cpuState->extended_regs, thread->arch_info.fpu_state,
|
||||||
|
sizeof(cpuState->extended_regs));
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
arch_set_breakpoint(void *address)
|
arch_set_breakpoint(void *address)
|
||||||
{
|
{
|
||||||
@@ -801,15 +826,9 @@ x86_handle_debug_exception(struct iframe *frame)
|
|||||||
bool watchpoint = true;
|
bool watchpoint = true;
|
||||||
for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
|
for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
|
||||||
if (dr6 & (1 << sDR6B[i])) {
|
if (dr6 & (1 << sDR6B[i])) {
|
||||||
// If it is an instruction breakpoint, we need to set RF in
|
|
||||||
// EFLAGS to prevent triggering the same exception
|
|
||||||
// again (breakpoint instructions are triggered *before*
|
|
||||||
// executing the instruction).
|
|
||||||
uint32 type = (dr7 >> sDR7RW[i]) & 0x3;
|
uint32 type = (dr7 >> sDR7RW[i]) & 0x3;
|
||||||
if (type == X86_INSTRUCTION_BREAKPOINT) {
|
if (type == X86_INSTRUCTION_BREAKPOINT)
|
||||||
frame->flags |= (1 << X86_EFLAGS_RF);
|
|
||||||
watchpoint = false;
|
watchpoint = false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2005-2008, Ingo Weinhold, ingo_weinhold@gmx.de.
|
* Copyright 2005-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include <arch/debug.h>
|
#include <arch/debug.h>
|
||||||
#include <arch/user_debugger.h>
|
#include <arch/user_debugger.h>
|
||||||
|
#include <commpage_defs.h>
|
||||||
#include <cpu.h>
|
#include <cpu.h>
|
||||||
#include <debugger.h>
|
#include <debugger.h>
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
@@ -1412,6 +1413,26 @@ nub_thread_cleanup(struct thread *nubThread)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! \brief Returns whether the given address can be accessed in principle.
|
||||||
|
No check whether there's an actually accessible area is performed, though.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
can_access_address(const void* address, bool write)
|
||||||
|
{
|
||||||
|
// user addresses are always fine
|
||||||
|
if (IS_USER_ADDRESS(address))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// a commpage address can at least be read
|
||||||
|
if ((addr_t)address >= USER_COMMPAGE_ADDR
|
||||||
|
&& (addr_t)address < USER_COMMPAGE_ADDR + COMMPAGE_SIZE) {
|
||||||
|
return !write;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** \brief Reads data from user memory.
|
/** \brief Reads data from user memory.
|
||||||
*
|
*
|
||||||
* Tries to read \a size bytes of data from user memory address \a address
|
* Tries to read \a size bytes of data from user memory address \a address
|
||||||
@@ -1435,7 +1456,7 @@ read_user_memory(const void *_address, void *_buffer, int32 size,
|
|||||||
char *buffer = (char*)_buffer;
|
char *buffer = (char*)_buffer;
|
||||||
|
|
||||||
// check the parameters
|
// check the parameters
|
||||||
if (!IS_USER_ADDRESS(address))
|
if (!can_access_address(address, false))
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
if (size <= 0)
|
if (size <= 0)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@@ -1446,7 +1467,7 @@ read_user_memory(const void *_address, void *_buffer, int32 size,
|
|||||||
bytesRead = 0;
|
bytesRead = 0;
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
// check whether we're still in user address space
|
// check whether we're still in user address space
|
||||||
if (!IS_USER_ADDRESS(address)) {
|
if (!can_access_address(address, false)) {
|
||||||
error = B_BAD_ADDRESS;
|
error = B_BAD_ADDRESS;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1486,7 +1507,7 @@ write_user_memory(void *_address, const void *_buffer, int32 size,
|
|||||||
const char *buffer = (const char*)_buffer;
|
const char *buffer = (const char*)_buffer;
|
||||||
|
|
||||||
// check the parameters
|
// check the parameters
|
||||||
if (!IS_USER_ADDRESS(address))
|
if (!can_access_address(address, true))
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
if (size <= 0)
|
if (size <= 0)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@@ -1497,7 +1518,7 @@ write_user_memory(void *_address, const void *_buffer, int32 size,
|
|||||||
bytesWritten = 0;
|
bytesWritten = 0;
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
// check whether we're still in user address space
|
// check whether we're still in user address space
|
||||||
if (!IS_USER_ADDRESS(address)) {
|
if (!can_access_address(address, true)) {
|
||||||
error = B_BAD_ADDRESS;
|
error = B_BAD_ADDRESS;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1589,7 +1610,7 @@ debug_nub_thread_get_thread_debug_port(struct thread *nubThread,
|
|||||||
else if (thread->debug_info.flags & B_THREAD_DEBUG_STOPPED)
|
else if (thread->debug_info.flags & B_THREAD_DEBUG_STOPPED)
|
||||||
threadDebugPort = thread->debug_info.debug_port;
|
threadDebugPort = thread->debug_info.debug_port;
|
||||||
else
|
else
|
||||||
result = B_BAD_VALUE;
|
result = B_BAD_THREAD_STATE;
|
||||||
} else
|
} else
|
||||||
result = B_BAD_THREAD_ID;
|
result = B_BAD_THREAD_ID;
|
||||||
|
|
||||||
@@ -1677,7 +1698,7 @@ debug_nub_thread(void *)
|
|||||||
status_t result = B_OK;
|
status_t result = B_OK;
|
||||||
|
|
||||||
// check the parameters
|
// check the parameters
|
||||||
if (!IS_USER_ADDRESS(address))
|
if (!can_access_address(address, false))
|
||||||
result = B_BAD_ADDRESS;
|
result = B_BAD_ADDRESS;
|
||||||
else if (size <= 0 || size > B_MAX_READ_WRITE_MEMORY_SIZE)
|
else if (size <= 0 || size > B_MAX_READ_WRITE_MEMORY_SIZE)
|
||||||
result = B_BAD_VALUE;
|
result = B_BAD_VALUE;
|
||||||
@@ -1713,7 +1734,7 @@ debug_nub_thread(void *)
|
|||||||
status_t result = B_OK;
|
status_t result = B_OK;
|
||||||
|
|
||||||
// check the parameters
|
// check the parameters
|
||||||
if (!IS_USER_ADDRESS(address))
|
if (!can_access_address(address, true))
|
||||||
result = B_BAD_ADDRESS;
|
result = B_BAD_ADDRESS;
|
||||||
else if (size <= 0 || size > realSize)
|
else if (size <= 0 || size > realSize)
|
||||||
result = B_BAD_VALUE;
|
result = B_BAD_VALUE;
|
||||||
@@ -1897,7 +1918,7 @@ debug_nub_thread(void *)
|
|||||||
|
|
||||||
// check the address
|
// check the address
|
||||||
status_t result = B_OK;
|
status_t result = B_OK;
|
||||||
if (address == NULL || !IS_USER_ADDRESS(address))
|
if (address == NULL || !can_access_address(address, false))
|
||||||
result = B_BAD_ADDRESS;
|
result = B_BAD_ADDRESS;
|
||||||
|
|
||||||
// set the breakpoint
|
// set the breakpoint
|
||||||
@@ -1925,7 +1946,7 @@ debug_nub_thread(void *)
|
|||||||
|
|
||||||
// check the address
|
// check the address
|
||||||
status_t result = B_OK;
|
status_t result = B_OK;
|
||||||
if (address == NULL || !IS_USER_ADDRESS(address))
|
if (address == NULL || !can_access_address(address, false))
|
||||||
result = B_BAD_ADDRESS;
|
result = B_BAD_ADDRESS;
|
||||||
|
|
||||||
// clear the breakpoint
|
// clear the breakpoint
|
||||||
@@ -1952,7 +1973,7 @@ debug_nub_thread(void *)
|
|||||||
|
|
||||||
// check the address and size
|
// check the address and size
|
||||||
status_t result = B_OK;
|
status_t result = B_OK;
|
||||||
if (address == NULL || !IS_USER_ADDRESS(address))
|
if (address == NULL || !can_access_address(address, false))
|
||||||
result = B_BAD_ADDRESS;
|
result = B_BAD_ADDRESS;
|
||||||
if (length < 0)
|
if (length < 0)
|
||||||
result = B_BAD_VALUE;
|
result = B_BAD_VALUE;
|
||||||
@@ -1982,7 +2003,7 @@ debug_nub_thread(void *)
|
|||||||
|
|
||||||
// check the address
|
// check the address
|
||||||
status_t result = B_OK;
|
status_t result = B_OK;
|
||||||
if (address == NULL || !IS_USER_ADDRESS(address))
|
if (address == NULL || !can_access_address(address, false))
|
||||||
result = B_BAD_ADDRESS;
|
result = B_BAD_ADDRESS;
|
||||||
|
|
||||||
// clear the watchpoint
|
// clear the watchpoint
|
||||||
@@ -2928,6 +2949,49 @@ _user_debug_thread(thread_id threadID)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
_user_get_thread_cpu_state(thread_id threadID,
|
||||||
|
struct debug_cpu_state *userCPUState)
|
||||||
|
{
|
||||||
|
TRACE(("[%ld] _user_get_thread_cpu_state(%ld, %p)\n", find_thread(NULL),
|
||||||
|
threadID, userCPUState));
|
||||||
|
|
||||||
|
if (userCPUState == NULL || !IS_USER_ADDRESS(userCPUState))
|
||||||
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
|
InterruptsSpinLocker locker(gThreadSpinlock);
|
||||||
|
|
||||||
|
// get and check the thread
|
||||||
|
struct thread *thread = thread_get_thread_struct_locked(threadID);
|
||||||
|
if (thread == NULL) {
|
||||||
|
// thread doesn't exist any longer
|
||||||
|
return B_BAD_THREAD_ID;
|
||||||
|
} else if (thread->team == team_get_kernel_team()) {
|
||||||
|
// we can't debug the kernel team
|
||||||
|
return B_NOT_ALLOWED;
|
||||||
|
} else if (thread->debug_info.flags & B_THREAD_DEBUG_DYING) {
|
||||||
|
// the thread is already dying
|
||||||
|
return B_BAD_THREAD_ID;
|
||||||
|
} else if (thread->debug_info.flags & B_THREAD_DEBUG_NUB_THREAD) {
|
||||||
|
// don't play with the nub thread
|
||||||
|
return B_NOT_ALLOWED;
|
||||||
|
} else if (thread->state == B_THREAD_RUNNING) {
|
||||||
|
// thread is running -- no way to get its CPU state
|
||||||
|
return B_BAD_THREAD_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the CPU state
|
||||||
|
debug_cpu_state cpuState;
|
||||||
|
status_t error = arch_get_thread_debug_cpu_state(thread, &cpuState);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
|
return user_memcpy(userCPUState, &cpuState, sizeof(cpuState));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
_user_wait_for_debugger(void)
|
_user_wait_for_debugger(void)
|
||||||
{
|
{
|
||||||
@@ -2942,7 +3006,7 @@ _user_set_debugger_breakpoint(void *address, uint32 type, int32 length,
|
|||||||
bool watchpoint)
|
bool watchpoint)
|
||||||
{
|
{
|
||||||
// check the address and size
|
// check the address and size
|
||||||
if (address == NULL || !IS_USER_ADDRESS(address))
|
if (address == NULL || !can_access_address(address, false))
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
if (watchpoint && length < 0)
|
if (watchpoint && length < 0)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@@ -2975,7 +3039,7 @@ status_t
|
|||||||
_user_clear_debugger_breakpoint(void *address, bool watchpoint)
|
_user_clear_debugger_breakpoint(void *address, bool watchpoint)
|
||||||
{
|
{
|
||||||
// check the address
|
// check the address
|
||||||
if (address == NULL || !IS_USER_ADDRESS(address))
|
if (address == NULL || !can_access_address(address, false))
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
// check whether a debugger is installed already
|
// check whether a debugger is installed already
|
||||||
|
|||||||
Reference in New Issue
Block a user