From 8adcd665fbc0a55ecc65394d104da738dc7e6c7b Mon Sep 17 00:00:00 2001 From: Sebastian Sumpf Date: Fri, 11 Jan 2013 17:29:20 +0100 Subject: [PATCH] X86: Single stepping This patch enables the user land to use the CPU's single stepping mode on x86_32 platforms. It is needed to enable the use of GDB monitor for user-level debugging. Was: 'foc_single_step_x86.patch' --- kernel/fiasco/src/Kconfig | 8 ++++ kernel/fiasco/src/kern/arm/thread-arm.cpp | 4 ++ kernel/fiasco/src/kern/ia32/32/entry-native.S | 39 +++++++++++++++++++ kernel/fiasco/src/kern/ia32/config-ia32.cpp | 6 +++ kernel/fiasco/src/kern/ia32/thread-ia32.cpp | 25 +++++++++++- kernel/fiasco/src/kern/ppc32/thread-ppc32.cpp | 4 ++ kernel/fiasco/src/kern/thread.cpp | 3 ++ kernel/fiasco/src/kern/thread_object.cpp | 2 + 8 files changed, 90 insertions(+), 1 deletion(-) diff --git a/kernel/fiasco/src/Kconfig b/kernel/fiasco/src/Kconfig index b79185ac..2d6dc8ce 100644 --- a/kernel/fiasco/src/Kconfig +++ b/kernel/fiasco/src/Kconfig @@ -730,6 +730,14 @@ config POWERSAVE_GETCHAR prevent some P4 processors from being overheated. This option requires a working timer IRQ to wakeup getchar periodically. +config USER_SINGLE_STEP + bool "Enable user level single stepping support" + depends on IA32 + default n + help + This option enables single stepping of user level applications outside of + JDB. + choice prompt "Warn levels" default WARN_WARNING diff --git a/kernel/fiasco/src/kern/arm/thread-arm.cpp b/kernel/fiasco/src/kern/arm/thread-arm.cpp index 01895e41..4127551e 100644 --- a/kernel/fiasco/src/kern/arm/thread-arm.cpp +++ b/kernel/fiasco/src/kern/arm/thread-arm.cpp @@ -618,6 +618,10 @@ Thread::condition_valid(Unsigned32 insn, Unsigned32 psr) return (v[insn >> 28] >> (psr >> 28)) & 1; } +IMPLEMENT inline +void Thread::user_single_step(bool) +{} + // ------------------------------------------------------------------------ IMPLEMENTATION [arm && armv6plus]: diff --git a/kernel/fiasco/src/kern/ia32/32/entry-native.S b/kernel/fiasco/src/kern/ia32/32/entry-native.S index 5fb9958d..1b996527 100644 --- a/kernel/fiasco/src/kern/ia32/32/entry-native.S +++ b/kernel/fiasco/src/kern/ia32/32/entry-native.S @@ -46,6 +46,30 @@ jmp slowtraps .endm +#ifdef CONFIG_USER_SINGLE_STEP +.macro HANDLE_USER_TRAP1 + /* Save EFLAGS, this may trap if user task had single stepping activated + * test for single stepping + */ + pushf + addl $4, %esp + testl $EFLAGS_TF, -4(%esp) +.endm + +.macro RESTORE_USER_TRAP1 + /* Restore single stepping if it has been set */ + je 1f + orl $EFLAGS_TF, (%esp) +1: +.endm +#else +.macro HANDLE_USER_TRAP1 +.endm + +.macro RESTORE_USER_TRAP1 +.endm +#endif + .p2align 4 .globl entry_vec01_debug entry_vec01_debug: @@ -59,6 +83,15 @@ entry_vec01_debug: cmpl $entry_sys_fast_ipc_log, (%esp) je 2f #endif + + /* test if trap was raised within kernel */ + testl $3, 4(%esp) + jne 1f + + /* turn of EFLAGS.TF */ + btrl $7, 8(%esp) + iret + 1: pushl $0 pushl $1 pusha @@ -226,10 +259,16 @@ alien_sys_fast_ipc_log: .p2align(4) .global entry_sys_fast_ipc_c entry_sys_fast_ipc_c: + + HANDLE_USER_TRAP1 + pop %esp pushl $(GDT_DATA_USER|SEL_PL_U) /* user ss */ pushl %ebp // push user SP (get in ebp) pushf // fake user eflags + + RESTORE_USER_TRAP1 + cld // Fake user cs. This cs value is never used with exception // that the thread is ex_regs'd before we leave with sysexit. diff --git a/kernel/fiasco/src/kern/ia32/config-ia32.cpp b/kernel/fiasco/src/kern/ia32/config-ia32.cpp index 8a32b753..2e03a171 100644 --- a/kernel/fiasco/src/kern/ia32/config-ia32.cpp +++ b/kernel/fiasco/src/kern/ia32/config-ia32.cpp @@ -86,6 +86,12 @@ public: // static const bool hlt_works_ok = false; static bool hlt_works_ok; +#ifdef CONFIG_USER_SINGLE_STEP + static const bool user_single_step = true; +#else + static const bool user_single_step = false; +#endif + // the default uart to use for serial console static const unsigned default_console_uart = 1; static const unsigned default_console_uart_baudrate = 115200; diff --git a/kernel/fiasco/src/kern/ia32/thread-ia32.cpp b/kernel/fiasco/src/kern/ia32/thread-ia32.cpp index 3594b7d0..60bcaf1d 100644 --- a/kernel/fiasco/src/kern/ia32/thread-ia32.cpp +++ b/kernel/fiasco/src/kern/ia32/thread-ia32.cpp @@ -191,6 +191,10 @@ Thread::handle_slow_trap(Trap_state *ts) goto generic_debug; } + if (Config::user_single_step && ts->_trapno == 1 && from_user) + if (send_exception(ts)) + goto success; + if (from_user && _space.user_mode()) { if (ts->_trapno == 14 && Kmem::is_io_bitmap_page_fault(ts->_cr2)) @@ -431,7 +435,8 @@ Thread::send_exception_arch(Trap_state *ts) // thread (not alien) and it's a debug trap, // debug traps for aliens are always reflected as exception IPCs if (!(state() & Thread_alien) - && (ts->_trapno == 1 || ts->_trapno == 3)) + && ((ts->_trapno == 1 && !Config::user_single_step) + || ts->_trapno == 3)) return 0; // we do not handle this if (ts->_trapno == 3) @@ -503,6 +508,11 @@ Thread::user_ip(Mword ip) } } +IMPLEMENT inline +void +Thread::user_single_step(bool) +{} + //---------------------------------------------------------------------------- IMPLEMENTATION [(ia32,amd64,ux) && !io]: @@ -855,3 +865,16 @@ PRIVATE static inline int Thread::call_nested_trap_handler(Trap_state *) { return -1; } + +//--------------------------------------------------------------------------- +IMPLEMENTATION [ia32]: + +IMPLEMENT inline +void +Thread::user_single_step(bool enable) +{ + if (!Config::user_single_step) + return; + + regs()->flags(enable ? user_flags() | EFLAGS_TF : user_flags() & ~EFLAGS_TF); +} diff --git a/kernel/fiasco/src/kern/ppc32/thread-ppc32.cpp b/kernel/fiasco/src/kern/ppc32/thread-ppc32.cpp index 63b0938c..55db9166 100644 --- a/kernel/fiasco/src/kern/ppc32/thread-ppc32.cpp +++ b/kernel/fiasco/src/kern/ppc32/thread-ppc32.cpp @@ -306,6 +306,10 @@ Thread::user_ip(Mword ip) } } +IMPLEMENT inline +void Thread::user_single_step(bool) +{} + PUBLIC inline NEEDS ["trap_state.h"] int Thread::send_exception_arch(Trap_state * /*ts*/) diff --git a/kernel/fiasco/src/kern/thread.cpp b/kernel/fiasco/src/kern/thread.cpp index 5f911b26..92e33d30 100644 --- a/kernel/fiasco/src/kern/thread.cpp +++ b/kernel/fiasco/src/kern/thread.cpp @@ -73,6 +73,7 @@ public: { Exr_cancel = 0x10000, Exr_trigger_exception = 0x20000, + Exr_single_step = 0x40000, }; enum Vcpu_ctl_flags @@ -140,6 +141,8 @@ public: inline Mword user_flags() const; + inline void user_single_step(bool); + /** nesting level in debugger (always critical) if >1 */ static Per_cpu nested_trap_recover; static void handle_remote_requests_irq() asm ("handle_remote_cpu_requests"); diff --git a/kernel/fiasco/src/kern/thread_object.cpp b/kernel/fiasco/src/kern/thread_object.cpp index 6d6fa049..0907d14a 100644 --- a/kernel/fiasco/src/kern/thread_object.cpp +++ b/kernel/fiasco/src/kern/thread_object.cpp @@ -529,6 +529,8 @@ Thread_object::ex_regs(Address ip, Address sp, if (o_ip) *o_ip = user_ip(); if (o_flags) *o_flags = user_flags(); + (ops & Exr_single_step) ? user_single_step(true) : user_single_step(false); + // Changing the run state is only possible when the thread is not in // an exception. if (!(ops & Exr_cancel) && (state() & Thread_in_exception))