forked from Imagelibrary/rtems
cpukit/libdebugger: Avoid cascade for interrupts
This updates behavior of libdebugger to handle debug exceptions in interrupt context by temporarily removing a software breakpoint, stepping, and then resuming afterward.
This commit is contained in:
committed by
Joel Sherrill
parent
dbdf38ea7b
commit
16d40ce7ff
@@ -167,6 +167,32 @@ rtems_debugger_target_reg_table_size(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_debugger_target_swbreak_is_configured( uintptr_t addr )
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
rtems_debugger_target_swbreak *swbreaks;
|
||||||
|
rtems_debugger_target *target = rtems_debugger->target;
|
||||||
|
|
||||||
|
if ( target == NULL ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
swbreaks = target->swbreaks.block;
|
||||||
|
|
||||||
|
if ( swbreaks == NULL ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( i = 0; i < target->swbreaks.level; ++i ) {
|
||||||
|
if ( (uintptr_t) swbreaks[ i ].address == addr ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
rtems_debugger_target_swbreak_control(bool insert, uintptr_t addr, DB_UINT kind)
|
rtems_debugger_target_swbreak_control(bool insert, uintptr_t addr, DB_UINT kind)
|
||||||
{
|
{
|
||||||
@@ -323,13 +349,81 @@ rtems_debugger_target_swbreak_remove(void)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uintptr_t saved_break_address = 0;
|
||||||
|
rtems_id saved_tid = 0;
|
||||||
|
|
||||||
|
static rtems_debugger_target_exc_action
|
||||||
|
soft_step_and_continue(CPU_Exception_frame* frame)
|
||||||
|
{
|
||||||
|
uintptr_t break_address;
|
||||||
|
rtems_debugger_target *target = rtems_debugger->target;
|
||||||
|
Thread_Control *thread = _Thread_Get_executing();
|
||||||
|
const rtems_id tid = thread->Object.id;
|
||||||
|
rtems_debugger_thread fake_debugger_thread;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this was a hwbreak, cascade. If this is a swbreak replace the contents
|
||||||
|
* of the instruction, step then return the swbreak's contents.
|
||||||
|
*/
|
||||||
|
if ((target->capabilities & RTEMS_DEBUGGER_TARGET_CAP_SWBREAK) == 0) {
|
||||||
|
target_printk("rtems-db: exception in an interrupt, cascading\n");
|
||||||
|
rtems_debugger_unlock();
|
||||||
|
return rtems_debugger_target_exc_cascade;
|
||||||
|
}
|
||||||
|
|
||||||
|
break_address = rtems_debugger_target_frame_pc( frame );
|
||||||
|
if ( rtems_debugger_target_swbreak_is_configured( break_address ) == false ) {
|
||||||
|
target_printk("rtems-db: exception in an interrupt, cascading\n");
|
||||||
|
rtems_debugger_unlock();
|
||||||
|
return rtems_debugger_target_exc_cascade;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove the current breakpoint */
|
||||||
|
rtems_debugger_target_swbreak_control(
|
||||||
|
false,
|
||||||
|
break_address,
|
||||||
|
target->breakpoint_size
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Save off thread ID and break address for later usage */
|
||||||
|
saved_tid = tid;
|
||||||
|
saved_break_address = break_address;
|
||||||
|
|
||||||
|
/* Populate the fake rtems_debugger_thread */
|
||||||
|
fake_debugger_thread.flags |= RTEMS_DEBUGGER_THREAD_FLAG_STEP;
|
||||||
|
fake_debugger_thread.frame = frame;
|
||||||
|
target_printk("rtems-db: stepping to the next instruction\n");
|
||||||
|
rtems_debugger_target_thread_stepping(&fake_debugger_thread);
|
||||||
|
|
||||||
|
/* rtems_debugger_unlock() not called until the step is resolved */
|
||||||
|
return rtems_debugger_target_exc_step;
|
||||||
|
}
|
||||||
|
|
||||||
rtems_debugger_target_exc_action
|
rtems_debugger_target_exc_action
|
||||||
rtems_debugger_target_exception(CPU_Exception_frame* frame)
|
rtems_debugger_target_exception(CPU_Exception_frame* frame)
|
||||||
{
|
{
|
||||||
|
Thread_Control* thread = _Thread_Get_executing();
|
||||||
|
const rtems_id tid = thread->Object.id;
|
||||||
|
|
||||||
|
/* Resolve outstanding step+continue */
|
||||||
|
if ( saved_break_address != 0 && tid == saved_tid ) {
|
||||||
|
rtems_debugger_target_swbreak_control(
|
||||||
|
true,
|
||||||
|
saved_break_address,
|
||||||
|
rtems_debugger->target->breakpoint_size
|
||||||
|
);
|
||||||
|
saved_break_address = saved_tid = 0;
|
||||||
|
|
||||||
|
/* Release the debugger lock now that the step+continue is complete */
|
||||||
|
target_printk("rtems-db: resuming after step\n");
|
||||||
|
rtems_debugger_unlock();
|
||||||
|
return rtems_debugger_target_exc_consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtems_debugger_lock();
|
||||||
|
|
||||||
if (!rtems_interrupt_is_in_progress()) {
|
if (!rtems_interrupt_is_in_progress()) {
|
||||||
rtems_debugger_threads* threads = rtems_debugger->threads;
|
rtems_debugger_threads* threads = rtems_debugger->threads;
|
||||||
Thread_Control* thread = _Thread_Get_executing();
|
|
||||||
const rtems_id tid = thread->Object.id;
|
|
||||||
rtems_id* excludes;
|
rtems_id* excludes;
|
||||||
uintptr_t pc;
|
uintptr_t pc;
|
||||||
const rtems_debugger_thread_stepper* stepper;
|
const rtems_debugger_thread_stepper* stepper;
|
||||||
@@ -340,8 +434,6 @@ rtems_debugger_target_exception(CPU_Exception_frame* frame)
|
|||||||
" frame:%08" PRIxPTR "\n",
|
" frame:%08" PRIxPTR "\n",
|
||||||
tid, (intptr_t) thread, (intptr_t) frame);
|
tid, (intptr_t) thread, (intptr_t) frame);
|
||||||
|
|
||||||
rtems_debugger_lock();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the thread is in the debugger recover. If the access is from gdb
|
* If the thread is in the debugger recover. If the access is from gdb
|
||||||
* continue else shutdown and let the user know.
|
* continue else shutdown and let the user know.
|
||||||
@@ -430,9 +522,10 @@ rtems_debugger_target_exception(CPU_Exception_frame* frame)
|
|||||||
return rtems_debugger_target_exc_consumed;
|
return rtems_debugger_target_exc_consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtems_debugger_printf("rtems-db: exception in an interrupt, cascading\n");
|
target_printk("[} tid:%08" PRIx32 ": exception in interrupt context\n", tid);
|
||||||
|
|
||||||
return rtems_debugger_target_exc_cascade;
|
/* soft_step_and_continue releases the debugger lock */
|
||||||
|
return soft_step_and_continue( frame );
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -221,6 +221,11 @@ extern int rtems_debugger_target_swbreak_insert(void);
|
|||||||
*/
|
*/
|
||||||
extern int rtems_debugger_target_swbreak_remove(void);
|
extern int rtems_debugger_target_swbreak_remove(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether a software breakpoint is configured for the given address.
|
||||||
|
*/
|
||||||
|
extern bool rtems_debugger_target_swbreak_is_configured( uintptr_t addr );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert hardware breakpoints into the hardware.
|
* Insert hardware breakpoints into the hardware.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user