diff options
Diffstat (limited to '')
-rw-r--r-- | cpukit/libdebugger/rtems-debugger-target.c | 125 |
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 |