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'
This commit is contained in:
Sebastian Sumpf
2013-01-11 17:29:20 +01:00
parent c9830dbc1e
commit 10d7926ce0
8 changed files with 90 additions and 1 deletions

View File

@@ -685,6 +685,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

View File

@@ -594,6 +594,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]:

View File

@@ -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
@@ -227,11 +260,17 @@ 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)
// 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.

View File

@@ -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;

View File

@@ -189,6 +189,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))
@@ -438,7 +442,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)
@@ -491,6 +496,11 @@ Thread::user_ip(Mword ip)
}
}
IMPLEMENT inline
void
Thread::user_single_step(bool)
{}
//----------------------------------------------------------------------------
IMPLEMENTATION [(ia32,amd64,ux) && !io]:
@@ -819,3 +829,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);
}

View File

@@ -308,6 +308,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*/)

View File

@@ -72,6 +72,7 @@ public:
{
Exr_cancel = 0x10000,
Exr_trigger_exception = 0x20000,
Exr_single_step = 0x40000,
};
enum Vcpu_ctl_flags
@@ -139,6 +140,8 @@ public:
inline Mword user_flags() const;
inline void user_single_step(bool);
/** nesting level in debugger (always critical) if >1 */
static Per_cpu<unsigned long> nested_trap_recover;
static void handle_remote_requests_irq() asm ("handle_remote_cpu_requests");

View File

@@ -520,6 +520,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))