From b2353ed92435c3f9301b795bf20bce14f0ddb01b Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 17 Jul 2017 09:53:11 +1000 Subject: libdebugger: Fixes to debugging, ARM support, locking, and gcc-7.1 warnings. - Add `printk` support to aid multi-core debugging. - Add lock trace to aid lock debugging. - Fixes to gcc-7.1 warnings. - Fixes from ticket #2879. - Add verbose command controls. - Change using the RTEMS sys/lock.h API to manage exception threads. - ARM hardware breakpoint fixes. Support for SMP stepping is not implemented, this requires use of the context id register. Closes #2879. --- cpukit/libdebugger/rtems-debugger-arm.c | 245 ++++++++++++++++--------- cpukit/libdebugger/rtems-debugger-block.c | 3 +- cpukit/libdebugger/rtems-debugger-block.h | 3 +- cpukit/libdebugger/rtems-debugger-cmd.c | 21 ++- cpukit/libdebugger/rtems-debugger-i386.c | 3 +- cpukit/libdebugger/rtems-debugger-remote-tcp.c | 3 +- cpukit/libdebugger/rtems-debugger-remote-tcp.h | 3 +- cpukit/libdebugger/rtems-debugger-remote.c | 3 +- cpukit/libdebugger/rtems-debugger-remote.h | 3 +- cpukit/libdebugger/rtems-debugger-server.c | 232 +++++++++++------------ cpukit/libdebugger/rtems-debugger-server.h | 35 ++-- cpukit/libdebugger/rtems-debugger-target.c | 126 ++++++++----- cpukit/libdebugger/rtems-debugger-target.h | 22 ++- cpukit/libdebugger/rtems-debugger-threads.c | 61 +++--- cpukit/libdebugger/rtems-debugger-threads.h | 16 +- 15 files changed, 466 insertions(+), 313 deletions(-) (limited to 'cpukit/libdebugger') diff --git a/cpukit/libdebugger/rtems-debugger-arm.c b/cpukit/libdebugger/rtems-debugger-arm.c index 200d758a6b..6e5c9dc5ae 100644 --- a/cpukit/libdebugger/rtems-debugger-arm.c +++ b/cpukit/libdebugger/rtems-debugger-arm.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2016 Chris Johns . All rights reserved. + * Copyright (c) 2016-2017 Chris Johns . + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -221,13 +222,19 @@ static arm_debug_hwbreak hw_breaks[ARM_HW_BREAKPOINT_MAX]; //static arm_debug_hwbreak hw_watches[ARM_HW_WATCHPOINT_MAX]; #if TARGET_DEBUG +void rtems_debugger_printk_lock(rtems_interrupt_lock_context* lock_context); +void rtems_debugger_printk_unlock(rtems_interrupt_lock_context* lock_context); + static void target_printk(const char* format, ...) RTEMS_PRINTFLIKE(1, 2); static void target_printk(const char* format, ...) { + rtems_interrupt_lock_context lock_context; va_list ap; va_start(ap, format); + rtems_debugger_printk_lock(&lock_context); vprintk(format, ap); + rtems_debugger_printk_unlock(&lock_context); va_end(ap); } static const char* @@ -261,45 +268,66 @@ mode_label(int mode) #endif /* - * Read and write a CP14 register. - * - * The software debug event registers are not easy to program because there are - * up to 32 registers and the instructions have to assembler for each of the 32 - * registers, you cannot program it. This means there is a switch table to do - * this. + * CP register access. */ -#define ARM_CP14_INSTR(_opc, _val, _CRn, _CRm, _opc2) \ - #_opc " p14, 0, %[" #_val "], c" #_CRn ", c" #_CRm ", " #_opc2 "\n" +#define ARM_CP_INSTR(_opc, _cp, _op1, _val, _CRn, _CRm, _op2) \ + #_opc " p" #_cp ", " #_op1 ", %[" #_val "], c" #_CRn ", c" #_CRm ", " #_op2 "\n" -#define ARM_CP14_WRITE(_val, _CRn, _CRm, _opc2) \ +#define ARM_CP_WRITE(_cp, _op1, _val, _CRn, _CRm, _op2) \ do { \ ARM_SWITCH_REG; \ asm volatile( \ ASM_ARM_MODE \ - ARM_CP14_INSTR(mcr, val, _CRn, _CRm, _opc2) \ + ARM_CP_INSTR(mcr, _cp, _op1, val, _CRn, _CRm, _op2) \ ASM_THUMB_MODE \ : ARM_SWITCH_REG_ASM \ : [val] "r" (_val)); \ } while (0) -#define ARM_CP14_READ(_val, _CRn, _CRm, _opc2) \ +#define ARM_CP_READ(_cp, _op1, _val, _CRn, _CRm, _op2) \ do { \ ARM_SWITCH_REG; \ asm volatile( \ ASM_ARM_MODE \ - ARM_CP14_INSTR(mrc, val, _CRn, _CRm, _opc2) \ + ARM_CP_INSTR(mrc, _cp, _op1, val, _CRn, _CRm, _op2) \ ASM_THUMB_MODE \ : ARM_SWITCH_REG_ASM, \ [val] "=&r" (_val)); \ } while (0) +/* + * Read and write a CP14 register. + * + * The software debug event registers are not easy to program because there are + * up to 32 registers and the instructions have to assembler for each of the 32 + * registers, you cannot program it. This means there is a switch table to do + * this. + */ +#define ARM_CP14_WRITE(_val, _CRn, _CRm, _op2) \ + ARM_CP_WRITE(14, 0, _val, _CRn, _CRm, _op2) + +#define ARM_CP14_READ(_val, _CRn, _CRm, _op2) \ + ARM_CP_READ(14, 0, _val, _CRn, _CRm, _op2) + +/* + * Read and write a CP15 register. + * + * The Context ID register is a process level context and used to scope + * hardware break points. + */ +#define ARM_CP15_WRITE(_val, _op1, _CRn, _CRm, _op2) \ + ARM_CP_WRITE(15, _op1, _val, _CRn, _CRm, _op2) + +#define ARM_CP15_READ(_val, _op1, _CRn, _CRm, _op2) \ + ARM_CP_READ(15, _op1, _val, _CRn, _CRm, _op2) + static int arm_debug_probe(rtems_debugger_target* target) { #define ID_VALUE(_i, _h, _l) ((_i >> _l) & ((1 << ((_h - _l) + 1)) -1)) uint32_t val; - const char const* vl = "[Invalid version]"; - const char const* labels[] = { + const char* vl = "[Invalid version]"; + const char* const labels[] = { "ARMv6 [v6]", "ARMv6 [v6.1]", "ARMv7 [v7, all CP14 registers]", @@ -471,39 +499,63 @@ arm_debug_break_write_value(int bp, uint32_t value) static void arm_debug_break_clear(void) { - arm_debug_hwbreak* bp = &hw_breaks[0]; - int i; + rtems_interrupt_lock_context lock_context; + arm_debug_hwbreak* bp = &hw_breaks[0]; + int i; + rtems_interrupt_lock_acquire(&target_lock, &lock_context); for (i = 0; i < hw_breakpoints; ++i, ++bp) { bp->enabled = false; bp->loaded = false; } + rtems_interrupt_lock_release(&target_lock, &lock_context); } +static inline void +arm_debug_set_context_id(const uint32_t id) +{ + ARM_CP15_WRITE(id, 0, 13, 0, 1); +} + +/* + * You can only load the hardware breaks points when in the SVC mode or the + * single step inverted break point will trigger. + */ static void arm_debug_break_load(void) { - arm_debug_hwbreak* bp = &hw_breaks[0]; - int i; - for (i = 0; i < hw_breakpoints; ++i, ++bp) { + rtems_interrupt_lock_context lock_context; + arm_debug_hwbreak* bp = &hw_breaks[0]; + int i; + rtems_interrupt_lock_acquire(&target_lock, &lock_context); + if (bp->enabled && !bp->loaded) { + arm_debug_set_context_id(0xdead1111); + arm_debug_break_write_value(0, bp->value); + arm_debug_break_write_control(0, bp->control); + } + ++bp; + for (i = 1; i < hw_breakpoints; ++i, ++bp) { if (bp->enabled && !bp->loaded) { bp->loaded = true; - target_printk("]]} hwbp: %i: v:%08lx c:%08lx l:%08x\n", - i, bp->value, bp->control, bp->length); arm_debug_break_write_value(i, bp->value); arm_debug_break_write_control(i, bp->control); } } + rtems_interrupt_lock_release(&target_lock, &lock_context); } static void arm_debug_break_unload(void) { - arm_debug_hwbreak* bp = &hw_breaks[0]; + rtems_interrupt_lock_context lock_context; + arm_debug_hwbreak* bp = &hw_breaks[0]; int i; + rtems_interrupt_lock_acquire(&target_lock, &lock_context); + arm_debug_set_context_id(0); for (i = 0; i < hw_breakpoints; ++i, ++bp) { bp->loaded = false; arm_debug_break_write_control(i, 0); } + rtems_interrupt_lock_release(&target_lock, &lock_context); } #if NOT_USED_BUT_KEEPING @@ -937,9 +989,9 @@ rtems_debugger_target_enable(void) { rtems_interrupt_lock_context lock_context; debug_session_active = true; - rtems_interrupt_lock_acquire(&target_lock, &lock_context); arm_debug_break_unload(); arm_debug_break_clear(); + rtems_interrupt_lock_acquire(&target_lock, &lock_context); rtems_debugger_target_set_vectors(); rtems_interrupt_lock_release(&target_lock, &lock_context); return 0; @@ -953,6 +1005,8 @@ rtems_debugger_target_disable(void) void* text_begin; void* text_end; #endif + arm_debug_break_unload(); + arm_debug_break_clear(); rtems_interrupt_lock_acquire(&target_lock, &lock_context); debug_session_active = false; #if DOES_NOT_WORK @@ -1063,11 +1117,11 @@ rtems_debugger_target_write_regs(rtems_debugger_thread* thread) uint32_t* regs = &thread->registers[0]; /* - * Only write to debugger controlled threads. Do not touch the registers - * for threads blocked in the context switcher. + * Only write to debugger controlled exception threads. Do not touch the + * registers for threads blocked in the context switcher. */ if (rtems_debugger_thread_flag(thread, - RTEMS_DEBUGGER_THREAD_FLAG_DEBUGGING)) { + RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION)) { CPU_Exception_frame* frame = thread->frame; frame->register_r0 = regs[REG_R0]; frame->register_r1 = regs[REG_R1]; @@ -1131,81 +1185,76 @@ rtems_debugger_target_tcb_sp(rtems_debugger_thread* thread) int rtems_debugger_target_thread_stepping(rtems_debugger_thread* thread) { - if (rtems_debugger_thread_flag(thread, - (RTEMS_DEBUGGER_THREAD_FLAG_STEP | - RTEMS_DEBUGGER_THREAD_FLAG_STEPPING))) { + if (rtems_debugger_thread_flag(thread, RTEMS_DEBUGGER_THREAD_FLAG_STEP_INSTR)) { /* * Single stepping and range stepping uses hardware debug breakpoint * 0. This is reserved for single stepping. */ CPU_Exception_frame* frame = thread->frame; arm_debug_hwbreak* bp = &hw_breaks[0]; - int i; - for (i = 0; i < hw_breakpoints; ++i, ++bp) { - if (!bp->enabled) { - const uint32_t addr = (intptr_t) frame->register_pc; - const bool thumb = (FRAME_SR & (1 << 5)) != 0 ? true : false; - uint32_t bas; - - bp->enabled = true; - bp->loaded = false; - bp->address = frame->register_pc; - bp->frame = frame; - bp->length = sizeof(uint32_t); - - if (thumb) { - uint16_t instr = *((uint16_t*) frame->register_pc); - switch (instr & 0xf800) { - case 0xe800: - case 0xf000: - case 0xf800: - break; - default: - bp->length = sizeof(uint16_t); - break; - } + target_printk("[} stepping: %s\n", bp->enabled ? "yes" : "no"); + if (!bp->enabled) { + const uint32_t addr = (intptr_t) frame->register_pc; + const bool thumb = (FRAME_SR & (1 << 5)) != 0 ? true : false; + uint32_t bas; + + bp->enabled = true; + bp->loaded = false; + bp->address = frame->register_pc; + bp->frame = frame; + bp->length = sizeof(uint32_t); + + if (thumb) { + uint16_t instr = *((uint16_t*) frame->register_pc); + switch (instr & 0xf800) { + case 0xe800: + case 0xf000: + case 0xf800: + break; + default: + bp->length = sizeof(uint16_t); + break; } + } - /* - * See table C3-2 Effect of byte address selection on Breakpoint - * generation and "Instruction address comparisoin programming - * examples. - */ - if (thumb) { - if ((addr & (1 << 1)) == 0) { - bas = 0x3; /* b0011 */ - } - else { - bas = 0xc; /* b1100 */ - } + /* + * See table C3-2 Effect of byte address selection on Breakpoint + * generation and "Instruction address comparision programming + * examples. + */ + if (thumb) { + if ((addr & (1 << 1)) == 0) { + bas = 0x3; /* b0011 */ } else { - bas = 0xf; /* b1111 */ + bas = 0xc; /* b1100 */ } + } + else { + bas = 0xf; /* b1111 */ + } - arm_debug_break_setup(bp, - addr & ~0x3, - ARM_HW_BP_UNLINKED_INSTR_MISMATCH, - bas, - ARM_HW_BP_PRIV_PL0_SUP_SYS); + arm_debug_break_setup(bp, + addr & ~0x3, + ARM_HW_BP_UNLINKED_INSTR_MISMATCH, + bas, + ARM_HW_BP_PRIV_PL0_SUP_SYS); - /* - * Save the interrupt state before stepping if set. - */ + /* + * Save the interrupt state before stepping if set. + */ #if ARM_PSR_HAS_INT_MASK - if ((FRAME_SR & CPSR_INTS_MASK) != 0) { - uint32_t int_state; - int_state = - (frame->register_cpsr & CPSR_INTS_MASK) << RTEMS_DEBUGGER_THREAD_FLAG_TARGET_BASE; - thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED | int_state; - } - /* - * Mask the interrupt when stepping. - */ - FRAME_SR |= CPSR_INTS_MASK; -#endif - break; + if ((FRAME_SR & CPSR_INTS_MASK) != 0) { + uint32_t int_state; + int_state = + (frame->register_cpsr & CPSR_INTS_MASK) << RTEMS_DEBUGGER_THREAD_FLAG_TARGET_BASE; + thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED | int_state; } + /* + * Mask the interrupt when stepping. + */ + FRAME_SR |= CPSR_INTS_MASK; +#endif } } return 0; @@ -1215,7 +1264,7 @@ int rtems_debugger_target_exception_to_signal(CPU_Exception_frame* frame) { int sig = RTEMS_DEBUGGER_SIGNAL_HUP; -#if defined(ARM_EXCEPTION_RESET) +#if defined(ARM_MULTILIB_ARCH_V4) switch (frame->vector) { case ARM_EXCEPTION_RESET: case ARM_EXCEPTION_SWI: @@ -1242,6 +1291,22 @@ rtems_debugger_target_exception_to_signal(CPU_Exception_frame* frame) return sig; } +int +rtems_debugger_target_hwbreak_insert(void) +{ + /* + * Do nothing, load on exit of the exception handler. + */ + return 0; +} + +int +rtems_debugger_target_hwbreak_remove(void) +{ + arm_debug_break_unload(); + return 0; +} + int rtems_debugger_target_hwbreak_control(rtems_debugger_target_watchpoint wp, bool insert, @@ -1262,7 +1327,7 @@ rtems_debugger_target_cache_sync(rtems_debugger_target_swbreak* swbreak) */ rtems_cache_flush_multiple_data_lines(swbreak->address, sizeof(breakpoint)); - rtems_cache_invalidate_multiple_instruction_lines(swbreak->address, - sizeof(breakpoint)); + rtems_cache_instruction_sync_after_code_change(swbreak->address, + sizeof(breakpoint)); return 0; } diff --git a/cpukit/libdebugger/rtems-debugger-block.c b/cpukit/libdebugger/rtems-debugger-block.c index 918e321ca6..c5d97b3e19 100644 --- a/cpukit/libdebugger/rtems-debugger-block.c +++ b/cpukit/libdebugger/rtems-debugger-block.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2016 Chris Johns . All rights reserved. + * Copyright (c) 2016 Chris Johns . + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/cpukit/libdebugger/rtems-debugger-block.h b/cpukit/libdebugger/rtems-debugger-block.h index c1c7fab2ac..eacc668ad7 100644 --- a/cpukit/libdebugger/rtems-debugger-block.h +++ b/cpukit/libdebugger/rtems-debugger-block.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2016 Chris Johns . All rights reserved. + * Copyright (c) 2016 Chris Johns . + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/cpukit/libdebugger/rtems-debugger-cmd.c b/cpukit/libdebugger/rtems-debugger-cmd.c index e292065e64..afa522aa91 100644 --- a/cpukit/libdebugger/rtems-debugger-cmd.c +++ b/cpukit/libdebugger/rtems-debugger-cmd.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2016 Chris Johns . All rights reserved. + * Copyright (c) 2016 Chris Johns . + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -180,11 +181,29 @@ static int rtems_shell_main_debugger(int argc, char *argv[]) return 1; } } + else if (strcasecmp(argv[1], "verbose") == 0) { + if (!rtems_debugger_running()) { + printf("error: debugger not running.\n"); + return 1; + } + + if (argc == 3 && strcasecmp(argv[2], "on") == 0) { + rtems_debugger_set_verbose(true); + } + else if (argc == 3 && strcasecmp(argv[2], "off") == 0) { + rtems_debugger_set_verbose(false); + } + else { + printf("debugger verbose: not on or off\n"); + return 1; + } + } else if (strcasecmp(argv[1], "help") == 0) { printf("debugger [start/stop/help] ...\n" \ " start -v -R remote -d device -t secs -P priority -l [stdout,stderr,kernel]\n" \ " stop\n" \ " remote-debug \n" \ + " verbose \n" \ " help\n"); } else { diff --git a/cpukit/libdebugger/rtems-debugger-i386.c b/cpukit/libdebugger/rtems-debugger-i386.c index 901ba85322..e9b81863a9 100644 --- a/cpukit/libdebugger/rtems-debugger-i386.c +++ b/cpukit/libdebugger/rtems-debugger-i386.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2016 Chris Johns . All rights reserved. + * Copyright (c) 2016 Chris Johns . + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/cpukit/libdebugger/rtems-debugger-remote-tcp.c b/cpukit/libdebugger/rtems-debugger-remote-tcp.c index ded51d604e..b62f3a1f52 100644 --- a/cpukit/libdebugger/rtems-debugger-remote-tcp.c +++ b/cpukit/libdebugger/rtems-debugger-remote-tcp.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2016 Chris Johns . All rights reserved. + * Copyright (c) 2016 Chris Johns . + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/cpukit/libdebugger/rtems-debugger-remote-tcp.h b/cpukit/libdebugger/rtems-debugger-remote-tcp.h index d9d7feeb48..3d9dab9f45 100644 --- a/cpukit/libdebugger/rtems-debugger-remote-tcp.h +++ b/cpukit/libdebugger/rtems-debugger-remote-tcp.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2016 Chris Johns . All rights reserved. + * Copyright (c) 2016 Chris Johns . + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/cpukit/libdebugger/rtems-debugger-remote.c b/cpukit/libdebugger/rtems-debugger-remote.c index f9a104db07..a79fe6f5a9 100644 --- a/cpukit/libdebugger/rtems-debugger-remote.c +++ b/cpukit/libdebugger/rtems-debugger-remote.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2016 Chris Johns . All rights reserved. + * Copyright (c) 2016 Chris Johns . + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/cpukit/libdebugger/rtems-debugger-remote.h b/cpukit/libdebugger/rtems-debugger-remote.h index 3ea2b14b1e..34ad9ee6d2 100644 --- a/cpukit/libdebugger/rtems-debugger-remote.h +++ b/cpukit/libdebugger/rtems-debugger-remote.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2016 Chris Johns . All rights reserved. + * Copyright (c) 2016 Chris Johns . + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/cpukit/libdebugger/rtems-debugger-server.c b/cpukit/libdebugger/rtems-debugger-server.c index 77b5697a50..6e70d08ebf 100644 --- a/cpukit/libdebugger/rtems-debugger-server.c +++ b/cpukit/libdebugger/rtems-debugger-server.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2016 Chris Johns . All rights reserved. + * Copyright (c) 2016-2017 Chris Johns . + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,10 +24,16 @@ * SUCH DAMAGE. */ +#define RTEMS_DEBUGGER_VERBOSE_LOCK 0 +#define RTEMS_DEBUGGER_PRINT_PRINTK 1 + #include #include #include +#include +#include + #include #include #include @@ -50,15 +57,15 @@ typedef int (*rtems_debugger_command)(uint8_t* buffer, int size); typedef struct rtems_debugger_packet { - const char const* label; + const char* const label; rtems_debugger_command command; } rtems_debugger_packet; /** * Common error strings. */ -static const char const* r_OK = "OK"; -static const char const* r_E01 = "E01"; +static const char* const r_OK = "OK"; +static const char* const r_E01 = "E01"; /* * Global Debugger. @@ -73,13 +80,59 @@ static const char const* r_E01 = "E01"; */ rtems_debugger_server* rtems_debugger; +/** + * Print lock ot make the prints sequential. This is to debug the debugger in + * SMP. + */ +#if RTEMS_DEBUGGER_PRINT_PRINTK +RTEMS_INTERRUPT_LOCK_DEFINE(static, printk_lock, "printk_lock") +#endif + +void +rtems_debugger_printk_lock(rtems_interrupt_lock_context* lock_context) +{ + rtems_interrupt_lock_acquire(&printk_lock, lock_context); +} + +void +rtems_debugger_printk_unlock(rtems_interrupt_lock_context* lock_context) +{ + rtems_interrupt_lock_release(&printk_lock, lock_context); +} + +int +rtems_debugger_clean_printf(const char* format, ...) +{ + int len; + va_list ap; + va_start(ap, format); + if (RTEMS_DEBUGGER_PRINT_PRINTK) { + rtems_interrupt_lock_context lock_context; + rtems_debugger_printk_lock(&lock_context); + len = vprintk(format, ap); + rtems_debugger_printk_unlock(&lock_context); + } + else + len = rtems_vprintf(&rtems_debugger->printer, format, ap); + va_end(ap); + return len; +} + int rtems_debugger_printf(const char* format, ...) { int len; va_list ap; va_start(ap, format); - len = rtems_vprintf(&rtems_debugger->printer, format, ap); + if (RTEMS_DEBUGGER_PRINT_PRINTK) { + rtems_interrupt_lock_context lock_context; + rtems_debugger_printk_lock(&lock_context); + printk("[CPU:%d] ", (int) _SMP_Get_current_processor ()); + len = vprintk(format, ap); + rtems_debugger_printk_unlock(&lock_context); + } + else + len = rtems_vprintf(&rtems_debugger->printer, format, ap); va_end(ap); return len; } @@ -158,74 +211,31 @@ thread_id_decode(const char* data, DB_UINT* pid, DB_UINT* tid) static inline bool check_pid(DB_UINT pid) { - return pid == 0|| rtems_debugger->pid == (pid_t) pid; + return pid == 0 || rtems_debugger->pid == (pid_t) pid; } -int +void rtems_debugger_lock(void) { - if (rtems_debugger->lock != 0) { - rtems_status_code sc; - sc = rtems_semaphore_obtain(rtems_debugger->lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT); - if (sc != RTEMS_SUCCESSFUL) { - rtems_debugger_printf("error: rtems-db: lock: %s\n", - rtems_status_text(sc)); - return -1; - } - } - return 0; + _Mutex_recursive_Acquire(&rtems_debugger->lock); } -int +void rtems_debugger_unlock(void) { - if (rtems_debugger->lock != 0) { - rtems_status_code sc; - sc = rtems_semaphore_release(rtems_debugger->lock); - if (sc != RTEMS_SUCCESSFUL) { - rtems_debugger_printf("error: rtems-db: unlock: %s\n", - rtems_status_text(sc)); - return -1; - } - } - return 0; + _Mutex_recursive_Release(&rtems_debugger->lock); } static int rtems_debugger_lock_create(void) { - #define LOCK_ATTRIBUTES \ - RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY | RTEMS_BINARY_SEMAPHORE - rtems_status_code sc; - sc = rtems_semaphore_create(rtems_build_name('G', 'D', 'B', 's'), - 1, - LOCK_ATTRIBUTES, - 0, - &rtems_debugger->lock); - if (sc != RTEMS_SUCCESSFUL) { - rtems_debugger_printf("error: rtems-db: sema create: %s\n", - rtems_status_text(sc)); - errno = EIO; - return -1; - } + _Mutex_recursive_Initialize_named(&rtems_debugger->lock, "DBlock"); return 0; } static int rtems_debugger_lock_destroy(void) { - rtems_debugger_lock(); - if (rtems_debugger->lock != 0) { - rtems_status_code sc; - rtems_semaphore_release(rtems_debugger->lock); - sc = rtems_semaphore_delete(rtems_debugger->lock); - rtems_debugger->lock = 0; - if (sc != RTEMS_SUCCESSFUL) { - rtems_debugger_printf("error: rtems-db: sema delete: %s\n", - rtems_status_text(sc)); - return -1; - } - } return 0; } @@ -333,52 +343,19 @@ rtems_debugger_connected(void) bool rtems_debugger_server_events_running(void) { - bool running; - rtems_debugger_lock(); - running = rtems_debugger->events_running; - rtems_debugger_unlock(); - return running; + return rtems_debugger->events_running; } -int -rtems_debugger_server_events_wake(void) +void +rtems_debugger_server_events_signal(void) { - rtems_status_code sc; - int r = 0; - sc = rtems_event_send(rtems_debugger->events_task, RTEMS_EVENT_1); - if (sc != RTEMS_SUCCESSFUL) { - rtems_debugger_printf("error: rtems-db: event send: %s\n", - rtems_status_text(sc)); - errno = EIO; - r = -1; - } - return r; + _Condition_Signal(&rtems_debugger->server_cond); } -static int +static void rtems_debugger_server_events_wait(void) { - rtems_event_set out = 0; - rtems_status_code sc; - int r = 0; - rtems_debugger_unlock(); - while (true) { - sc = rtems_event_receive(RTEMS_EVENT_1, - RTEMS_EVENT_ALL | RTEMS_WAIT, - RTEMS_NO_TIMEOUT, - &out); - if (sc != RTEMS_SUCCESSFUL) { - rtems_debugger_printf("error: rtems-db: event receive: %s\n", - rtems_status_text(sc)); - errno = EIO; - r = -1; - break; - } - if (out == RTEMS_EVENT_1) - break; - } - rtems_debugger_lock(); - return r; + _Condition_Wait_recursive(&rtems_debugger->server_cond, &rtems_debugger->lock); } static int @@ -432,8 +409,8 @@ rtems_debugger_remote_send(void) size_t i = 0; rtems_debugger_printf("rtems-db: put:%4zu: ", rtems_debugger->output_level); while (i < rtems_debugger->output_level) - rtems_debugger_printf("%c", (char) rtems_debugger->output[i++]); - rtems_debugger_printf("\n"); + rtems_debugger_clean_printf("%c", (char) rtems_debugger->output[i++]); + rtems_debugger_clean_printf("\n"); } while (size) { @@ -533,14 +510,14 @@ rtems_debugger_remote_packet_in(void) } if (rtems_debugger->remote_debug) - rtems_debugger_printf("%c", c); + rtems_debugger_clean_printf("%c", c); switch (state) { case 'H': switch (c) { case '+': if (rtems_debugger->remote_debug) { - rtems_debugger_printf(" [[ACK%s]]\n", + rtems_debugger_clean_printf(" [[ACK%s]]\n", rtems_debugger->ack_pending ? "" : "?"); remote_debug_header = true; } @@ -548,7 +525,7 @@ rtems_debugger_remote_packet_in(void) break; case '-': if (rtems_debugger->remote_debug) { - rtems_debugger_printf(" [[NACK]]\n"); + rtems_debugger_clean_printf(" [[NACK]]\n"); remote_debug_header = true; } /* @@ -561,13 +538,13 @@ rtems_debugger_remote_packet_in(void) csum = 0; in = 0; if (junk && rtems_debugger->remote_debug) { - rtems_debugger_printf("\b [[junk dropped]]\nrtems-db: get: : $"); + rtems_debugger_clean_printf("\b [[junk dropped]]\nrtems-db: get: : $"); remote_debug_header = false; } break; case '\x3': if (rtems_debugger->remote_debug) - rtems_debugger_printf("^C [[BREAK]]\n"); + rtems_debugger_clean_printf("^C [[BREAK]]\n"); rtems_debugger->ack_pending = false; rtems_debugger->input[0] = '^'; rtems_debugger->input[1] = 'C'; @@ -586,7 +563,7 @@ rtems_debugger_remote_packet_in(void) csum = 0; in = 0; if (rtems_debugger->remote_debug) { - rtems_debugger_printf("\n"); + rtems_debugger_clean_printf("\n"); remote_debug_header = true; } } @@ -613,12 +590,12 @@ rtems_debugger_remote_packet_in(void) if (csum == rx_csum) { state = 'F'; if (rtems_debugger->remote_debug) - rtems_debugger_printf("\n"); + rtems_debugger_clean_printf("\n"); rtems_debugger_remote_send_ack(); } else { if (rtems_debugger->remote_debug) { - rtems_debugger_printf(" [[invalid checksum]]\n"); + rtems_debugger_clean_printf(" [[invalid checksum]]\n"); remote_debug_header = true; rtems_debugger_remote_send_nack(); } @@ -627,7 +604,7 @@ rtems_debugger_remote_packet_in(void) break; case 'F': if (rtems_debugger->remote_debug) - rtems_debugger_printf(" [[extra data: 0x%02x]]", (int) c); + rtems_debugger_clean_printf(" [[extra data: 0x%02x]]", (int) c); break; default: rtems_debugger_printf("rtems-db: bad state\n"); @@ -810,6 +787,9 @@ remote_packet_dispatch(const rtems_debugger_packet* packet, if (strncmp(p->label, (const char*) &buffer[0], strlen(p->label)) == 0) { + if (rtems_debugger_server_flag(RTEMS_DEBUGGER_FLAG_VERBOSE_CMDS)) + rtems_debugger_printf("rtems-db: cmd: %s [%d] '%s'\n", + p->label, size, (const char*) buffer); r = p->command(buffer, size); break; } @@ -904,7 +884,7 @@ remote_gq_thread_extra_info(uint8_t* buffer, int size) DB_UINT tid = 0; bool extended; extended = thread_id_decode(comma + 1, &pid, &tid); - if (!extended || (extended && check_pid(pid))) { + if (extended || check_pid(pid)) { int r; r = rtems_debugger_thread_find_index(tid); if (r >= 0) { @@ -954,7 +934,7 @@ remote_gq_supported(uint8_t* buffer, int size) p = strchr((const char*) buffer, ':'); if (p != NULL) ++p; - while (p != NULL && p != '\0') { + while (p != NULL && *p != '\0') { bool echo = false; char* sc; sc = strchr(p, ';'); @@ -1022,8 +1002,8 @@ remote_gq_supported(uint8_t* buffer, int size) static int remote_gq_attached(uint8_t* buffer, int size) { - const char const* response = "1"; - const char* colon = strchr((const char*) buffer, ':'); + const char* response = "1"; + const char* colon = strchr((const char*) buffer, ':'); if (colon != NULL) { DB_UINT pid = hex_decode_uint((const uint8_t*) colon + 1); if ((pid_t) pid != rtems_debugger->pid) @@ -1061,7 +1041,7 @@ remote_general_query(uint8_t* buffer, int size) static int remote_gs_non_stop(uint8_t* buffer, int size) { - const char const* response = r_E01; + const char* response = r_E01; char* p = strchr((char*) buffer, ':'); if (p != NULL) { ++p; @@ -1173,6 +1153,7 @@ remote_v_continue(uint8_t* buffer, int size) if (r == 0) resume = true; break; + case 'S': case 's': if (thread != NULL) { r = rtems_debugger_thread_step(thread); @@ -1202,6 +1183,7 @@ remote_v_continue(uint8_t* buffer, int size) } break; default: + rtems_debugger_printf("rtems-db: vCont: unkown action: %c\n", action); ok = false; break; } @@ -1210,6 +1192,7 @@ remote_v_continue(uint8_t* buffer, int size) } } else { + rtems_debugger_printf("rtems-db: vCont: no colon\n"); ok = false; } semi = strchr(semi + 1, ';'); @@ -1257,8 +1240,8 @@ remote_v_packets(uint8_t* buffer, int size) static int remote_thread_select(uint8_t* buffer, int size) { - const char const* response = r_OK; - int* index = NULL; + const char* response = r_OK; + int* index = NULL; if (buffer[1] == 'g') index = &rtems_debugger->threads->selector_gen; @@ -1299,10 +1282,10 @@ remote_thread_select(uint8_t* buffer, int size) static int remote_thread_alive(uint8_t* buffer, int size) { - const char const* response = r_E01; - DB_UINT pid = 0; - DB_UINT tid = 0; - bool extended; + const char* response = r_E01; + DB_UINT pid = 0; + DB_UINT tid = 0; + bool extended; extended = thread_id_decode((const char*) &buffer[1], &pid, &tid); if (!extended || (extended && check_pid(pid))) { int r; @@ -1423,7 +1406,7 @@ static int remote_write_reg(uint8_t* buffer, int size) { rtems_debugger_threads* threads = rtems_debugger->threads; - const char const* response = r_E01; + const char* response = r_E01; if (threads->selector_gen >= 0 && threads->selector_gen < (int) threads->current.level) { const char* equals; @@ -1487,9 +1470,9 @@ remote_read_memory(uint8_t* buffer, int size) static int remote_write_memory(uint8_t* buffer, int size) { - const char const* response = r_E01; - const char* comma; - const char* colon; + const char* response = r_E01; + const char* comma; + const char* colon; comma = strchr((const char*) buffer, ','); colon = strchr((const char*) buffer, ':'); if (comma != NULL && colon != NULL) { @@ -1684,9 +1667,7 @@ rtems_debugger_events(rtems_task_argument arg) rtems_debugger_target_enable(); while (rtems_debugger_server_events_running()) { - r = rtems_debugger_server_events_wait(); - if (r < 0) - break; + rtems_debugger_server_events_wait(); if (!rtems_debugger_server_events_running()) break; r = rtems_debugger_thread_system_suspend(); @@ -1767,7 +1748,7 @@ rtems_debugger_session(void) } rtems_debugger->events_running = false; - rtems_debugger_server_events_wake(); + rtems_debugger_server_events_signal(); rtems_debugger_unlock(); @@ -1837,6 +1818,8 @@ rtems_debugger_create(const char* remote, rtems_debugger->pid = getpid(); rtems_debugger->remote_debug = false; + rtems_chain_initialize_empty(&rtems_debugger->exception_threads); + rtems_debugger->remote = rtems_debugger_remote_find(remote); if (rtems_debugger->remote== NULL) { rtems_printf(printer, "error: rtems-db: remote not found: %s\n", remote); @@ -1851,6 +1834,7 @@ rtems_debugger_create(const char* remote, rtems_debugger->remote->name, strerror(errno)); free(rtems_debugger); rtems_debugger = NULL; + return -1; } /* @@ -1907,7 +1891,6 @@ rtems_debugger_main(rtems_task_argument arg) { int r; - rtems_debugger_lock(); rtems_debugger->server_running = true; rtems_debugger->server_finished = false; @@ -1949,6 +1932,7 @@ rtems_debugger_start(const char* remote, rtems_debugger_lock(); rtems_debugger->server_running = false; rtems_debugger->server_finished = true; + _Condition_Initialize_named(&rtems_debugger->server_cond, "DBserver"); rtems_debugger_unlock(); r = rtems_debugger_task_create("DBSs", diff --git a/cpukit/libdebugger/rtems-debugger-server.h b/cpukit/libdebugger/rtems-debugger-server.h index 0941933ba9..a345d7649e 100644 --- a/cpukit/libdebugger/rtems-debugger-server.h +++ b/cpukit/libdebugger/rtems-debugger-server.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2016 Chris Johns . All rights reserved. + * Copyright (c) 2016-2017 Chris Johns . + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -100,6 +101,8 @@ extern "C" { #define RTEMS_DEBUGGER_FLAG_NON_STOP (1 << 2) #define RTEMS_DEBUGGER_FLAG_VCONT (1 << 3) #define RTEMS_DEBUGGER_FLAG_MULTIPROCESS (1 << 4) +#define RTEMS_DEBUGGER_FLAG_VERBOSE_LOCK (1 << 5) +#define RTEMS_DEBUGGER_FLAG_VERBOSE_CMDS (1 << 6) /** * Forward decl for the threads and targets. @@ -108,6 +111,12 @@ typedef struct rtems_debugger_remote rtems_debugger_remote; typedef struct rtems_debugger_threads rtems_debugger_threads; typedef struct rtems_debugger_target rtems_debugger_target; +/** + * Local types for the RTEMS-X interface. + */ +typedef struct _Condition_Control rtems_rx_cond; +typedef struct _Mutex_recursive_Control rtems_rx_mutex; + /** * Debugger data. */ @@ -116,10 +125,10 @@ typedef struct int port; int timeout; rtems_task_priority priority; - rtems_id lock; - rtems_id lock_output; + rtems_rx_mutex lock; rtems_debugger_remote* remote; rtems_id server_task; + rtems_rx_cond server_cond; volatile bool server_running; volatile bool server_finished; rtems_id events_task; @@ -134,6 +143,7 @@ typedef struct uint8_t input[RTEMS_DEBUGGER_BUFFER_SIZE]; uint8_t output[RTEMS_DEBUGGER_BUFFER_SIZE]; rtems_debugger_threads* threads; + rtems_chain_control exception_threads; int signal; rtems_debugger_target* target; } rtems_debugger_server; @@ -147,41 +157,44 @@ extern rtems_debugger_server* rtems_debugger; * Debug server printer. */ extern int rtems_debugger_printf(const char* format, ...) RTEMS_PRINTFLIKE(1, 2); +extern int rtems_debugger_clean_printf(const char* format, ...) RTEMS_PRINTFLIKE(1, 2); +extern void rtems_debugger_printk_lock(rtems_interrupt_lock_context* lock_context); +extern void rtems_debugger_printk_unlock(rtems_interrupt_lock_context* lock_context); /** * Lock the Debugger. */ -extern int rtems_debugger_lock(void); +extern void rtems_debugger_lock(void); /** * Unlock the Debugger. */ -extern int rtems_debugger_unlock(void); +extern void rtems_debugger_unlock(void); /** * Is the server still running? */ -bool rtems_debugger_server_running(void); +extern bool rtems_debugger_server_running(void); /** * Get the remote handle from the debugger. */ -rtems_debugger_remote* rtems_debugger_remote_handle(void); +extern rtems_debugger_remote* rtems_debugger_remote_handle(void); /** * Is the debugger connected? */ -bool rtems_debugger_connected(void); +extern bool rtems_debugger_connected(void); /** * Is the debugger events thread runnins? */ -bool rtems_debugger_server_events_running(void); +extern bool rtems_debugger_server_events_running(void); /** - * Wake events thread in the debug server. + * Signal events thread in the debug server to run. */ -extern int rtems_debugger_server_events_wake(void); +extern void rtems_debugger_server_events_signal(void); /** * Check if verbose is on. diff --git a/cpukit/libdebugger/rtems-debugger-target.c b/cpukit/libdebugger/rtems-debugger-target.c index 65b878469d..eac9498535 100644 --- a/cpukit/libdebugger/rtems-debugger-target.c +++ b/cpukit/libdebugger/rtems-debugger-target.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2016 Chris Johns . All rights reserved. + * Copyright (c) 2016-2017 Chris Johns . + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -40,12 +41,15 @@ #include "rtems-debugger-threads.h" /** - * Frame signature. + * Exception local stack frame data to synchronise with the debugger + * server's events loop processor. */ -#define TARGET_FRAME_MAGIC_NUM (2) -#define TARGET_FRAME_MAGIC 0xdeadbeef, 0xb2107016 -static const uint32_t - frame_magic[TARGET_FRAME_MAGIC_NUM] = { TARGET_FRAME_MAGIC }; +typedef struct { + rtems_chain_node node; + rtems_id id; + CPU_Exception_frame* frame; + rtems_rx_cond cond; +} rtems_debugger_exception; #if TARGET_DEBUG #include @@ -53,9 +57,12 @@ static void target_printk(const char* format, ...) RTEMS_PRINTFLIKE(1, 2); static void target_printk(const char* format, ...) { + rtems_interrupt_lock_context lock_context; va_list ap; va_start(ap, format); + rtems_debugger_printk_lock(&lock_context); vprintk(format, ap); + rtems_debugger_printk_unlock(&lock_context); va_end(ap); } #else @@ -219,6 +226,11 @@ rtems_debugger_target_swbreak_insert(void) if (target->breakpoint_size > 4) memcpy(loc, &target->breakpoint[0], target->breakpoint_size); else { + if (rtems_debugger_verbose()) + rtems_debugger_printf("rtems-db: bp: in: %p %p %d %d %d\n", + loc, &target->breakpoint[0], + (int) target->breakpoint_size, + (int) i, (int) target->swbreaks.level); switch (target->breakpoint_size) { case 4: loc[3] = target->breakpoint[3]; @@ -276,30 +288,22 @@ rtems_debugger_target_swbreak_remove(void) rtems_debugger_target_exc_action rtems_debugger_target_exception(CPU_Exception_frame* frame) { - volatile const uint32_t magic[3] = { - (uint32_t) frame, TARGET_FRAME_MAGIC - }; - - (void) magic; - if (!rtems_interrupt_is_in_progress()) { rtems_debugger_threads* threads = rtems_debugger->threads; - #if USE_THREAD_EXECUTING - Thread_Control* thread = _Thread_Executing; - #else - const Per_CPU_Control* cpu = _Per_CPU_Get_snapshot(); - Thread_Control* thread = _Per_CPU_Get_executing(cpu); - #endif - rtems_id* excludes; + Thread_Control* thread = _Thread_Get_executing(); const rtems_id tid = thread->Object.id; + rtems_id* excludes; DB_UINT pc; const rtems_debugger_thread_stepper* stepper; + rtems_debugger_exception target_exception; size_t i; target_printk("[} tid:%08" PRIx32 ": thread:%08" PRIxPTR " frame:%08" PRIxPTR "\n", tid, (intptr_t) thread, (intptr_t) frame); + rtems_debugger_lock(); + /* * If the thread is the debugger recover. */ @@ -307,9 +311,11 @@ rtems_debugger_target_exception(CPU_Exception_frame* frame) if (rtems_debugger->target->memory_access) { target_printk("[} server access fault\n"); rtems_debugger->target->memory_access = true; + rtems_debugger_unlock(); longjmp(rtems_debugger->target->access_return, -1); } target_printk("[} server exception\n"); + rtems_debugger_unlock(); return rtems_debugger_target_exc_cascade; } @@ -327,6 +333,7 @@ rtems_debugger_target_exception(CPU_Exception_frame* frame) * swbreak's contents. */ target_printk("[} tid:%08lx: excluded\n", tid); + rtems_debugger_unlock(); return rtems_debugger_target_exc_cascade; } } @@ -340,18 +347,39 @@ rtems_debugger_target_exception(CPU_Exception_frame* frame) stepper->thread->frame = frame; rtems_debugger_target_thread_stepping(stepper->thread); target_printk("[} tid:%08lx: stepping\n", tid); + rtems_debugger_unlock(); return rtems_debugger_target_exc_step; } target_printk("[} tid:%08lx: suspending\n", tid); /* - * Tag the thread as being debugged, wake the debug server's event thread, - * then suspend this thread. + * Initialise the target exception data and queue ready for the debugger + * server's event processor to handle. + */ + rtems_chain_initialize_node(&target_exception.node); + target_exception.frame = frame; + target_exception.id = tid; + _Condition_Initialize(&target_exception.cond); + + rtems_chain_append_unprotected(&rtems_debugger->exception_threads, + &target_exception.node); + + /* + * Signal the debug server's thread. + */ + rtems_debugger_server_events_signal(); + + /* + * Block on the exception thread's condition variable unlocking the + * debugger's mutex and letting the server's thread run. + */ + _Condition_Wait_recursive(&target_exception.cond, &rtems_debugger->lock); + + /* + * Unlock the debugger's lock now the exception is resuming. */ - _Thread_Set_state(thread, STATES_DEBUGGER); - rtems_debugger_server_events_wake(); - rtems_task_suspend(tid); + rtems_debugger_unlock(); target_printk("[} tid:%08lx: resuming\n", tid); @@ -363,31 +391,39 @@ rtems_debugger_target_exception(CPU_Exception_frame* frame) return rtems_debugger_target_exc_cascade; } -int -rtems_debugger_target_set_exception_frame(rtems_debugger_thread* thread) +void +rtems_debugger_target_exception_thread(rtems_debugger_thread* thread) { - int r = 0; + rtems_chain_node* node; thread->frame = NULL; - thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_DEBUGGING; - if ((thread->tcb->current_state & STATES_DEBUGGER) != 0) { - CPU_Exception_frame* frame = NULL; - DB_UINT* sp; - int i; - sp = (DB_UINT*) rtems_debugger_target_tcb_sp(thread); - for (i = 0; i < 128; ++i) { - if (sp[i] == frame_magic[0] && sp[i + 1] == frame_magic[1]) { - frame = (CPU_Exception_frame*) sp[i + 2]; - break; - } + thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION; + for (node = rtems_chain_first(&rtems_debugger->exception_threads); + !rtems_chain_is_tail(&rtems_debugger->exception_threads, node); + node = rtems_chain_next(node)) { + rtems_debugger_exception* target_exception = (rtems_debugger_exception*) node; + if (target_exception->id == thread->id) { + thread->frame = target_exception->frame; + thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION; + } + } +} + +void +rtems_debugger_target_exception_thread_resume(rtems_debugger_thread* thread) +{ + rtems_chain_node* node; + for (node = rtems_chain_first(&rtems_debugger->exception_threads); + !rtems_chain_is_tail(&rtems_debugger->exception_threads, node); + node = rtems_chain_next(node)) { + rtems_debugger_exception* target_exception = (rtems_debugger_exception*) node; + if (target_exception->id == thread->id) { + rtems_chain_extract(node); + thread->frame = NULL; + thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION; + _Condition_Signal(&target_exception->cond); + break; } - _Thread_Clear_state(thread->tcb, STATES_DEBUGGER); - thread->frame = frame; - if (frame != NULL) - thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_DEBUGGING; - else - r = -1; } - return r; } int diff --git a/cpukit/libdebugger/rtems-debugger-target.h b/cpukit/libdebugger/rtems-debugger-target.h index 82230e8d8b..0e1156c889 100644 --- a/cpukit/libdebugger/rtems-debugger-target.h +++ b/cpukit/libdebugger/rtems-debugger-target.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2016 Chris Johns . All rights reserved. + * Copyright (c) 2016-2017 Chris Johns . + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -193,6 +194,16 @@ extern int rtems_debugger_target_swbreak_insert(void); */ extern int rtems_debugger_target_swbreak_remove(void); +/** + * Insert hardware breakpoints into the hardware. + */ +extern int rtems_debugger_target_hwbreak_insert(void); + +/** + * Remove hardware breakpoints from the hardware. + */ +extern int rtems_debugger_target_hwbreak_remove(void); + /** * Hardware breakpoints. */ @@ -208,9 +219,14 @@ extern rtems_debugger_target_exc_action rtems_debugger_target_exception(CPU_Exception_frame* frame); /** - * Set the thread's exception stack frame pointer. + * See if the thread is an exception thread. + */ +extern void rtems_debugger_target_exception_thread(rtems_debugger_thread* thread); + +/** + * If the thread is an exception thread, resume it. */ -extern int rtems_debugger_target_set_exception_frame(rtems_debugger_thread* thread); +extern void rtems_debugger_target_exception_thread_resume(rtems_debugger_thread* thread); /** * Target instruction cache sync. This depends on the target but it normally diff --git a/cpukit/libdebugger/rtems-debugger-threads.c b/cpukit/libdebugger/rtems-debugger-threads.c index 4f8c062e7f..bc6e952b11 100644 --- a/cpukit/libdebugger/rtems-debugger-threads.c +++ b/cpukit/libdebugger/rtems-debugger-threads.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2016 Chris Johns . All rights reserved. + * Copyright (c) 2016-2017 Chris Johns . + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -43,6 +44,7 @@ static const char * const excludes_defaults[] = "IRQS", "DBSs", "DBSe", + "IDLE", }; static void @@ -240,23 +242,13 @@ snapshot_thread(rtems_tcb* tcb, void* arg) * See if there is a valid exception stack frame and if the thread is being * debugged. */ - r = rtems_debugger_target_set_exception_frame(thread); - if (r < 0) { - rtems_debugger_printf("error: rtems-db: thread: snap: %08lx: not valid frame\n", - id); - } - - /* - * Read the target registers into the thread register array. - */ - rtems_debugger_target_read_regs(thread); + rtems_debugger_target_exception_thread(thread); /* - * Debugger threads are stopped for breakpoint, segv or other errors have - * the RTEMS_DEBUGGER_THREAD_FLAG_DEBUGGING set. + * Exception threads have stopped for breakpoint, segv or other errors. */ if (rtems_debugger_thread_flag(thread, - RTEMS_DEBUGGER_THREAD_FLAG_DEBUGGING)) { + RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION)) { rtems_id* stopped; r = rtems_debugger_block_resize(&threads->stopped); if (r < 0) { @@ -276,6 +268,11 @@ snapshot_thread(rtems_tcb* tcb, void* arg) } } + /* + * Read the target registers into the thread register array. + */ + rtems_debugger_target_read_regs(thread); + if (rtems_debugger_server_flag(RTEMS_DEBUGGER_FLAG_VERBOSE)) rtems_debugger_printf("rtems-db: sys: thd: %08lx: signal: %d\n", id, thread->signal); @@ -300,6 +297,8 @@ rtems_debugger_thread_system_suspend(void) if (rtems_debugger_verbose()) rtems_debugger_printf("rtems-db: sys: : suspending\n"); r = rtems_debugger_target_swbreak_remove(); + if (r == 0) + r = rtems_debugger_target_hwbreak_remove(); if (r == 0) { rtems_debugger_thread* current; threads->current.level = 0; @@ -352,15 +351,19 @@ rtems_debugger_thread_system_resume(bool detaching) size_t i; if (rtems_debugger_verbose()) rtems_debugger_printf("rtems-db: sys: : resuming\n"); - if (!detaching) + if (!detaching) { r = rtems_debugger_target_swbreak_insert(); + if (r == 0) + r = rtems_debugger_target_hwbreak_insert(); + } if (r == 0) { for (i = 0; i < threads->current.level; ++i) { rtems_debugger_thread* thread = ¤t[i]; rtems_status_code sc; int rr; /* - * Check if resuming, which is continuing, a step, or stepping a range. + * Check if resuming, which can be continuing, a step, or stepping a + * range. */ if (detaching || rtems_debugger_thread_flag(thread, @@ -376,10 +379,18 @@ rtems_debugger_thread_system_resume(bool detaching) r = rr; } } - sc = rtems_task_resume(thread->id); - if (sc != RTEMS_SUCCESSFUL) { - rtems_debugger_printf("error: rtems-db: thread: resume: %08lx: %s\n", - thread->id, rtems_status_text(sc)); + if (rtems_debugger_verbose()) + rtems_debugger_printf("rtems-db: sys: : resume: 0x%08lx\n", + thread->id); + if (rtems_debugger_thread_flag(thread, + RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION)) { + rtems_debugger_target_exception_thread_resume(thread); + } else { + sc = rtems_task_resume(thread->id); + if (sc != RTEMS_SUCCESSFUL) { + rtems_debugger_printf("error: rtems-db: thread: resume: %08lx: %s\n", + thread->id, rtems_status_text(sc)); + } } thread->flags &= ~(RTEMS_DEBUGGER_THREAD_FLAG_CONTINUE | RTEMS_DEBUGGER_THREAD_FLAG_STEP); @@ -420,10 +431,12 @@ rtems_debugger_thread_continue_all(void) size_t i; for (i = 0; i < threads->current.level; ++i) { rtems_debugger_thread* thread = ¤t[i]; - int r; - r = rtems_debugger_thread_continue(thread); - if (r < 0) - break; + if (!rtems_debugger_thread_flag(thread, + RTEMS_DEBUGGER_THREAD_FLAG_STEP_INSTR)) { + r = rtems_debugger_thread_continue(thread); + if (r < 0) + break; + } } } else { diff --git a/cpukit/libdebugger/rtems-debugger-threads.h b/cpukit/libdebugger/rtems-debugger-threads.h index 563b402d83..f0217882f6 100644 --- a/cpukit/libdebugger/rtems-debugger-threads.h +++ b/cpukit/libdebugger/rtems-debugger-threads.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2016 Chris Johns . All rights reserved. + * Copyright (c) 2016-2017 Chris Johns . + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -51,7 +52,7 @@ extern "C" { /** * Debugger thread flags. */ -#define RTEMS_DEBUGGER_THREAD_FLAG_DEBUGGING (1 << 0) +#define RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION (1 << 0) #define RTEMS_DEBUGGER_THREAD_FLAG_REG_VALID (1 << 1) #define RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY (1 << 2) #define RTEMS_DEBUGGER_THREAD_FLAG_CONTINUE (1 << 3) @@ -162,8 +163,8 @@ extern int rtems_debugger_thread_step(rtems_debugger_thread* thread); * Thread is stepping so record the details. */ extern int rtems_debugger_thread_stepping(rtems_debugger_thread* thread, - DB_UINT start, - DB_UINT end); + DB_UINT start, + DB_UINT end); /** * Thread's PC in the stepping range? Returns the stepper is in range else @@ -196,8 +197,8 @@ extern int rtems_debugger_thread_state(rtems_debugger_thread* thread); * Return a string of the thread's state. */ extern int rtems_debugger_thread_state_str(rtems_debugger_thread* thread, - char* buffer, - size_t size); + char* buffer, + size_t size); /** * Return the thread's stack size. @@ -214,8 +215,7 @@ extern void* rtems_debugger_thread_stack_area(rtems_debugger_thread* thread); * set. */ static inline bool -rtems_debugger_thread_flag(rtems_debugger_thread* thread, - uint32_t mask) +rtems_debugger_thread_flag(rtems_debugger_thread* thread, uint32_t mask) { return (thread->flags & mask) != 0; } -- cgit v1.2.3