kernel: +arch_get_thread_debug_cpu_state()

Similar to arch_get_debug_cpu_state(), but the thread whose CPU state
to retrieve is specified. Works only for threads that aren't running,
and on x86-64 we can get the FPU state only when the thread was
interrupted in userland.
Not implemented for the incomplete architecture ports.
This commit is contained in:
Ingo Weinhold
2016-04-24 17:29:28 +02:00
parent 7a187cd629
commit 99f00556a4
5 changed files with 97 additions and 34 deletions
+8 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2005-2011, Ingo Weinhold, [email protected]. * Copyright 2005-2016, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef KERNEL_ARCH_USER_DEBUGGER_H #ifndef KERNEL_ARCH_USER_DEBUGGER_H
@@ -19,6 +19,11 @@ extern "C" {
struct arch_team_debug_info; struct arch_team_debug_info;
struct arch_thread_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_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);
@@ -29,6 +34,8 @@ void arch_update_thread_single_step();
void arch_set_debug_cpu_state(const debug_cpu_state *cpuState); void arch_set_debug_cpu_state(const debug_cpu_state *cpuState);
void arch_get_debug_cpu_state(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_set_breakpoint(void *address);
status_t arch_clear_breakpoint(void *address); status_t arch_clear_breakpoint(void *address);
@@ -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 status_t
arch_get_thread_debug_cpu_state(Thread *thread, debug_cpu_state *cpuState) arch_get_thread_debug_cpu_state(Thread *thread, debug_cpu_state *cpuState)
{ {
@@ -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 status_t
arch_set_breakpoint(void *address) arch_set_breakpoint(void *address)
{ {
@@ -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 status_t
arch_set_breakpoint(void *address) arch_set_breakpoint(void *address)
{ {
@@ -1,5 +1,5 @@
/* /*
* Copyright 2005-2011, Ingo Weinhold, [email protected]. * Copyright 2005-2016, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License. * 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__ #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 static inline void
install_breakpoints(const arch_team_debug_info& teamInfo) install_breakpoints(const arch_team_debug_info& teamInfo)
{ {
@@ -719,38 +764,28 @@ arch_set_debug_cpu_state(const debug_cpu_state* cpuState)
void void
arch_get_debug_cpu_state(debug_cpu_state* cpuState) arch_get_debug_cpu_state(debug_cpu_state* cpuState)
{ {
if (iframe* frame = x86_get_user_iframe()) { if (iframe* frame = x86_get_user_iframe())
// For the floating point state to be correct the calling function must get_cpu_state(thread_get_current_thread(), frame, cpuState);
// not use these registers (not even indirectly). }
#ifdef __x86_64__
if (frame->fpu != nullptr) {
memcpy(&cpuState->extended_registers, frame->fpu, /*! \brief Retrieves the CPU state for the given thread.
sizeof(cpuState->extended_registers)); The thread must not be running and the thread's scheduler spinlock must be
} else { held.
memset(&cpuState->extended_registers, 0, \param thread The thread whose CPU state to retrieve.
sizeof(cpuState->extended_registers)); \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
#else state could not be retrieved.
if (gHasSSE) { */
// Since fxsave requires 16-byte alignment and this isn't guaranteed status_t
// passed buffer, we use our thread's fpu_state field as temporary arch_get_thread_debug_cpu_state(Thread* thread, debug_cpu_state* cpuState)
// buffer. We need to disable interrupts to make use of it. {
Thread* thread = thread_get_current_thread(); iframe* frame = x86_get_thread_user_iframe(thread);
InterruptsLocker locker; if (frame == NULL)
x86_fxsave(thread->arch_info.fpu_state); return B_BAD_VALUE;
// unlike fnsave, fxsave doesn't reinit the FPU state
memcpy(&cpuState->extended_registers, thread->arch_info.fpu_state, get_cpu_state(thread, frame, cpuState);
sizeof(cpuState->extended_registers)); return B_OK;
} 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);
}
} }