From 0b11ecb18c9afe14114fac959f698a2bfa5b7230 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 21 Jul 2009 22:18:39 +0000 Subject: [PATCH] * Always include the public arch_debugger.h headers. The structures defined there are prefixed with the respective architecture name. Useful for remote debugging a different architecture. * : Introduced a structure for the FPU state, so that it isn't left to the debugger. * Removed the _kern_get_thread_cpu_state() syscall. Was originally intended for bdb compatiblity, but isn't really needed. * Kernel x86 arch_get_debug_cpu_state(): The use of fnsave was broken, since it reinits the FPU after saving the state. This resulted in weird results when debugging functions using the FPU. We now use fxsave, if available. Otherwise fnsave + frstor should be used -- not fully implemented yet. Same for arch_set_debug_cpu_state(). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31682 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/arch/m68k/arch_debugger.h | 6 +- headers/os/arch/mipsel/arch_debugger.h | 6 +- headers/os/arch/ppc/arch_debugger.h | 6 +- headers/os/arch/x86/arch_debugger.h | 44 ++++++++++- headers/os/kernel/debugger.h | 16 ++-- headers/private/kernel/arch/user_debugger.h | 6 +- headers/private/kernel/user_debugger.h | 2 - headers/private/system/syscalls.h | 5 +- src/bin/gdb/gdb/i386-haiku-nat.c | 8 +- .../kernel/arch/m68k/arch_user_debugger.cpp | 12 +-- .../kernel/arch/ppc/arch_user_debugger.cpp | 12 +-- .../kernel/arch/x86/arch_user_debugger.cpp | 73 +++++++++++-------- src/system/kernel/debug/user_debugger.cpp | 44 +---------- 13 files changed, 118 insertions(+), 122 deletions(-) diff --git a/headers/os/arch/m68k/arch_debugger.h b/headers/os/arch/m68k/arch_debugger.h index 8843571eb8..cc2ad42952 100644 --- a/headers/os/arch/m68k/arch_debugger.h +++ b/headers/os/arch/m68k/arch_debugger.h @@ -1,11 +1,11 @@ /* - * Copyright 2005, Haiku Inc. + * Copyright 2005-2009, Haiku Inc. * Distributed under the terms of the MIT License. */ #ifndef _ARCH_M68K_DEBUGGER_H #define _ARCH_M68K_DEBUGGER_H -struct debug_cpu_state { +struct m68k_debug_cpu_state { uint32 d0; uint32 d1; uint32 d2; @@ -24,7 +24,7 @@ struct debug_cpu_state { uint32 a7; uint32 pc; uint16 sr; -#warning M68K: missing members! +//#warning M68K: missing members! uint32 dummy; } __attribute__((aligned(8))); diff --git a/headers/os/arch/mipsel/arch_debugger.h b/headers/os/arch/mipsel/arch_debugger.h index 17a8210873..29f87d71e4 100644 --- a/headers/os/arch/mipsel/arch_debugger.h +++ b/headers/os/arch/mipsel/arch_debugger.h @@ -5,9 +5,11 @@ #ifndef _ARCH_MIPSEL_DEBUGGER_H #define _ARCH_MIPSEL_DEBUGGER_H -#warning MIPSEL: fixme -struct debug_cpu_state { + +//#warning MIPSEL: fixme +struct mipsel_debug_cpu_state { uint32 dummy; } __attribute__((aligned(8))); + #endif // _ARCH_MIPSEL_DEBUGGER_H diff --git a/headers/os/arch/ppc/arch_debugger.h b/headers/os/arch/ppc/arch_debugger.h index 0f82da4911..be5f704566 100644 --- a/headers/os/arch/ppc/arch_debugger.h +++ b/headers/os/arch/ppc/arch_debugger.h @@ -1,12 +1,14 @@ /* - * Copyright 2005, Haiku Inc. + * Copyright 2005-2009, Haiku Inc. * Distributed under the terms of the MIT License. */ #ifndef _ARCH_PPC_DEBUGGER_H #define _ARCH_PPC_DEBUGGER_H -struct debug_cpu_state { + +struct ppc_debug_cpu_state { uint32 dummy; } __attribute__((aligned(8))); + #endif // _ARCH_PPC_DEBUGGER_H diff --git a/headers/os/arch/x86/arch_debugger.h b/headers/os/arch/x86/arch_debugger.h index 13e4415176..dbe686e3b6 100644 --- a/headers/os/arch/x86/arch_debugger.h +++ b/headers/os/arch/x86/arch_debugger.h @@ -1,12 +1,47 @@ /* - * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. + * Copyright 2005-2009, Haiku Inc. * Distributed under the terms of the MIT License. */ #ifndef _ARCH_X86_DEBUGGER_H #define _ARCH_X86_DEBUGGER_H -struct debug_cpu_state { - uint8 extended_regs[512]; + +typedef struct x86_fp_register { + uint8 value[10]; + uint8 reserved[6]; +} x86_fp_register; + + +typedef struct x86_xmm_register { + uint8 value[16]; +} x86_xmm_register; + + +typedef struct x86_extended_registers { + uint16 control; + uint16 status; + uint8 tag; + uint8 reserved1; + uint16 opcode; + uint32 instruction_pointer; + uint16 cs; + uint16 reserved2; + uint32 data_pointer; + uint16 ds; + uint16 reserved3; + uint32 mxcsr; + uint32 mxcsr_mask; + union { + x86_fp_register fp_registers[8]; // st0-st7 + x86_fp_register mmx_registers[8]; // mm0-mm7 + }; + x86_xmm_register xmm_registers[8]; // xmm0-xmm7 + uint8 reserved4[224]; // 288 - 512 +} x86_extended_registers; + + +struct x86_debug_cpu_state { + x86_extended_registers extended_registers; uint32 gs; uint32 fs; @@ -27,6 +62,7 @@ struct debug_cpu_state { uint32 eflags; uint32 user_esp; uint32 user_ss; -} __attribute__((aligned(8))); +} __attribute__((aligned(16))); + #endif // _ARCH_X86_DEBUGGER_H diff --git a/headers/os/kernel/debugger.h b/headers/os/kernel/debugger.h index 65b9e0801a..ce903b3a92 100644 --- a/headers/os/kernel/debugger.h +++ b/headers/os/kernel/debugger.h @@ -11,19 +11,23 @@ #include // include architecture specific definitions +#include +#include +#include +#include + #ifdef __INTEL__ - #include + typedef struct x86_debug_cpu_state debug_cpu_state; #elif __POWERPC__ - #include + typedef struct ppc_debug_cpu_state debug_cpu_state; #elif __M68K__ - #include + typedef struct m68k_debug_cpu_state debug_cpu_state; #elif __MIPSEL__ - #include + typedef struct mipsel_debug_cpu_state debug_cpu_state; #else - #error you need to write a /arch_debugger.h> + #error unsupported architecture #endif -typedef struct debug_cpu_state debug_cpu_state; #ifdef __cplusplus extern "C" { diff --git a/headers/private/kernel/arch/user_debugger.h b/headers/private/kernel/arch/user_debugger.h index 93b1e87e50..7ab43e1f8a 100644 --- a/headers/private/kernel/arch/user_debugger.h +++ b/headers/private/kernel/arch/user_debugger.h @@ -26,10 +26,8 @@ void arch_destroy_thread_debug_info(struct arch_thread_debug_info *info); void arch_update_thread_single_step(); -void arch_set_debug_cpu_state(const 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); +void arch_set_debug_cpu_state(const debug_cpu_state *cpuState); +void arch_get_debug_cpu_state(debug_cpu_state *cpuState); status_t arch_set_breakpoint(void *address); status_t arch_clear_breakpoint(void *address); diff --git a/headers/private/kernel/user_debugger.h b/headers/private/kernel/user_debugger.h index 3de07f2a3b..5597fa5dea 100644 --- a/headers/private/kernel/user_debugger.h +++ b/headers/private/kernel/user_debugger.h @@ -252,8 +252,6 @@ status_t _user_install_default_debugger(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_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); status_t _user_set_debugger_breakpoint(void *address, uint32 type, diff --git a/headers/private/system/syscalls.h b/headers/private/system/syscalls.h index 558df6970e..97f1f79af7 100644 --- a/headers/private/system/syscalls.h +++ b/headers/private/system/syscalls.h @@ -7,9 +7,9 @@ #include +#include #include #include -#include #include #include @@ -19,7 +19,6 @@ extern "C" { #endif -struct debug_cpu_state; struct dirent; struct Elf32_Sym; struct fd_info; @@ -422,8 +421,6 @@ extern port_id _kern_install_team_debugger(team_id team, port_id debuggerPort); extern status_t _kern_remove_team_debugger(team_id team); 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 status_t _kern_set_debugger_breakpoint(void *address, uint32 type, diff --git a/src/bin/gdb/gdb/i386-haiku-nat.c b/src/bin/gdb/gdb/i386-haiku-nat.c index af72bd4b27..87ef19e6b4 100644 --- a/src/bin/gdb/gdb/i386-haiku-nat.c +++ b/src/bin/gdb/gdb/i386-haiku-nat.c @@ -28,7 +28,7 @@ #include "target.h" /* Offset in `struct debug_cpu_state' where MEMBER is stored. */ -#define REG_OFFSET(member) offsetof (struct debug_cpu_state, member) +#define REG_OFFSET(member) offsetof (struct x86_debug_cpu_state, member) /* At kHaikuI386RegOffset[REGNUM] you'll find the offset in `struct debug_cpu_state' where the GDB register REGNUM is stored. */ @@ -63,7 +63,8 @@ haiku_supply_registers(int reg, const debug_cpu_state *cpuState) int offset = kHaikuI386RegOffset[reg]; regcache_raw_supply (current_regcache, reg, (char*)cpuState + offset); } else { - i387_supply_fxsave (current_regcache, -1, cpuState->extended_regs); + i387_supply_fxsave (current_regcache, -1, + &cpuState->extended_registers); } } @@ -79,7 +80,8 @@ haiku_collect_registers(int reg, debug_cpu_state *cpuState) int offset = kHaikuI386RegOffset[reg]; regcache_raw_collect (current_regcache, reg, (char*)cpuState + offset); } else { - i387_collect_fsave (current_regcache, -1, cpuState->extended_regs); + i387_collect_fxsave (current_regcache, -1, + &cpuState->extended_registers); } } diff --git a/src/system/kernel/arch/m68k/arch_user_debugger.cpp b/src/system/kernel/arch/m68k/arch_user_debugger.cpp index e1909e4a3f..028c63c012 100644 --- a/src/system/kernel/arch/m68k/arch_user_debugger.cpp +++ b/src/system/kernel/arch/m68k/arch_user_debugger.cpp @@ -65,25 +65,17 @@ arch_update_thread_single_step() void -arch_set_debug_cpu_state(const struct debug_cpu_state *cpuState) +arch_set_debug_cpu_state(const debug_cpu_state *cpuState) { } void -arch_get_debug_cpu_state(struct debug_cpu_state *cpuState) +arch_get_debug_cpu_state(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 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 b4710494a3..99ae27b605 100644 --- a/src/system/kernel/arch/ppc/arch_user_debugger.cpp +++ b/src/system/kernel/arch/ppc/arch_user_debugger.cpp @@ -43,25 +43,17 @@ arch_update_thread_single_step() void -arch_set_debug_cpu_state(const struct debug_cpu_state *cpuState) +arch_set_debug_cpu_state(const debug_cpu_state *cpuState) { } void -arch_get_debug_cpu_state(struct debug_cpu_state *cpuState) +arch_get_debug_cpu_state(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 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 7a707bd64f..92298f158d 100644 --- a/src/system/kernel/arch/x86/arch_user_debugger.cpp +++ b/src/system/kernel/arch/x86/arch_user_debugger.cpp @@ -3,6 +3,7 @@ * Distributed under the terms of the MIT License. */ + #include #include @@ -12,6 +13,7 @@ #include #include #include +#include //#define TRACE_ARCH_USER_DEBUGGER @@ -28,7 +30,10 @@ #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. + // TODO: Make those real error codes. + + +extern bool gHasSSE; // The software breakpoint instruction (int3). const uint8 kX86SoftwareBreakpoint[1] = { 0xcc }; @@ -64,7 +69,7 @@ static bool sQEmuSingleStepHack = false; static void -get_iframe_registers(struct iframe *frame, struct debug_cpu_state *cpuState) +get_iframe_registers(struct iframe *frame, debug_cpu_state *cpuState) { cpuState->gs = frame->gs; cpuState->fs = frame->fs; @@ -576,12 +581,25 @@ arch_update_thread_single_step() void -arch_set_debug_cpu_state(const struct debug_cpu_state *cpuState) +arch_set_debug_cpu_state(const debug_cpu_state *cpuState) { if (struct iframe *frame = i386_get_user_iframe()) { - i386_frstor(cpuState->extended_regs); - // For this to be correct the calling function must not use these - // registers (not even indirectly). + // For the floating point state to be correct the calling function must + // not use these registers (not even indirectly). + if (gHasSSE) { + // Since fxrstor 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. + struct thread* thread = thread_get_current_thread(); + InterruptsLocker locker; + memcpy(thread->arch_info.fpu_state, &cpuState->extended_registers, + sizeof(&cpuState->extended_registers)); + i386_fxrstor(thread->arch_info.fpu_state); + } else { + // TODO: Implement! We need to convert the format first. +// i386_frstor(&cpuState->extended_registers); + } // frame->gs = cpuState->gs; // frame->fs = cpuState->fs; @@ -608,36 +626,33 @@ arch_set_debug_cpu_state(const struct debug_cpu_state *cpuState) void -arch_get_debug_cpu_state(struct debug_cpu_state *cpuState) +arch_get_debug_cpu_state(debug_cpu_state *cpuState) { if (struct iframe *frame = i386_get_user_iframe()) { - i386_fnsave(cpuState->extended_regs); - // For this to be correct the calling function must not use these - // registers (not even indirectly). + // For the floating point state to be correct the calling function must + // not use these registers (not even indirectly). + 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. + struct thread* thread = thread_get_current_thread(); + InterruptsLocker locker; + i386_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 { + i386_fnsave(&cpuState->extended_registers); + i386_frstor(&cpuState->extended_registers); + // fnsave reinits the FPU state after saving, so we need to + // load it again + // TODO: Convert to fxsave format! + } get_iframe_registers(frame, cpuState); } } -/*! \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 arch_set_breakpoint(void *address) { diff --git a/src/system/kernel/debug/user_debugger.cpp b/src/system/kernel/debug/user_debugger.cpp index d6214afb70..2de1c3221e 100644 --- a/src/system/kernel/debug/user_debugger.cpp +++ b/src/system/kernel/debug/user_debugger.cpp @@ -3,6 +3,7 @@ * Distributed under the terms of the MIT License. */ + #include #include #include @@ -2903,49 +2904,6 @@ _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 _user_wait_for_debugger(void) {