Index: kernel/fiasco/src/Kconfig =================================================================== --- kernel/fiasco/src/Kconfig (revision 38) +++ kernel/fiasco/src/Kconfig (working copy) @@ -694,6 +694,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 38) +++ kernel/fiasco/src/kern/ia32/config-ia32.cpp (working copy) @@ -98,6 +98,12 @@ static const bool kinfo_timer_uses_rdtsc = false; #endif +#ifdef CONFIG_USER_SINGLE_STEP + static const bool user_single_step = true; +#else + static const bool user_single_step = false; +#endif + static const bool old_sigma0_adapter_hack = false; // the default uart to use for serial console Index: kernel/fiasco/src/kern/ia32/32/entry-native.S =================================================================== --- kernel/fiasco/src/kern/ia32/32/entry-native.S (revision 38) +++ 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: @@ -55,6 +79,15 @@ cmpl $VAL__MEM_LAYOUT__TCBS_END, %esp jbe 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 @@ -214,11 +247,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 38) +++ kernel/fiasco/src/kern/ia32/thread-ia32.cpp (working copy) @@ -196,12 +196,19 @@ Address ip; int from_user = ts->cs() & 3; + //if (ts->_trapno != 3) + // LOG_MSG_3VAL(this, "trap", ts->_trapno, from_user, ts->ip()); + if (EXPECT_FALSE(ts->_trapno == 0xee)) //debug IPI { Ipi::eoi(Ipi::Debug); 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)) @@ -521,7 +528,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) @@ -574,6 +582,11 @@ } } +IMPLEMENT inline +void +Thread::user_single_step(bool) +{} + //---------------------------------------------------------------------------- IMPLEMENTATION [ia32]: @@ -586,6 +599,16 @@ _gs = _fs = Utcb_init::utcb_segment(); } +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); +} + //---------------------------------------------------------------------------- IMPLEMENTATION [amd64]: Index: kernel/fiasco/src/kern/thread_object.cpp =================================================================== --- kernel/fiasco/src/kern/thread_object.cpp (revision 38) +++ kernel/fiasco/src/kern/thread_object.cpp (working copy) @@ -524,6 +524,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 38) +++ kernel/fiasco/src/kern/thread.cpp (working copy) @@ -70,6 +70,7 @@ { Exr_cancel = 0x10000, Exr_trigger_exception = 0x20000, + Exr_single_step = 0x40000, }; enum Vcpu_ctl_flags @@ -137,6 +138,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 38) +++ kernel/fiasco/src/kern/arm/thread-arm.cpp (working copy) @@ -549,6 +549,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 38) +++ kernel/fiasco/src/kern/ppc32/thread-ppc32.cpp (working copy) @@ -307,6 +307,10 @@ } } +IMPLEMENT inline +void Thread::user_single_step(bool) +{} + PUBLIC inline NEEDS ["trap_state.h"] int Thread::send_exception_arch(Trap_state * /*ts*/)