Index: kernel/fiasco/src/Kconfig =================================================================== --- kernel/fiasco/src/Kconfig (revision 40) +++ kernel/fiasco/src/Kconfig (working copy) @@ -685,6 +685,14 @@ 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 Index: kernel/fiasco/src/kern/ia32/config-ia32.cpp =================================================================== --- kernel/fiasco/src/kern/ia32/config-ia32.cpp (revision 40) +++ kernel/fiasco/src/kern/ia32/config-ia32.cpp (working copy) @@ -86,6 +86,12 @@ // 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; Index: kernel/fiasco/src/kern/ia32/32/entry-native.S =================================================================== --- kernel/fiasco/src/kern/ia32/32/entry-native.S (revision 40) +++ kernel/fiasco/src/kern/ia32/32/entry-native.S (working copy) @@ -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 @@ 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 @@ -227,11 +260,17 @@ .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) // Fake user eflags, set IOPL to 3 pushl $(EFLAGS_IOPL_U | EFLAGS_IF) + + 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. Index: kernel/fiasco/src/kern/ia32/thread-ia32.cpp =================================================================== --- kernel/fiasco/src/kern/ia32/thread-ia32.cpp (revision 40) +++ kernel/fiasco/src/kern/ia32/thread-ia32.cpp (working copy) @@ -189,6 +189,10 @@ 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)) @@ -438,7 +442,8 @@ // 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) @@ -491,6 +496,11 @@ } } +IMPLEMENT inline +void +Thread::user_single_step(bool) +{} + //---------------------------------------------------------------------------- IMPLEMENTATION [(ia32,amd64,ux) && !io]: @@ -819,3 +829,16 @@ 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); +} Index: kernel/fiasco/src/kern/thread_object.cpp =================================================================== --- kernel/fiasco/src/kern/thread_object.cpp (revision 40) +++ kernel/fiasco/src/kern/thread_object.cpp (working copy) @@ -520,6 +520,8 @@ 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)) Index: kernel/fiasco/src/kern/thread.cpp =================================================================== --- kernel/fiasco/src/kern/thread.cpp (revision 40) +++ kernel/fiasco/src/kern/thread.cpp (working copy) @@ -72,6 +72,7 @@ { Exr_cancel = 0x10000, Exr_trigger_exception = 0x20000, + Exr_single_step = 0x40000, }; enum Vcpu_ctl_flags @@ -139,6 +140,8 @@ 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"); Index: kernel/fiasco/src/kern/arm/thread-arm.cpp =================================================================== --- kernel/fiasco/src/kern/arm/thread-arm.cpp (revision 40) +++ kernel/fiasco/src/kern/arm/thread-arm.cpp (working copy) @@ -590,6 +590,10 @@ return (v[insn >> 28] >> (psr >> 28)) & 1; } +IMPLEMENT inline +void Thread::user_single_step(bool) +{} + // ------------------------------------------------------------------------ IMPLEMENTATION [arm && armv6plus]: Index: kernel/fiasco/src/kern/ppc32/thread-ppc32.cpp =================================================================== --- kernel/fiasco/src/kern/ppc32/thread-ppc32.cpp (revision 40) +++ kernel/fiasco/src/kern/ppc32/thread-ppc32.cpp (working copy) @@ -308,6 +308,10 @@ } } +IMPLEMENT inline +void Thread::user_single_step(bool) +{} + PUBLIC inline NEEDS ["trap_state.h"] int Thread::send_exception_arch(Trap_state * /*ts*/)