Author: bonefish Date: 2010-10-30 13:31:01 +0200 (Sat, 30 Oct 2010) New Revision: 39201 Changeset: http://dev.haiku-os.org/changeset/39201 Ticket: http://dev.haiku-os.org/ticket/6751 Modified: haiku/trunk/headers/private/kernel/thread_types.h haiku/trunk/src/system/kernel/arch/x86/arch_interrupts.S haiku/trunk/src/system/kernel/arch/x86/arch_user_debugger.cpp haiku/trunk/src/system/kernel/debug/user_debugger.cpp Log: * Added new thread flag THREAD_FLAGS_SINGLE_STEP, which is set to indicate that userland single-stepping is enabled for the thread. * x86_exit_user_debug_at_kernel_entry(): Always store DR6 and DR7 in the CPU structure, not only when breakpoints are installed. * x86_handle_debug_exception(): When encountering a syscall single-step, also set the THREAD_FLAGS_DEBUG_THREAD thread flag. Otherwise the B_THREAD_DEBUG_STOP would be ignored. * x86 interrupt handling, DISABLE_BREAKPOINTS(): - Renamed to STOP_USER_DEBUGGING(). - Now it also call x86_exit_user_debug_at_kernel_entry() when THREAD_FLAGS_SINGLE_STEP is set, so that the debug registers are saved. Fixes #6751. Modified: haiku/trunk/headers/private/kernel/thread_types.h =================================================================== --- haiku/trunk/headers/private/kernel/thread_types.h 2010-10-30 10:33:04 UTC (rev 39200) +++ haiku/trunk/headers/private/kernel/thread_types.h 2010-10-30 11:31:01 UTC (rev 39201) @@ -352,27 +352,29 @@ #define THREAD_FLAGS_DEBUG_THREAD 0x0002 // forces the thread into the debugger as soon as possible (set by // debug_thread()) -#define THREAD_FLAGS_DEBUGGER_INSTALLED 0x0004 +#define THREAD_FLAGS_SINGLE_STEP 0x0004 + // indicates that the thread is in single-step mode (in userland) +#define THREAD_FLAGS_DEBUGGER_INSTALLED 0x0008 // a debugger is installed for the current team (computed flag for // optimization purposes) -#define THREAD_FLAGS_BREAKPOINTS_DEFINED 0x0008 +#define THREAD_FLAGS_BREAKPOINTS_DEFINED 0x0010 // hardware breakpoints are defined for the current team (computed flag for // optimization purposes) -#define THREAD_FLAGS_BREAKPOINTS_INSTALLED 0x0010 +#define THREAD_FLAGS_BREAKPOINTS_INSTALLED 0x0020 // breakpoints are currently installed for the thread (i.e. the hardware is // actually set up to trigger debug events for them) -#define THREAD_FLAGS_64_BIT_SYSCALL_RETURN 0x0020 +#define THREAD_FLAGS_64_BIT_SYSCALL_RETURN 0x0040 // set by 64 bit return value syscalls -#define THREAD_FLAGS_RESTART_SYSCALL 0x0040 +#define THREAD_FLAGS_RESTART_SYSCALL 0x0080 // set by handle_signals(), if the current syscall shall be restarted -#define THREAD_FLAGS_DONT_RESTART_SYSCALL 0x0080 +#define THREAD_FLAGS_DONT_RESTART_SYSCALL 0x0100 // explicitly disables automatic syscall restarts (e.g. resume_thread()) -#define THREAD_FLAGS_ALWAYS_RESTART_SYSCALL 0x0100 +#define THREAD_FLAGS_ALWAYS_RESTART_SYSCALL 0x0200 // force syscall restart, even if a signal handler without SA_RESTART was // invoked (e.g. sigwait()) -#define THREAD_FLAGS_SYSCALL_RESTARTED 0x0200 +#define THREAD_FLAGS_SYSCALL_RESTARTED 0x0400 // the current syscall has been restarted -#define THREAD_FLAGS_SYSCALL 0x0400 +#define THREAD_FLAGS_SYSCALL 0x0800 // the thread is currently in a syscall; set/reset only for certain // functions (e.g. ioctl()) to allow inner functions to discriminate // whether e.g. parameters were passed from userland or kernel Modified: haiku/trunk/src/system/kernel/arch/x86/arch_interrupts.S =================================================================== --- haiku/trunk/src/system/kernel/arch/x86/arch_interrupts.S 2010-10-30 10:33:04 UTC (rev 39200) +++ haiku/trunk/src/system/kernel/arch/x86/arch_interrupts.S 2010-10-30 11:31:01 UTC (rev 39201) @@ -98,8 +98,9 @@ original eax/edx values */ \ iret -#define DISABLE_BREAKPOINTS() \ - testl $THREAD_FLAGS_BREAKPOINTS_INSTALLED, THREAD_flags(%edi); \ +#define STOP_USER_DEBUGGING() \ + testl $(THREAD_FLAGS_BREAKPOINTS_INSTALLED \ + | THREAD_FLAGS_SINGLE_STEP), THREAD_flags(%edi); \ jz 1f; \ call x86_exit_user_debug_at_kernel_entry; \ 1: @@ -521,7 +522,7 @@ // disable breakpoints, if installed movl %dr3, %edi // thread pointer cli // disable interrupts - DISABLE_BREAKPOINTS() + STOP_USER_DEBUGGING() // update the thread's user time UPDATE_THREAD_USER_TIME() @@ -615,7 +616,7 @@ // disable breakpoints, if installed cli // disable interrupts - DISABLE_BREAKPOINTS() + STOP_USER_DEBUGGING() // update the thread's user time UPDATE_THREAD_USER_TIME_PUSH_TIME() Modified: haiku/trunk/src/system/kernel/arch/x86/arch_user_debugger.cpp =================================================================== --- haiku/trunk/src/system/kernel/arch/x86/arch_user_debugger.cpp 2010-10-30 10:33:04 UTC (rev 39200) +++ haiku/trunk/src/system/kernel/arch/x86/arch_user_debugger.cpp 2010-10-30 11:31:01 UTC (rev 39201) @@ -571,7 +571,8 @@ if (struct iframe* frame = i386_get_user_iframe()) { struct thread* thread = thread_get_current_thread(); - // set/clear TF in EFLAGS depending on if single stepping is desired + // set/clear TF in EFLAGS depending on whether single stepping is + // desired if (thread->debug_info.flags & B_THREAD_DEBUG_SINGLE_STEP) frame->flags |= (1 << X86_EFLAGS_TF); else @@ -803,15 +804,17 @@ { struct thread *thread = thread_get_current_thread(); - if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_INSTALLED)) - return; - // We need to save the current values of dr6 and dr7 in the CPU structure, // since in case of a debug exception we might overwrite them before - // x86_handle_debug_exception() is called. + // x86_handle_debug_exception() is called. Debug exceptions occur when + // hitting a hardware break/watchpoint or when single-stepping. asm("movl %%dr6, %0" : "=r"(thread->cpu->arch.dr6)); asm("movl %%dr7, %0" : "=r"(thread->cpu->arch.dr7)); + // The remainder needs only be done, when user breakpoints are installed. + if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_INSTALLED)) + return; + GRAB_THREAD_LOCK(); // disable user breakpoints @@ -910,7 +913,7 @@ if (thread->team != team_get_kernel_team() && i386_get_user_iframe() == NULL) { // TODO: This is not yet fully correct, since a newly created - // thread that doesn't have entered userland yet also has this + // thread that hasn't entered userland yet also has this // property. inKernel = false; } @@ -937,6 +940,9 @@ atomic_or(&thread->debug_info.flags, B_THREAD_DEBUG_NOTIFY_SINGLE_STEP | B_THREAD_DEBUG_STOP); + + // also set the respective thread flag + atomic_or(&thread->flags, THREAD_FLAGS_DEBUG_THREAD); } } } Modified: haiku/trunk/src/system/kernel/debug/user_debugger.cpp =================================================================== --- haiku/trunk/src/system/kernel/debug/user_debugger.cpp 2010-10-30 10:33:04 UTC (rev 39200) +++ haiku/trunk/src/system/kernel/debug/user_debugger.cpp 2010-10-30 11:31:01 UTC (rev 39201) @@ -749,9 +749,10 @@ if (singleStep) { atomic_or(&thread->debug_info.flags, B_THREAD_DEBUG_SINGLE_STEP); + atomic_or(&thread->flags, THREAD_FLAGS_SINGLE_STEP); } else { atomic_and(&thread->debug_info.flags, - ~B_THREAD_DEBUG_SINGLE_STEP); + ~(int32)B_THREAD_DEBUG_SINGLE_STEP); } // unset the "stopped" state @@ -1282,6 +1283,10 @@ void user_debug_single_stepped() { + // clear the single-step thread flag + struct thread* thread = thread_get_current_thread(); + atomic_and(&thread->flags, ~(int32)THREAD_FLAGS_SINGLE_STEP); + // prepare the message debug_single_step message; arch_get_debug_cpu_state(&message.cpu_state);