summaryrefslogtreecommitdiffstats
path: root/cpukit/libdebugger/rtems-debugger-target.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libdebugger/rtems-debugger-target.c')
-rw-r--r--cpukit/libdebugger/rtems-debugger-target.c125
1 files changed, 117 insertions, 8 deletions
diff --git a/cpukit/libdebugger/rtems-debugger-target.c b/cpukit/libdebugger/rtems-debugger-target.c
index bf7579700d..2b55c93513 100644
--- a/cpukit/libdebugger/rtems-debugger-target.c
+++ b/cpukit/libdebugger/rtems-debugger-target.c
@@ -167,8 +167,34 @@ rtems_debugger_target_reg_table_size(void)
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
-rtems_debugger_target_swbreak_control(bool insert, DB_UINT addr, DB_UINT kind)
+rtems_debugger_target_swbreak_control(bool insert, uintptr_t addr, DB_UINT kind)
{
rtems_debugger_target* target = rtems_debugger->target;
rtems_debugger_target_swbreak* swbreaks;
@@ -191,6 +217,22 @@ rtems_debugger_target_swbreak_control(bool insert, DB_UINT addr, DB_UINT kind)
if (loc == swbreaks[i].address) {
size_t remaining;
if (!insert) {
+ if (target->breakpoint_size > 4)
+ memcpy(loc, swbreaks[i].contents, target->breakpoint_size);
+ else {
+ switch (target->breakpoint_size) {
+ case 4:
+ loc[3] = swbreaks[i].contents[3];
+ case 3:
+ loc[2] = swbreaks[i].contents[2];
+ case 2:
+ loc[1] = swbreaks[i].contents[1];
+ case 1:
+ loc[0] = swbreaks[i].contents[0];
+ break;
+ }
+ }
+ rtems_debugger_target_cache_sync(&swbreaks[i]);
--target->swbreaks.level;
remaining = (target->swbreaks.level - i) * swbreak_size;
memmove(&swbreaks[i], &swbreaks[i + 1], remaining);
@@ -307,15 +349,83 @@ rtems_debugger_target_swbreak_remove(void)
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_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()) {
rtems_debugger_threads* threads = rtems_debugger->threads;
- Thread_Control* thread = _Thread_Get_executing();
- const rtems_id tid = thread->Object.id;
rtems_id* excludes;
- DB_UINT pc;
+ uintptr_t pc;
const rtems_debugger_thread_stepper* stepper;
rtems_debugger_exception target_exception;
size_t i;
@@ -324,8 +434,6 @@ rtems_debugger_target_exception(CPU_Exception_frame* frame)
" frame:%08" PRIxPTR "\n",
tid, (intptr_t) thread, (intptr_t) frame);
- rtems_debugger_lock();
-
/*
* If the thread is in the debugger recover. If the access is from gdb
* continue else shutdown and let the user know.
@@ -414,9 +522,10 @@ rtems_debugger_target_exception(CPU_Exception_frame* frame)
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