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:
@@ -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
|
||||
|
||||
@@ -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]:
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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*/)
|
||||
|
||||
@@ -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<unsigned long> nested_trap_recover;
|
||||
static void handle_remote_requests_irq() asm ("handle_remote_cpu_requests");
|
||||
|
||||
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user