diff --git a/headers/private/kernel/arch/user_debugger.h b/headers/private/kernel/arch/user_debugger.h index 90240f76ab..9066bf6dbc 100644 --- a/headers/private/kernel/arch/user_debugger.h +++ b/headers/private/kernel/arch/user_debugger.h @@ -1,5 +1,5 @@ /* - * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2005-2016, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ #ifndef KERNEL_ARCH_USER_DEBUGGER_H @@ -19,6 +19,11 @@ extern "C" { struct arch_team_debug_info; struct arch_thread_debug_info; +namespace BKernel { + struct Thread; +} +using BKernel::Thread; + void arch_clear_team_debug_info(struct arch_team_debug_info *info); void arch_destroy_team_debug_info(struct arch_team_debug_info *info); @@ -29,6 +34,8 @@ void arch_update_thread_single_step(); void arch_set_debug_cpu_state(const debug_cpu_state *cpuState); void arch_get_debug_cpu_state(debug_cpu_state *cpuState); +status_t arch_get_thread_debug_cpu_state(Thread *thread, + debug_cpu_state *cpuState); status_t arch_set_breakpoint(void *address); status_t arch_clear_breakpoint(void *address); diff --git a/src/system/kernel/arch/arm/arch_user_debugger.cpp b/src/system/kernel/arch/arm/arch_user_debugger.cpp index 5ae6e79b2f..ad14e201a5 100644 --- a/src/system/kernel/arch/arm/arch_user_debugger.cpp +++ b/src/system/kernel/arch/arm/arch_user_debugger.cpp @@ -60,6 +60,13 @@ arch_get_debug_cpu_state(debug_cpu_state *cpuState) } +status_t +arch_get_thread_debug_cpu_state(Thread* thread, debug_cpu_state* cpuState) +{ + return B_UNSUPPORTED; +} + + status_t arch_get_thread_debug_cpu_state(Thread *thread, debug_cpu_state *cpuState) { diff --git a/src/system/kernel/arch/m68k/arch_user_debugger.cpp b/src/system/kernel/arch/m68k/arch_user_debugger.cpp index 7203483fc1..c678f42072 100644 --- a/src/system/kernel/arch/m68k/arch_user_debugger.cpp +++ b/src/system/kernel/arch/m68k/arch_user_debugger.cpp @@ -76,6 +76,13 @@ arch_get_debug_cpu_state(debug_cpu_state *cpuState) } +status_t +arch_get_thread_debug_cpu_state(Thread* thread, debug_cpu_state* cpuState) +{ + return B_UNSUPPORTED; +} + + status_t arch_set_breakpoint(void *address) { diff --git a/src/system/kernel/arch/ppc/arch_user_debugger.cpp b/src/system/kernel/arch/ppc/arch_user_debugger.cpp index 99ae27b605..19a898cfea 100644 --- a/src/system/kernel/arch/ppc/arch_user_debugger.cpp +++ b/src/system/kernel/arch/ppc/arch_user_debugger.cpp @@ -54,6 +54,13 @@ arch_get_debug_cpu_state(debug_cpu_state *cpuState) } +status_t +arch_get_thread_debug_cpu_state(Thread* thread, debug_cpu_state* cpuState) +{ + return B_UNSUPPORTED; +} + + status_t arch_set_breakpoint(void *address) { diff --git a/src/system/kernel/arch/x86/arch_user_debugger.cpp b/src/system/kernel/arch/x86/arch_user_debugger.cpp index 8b621d9e3c..952c091924 100644 --- a/src/system/kernel/arch/x86/arch_user_debugger.cpp +++ b/src/system/kernel/arch/x86/arch_user_debugger.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2005-2016, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ @@ -196,6 +196,51 @@ set_iframe_registers(iframe* frame, const debug_cpu_state* cpuState) #endif // __x86_64__ +static void +get_cpu_state(Thread* thread, iframe* frame, debug_cpu_state* cpuState) +{ + // For the floating point state to be correct the calling function must + // not use these registers (not even indirectly). +#ifdef __x86_64__ + if (frame->fpu != nullptr) { + memcpy(&cpuState->extended_registers, frame->fpu, + sizeof(cpuState->extended_registers)); + } else { + memset(&cpuState->extended_registers, 0, + sizeof(cpuState->extended_registers)); + } +#else + Thread* thisThread = thread_get_current_thread(); + if (gHasSSE) { + if (thread == thisThread) { + // Since fxsave requires 16-byte alignment and this isn't guaranteed + // for the passed buffer, we use our thread's fpu_state field as + // temporary buffer. We need to disable interrupts to make use of + // it. + Thread* thread = thread_get_current_thread(); + InterruptsLocker locker; + x86_fxsave(thread->arch_info.fpu_state); + // unlike fnsave, fxsave doesn't reinit the FPU state + } + memcpy(&cpuState->extended_registers, thread->arch_info.fpu_state, + sizeof(cpuState->extended_registers)); + } else { + if (thread == thisThread) { + x86_fnsave(&cpuState->extended_registers); + // fnsave reinits the FPU state after saving, so we need to + // load it again + x86_frstor(&cpuState->extended_registers); + } else { + memcpy(&cpuState->extended_registers, thread->arch_info.fpu_state, + sizeof(cpuState->extended_registers)); + } + // TODO: Convert to fxsave format! + } +#endif + get_iframe_registers(frame, cpuState); +} + + static inline void install_breakpoints(const arch_team_debug_info& teamInfo) { @@ -719,38 +764,28 @@ arch_set_debug_cpu_state(const debug_cpu_state* cpuState) void arch_get_debug_cpu_state(debug_cpu_state* cpuState) { - if (iframe* frame = x86_get_user_iframe()) { - // For the floating point state to be correct the calling function must - // not use these registers (not even indirectly). -#ifdef __x86_64__ - if (frame->fpu != nullptr) { - memcpy(&cpuState->extended_registers, frame->fpu, - sizeof(cpuState->extended_registers)); - } else { - memset(&cpuState->extended_registers, 0, - sizeof(cpuState->extended_registers)); - } -#else - if (gHasSSE) { - // Since fxsave requires 16-byte alignment and this isn't guaranteed - // passed buffer, we use our thread's fpu_state field as temporary - // buffer. We need to disable interrupts to make use of it. - Thread* thread = thread_get_current_thread(); - InterruptsLocker locker; - x86_fxsave(thread->arch_info.fpu_state); - // unlike fnsave, fxsave doesn't reinit the FPU state - memcpy(&cpuState->extended_registers, thread->arch_info.fpu_state, - sizeof(cpuState->extended_registers)); - } else { - x86_fnsave(&cpuState->extended_registers); - x86_frstor(&cpuState->extended_registers); - // fnsave reinits the FPU state after saving, so we need to - // load it again - // TODO: Convert to fxsave format! - } -#endif - get_iframe_registers(frame, cpuState); - } + if (iframe* frame = x86_get_user_iframe()) + get_cpu_state(thread_get_current_thread(), frame, cpuState); +} + + +/*! \brief Retrieves the CPU state for the given thread. + The thread must not be running and the thread's scheduler spinlock must be + held. + \param thread The thread whose CPU state to retrieve. + \param cpuState Pointer to pre-allocated storage for the CPU state. + \return \c B_OK, if everything goes fine, another error code, if the CPU + state could not be retrieved. +*/ +status_t +arch_get_thread_debug_cpu_state(Thread* thread, debug_cpu_state* cpuState) +{ + iframe* frame = x86_get_thread_user_iframe(thread); + if (frame == NULL) + return B_BAD_VALUE; + + get_cpu_state(thread, frame, cpuState); + return B_OK; }