[PATCH] libdebugger: Fixes to debugging, ARM support, locking, and gcc-7.1 warnings.

Chris Johns chrisj at rtems.org
Mon Aug 14 03:46:17 UTC 2017


- 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(-)

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 <chrisj at rtems.org>.  All rights reserved.
+ * Copyright (c) 2016-2017 Chris Johns <chrisj at rtems.org>.
+ * 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:
@@ -1243,6 +1292,22 @@ rtems_debugger_target_exception_to_signal(CPU_Exception_frame* frame)
 }
 
 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,
                                       DB_UINT                          addr,
@@ -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 <chrisj at rtems.org>.  All rights reserved.
+ * Copyright (c) 2016 Chris Johns <chrisj at rtems.org>.
+ * 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 <chrisj at rtems.org>.  All rights reserved.
+ * Copyright (c) 2016 Chris Johns <chrisj at rtems.org>.
+ * 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 <chrisj at rtems.org>.  All rights reserved.
+ * Copyright (c) 2016 Chris Johns <chrisj at rtems.org>.
+ * 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 <on/off>\n" \
+           "  verbose <on/off>\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 <chrisj at rtems.org>.  All rights reserved.
+ * Copyright (c) 2016 Chris Johns <chrisj at rtems.org>.
+ * 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 <chrisj at rtems.org>.  All rights reserved.
+ * Copyright (c) 2016 Chris Johns <chrisj at rtems.org>.
+ * 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 <chrisj at rtems.org>.  All rights reserved.
+ * Copyright (c) 2016 Chris Johns <chrisj at rtems.org>.
+ * 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 <chrisj at rtems.org>.  All rights reserved.
+ * Copyright (c) 2016 Chris Johns <chrisj at rtems.org>.
+ * 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 <chrisj at rtems.org>.  All rights reserved.
+ * Copyright (c) 2016 Chris Johns <chrisj at rtems.org>.
+ * 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 <chrisj at rtems.org>.  All rights reserved.
+ * Copyright (c) 2016-2017 Chris Johns <chrisj at rtems.org>.
+ * 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 <errno.h>
 #include <stdlib.h>
 #include <unistd.h>
 
+#include <rtems/bspIo.h>
+#include <rtems/score/smp.h>
+
 #include <rtems/rtems-debugger.h>
 #include <rtems/debugger/rtems-debugger-server.h>
 #include <rtems/debugger/rtems-debugger-remote.h>
@@ -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 <chrisj at rtems.org>.  All rights reserved.
+ * Copyright (c) 2016-2017 Chris Johns <chrisj at rtems.org>.
+ * 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.
@@ -109,6 +112,12 @@ 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.
  */
 typedef struct
@@ -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 <chrisj at rtems.org>.  All rights reserved.
+ * Copyright (c) 2016-2017 Chris Johns <chrisj at rtems.org>.
+ * 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 <rtems/bspIo.h>
@@ -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 <chrisj at rtems.org>.  All rights reserved.
+ * Copyright (c) 2016-2017 Chris Johns <chrisj at rtems.org>.
+ * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -194,6 +195,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.
  */
 extern int rtems_debugger_target_hwbreak_control(rtems_debugger_target_watchpoint type,
@@ -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 <chrisj at rtems.org>.  All rights reserved.
+ * Copyright (c) 2016-2017 Chris Johns <chrisj at rtems.org>.
+ * 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 = &current[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 = &current[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 <chrisj at rtems.org>.  All rights reserved.
+ * Copyright (c) 2016-2017 Chris Johns <chrisj at rtems.org>.
+ * 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;
 }
-- 
2.13.2



More information about the devel mailing list