[rtems commit] cpukit: Add libdebugger, a remote debugger agent for GDB.

Chris Johns chrisj at rtems.org
Mon Nov 28 22:10:23 UTC 2016


Module:    rtems
Branch:    master
Commit:    a0d4e9933c57693f99203da358bb8aaa8a5d50d9
Changeset: http://git.rtems.org/rtems/commit/?id=a0d4e9933c57693f99203da358bb8aaa8a5d50d9

Author:    Chris Johns <chrisj at rtems.org>
Date:      Fri Nov 25 15:13:36 2016 +1100

cpukit: Add libdebugger, a remote debugger agent for GDB.

---

 cpukit/Makefile.am                             |    9 +
 cpukit/configure.ac                            |   12 +
 cpukit/libdebugger/Makefile.am                 |   23 +
 cpukit/libdebugger/preinstall.am               |    9 +
 cpukit/libdebugger/rtems-debugger-arm.c        | 1193 ++++++++++++++
 cpukit/libdebugger/rtems-debugger-block.c      |   73 +
 cpukit/libdebugger/rtems-debugger-block.h      |   75 +
 cpukit/libdebugger/rtems-debugger-cmd.c        |  208 +++
 cpukit/libdebugger/rtems-debugger-i386.c       |  421 +++++
 cpukit/libdebugger/rtems-debugger-remote-tcp.c |  342 ++++
 cpukit/libdebugger/rtems-debugger-remote-tcp.h |   47 +
 cpukit/libdebugger/rtems-debugger-remote.c     |   68 +
 cpukit/libdebugger/rtems-debugger-remote.h     |   71 +
 cpukit/libdebugger/rtems-debugger-server.c     | 1993 ++++++++++++++++++++++++
 cpukit/libdebugger/rtems-debugger-server.h     |  204 +++
 cpukit/libdebugger/rtems-debugger-target.c     |  400 +++++
 cpukit/libdebugger/rtems-debugger-target.h     |  237 +++
 cpukit/libdebugger/rtems-debugger-threads.c    |  577 +++++++
 cpukit/libdebugger/rtems-debugger-threads.h    |  272 ++++
 cpukit/libdebugger/rtems-debugger.h            |   81 +
 cpukit/preinstall.am                           |   18 +
 cpukit/wrapup/Makefile.am                      |    4 +
 testsuites/libtests/Makefile.am                |    4 +
 testsuites/libtests/configure.ac               |   12 +
 testsuites/libtests/debugger01/Makefile.am     |   21 +
 testsuites/libtests/debugger01/debugger01.doc  |   18 +
 testsuites/libtests/debugger01/debugger01.scn  |  188 +++
 testsuites/libtests/debugger01/init.c          |   53 +
 testsuites/libtests/debugger01/remote.c        |  321 ++++
 testsuites/libtests/debugger01/system.h        |   37 +
 30 files changed, 6991 insertions(+)

diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am
index 6ca5e16..73bf35d 100644
--- a/cpukit/Makefile.am
+++ b/cpukit/Makefile.am
@@ -18,6 +18,7 @@ SUBDIRS += libmd
 SUBDIRS += libgnat
 SUBDIRS += libdl
 SUBDIRS += libstdthreads
+SUBDIRS += libdebugger
 SUBDIRS += wrapup
 
 SUBDIRS += zlib
@@ -99,6 +100,14 @@ include_rtems_rtl_HEADERS += libdl/rtl-indirect-ptr.h libdl/rtl-sym.h libdl/rtl-
 include_rtems_rtl_HEADERS += libdl/rap.h libdl/rap-shell.h
 endif
 
+if LIBDEBUGGER
+include_rtems_HEADERS += libdebugger/rtems-debugger.h
+include_rtems_debuggerdir = $(includedir)/rtems/debugger
+include_rtems_debugger_HEADERS  =
+include_rtems_debugger_HEADERS += libdebugger/rtems-debugger-server.h
+include_rtems_debugger_HEADERS +=  libdebugger/rtems-debugger-remote.h
+endif
+
 include_rtems_HEADERS += include/rtems/bspIo.h
 include_rtems_HEADERS += include/rtems/print.h
 include_rtems_HEADERS += include/rtems/printer.h
diff --git a/cpukit/configure.ac b/cpukit/configure.ac
index 5a6c2e6..3ebf596 100644
--- a/cpukit/configure.ac
+++ b/cpukit/configure.ac
@@ -396,6 +396,17 @@ esac
 AM_CONDITIONAL(LIBDL,[test x"$HAVE_LIBDL" = x"yes"])
 AC_MSG_RESULT([$HAVE_LIBDL])
 
+# Filter debugger to only build for architectures that have a target backend
+AC_MSG_CHECKING([whether CPU supports libdebugger])
+case $RTEMS_CPU in
+  arm | i386)
+   HAVE_LIBDEBUGGER=yes ;;
+  *)
+   HAVE_LIBDEBUGGER=no ;;
+esac
+AM_CONDITIONAL(LIBDEBUGGER,[test x"$HAVE_LIBDEBUGGER" = x"yes"])
+AC_MSG_RESULT([$HAVE_LIBDEBUGGER])
+
 AC_MSG_CHECKING([whether CPU supports SHA])
 case $RTEMS_CPU in
   m32c)
@@ -474,6 +485,7 @@ libi2c/Makefile
 libmd/Makefile
 libdl/Makefile
 libstdthreads/Makefile
+libdebugger/Makefile
 zlib/Makefile
 ftpd/Makefile
 telnetd/Makefile
diff --git a/cpukit/libdebugger/Makefile.am b/cpukit/libdebugger/Makefile.am
new file mode 100644
index 0000000..72a8944
--- /dev/null
+++ b/cpukit/libdebugger/Makefile.am
@@ -0,0 +1,23 @@
+if LIBDEBUGGER
+
+include $(top_srcdir)/automake/compile.am
+
+noinst_LIBRARIES = libdebugger.a
+libdebugger_a_SOURCES = \
+  rtems-debugger-block.c \
+  rtems-debugger-cmd.c \
+  rtems-debugger-remote.c \
+  rtems-debugger-server.c \
+  rtems-debugger-target.c \
+  rtems-debugger-threads.c \
+  rtems-debugger- at RTEMS_CPU@.c
+
+if LIBNETWORKING
+libdebugger_a_SOURCES += \
+  rtems-debugger-remote-tcp.c
+endif
+
+endif
+
+include $(srcdir)/preinstall.am
+include $(top_srcdir)/automake/local.am
diff --git a/cpukit/libdebugger/preinstall.am b/cpukit/libdebugger/preinstall.am
new file mode 100644
index 0000000..695eb30
--- /dev/null
+++ b/cpukit/libdebugger/preinstall.am
@@ -0,0 +1,9 @@
+## Automatically generated by ampolish3 - Do not edit
+
+if AMPOLISH3
+$(srcdir)/preinstall.am: Makefile.am
+	$(AMPOLISH3) $(srcdir)/Makefile.am > $(srcdir)/preinstall.am
+endif
+
+if LIBDEBUGGER
+endif
diff --git a/cpukit/libdebugger/rtems-debugger-arm.c b/cpukit/libdebugger/rtems-debugger-arm.c
new file mode 100644
index 0000000..945dc9c
--- /dev/null
+++ b/cpukit/libdebugger/rtems-debugger-arm.c
@@ -0,0 +1,1193 @@
+/*
+ * 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define TARGET_DEBUG 0
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include <rtems.h>
+#include <rtems/score/threadimpl.h>
+
+#include <libcpu/arm-cp15.h>
+#include <bsp/linker-symbols.h>
+
+#include "rtems-debugger-target.h"
+#include "rtems-debugger-threads.h"
+
+#if TARGET_DEBUG
+#include <rtems/bspIo.h>
+#endif
+
+/*
+ * The ARM has 2 interrupt bits.
+ */
+#define CPSR_IRQ_DISABLE 0x80    /* IIQ disabled when 1 */
+#define CPSR_FIQ_DISABLE 0x40    /* FIQ disabled when 1 */
+#define CPSR_INTS_MASK   (CPSR_IRQ_DISABLE | CPSR_FIQ_DISABLE)
+
+/*
+ * Software breakpoint block size.
+ */
+#define RTEMS_DEBUGGER_SWBREAK_NUM 64
+
+/*
+ * Number of registers.
+ */
+#define RTEMS_DEBUGGER_NUMREGS 26
+
+/*
+ * Number of bytes per register.
+ */
+#define RTEMS_DEBUGGER_REGBYTES 4
+
+/*
+ * Number of bytes of registers.
+ */
+#define RTEMS_DEBUGGER_NUMREGBYTES \
+  (RTEMS_DEBUGGER_NUMREGS * RTEMS_DEBUGGER_REGBYTES)
+
+/*
+ * Debugger registers layout.
+ */
+#define REG_R0    0
+#define REG_R1    1
+#define REG_R2    2
+#define REG_R3    3
+#define REG_R4    4
+#define REG_R5    5
+#define REG_R6    6
+#define REG_R7    7
+#define REG_R8    8
+#define REG_R9    9
+#define REG_R10   10
+#define REG_R11   11
+#define REG_R12   12
+#define REG_SP    13
+#define REG_LR    14
+#define REG_PC    15
+#define REG_CPSR  25
+
+/**
+ * The various status registers.
+ */
+#if defined(ARM_MULTILIB_ARCH_V4)
+ #define FRAME_SR frame->register_cpsr
+#elif defined(ARM_MULTILIB_ARCH_V7M)
+ #define FRAME_SR frame->register_xpsr
+#else
+ #error ARM architecture is not supported.
+#endif
+
+/**
+ * The breakpoint.
+ */
+#ifdef __thumb__
+ static const uint8_t breakpoint[2] = { 0x55, 0xbe };
+#else
+ static const uint8_t breakpoint[4] = { 0x75, 0xe0a, 0x20, 0xe1 };
+#endif
+
+/**
+ * Target lock.
+ */
+RTEMS_INTERRUPT_LOCK_DEFINE(static, target_lock, "target_lock")
+
+/**
+ * The init value for the text section.
+ */
+static uint32_t text_section_flags;
+
+/**
+ * Is a session active?
+ */
+static bool debug_session_active;
+
+/*
+ * ARM debug hardware.
+ */
+static int debug_version;
+static int debug_revision;;
+static int hw_breakpoints;
+static int hw_watchpoints;
+
+/**
+ * Hardware break and watch points.
+ */
+typedef struct
+{
+  bool                 enabled;
+  bool                 loaded;
+  void*                address;
+  size_t               length;
+  CPU_Exception_frame* frame;
+  uint32_t             control;
+  uint32_t             value;
+} arm_debug_hwbreak;
+
+#define ARM_HW_BREAKPOINT_MAX (16)
+#define ARM_HW_WATCHPOINT_MAX (16)
+
+/*
+ * Types of break points. Only the 2 we use listed.
+ */
+#define ARM_HW_BP_UNLINKED_INSTR_MATCH    (0x00)
+#define ARM_HW_BP_UNLINKED_INSTR_MISMATCH (0x04)
+
+/*
+ * Privilege levels.
+ */
+#define ARM_HW_BP_PRIV_PL0_SUP_SYS (0x00)
+#define ARM_HW_BP_PRIV_PL1_ONLY    (0x01)
+#define ARM_HW_BP_PRIV_PL0_ONLY    (0x02)
+#define ARM_HW_BP_PRIV_ALL_MODES   (0x03)
+
+static arm_debug_hwbreak hw_breaks[ARM_HW_BREAKPOINT_MAX];
+//static arm_debug_hwbreak hw_watches[ARM_HW_WATCHPOINT_MAX];
+
+#if TARGET_DEBUG
+static void target_printk(const char* format, ...) RTEMS_PRINTFLIKE(1, 2);
+static void
+target_printk(const char* format, ...)
+{
+  va_list ap;
+  va_start(ap, format);
+  vprintk(format, ap);
+  va_end(ap);
+}
+static const char*
+mode_label(int mode)
+{
+  switch (mode) {
+  case 0x10:
+    return "USR";
+  case 0x11:
+    return "FIQ";
+  case 0x12:
+    return "IRQ";
+  case 0x13:
+    return "SVC";
+  case 0x16:
+    return "MON";
+  case 0x17:
+    return "ABT";
+  case 0x1a:
+    return "HYP";
+  case 0x1b:
+    return "UND";
+  case 0x1f:
+    return "SYS";
+  }
+  return "---";
+}
+#else
+#define target_printk(_fmt, ...)
+#define mode_labels(_m) NULL
+#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.
+ */
+#define ARM_CP14_INSTR(_opc, _val, _CRn, _CRm, _opc2)                   \
+  #_opc " p14, 0, %[" #_val "], c" #_CRn ", c" #_CRm ", " #_opc2 "\n"
+
+#define ARM_CP14_WRITE(_val, _CRn, _CRm, _opc2)            \
+  do {                                                     \
+    ARM_SWITCH_REGISTERS;                                  \
+    asm volatile(                                          \
+      ARM_SWITCH_TO_ARM                                    \
+      ARM_CP14_INSTR(mcr, val, _CRn, _CRm, _opc2)          \
+      ARM_SWITCH_BACK                                      \
+      :  ARM_SWITCH_OUTPUT : [val] "r" (_val));            \
+  } while (0)
+
+#define ARM_CP14_READ(_val, _CRn, _CRm, _opc2)             \
+  do {                                                     \
+    ARM_SWITCH_REGISTERS;                                  \
+    asm volatile(                                          \
+      ARM_SWITCH_TO_ARM                                    \
+      ARM_CP14_INSTR(mrc, val, _CRn, _CRm, _opc2)          \
+      ARM_SWITCH_BACK                                      \
+      : [val] "=&r" (_val) ARM_SWITCH_ADDITIONAL_OUTPUT);  \
+  } while (0)
+
+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[] = {
+    "ARMv6 [v6]",
+    "ARMv6 [v6.1]",
+    "ARMv7 [v7, all CP14 registers]",
+    "ARMv7 [v7, baseline CP14 registers]",
+    "ARMv7 [v7.1]"
+  };
+  ARM_CP14_READ(val, 0, 0, 0);
+  debug_version = ID_VALUE(val, 19, 16);
+  if (debug_version < 1 || debug_version > 5) {
+    rtems_debugger_printf("rtems-db: arm debug: (v%d.%d) not supported\n",
+                          debug_version, debug_revision);
+    errno = EIO;
+    return -1;
+  }
+  vl = labels[debug_version - 1];
+  debug_revision = ID_VALUE(val, 3, 0);
+  hw_breakpoints = ID_VALUE(val, 27, 24);
+  hw_watchpoints = ID_VALUE(val, 31, 28);
+  rtems_debugger_printf("rtems-db: arm debug: (v%d.%d) %s breakpoints:%d watchpoints:%d\n",
+                        debug_version, debug_revision, vl,
+                        hw_breakpoints, hw_watchpoints);
+  ARM_CP14_READ(val, 0, 1, 0);
+  if ((val & (1 << 15)) == 0) {
+    switch (debug_version) {
+    case 1:
+    case 2:
+      ARM_CP14_WRITE(val | (1 << 15), 0, 1, 0);
+      break;
+    case 3:
+    case 4:
+    case 5:
+    default:
+      ARM_CP14_WRITE(val | (1 << 15), 0, 2, 2);
+      break;
+    }
+    ARM_CP14_READ(val, 0, 1, 0);
+    if ((val & (1 << 15)) == 0) {
+      rtems_debugger_printf("rtems-db: arm debug: cannot enter monitor mode\n");
+      errno = EIO;
+      return -1;
+    }
+  }
+  return 0;
+}
+
+static inline void
+arm_debug_break_setup(arm_debug_hwbreak* bp,
+                      uint32_t           address,
+                      uint32_t           type,
+                      uint32_t           byte_address_select,
+                      uint32_t           privilege)
+{
+  bp->control = (((type & 0xf) << 20) |
+                 ((byte_address_select & 0xf) << 5) |
+                 ((privilege & 0x3) << 1) | 1);
+  bp->value = (intptr_t) address;
+}
+
+static void
+arm_debug_break_write_control(int bp, uint32_t control)
+{
+  switch (bp) {
+  case 0:
+    ARM_CP14_WRITE(control, 0, 0, 5);
+    break;
+  case 1:
+    ARM_CP14_WRITE(control, 0, 1, 5);
+    break;
+  case 2:
+    ARM_CP14_WRITE(control, 0, 2, 5);
+    break;
+  case 3:
+    ARM_CP14_WRITE(control, 0, 3, 5);
+    break;
+  case 4:
+    ARM_CP14_WRITE(control, 0, 4, 5);
+    break;
+  case 5:
+    ARM_CP14_WRITE(control, 0, 5, 5);
+    break;
+  case 6:
+    ARM_CP14_WRITE(control, 0, 6, 5);
+    break;
+  case 7:
+    ARM_CP14_WRITE(control, 0, 7, 5);
+    break;
+  case 8:
+    ARM_CP14_WRITE(control, 0, 8, 5);
+    break;
+  case 9:
+    ARM_CP14_WRITE(control, 0, 9, 5);
+    break;
+  case 10:
+    ARM_CP14_WRITE(control, 0, 10, 5);
+    break;
+  case 11:
+    ARM_CP14_WRITE(control, 0, 11, 5);
+    break;
+  case 12:
+    ARM_CP14_WRITE(control, 0, 12, 5);
+    break;
+  case 13:
+    ARM_CP14_WRITE(control, 0, 13, 5);
+    break;
+  case 14:
+    ARM_CP14_WRITE(control, 0, 14, 5);
+    break;
+  case 15:
+    ARM_CP14_WRITE(control, 0, 15, 5);
+    break;
+  }
+}
+
+static void
+arm_debug_break_write_value(int bp, uint32_t value)
+{
+  switch (bp) {
+  case 0:
+    ARM_CP14_WRITE(value, 0, 0, 4);
+    break;
+  case 1:
+    ARM_CP14_WRITE(value, 0, 1, 4);
+    break;
+  case 2:
+    ARM_CP14_WRITE(value, 0, 2, 4);
+    break;
+  case 3:
+    ARM_CP14_WRITE(value, 0, 3, 4);
+    break;
+  case 4:
+    ARM_CP14_WRITE(value, 0, 4, 4);
+    break;
+  case 5:
+    ARM_CP14_WRITE(value, 0, 5, 4);
+    break;
+  case 6:
+    ARM_CP14_WRITE(value, 0, 6, 4);
+    break;
+  case 7:
+    ARM_CP14_WRITE(value, 0, 7, 4);
+    break;
+  case 8:
+    ARM_CP14_WRITE(value, 0, 8, 4);
+    break;
+  case 9:
+    ARM_CP14_WRITE(value, 0, 9, 4);
+    break;
+  case 10:
+    ARM_CP14_WRITE(value, 0, 10, 4);
+    break;
+  case 11:
+    ARM_CP14_WRITE(value, 0, 11, 4);
+    break;
+  case 12:
+    ARM_CP14_WRITE(value, 0, 12, 4);
+    break;
+  case 13:
+    ARM_CP14_WRITE(value, 0, 13, 4);
+    break;
+  case 14:
+    ARM_CP14_WRITE(value, 0, 14, 4);
+    break;
+  case 15:
+    ARM_CP14_WRITE(value, 0, 15, 4);
+    break;
+  }
+}
+
+static void
+arm_debug_break_clear(void)
+{
+  arm_debug_hwbreak* bp = &hw_breaks[0];
+  int                i;
+  for (i = 0; i < hw_breakpoints; ++i, ++bp) {
+    bp->enabled = false;
+    bp->loaded = false;
+  }
+}
+
+static void
+arm_debug_break_load(void)
+{
+  arm_debug_hwbreak* bp = &hw_breaks[0];
+  int                i;
+  for (i = 0; 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);
+    }
+  }
+}
+
+static void
+arm_debug_break_unload(void)
+{
+  arm_debug_hwbreak* bp = &hw_breaks[0];
+  int                i;
+  for (i = 0; i < hw_breakpoints; ++i, ++bp) {
+    bp->loaded = false;
+    arm_debug_break_write_control(i, 0);
+  }
+}
+
+#if NOT_USED_BUT_KEEPING
+static size_t
+arm_debug_break_length(void* pc)
+{
+  arm_debug_hwbreak* bp = &hw_breaks[0];
+  int                i;
+
+  for (i = 0; i < hw_breakpoints; ++i, ++bp) {
+    if (bp->enabled && bp->address == pc) {
+      return bp->length;
+    }
+  }
+  return sizeof(DB_UINT);
+}
+#endif
+
+int
+rtems_debugger_target_configure(rtems_debugger_target* target)
+{
+  target->capabilities = (RTEMS_DEBUGGER_TARGET_CAP_SWBREAK);
+  target->reg_num = RTEMS_DEBUGGER_NUMREGS;
+  target->reg_size = sizeof(uint32_t);
+  target->breakpoint = &breakpoint[0];
+  target->breakpoint_size = sizeof(breakpoint);
+  return arm_debug_probe(target);
+}
+
+static void
+target_exception(CPU_Exception_frame* frame)
+{
+#if TARGET_DEBUG
+  uint32_t ifsr = arm_cp15_get_instruction_fault_status();
+#endif
+
+  target_printk("[} frame = %08lx sig=%d vector=%x ifsr=%08lx pra=%08x\n",
+                (uint32_t) frame,
+                rtems_debugger_target_exception_to_signal(frame),
+                frame->vector, ifsr, (intptr_t) frame->register_pc);
+
+  if ((FRAME_SR & (1 <<  5)) == 0)
+    frame->register_pc = (void*) ((intptr_t) frame->register_pc - 8);
+  else
+    frame->register_pc = (void*) ((intptr_t) frame->register_pc - 4);
+
+  target_printk("[}  R0 = %08" PRIx32 "  R1 = %08" PRIx32       \
+                "  R2 = %08" PRIx32 "  R3 = %08" PRIx32 "\n",
+                frame->register_r0, frame->register_r1,
+                frame->register_r2, frame->register_r3);
+  target_printk("[}  R4 = %08" PRIx32 "  R5 = %08" PRIx32       \
+                "  R6 = %08" PRIx32 "  R7 = %08" PRIx32 "\n",
+                frame->register_r4, frame->register_r5,
+                frame->register_r6, frame->register_r7);
+  target_printk("[}  R8 = %08" PRIx32 "  R9 = %08" PRIx32       \
+                " R10 = %08" PRIx32 " R11 = %08" PRIx32 "\n",
+                frame->register_r8, frame->register_r9,
+                frame->register_r10, frame->register_r11);
+  target_printk("[} R12 = %08" PRIx32 "  SP = %08" PRIx32       \
+                "  LR = %08" PRIxPTR "  PC = %08" PRIxPTR "\n", \
+                frame->register_r12, frame->register_sp,
+                (intptr_t) frame->register_lr, (intptr_t) frame->register_pc);
+  target_printk("[}  CPSR = %08" PRIx32 " %c%c%c%c%c%c%c%c%c%c%c" \
+                " GE:%" PRIx32 " IT:%02" PRIx32 " M:%" PRIx32 " %s\n",
+                FRAME_SR,
+                (FRAME_SR & (1 << 31)) != 0 ? 'N' : '-',
+                (FRAME_SR & (1 << 30)) != 0 ? 'Z' : '-',
+                (FRAME_SR & (1 << 29)) != 0 ? 'C' : '-',
+                (FRAME_SR & (1 << 28)) != 0 ? 'V' : '-',
+                (FRAME_SR & (1 << 27)) != 0 ? 'Q' : '-',
+                (FRAME_SR & (1 << 24)) != 0 ? 'J' : '-',
+                (FRAME_SR & (1 <<  9)) != 0 ? 'E' : '-',
+                (FRAME_SR & (1 <<  8)) != 0 ? 'A' : '-',
+                (FRAME_SR & (1 <<  7)) != 0 ? 'I' : '-',
+                (FRAME_SR & (1 <<  6)) != 0 ? 'F' : '-',
+                (FRAME_SR & (1 <<  5)) != 0 ? 'T' : '-',
+                ((FRAME_SR >> (25 - 5)) & (0x3 << 5)) | ((FRAME_SR >> 10) & 0x1f),
+                (FRAME_SR >> 16) & 0xf,
+                FRAME_SR & 0x1f, mode_label(FRAME_SR & 0x1f));
+
+  arm_debug_break_clear();
+
+  if (!debug_session_active)
+    _ARM_Exception_default(frame);
+
+  switch (rtems_debugger_target_exception(frame)) {
+  case rtems_debugger_target_exc_consumed:
+  default:
+    break;
+  case rtems_debugger_target_exc_step:
+    FRAME_SR |= CPSR_INTS_MASK;
+    break;
+  case rtems_debugger_target_exc_cascade:
+    target_printk("rtems-db: unhandled exception: cascading\n");
+    _ARM_Exception_default(frame);
+    break;
+  }
+
+  target_printk("[} resuming frame = %08lx PC = %08" PRIxPTR " CPSR = %08" PRIx32 "\n",
+                (uint32_t) frame, (intptr_t) frame->register_pc, FRAME_SR);
+}
+
+/**
+ * If thumb build of code switch the asm to thumb as required.
+ */
+#ifdef __thumb__
+  #define ASM_ARM_MODE   ".align 2\nbx pc\n.arm\n"
+  #define ASM_THUMB_MODE "add %[arm_switch_reg], pc, #1\nbx %[arm_switch_reg]\n.thumb\n"
+  #define ARM_SWITCH_REG uint32_t arm_switch_reg
+#else
+  #define ASM_ARM_MODE
+  #define ASM_THUMB_MODE
+  #define ARM_SWITCH_REG
+#endif
+
+/**
+ * Exception stack frame size.
+ *
+ * The size is the exception stack frame plus the CPSR from the exception. We
+ * save the CPSR and restore it when we exit the exception.
+ */
+#define EXCEPTION_FRAME_SIZE (sizeof(CPU_Exception_frame) + sizeof(uint32_t))
+
+/**
+ * Exception stack frame FPU offsets and sizes.
+ */
+#define EXCEPTION_FRAME_FPU_SIZE   ARM_VFP_CONTEXT_SIZE
+#define EXCEPTION_FRAME_FPU_OFFSET ARM_EXCEPTION_FRAME_VFP_CONTEXT_OFFSET
+
+/**
+ * Exception entry.
+ *
+ * We have switched from svc (or even user) to an exception mode. Save the
+ * current CPSR and create an exception frame on the exception's stack and then
+ * copy it to the thread's stack. Switch back to the thread's context and mode
+ * to handle the exception to avoid any stack checks thinking the stack is
+ * blown. This lets the thread be suspended.
+ *
+ * The entry is in two parts, the exception mode entry and the trhead mode
+ * entry. This lets us disable any hardware breakpoint support. We need to do
+ * this because it is enabled in PL0 mode.
+ *
+ * Note, the code currently assumes cp15 has been set up to match the
+ *       instruction set being used.
+ */
+#define EXCEPTION_ENTRY_EXC()                                           \
+  __asm__ volatile(                                                     \
+    ASM_ARM_MODE                                                        \
+    "sub  sp, %[frame_size]\n"           /* alloc the frame and CPSR */ \
+    "stm  sp, {r0-r12}\n"                            /* store r0-r12 */ \
+    "sub  sp, #4\n"                                                     \
+    "str  lr, [sp]\n"                           /* save the link reg */ \
+    ASM_THUMB_MODE                                                      \
+    : [arm_switch_reg] "=&r" (arm_switch_reg)                           \
+    : [frame_size] "i" (EXCEPTION_FRAME_SIZE)                           \
+    : "memory")
+
+/*
+ * FPU entry. Conditionally D16 or D32 support.
+ */
+#ifdef ARM_MULTILIB_VFP
+#ifdef ARM_MULTILIB_VFP_D32
+#define FPU_ENTRY_VFP_D32                                               \
+    "vstmia  r5!, {d16-d31}\n"
+#else  /* ARM_MULTILIB_VFP_D32 */
+#define FPU_ENTRY_VFP_D32                                               \
+    "mov    r3, #0\n"                                                   \
+    "mov    r4, #0\n"                                                   \
+    "adds   r6, r5, #128\n"                                             \
+    "3:\n"                                                              \
+    "stmia  r5!, {r3-r4}\n"                                             \
+    "cmp    r5, r6\n"                                                   \
+    "bne    3b\n"
+#endif /* ARM_MULTILIB_VFP_D32 */
+#define EXCEPTION_ENTRY_FPU(frame_fpu_size)                             \
+    "sub    sp, %[frame_fpu_size]\n" /* size includes alignment size */ \
+    "add    r5, sp, #4\n"                        /* up to align down */ \
+    "bic    r5, r5, #7\n"                     /* align the FPU frame */ \
+    "str    r5, [r2]\n"               /* store the FPU frame pointer */ \
+    "vmrs   r3, FPEXC\n"                                                \
+    "vmrs   r4, FPSCR\n"                                                \
+    "stmia  r5!, {r3-r4}\n"                                             \
+    "vstmia r5!, {d0-d15}\n"                                            \
+    FPU_ENTRY_VFP_D32
+#else  /* ARM_MULTILIB_VFP */
+#define EXCEPTION_ENTRY_FPU(frame_fpu_size)
+#endif /* ARM_MULTILIB_VFP */
+
+#define EXCEPTION_ENTRY_THREAD(_frame)                                  \
+  __asm__ volatile(                                                     \
+    ASM_ARM_MODE                                                        \
+    "ldr  lr, [sp]\n"                        /* recover the link reg */ \
+    "add  sp, #4\n"                                                     \
+    "add  r0, sp, %[r0_r12_size]\n"       /* get the sp in the frame */ \
+    "mrs  r1, spsr\n"                            /* get the saved sr */ \
+    "mov  r6, r1\n"                            /* stash it for later */ \
+    "bic  r1, r1, %[psr_t]\n"         /* clear thumb mode, not sure? */ \
+    "orr  r1, r1, %[psr_i]\n"                           /* mask irqs */ \
+    "mrs  r2, cpsr\n"                          /* get the current sr */ \
+    "str  r2, [sp, %[frame_cpsr]]\n"          /* save for exc return */ \
+    "msr  cpsr, r1\n"                         /* switch to user mode */ \
+    "mov  r3, sp\n"                         /* get the stack pointer */ \
+    "mov  r4, lr\n"                              /* get the link reg */ \
+    "msr  cpsr, r2\n"                            /* back to exc mode */ \
+    "mov  r5, lr\n"                                   /* get the PRA */ \
+    "stm  r0, {r3-r6}\n"                      /* save into the frame */ \
+    "sub  r4, r3, %[frame_size]\n"            /* destination address */ \
+    "mov  r6, r4\n"                                /* save the frame */ \
+    "sub  r4, #1\n"                          /* one before the start */ \
+    "add  r3, #1\n"                              /* one past the end */ \
+    "sub  r5, sp, #1\n"                            /* source address */ \
+    "1:\n"                                                              \
+    "ldrb r0, [r5, #1]!\n"                             /* get a byte */ \
+    "strb r0, [r4, #1]!\n"                           /* put the byte */ \
+    "cmp  r3, r4\n"                                      /* the end? */ \
+    "bne  1b\n"                                                         \
+    "add  sp, %[frame_size]\n"            /* free the frame and CPSR */ \
+    "mrs  r1, spsr\n"                   /* get the thread's saved sr */ \
+    "orr  r2, r1, %[psr_i]\n"                           /* mask irqs */ \
+    "msr  cpsr, r2\n"         /* switch back to the thread's context */ \
+    "sub  sp, %[frame_size]\n"          /* alloc in the thread stack */ \
+    "mov  %[o_frame], sp\n"                        /* save the frame */ \
+    "add  r2, sp, %[o_frame_fpu]\n"            /* get the FPU offset */ \
+    "mov  r3, #0\n"                                                     \
+    "str  r3, [r2]\n"                 /* clear the FPU frame pointer */ \
+    EXCEPTION_ENTRY_FPU(frame_fpu_size)                                 \
+    "msr  cpsr, r1\n"                        /* restore the irq mask */ \
+    ASM_THUMB_MODE                                                      \
+    : [arm_switch_reg] "=&r" (arm_switch_reg),                          \
+      [o_frame] "=r" (_frame)                                           \
+    : [psr_t] "i" (ARM_PSR_T),                                          \
+      [psr_i] "i" (ARM_PSR_I),                                          \
+      [r0_r12_size] "i" (13 * sizeof(uint32_t)),                        \
+      [frame_cpsr] "i" (EXCEPTION_FRAME_SIZE - sizeof(uint32_t)),       \
+      [frame_size] "i" (EXCEPTION_FRAME_SIZE),                          \
+      [o_frame_fpu] "i" (EXCEPTION_FRAME_FPU_OFFSET),                   \
+      [frame_fpu_size] "i" (EXCEPTION_FRAME_FPU_SIZE + 4)               \
+    : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "memory")
+
+/*
+ * FPU exit. Conditionally D16 or D32 support.
+ */
+#ifdef ARM_MULTILIB_VFP
+#ifdef ARM_MULTILIB_VFP_D32
+#define FPU_EXIT_VFP_D32                                                \
+    "vldmia r0, {d16-d31}\n"
+#else  /* ARM_MULTILIB_VFP_D32 */
+#define FPU_EXIT_VFP_D32
+#endif /* ARM_MULTILIB_VFP_D32 */
+#define EXCEPTION_EXIT_FPU(frame_fpu_size)                              \
+    "ldmia  r0!, {r1-r2}\n"                                             \
+    "vldmia r0!, {d0-d15}\n"                                            \
+    FPU_EXIT_VFP_D32                                                    \
+    "vmsr   FPEXC, r1\n"                                                \
+    "vmsr   FPSCR, r2\n"                                                \
+    "add    sp, %[frame_fpu_size]\n" /* size includes alignment size */
+#else  /* ARM_MULTILIB_VFP */
+#define EXCEPTION_EXIT_FPU(frame_fpu_size)
+#endif /* ARM_MULTILIB_VFP */
+
+/**
+ * Exception exit.
+ *
+ * The thread is to be resumed so we are still in the thread's mode. Copy the
+ * exception frame from the thread's stack back to the exception's stack and
+ * restore the thread's context before returning from the exception to the
+ * thread.
+ *
+ * Note, the code currently assumes cp15 has been set up to match the
+ *       instruction set being used.
+ */
+#define EXCEPTION_EXIT_THREAD(_frame)                                   \
+  __asm__ volatile(                                                     \
+    ASM_ARM_MODE                                                        \
+    "mov  r0, %[i_frame]\n"                         /* get the frame */ \
+    "ldr  r0, [r0, %[frame_fpu]]\n"     /* recover FPU frame pointer */ \
+    EXCEPTION_EXIT_FPU(frame_fpu_size)                                  \
+    "ldr  r2, [sp, %[frame_cpsr]]\n" /* recover exc CPSR from thread */ \
+    "mov  r0, sp\n"                  /* get the thread frame pointer */ \
+    "msr  cpsr, r2\n"            /* switch back to the exc's context */ \
+    "add  r3, sp, #1\n"                               /* get the end */ \
+    "sub  sp, %[frame_size]\n"                    /* alloc the frame */ \
+    "sub  r4, sp, #1\n"                       /* destination address */ \
+    "sub  r5, r0, #1\n"                            /* source address */ \
+    "1:\n"                                                              \
+    "ldrb r1, [r5, #1]!\n"                             /* get a byte */ \
+    "strb r1, [r4, #1]!\n"                           /* put the byte */ \
+    "cmp  r3, r4\n"                                      /* the end? */ \
+    "bne  1b\n"                                                         \
+    "add  r1, r0, %[r0_r12_size]\n"       /* get the sp in the frame */ \
+    "ldm  r1, {r3-r6}\n"                   /* recover from the frame */ \
+    "orr  r1, r6, %[psr_i]\n"  /* get the thread's psr and mask irqs */ \
+    "msr  cpsr, r1\n"                         /* switch to user mode */ \
+    "mov  sp, r3\n"                         /* set the stack pointer */ \
+    "mov  lr, r4\n"                              /* set the link reg */ \
+    "msr  cpsr, r2\n"            /* switch back to the exc's context */ \
+    "msr  spsr, r6\n"                       /* set the thread's CPSR */ \
+    "sub  sp, #4\n"                                                     \
+    "mov  lr, r5\n"                                    /* get the PC */ \
+    "str  lr, [sp]\n"                           /* save the link reg */ \
+    ASM_THUMB_MODE                                                      \
+    : [arm_switch_reg] "=&r" (arm_switch_reg)                           \
+    : [psr_i] "i" (ARM_PSR_I),                                          \
+      [r0_r12_size] "i" (13 * sizeof(uint32_t)),                        \
+      [frame_cpsr] "i" (EXCEPTION_FRAME_SIZE - sizeof(uint32_t)),       \
+      [frame_size] "i" (EXCEPTION_FRAME_SIZE),                          \
+      [frame_fpu] "i" (EXCEPTION_FRAME_FPU_OFFSET),                     \
+      [frame_fpu_size] "i" (EXCEPTION_FRAME_FPU_SIZE + 4),              \
+      [i_frame] "r" (_frame)                                            \
+    : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "memory")
+
+#define EXCEPTION_EXIT_EXC()                                            \
+  __asm__ volatile(                                                     \
+    ASM_ARM_MODE                                                        \
+    "ldr  lr, [sp]\n"                        /* recover the link reg */ \
+    "add  sp, #4\n"                                                     \
+    "ldm  sp, {r0-r12}\n"            /* restore the trhead's context */ \
+    "add  sp, %[frame_size]\n"                     /* free the frame */ \
+    "subs pc, lr, #0\n"                       /* return from the exc */ \
+    :                                                                   \
+    : [frame_size] "i" (EXCEPTION_FRAME_SIZE)                           \
+    : "memory")
+
+
+static void __attribute__((naked))
+target_exception_undefined_instruction(void)
+{
+  CPU_Exception_frame* frame;
+  ARM_SWITCH_REG;
+  EXCEPTION_ENTRY_EXC();
+  arm_debug_break_unload();
+  EXCEPTION_ENTRY_THREAD(frame);
+  frame->vector = 1;
+  target_exception(frame);
+  EXCEPTION_EXIT_THREAD(frame);
+  arm_debug_break_load();
+  EXCEPTION_EXIT_EXC();
+}
+
+static void __attribute__((naked))
+target_exception_supervisor_call(void)
+{
+  CPU_Exception_frame* frame;
+  ARM_SWITCH_REG;
+  /*
+   * The PC offset needs to be review so we move past a svc instruction. This
+   * can then used as a user breakpoint. The issue is this exception is used by
+   * the BKPT instruction in the prefetch abort handler to signal a TRAP.
+   */
+  EXCEPTION_ENTRY_EXC();
+  arm_debug_break_unload();
+  EXCEPTION_ENTRY_THREAD(frame);
+  frame->vector = 2;
+  target_exception(frame);
+  EXCEPTION_EXIT_THREAD(frame);
+  arm_debug_break_load();
+  EXCEPTION_EXIT_EXC();
+}
+
+static void __attribute__((naked))
+target_exception_prefetch_abort(void)
+{
+  CPU_Exception_frame* frame;
+  ARM_SWITCH_REG;
+  EXCEPTION_ENTRY_EXC();
+  arm_debug_break_unload();
+  EXCEPTION_ENTRY_THREAD(frame);
+  if ((arm_cp15_get_instruction_fault_status() & 0x1f) == 0x02)
+    frame->vector = 2;
+  else
+    frame->vector = 3;
+  target_exception(frame);
+  EXCEPTION_EXIT_THREAD(frame);
+  arm_debug_break_load();
+  EXCEPTION_EXIT_EXC();
+}
+
+static void __attribute__((naked))
+target_exception_data_abort(void)
+{
+  CPU_Exception_frame* frame;
+  ARM_SWITCH_REG;
+  EXCEPTION_ENTRY_EXC();
+  arm_debug_break_unload();
+  EXCEPTION_ENTRY_THREAD(frame);
+  frame->vector = 4;
+  target_exception(frame);
+  EXCEPTION_EXIT_THREAD(frame);
+  arm_debug_break_load();
+  EXCEPTION_EXIT_EXC();
+}
+
+int
+rtems_debugger_target_enable(void)
+{
+  rtems_interrupt_lock_context lock_context;
+  void*                        text_begin;
+  void*                        text_end;
+  debug_session_active = true;
+  text_begin = &bsp_section_text_begin[0];
+  text_end = &bsp_section_text_end[0];
+  rtems_interrupt_lock_acquire(&target_lock, &lock_context);
+  arm_debug_break_unload();
+  arm_debug_break_clear();
+  text_section_flags =
+    arm_cp15_set_translation_table_entries(text_begin,
+                                           text_end,
+                                           ARMV7_MMU_DATA_READ_WRITE_CACHED);
+  arm_cp15_set_exception_handler(ARM_EXCEPTION_UNDEF,
+                                 target_exception_undefined_instruction);
+  arm_cp15_set_exception_handler(ARM_EXCEPTION_SWI,
+                                 target_exception_supervisor_call);
+  arm_cp15_set_exception_handler(ARM_EXCEPTION_PREF_ABORT,
+                                 target_exception_prefetch_abort);
+  arm_cp15_set_exception_handler(ARM_EXCEPTION_DATA_ABORT,
+                                 target_exception_data_abort);
+  rtems_interrupt_lock_release(&target_lock, &lock_context);
+  return 0;
+}
+
+int
+rtems_debugger_target_disable(void)
+{
+  rtems_interrupt_lock_context lock_context;
+#if DOES_NOT_WORK
+  void*                        text_begin;
+  void*                        text_end;
+#endif
+  rtems_interrupt_lock_acquire(&target_lock, &lock_context);
+  debug_session_active = false;
+#if DOES_NOT_WORK
+  text_begin = &bsp_section_text_begin[0];
+  text_end = &bsp_section_text_end[0];
+  arm_cp15_set_translation_table_entries(text_begin,
+                                         text_end,
+                                         text_section_flags);
+#endif
+  rtems_interrupt_lock_release(&target_lock, &lock_context);
+  return 0;
+}
+
+int
+rtems_debugger_target_read_regs(rtems_debugger_thread* thread)
+{
+  if (!rtems_debugger_thread_flag(thread,
+                                  RTEMS_DEBUGGER_THREAD_FLAG_REG_VALID)) {
+    static const uint32_t good_address = (uint32_t) &good_address;
+    uint32_t*             regs = &thread->registers[0];
+    int                   i;
+
+    for (i = 0; i < RTEMS_DEBUGGER_NUMREGS; ++i)
+      regs[i] = (uint32_t) &good_address;
+
+    if (thread->frame) {
+      CPU_Exception_frame* frame = thread->frame;
+
+      /*
+       * Assume interrupts are not masked and if masked set them to the saved
+       * value.
+       */
+      FRAME_SR &= ~CPSR_INTS_MASK;
+
+      if (rtems_debugger_thread_flag(thread,
+                                     RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED)) {
+        FRAME_SR |=
+          (thread->flags >> RTEMS_DEBUGGER_THREAD_FLAG_TARGET_BASE) & CPSR_INTS_MASK;
+        thread->flags = ~RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED;
+      }
+
+      regs[REG_R0]   = frame->register_r0;
+      regs[REG_R1]   = frame->register_r1;
+      regs[REG_R2]   = frame->register_r2;
+      regs[REG_R3]   = frame->register_r3;
+      regs[REG_R4]   = frame->register_r4;
+      regs[REG_R5]   = frame->register_r5;
+      regs[REG_R6]   = frame->register_r6;
+      regs[REG_R7]   = frame->register_r7;
+      regs[REG_R8]   = frame->register_r8;
+      regs[REG_R9]   = frame->register_r9;
+      regs[REG_R10]  = frame->register_r10;
+      regs[REG_R11]  = frame->register_r11;
+      regs[REG_R12]  = frame->register_r12;
+      regs[REG_SP]   = frame->register_sp;
+      regs[REG_LR]   = (uint32_t) frame->register_lr;
+      regs[REG_PC]   = (uint32_t) frame->register_pc;
+      regs[REG_CPSR] = FRAME_SR;
+      /*
+       * Get the signal from the frame.
+       */
+      thread->signal = rtems_debugger_target_exception_to_signal(frame);
+    }
+    else {
+#if defined(ARM_MULTILIB_ARCH_V4)
+      regs[REG_R4]  = thread->tcb->Registers.register_r4;
+      regs[REG_R5]  = thread->tcb->Registers.register_r5;
+      regs[REG_R6]  = thread->tcb->Registers.register_r6;
+      regs[REG_R7]  = thread->tcb->Registers.register_r7;
+      regs[REG_R8]  = thread->tcb->Registers.register_r8;
+      regs[REG_R9]  = thread->tcb->Registers.register_r9;
+      regs[REG_R10] = thread->tcb->Registers.register_r10;
+      regs[REG_R11] = thread->tcb->Registers.register_fp;
+      regs[REG_LR]  = (intptr_t) thread->tcb->Registers.register_lr;
+      regs[REG_PC]  = (intptr_t) thread->tcb->Registers.register_lr;
+      regs[REG_SP]  = (intptr_t) thread->tcb->Registers.register_sp;
+#elif defined(ARM_MULTILIB_ARCH_V7M)
+      regs[REG_R4]  = thread->tcb->Registers.register_r4;
+      regs[REG_R5]  = thread->tcb->Registers.register_r5;
+      regs[REG_R6]  = thread->tcb->Registers.register_r6;
+      regs[REG_R7]  = thread->tcb->Registers.register_r7;
+      regs[REG_R8]  = thread->tcb->Registers.register_r8;
+      regs[REG_R9]  = thread->tcb->Registers.register_r9;
+      regs[REG_R10] = thread->tcb->Registers.register_r10;
+      regs[REG_R11] = thread->tcb->Registers.register_r11;
+      regs[REG_LR]  = (intptr_t) thread->tcb->Registers.register_lr;
+      regs[REG_PC]  = (intptr_t) thread->tcb->Registers.register_lr;
+      regs[REG_SP]  = (intptr_t) thread->tcb->Registers.register_sp;
+#endif
+      /*
+       * Blocked threads have no signal.
+       */
+      thread->signal = 0;
+    }
+
+    thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_REG_VALID;
+    thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
+  }
+
+  return 0;
+}
+
+int
+rtems_debugger_target_write_regs(rtems_debugger_thread* thread)
+{
+  if (rtems_debugger_thread_flag(thread,
+                                 RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY)) {
+    uint32_t* regs = &thread->registers[0];
+
+    /*
+     * Only write to debugger controlled threads. Do not touch the registers
+     * for threads blocked in the context switcher.
+     */
+    if (rtems_debugger_thread_flag(thread,
+                                   RTEMS_DEBUGGER_THREAD_FLAG_DEBUGGING)) {
+      CPU_Exception_frame* frame = thread->frame;
+      frame->register_r0  = regs[REG_R0];
+      frame->register_r1  = regs[REG_R1];
+      frame->register_r2  = regs[REG_R2];
+      frame->register_r3  = regs[REG_R3];
+      frame->register_r4  = regs[REG_R4];
+      frame->register_r5  = regs[REG_R5];
+      frame->register_r6  = regs[REG_R6];
+      frame->register_r7  = regs[REG_R7];
+      frame->register_r8  = regs[REG_R8];
+      frame->register_r9  = regs[REG_R9];
+      frame->register_r10 = regs[REG_R10];
+      frame->register_r11 = regs[REG_R11];
+      frame->register_r12 = regs[REG_R12];
+      frame->register_sp  = regs[REG_SP];
+      frame->register_lr  = (void*) regs[REG_LR];
+      frame->register_pc  = (void*) regs[REG_PC];
+      FRAME_SR            = regs[REG_CPSR];
+    }
+    thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
+  }
+  return 0;
+}
+
+DB_UINT
+rtems_debugger_target_reg_pc(rtems_debugger_thread* thread)
+{
+  int r;
+  r = rtems_debugger_target_read_regs(thread);
+  if (r >= 0) {
+    uint32_t* regs = &thread->registers[0];
+    return regs[REG_PC];
+  }
+  return 0;
+}
+
+DB_UINT
+rtems_debugger_target_frame_pc(CPU_Exception_frame* frame)
+{
+  return (DB_UINT) frame->register_pc;
+}
+
+DB_UINT
+rtems_debugger_target_reg_sp(rtems_debugger_thread* thread)
+{
+  int r;
+  r = rtems_debugger_target_read_regs(thread);
+  if (r >= 0) {
+    uint32_t* regs = &thread->registers[0];
+    return regs[REG_SP];
+  }
+  return 0;
+}
+
+DB_UINT
+rtems_debugger_target_tcb_sp(rtems_debugger_thread* thread)
+{
+  return (DB_UINT) thread->tcb->Registers.register_sp;
+}
+
+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))) {
+    /*
+     * 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;
+          }
+        }
+
+        /*
+         * 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 */
+          }
+        }
+        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);
+
+        /*
+         * Save the interrupt state before stepping if set.
+         */
+        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;
+        break;
+      }
+    }
+  }
+  return 0;
+}
+
+int
+rtems_debugger_target_exception_to_signal(CPU_Exception_frame* frame)
+{
+  int sig = RTEMS_DEBUGGER_SIGNAL_HUP;
+  switch (frame->vector) {
+  case ARM_EXCEPTION_RESET:
+  case ARM_EXCEPTION_SWI:
+    sig = RTEMS_DEBUGGER_SIGNAL_TRAP;
+    break;
+  case ARM_EXCEPTION_UNDEF:
+    sig = RTEMS_DEBUGGER_SIGNAL_ILL;
+    break;
+  case ARM_EXCEPTION_FIQ:
+    sig = RTEMS_DEBUGGER_SIGNAL_FPE;
+    break;
+  case ARM_EXCEPTION_PREF_ABORT:
+  case ARM_EXCEPTION_DATA_ABORT:
+    sig = RTEMS_DEBUGGER_SIGNAL_SEGV;
+    break;
+  case ARM_EXCEPTION_RESERVED:
+  case ARM_EXCEPTION_IRQ:
+    sig = RTEMS_DEBUGGER_SIGNAL_BUS;
+    break;
+  default:
+    break;
+  }
+  return sig;
+}
+
+int
+rtems_debugger_target_hwbreak_control(rtems_debugger_target_watchpoint wp,
+                                      bool                             insert,
+                                      DB_UINT                          addr,
+                                      DB_UINT                          kind)
+{
+  /*
+   * To do.
+   */
+  return 0;
+}
+
+int
+rtems_debugger_target_cache_sync(rtems_debugger_target_swbreak* swbreak)
+{
+  /*
+   * Flush the data cache and invalidate the instruction cache.
+   */
+  rtems_cache_flush_multiple_data_lines(swbreak->address,
+                                        sizeof(breakpoint));
+  rtems_cache_invalidate_multiple_instruction_lines(swbreak->address,
+                                                    sizeof(breakpoint));
+  return 0;
+}
diff --git a/cpukit/libdebugger/rtems-debugger-block.c b/cpukit/libdebugger/rtems-debugger-block.c
new file mode 100644
index 0000000..918e321
--- /dev/null
+++ b/cpukit/libdebugger/rtems-debugger-block.c
@@ -0,0 +1,73 @@
+/*
+ * 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include "rtems-debugger-block.h"
+
+int
+rtems_debugger_block_create(rtems_debugger_block* block,
+                            size_t                step,
+                            size_t                size)
+{
+  int r = 0;
+  block->level = 0;
+  block->step = step;
+  block->count = step;
+  block->size = size;
+  block->block = calloc(block->count, block->size);
+  if (block->block == NULL)
+    errno = ENOMEM;
+  return r;
+}
+
+int
+rtems_debugger_block_destroy(rtems_debugger_block* block)
+{
+  free(block->block);
+  block->block = NULL;
+  block->level = 0;
+  block->count = 0;
+  block->size = 0;
+  return 0;
+}
+
+int
+rtems_debugger_block_resize(rtems_debugger_block* block)
+{
+  int r = 0;
+  if (block->level >= block->count) {
+    block->count += block->step;
+    block->block = realloc(block->block, block->count * block->size);
+    if (block->block == NULL) {
+      block->level = 0;
+      block->count = 0;
+      errno = ENOMEM;
+      r = -1;
+    }
+  }
+  return r;
+}
diff --git a/cpukit/libdebugger/rtems-debugger-block.h b/cpukit/libdebugger/rtems-debugger-block.h
new file mode 100644
index 0000000..c1c7fab
--- /dev/null
+++ b/cpukit/libdebugger/rtems-debugger-block.h
@@ -0,0 +1,75 @@
+/*
+ * 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Debugger for RTEMS.
+ */
+
+#ifndef _RTEMS_DEBUGGER_BLOCK_h
+#define _RTEMS_DEBUGGER_BLOCK_h
+
+#include <rtems/rtems-debugger.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * DB server block manages a block of re-sizable memory. The block only
+ * grows. As more threads enter the system the block becomes the peak and then
+ * sits at that level.
+ */
+typedef struct rtems_debugger_block
+{
+  void*  block;  /**< The block of memory. */
+  size_t step;   /**< The step size the block is increased by. */
+  size_t size;   /**< The size of the elements in the block. */
+  size_t count;  /**< The number of elements in the block. */
+  size_t level;  /**< The usage level in the block. */
+} rtems_debugger_block;
+
+/**
+ * Create a block.
+ */
+extern int rtems_debugger_block_create(rtems_debugger_block* block,
+				       size_t                step,
+				       size_t                size);
+
+/**
+ * Destroy a block.
+ */
+extern int rtems_debugger_block_destroy(rtems_debugger_block* block);
+
+/**
+ * Resize a block.
+ */
+extern int rtems_debugger_block_resize(rtems_debugger_block* block);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif
diff --git a/cpukit/libdebugger/rtems-debugger-cmd.c b/cpukit/libdebugger/rtems-debugger-cmd.c
new file mode 100644
index 0000000..e292065
--- /dev/null
+++ b/cpukit/libdebugger/rtems-debugger-cmd.c
@@ -0,0 +1,208 @@
+/*
+ * 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define __need_getopt_newlib
+#include <getopt.h>
+
+#include <rtems.h>
+#include <rtems/printer.h>
+#include <rtems/shell.h>
+
+#include <rtems/rtems-debugger.h>
+
+/*
+ * Debugger command for the RTEMS shell.
+ */
+
+static int rtems_shell_main_debugger(int argc, char *argv[])
+{
+  if (argc == 1) {
+    printf("RTEMS debugger is %srunning\n", rtems_debugger_running() ? "" : "not ");
+    return 0;
+  }
+
+  if (strcasecmp(argv[1], "start") == 0) {
+    rtems_printer       printer;
+    const char*         remote = "tcp";
+    const char*         device = "1122";
+    int                 timeout = RTEMS_DEBUGGER_TIMEOUT;
+    rtems_task_priority priority = 1;
+    bool                verbose = false;
+    struct getopt_data  data;
+    char*               end;
+    int                 r;
+
+    if (rtems_debugger_running()) {
+      printf("error: debugger already running.\n");
+      return 1;
+    }
+
+    memset(&data, 0, sizeof(data));
+
+    rtems_print_printer_fprintf(&printer, stdout);
+
+    argv += 1;
+    argc -= 1;
+
+    while (true) {
+      int c;
+
+      c = getopt_r(argc, argv, "vR:d:t:P:l:", &data);
+      if (c == -1)
+        break;
+
+      switch (c) {
+      case 'v':
+        verbose = true;
+        break;
+      case 'R':
+        remote = data.optarg;
+        break;
+      case 'd':
+        device = data.optarg;
+        break;
+      case 't':
+        timeout = strtoul(data.optarg, &end, 10);
+        if (timeout == 0 || *end != '\0') {
+          printf("error: invalid timeout: %s\n", data.optarg);
+          return 1;
+        }
+        break;
+      case 'P':
+        priority = strtoul(data.optarg, &end, 10);
+        if (priority == 0 || *end != '\0') {
+          printf("error: invalid priority: %s\n", data.optarg);
+          return 1;
+        }
+        break;
+      case 'l':
+        if (strcasecmp(data.optarg, "stdout") == 0)
+          rtems_print_printer_fprintf(&printer, stdout);
+        else if (strcasecmp(data.optarg, "stderr") == 0)
+          rtems_print_printer_fprintf(&printer, stderr);
+        else if (strcasecmp(data.optarg, "kernel") == 0)
+          rtems_print_printer_printk(&printer);
+        else {
+          printf("error: unknown printer (stdout, stderr, kernel): %s\n", data.optarg);
+          return 1;
+        }
+        break;
+      default:
+      case '?':
+        if (data.optarg != NULL)
+          printf("error: unknown option: %s\n", data.optarg);
+        else
+          printf("error: invalid start command\n");
+        return 1;
+      }
+    }
+
+    printf("RTEMS Debugger start: remote=%s device=%s priority=%" PRIu32 "\n",
+           remote, device, priority);
+
+    r = rtems_debugger_start(remote, device, timeout, priority, &printer);
+    if (r < 0) {
+      printf("debugger start failed\n");
+      return 1;
+    }
+
+    rtems_debugger_set_verbose(verbose);
+  }
+  else if (strcasecmp(argv[1], "stop") == 0) {
+    int r;
+
+    if (!rtems_debugger_running()) {
+      printf("error: debugger not running.\n");
+      return 1;
+    }
+
+    r = rtems_debugger_stop();
+    if (r < 0) {
+      printf("debugger stop failed\n");
+      return 1;
+    }
+  }
+  else if (strcasecmp(argv[1], "remote-debug") == 0) {
+    int r;
+
+    if (!rtems_debugger_running()) {
+      printf("error: debugger not running.\n");
+      return 1;
+    }
+
+    if (argc == 3 && strcasecmp(argv[2], "on") == 0) {
+      r = rtems_debugger_remote_debug(true);
+      if (r < 0) {
+        printf("debugger remote-debug on failed\n");
+        return 1;
+      }
+    }
+    else if (argc == 3 && strcasecmp(argv[2], "off") == 0) {
+      r = rtems_debugger_remote_debug(false);
+      if (r < 0) {
+        printf("debugger remote-debug off failed\n");
+        return 1;
+      }
+    }
+    else {
+      printf("debugger remote-debug: 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" \
+           "  help\n");
+  }
+  else {
+    printf("error: unknown command: %s\n", argv[1]);
+    return 1;
+  }
+
+  return 0;
+}
+
+rtems_shell_cmd_t rtems_shell_DEBUGGER_Command = {
+  "debugger",                               /* name */
+  "debugger [start/stop] [options ...]",    /* usage */
+  "misc",                                   /* topic */
+  rtems_shell_main_debugger,                /* command */
+  NULL,                                     /* alias */
+  NULL,                                     /* next */
+  0755,
+  0,
+  0
+};
diff --git a/cpukit/libdebugger/rtems-debugger-i386.c b/cpukit/libdebugger/rtems-debugger-i386.c
new file mode 100644
index 0000000..901ba85
--- /dev/null
+++ b/cpukit/libdebugger/rtems-debugger-i386.c
@@ -0,0 +1,421 @@
+/*
+ * 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define TARGET_DEBUG 1
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include <rtems.h>
+#include <rtems/score/threadimpl.h>
+
+#include "rtems-debugger-target.h"
+#include "rtems-debugger-threads.h"
+
+/*
+ * Hardware breakpoints. Limited by hardware
+ */
+#define RTEMS_DEBUGGER_HWBREAK_NUM 4
+
+/*
+ * Number of registers.
+ */
+#define RTEMS_DEBUGGER_NUMREGS 16
+
+/*
+ * Number of bytes per register.
+ */
+#define RTEMS_DEBUGGER_REGBYTES 4
+
+/*
+ * Number of bytes of registers.
+ */
+#define RTEMS_DEBUGGER_NUMREGBYTES \
+  (RTEMS_DEBUGGER_NUMREGS * RTEMS_DEBUGGER_REGBYTES)
+
+/*
+ * Debugger registers layout.
+ */
+#define REG_EAX    0
+#define REG_ECX    1
+#define REG_EDX    2
+#define REG_EBX    3
+#define REG_ESP    4
+#define REG_EBP    5
+#define REG_ESI    6
+#define REG_EDI    7
+#define REG_PC     8
+#define REG_EIP    REG_PC
+#define REG_PS     9
+#define REG_EFLAGS REG_PS
+#define REG_CS     10
+#define REG_SS     11
+#define REG_DS     12
+#define REG_ES     13
+#define REG_FS     14
+#define REG_GS     15
+
+/**
+ * The int 3 opcode.
+ */
+#define TARGET_BKPT 0xcc
+
+static const uint8_t breakpoint[1] = { TARGET_BKPT };
+
+/*
+ * Get a copy of a register.
+ */
+#define GET_REG(_r, _v) asm volatile("pushl %%" #_r "; popl %0" : "=rm" (_v))
+
+/*
+ * Get a copy of a segment register.
+ */
+#define GET_SEG_REG(_r, _v) \
+  do {                      \
+    int _i;                 \
+    GET_REG(_r, _i);        \
+    _v = _i & 0xffff;       \
+  } while (0)
+
+/**
+ * Target lock.
+ */
+RTEMS_INTERRUPT_LOCK_DEFINE(static, target_lock, "target_lock")
+
+/**
+ * The orginal exception handler.
+ */
+static void (*orig_currentExcHandler)(CPU_Exception_frame* frame);
+
+#if TARGET_DEBUG
+#include <rtems/bspIo.h>
+static void target_printk(const char* format, ...) RTEMS_PRINTFLIKE(1, 2);
+static void
+target_printk(const char* format, ...)
+{
+  va_list ap;
+  va_start(ap, format);
+  vprintk(format, ap);
+  va_end(ap);
+}
+#else
+#define target_printk(_fmt, ...)
+#endif
+
+#if TODO
+/**
+ * Target description.
+ */
+static const char* const target_xml =
+"<?xml version=\"1.0\">                        \
+ <!DOCTYPE target SYSTEM \"gdb-target.dtd\">   \
+ <target version=\"1.0\">                      \
+  <architecture>i386</architecture>            \
+  <xi:include href=\"32bit-core.xml\"/>        \
+  <xi:include href=\"32bit-sse.xml\"/>         \
+</target>";
+#endif
+
+int
+rtems_debugger_target_configure(rtems_debugger_target* target)
+{
+  target->capabilities = (RTEMS_DEBUGGER_TARGET_CAP_SWBREAK);
+  target->reg_num = RTEMS_DEBUGGER_NUMREGS;
+  target->reg_size = sizeof(uint32_t);
+  target->breakpoint = &breakpoint[0];
+  target->breakpoint_size = sizeof(breakpoint);
+  return 0;
+}
+
+static void
+target_exception(CPU_Exception_frame* frame)
+{
+  target_printk("[} frame = %08lx sig=%d (%lx)\n",
+                (uint32_t) frame,
+                rtems_debugger_target_exception_to_signal(frame),
+                frame->idtIndex);
+  target_printk("[} EAX = %" PRIx32 " EBX = %" PRIx32 \
+                " ECX = %" PRIx32 " EDX = %" PRIx32 "\n",
+                frame->eax, frame->ebx, frame->ecx, frame->edx);
+  target_printk("[} ESI = %" PRIx32 " EDI = %" PRIx32           \
+                " EBP = %" PRIx32 " ESP = %" PRIx32 "\n",
+                frame->esi, frame->edi, frame->ebp, frame->esp0);
+  target_printk("[} EIP = %" PRIx32"\n", frame->eip);
+
+  frame->eflags &= ~EFLAGS_TRAP;
+
+  switch (rtems_debugger_target_exception(frame)) {
+  case rtems_debugger_target_exc_consumed:
+  default:
+    break;
+  case rtems_debugger_target_exc_step:
+    frame->eflags |= EFLAGS_TRAP;
+    break;
+  case rtems_debugger_target_exc_cascade:
+    orig_currentExcHandler(frame);
+    break;
+  }
+}
+
+int
+rtems_debugger_target_enable(void)
+{
+  rtems_interrupt_lock_context lock_context;
+  rtems_interrupt_lock_acquire(&target_lock, &lock_context);
+  if (orig_currentExcHandler == NULL) {
+    orig_currentExcHandler = _currentExcHandler;
+    _currentExcHandler = target_exception;
+  }
+  rtems_interrupt_lock_release(&target_lock, &lock_context);
+  return 0;
+}
+
+int
+rtems_debugger_target_disable(void)
+{
+  rtems_interrupt_lock_context lock_context;
+  rtems_interrupt_lock_acquire(&target_lock, &lock_context);
+  if (orig_currentExcHandler != NULL)
+    _currentExcHandler = orig_currentExcHandler;
+  rtems_interrupt_lock_release(&target_lock, &lock_context);
+  return 0;
+}
+
+int
+rtems_debugger_target_read_regs(rtems_debugger_thread* thread)
+{
+  if (!rtems_debugger_thread_flag(thread,
+                                  RTEMS_DEBUGGER_THREAD_FLAG_REG_VALID)) {
+    uint32_t* regs = &thread->registers[0];
+    size_t    i;
+
+    for (i = 0; i < rtems_debugger_target_reg_num(); ++i)
+      regs[i] = 0xdeaddead;
+
+    if (thread->frame) {
+      CPU_Exception_frame* frame = thread->frame;
+      regs[REG_EAX]    = frame->eax;
+      regs[REG_ECX]    = frame->ecx;
+      regs[REG_EDX]    = frame->edx;
+      regs[REG_EBX]    = frame->ebx;
+      regs[REG_ESP]    = frame->esp0;
+      regs[REG_EBP]    = frame->ebp;
+      regs[REG_ESI]    = frame->esi;
+      regs[REG_EDI]    = frame->edi;
+      regs[REG_EIP]    = frame->eip;
+      regs[REG_EFLAGS] = frame->eflags;
+      regs[REG_CS]     = frame->cs;
+
+      /*
+       * Get the signal from the frame.
+       */
+      thread->signal = rtems_debugger_target_exception_to_signal(frame);
+    }
+    else {
+      regs[REG_EBX]    = thread->tcb->Registers.ebx;
+      regs[REG_ESI]    = thread->tcb->Registers.esi;
+      regs[REG_EDI]    = thread->tcb->Registers.edi;
+      regs[REG_EFLAGS] = thread->tcb->Registers.eflags;
+      regs[REG_ESP]    = (intptr_t) thread->tcb->Registers.esp;
+      regs[REG_EBP]    = (intptr_t) thread->tcb->Registers.ebp;
+      regs[REG_EIP]    = *((DB_UINT*) thread->tcb->Registers.esp);
+      regs[REG_EAX]    = (intptr_t) thread;
+
+      GET_SEG_REG(CS, regs[REG_CS]);
+
+      /*
+       * Blocked threads have no signal.
+       */
+      thread->signal = 0;
+    }
+
+    GET_SEG_REG(SS, regs[REG_SS]);
+    GET_SEG_REG(DS, regs[REG_DS]);
+    GET_SEG_REG(ES, regs[REG_ES]);
+    GET_SEG_REG(FS, regs[REG_FS]);
+    GET_SEG_REG(GS, regs[REG_GS]);
+
+    thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_REG_VALID;
+    thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
+  }
+
+  return 0;
+}
+
+int
+rtems_debugger_target_write_regs(rtems_debugger_thread* thread)
+{
+  if (rtems_debugger_thread_flag(thread,
+                                 RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY)) {
+    uint32_t* regs = &thread->registers[0];
+
+    /*
+     * Only write to debugger controlled threads. Do not touch the registers
+     * for threads blocked in the context switcher.
+     */
+    if (rtems_debugger_thread_flag(thread,
+                                   RTEMS_DEBUGGER_THREAD_FLAG_DEBUGGING)) {
+      CPU_Exception_frame* frame = thread->frame;
+      frame->eax    = regs[REG_EAX];
+      frame->ecx    = regs[REG_ECX];
+      frame->edx    = regs[REG_EDX];
+      frame->ebx    = regs[REG_EBX];
+      frame->esp0   = regs[REG_ESP];
+      frame->ebp    = regs[REG_EBP];
+      frame->esi    = regs[REG_ESI];
+      frame->edi    = regs[REG_EDI];
+      frame->eip    = regs[REG_EIP];
+      frame->eflags = regs[REG_EFLAGS];
+      frame->cs     = regs[REG_CS];
+    }
+    thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
+  }
+  return 0;
+}
+
+DB_UINT
+rtems_debugger_target_reg_pc(rtems_debugger_thread* thread)
+{
+  int r;
+  r = rtems_debugger_target_read_regs(thread);
+  if (r >= 0) {
+    uint32_t* regs = &thread->registers[0];
+    return regs[REG_EIP];
+  }
+  return 0;
+}
+
+DB_UINT
+rtems_debugger_target_frame_pc(CPU_Exception_frame* frame)
+{
+  return (DB_UINT) frame->eip;
+}
+
+DB_UINT
+rtems_debugger_target_reg_sp(rtems_debugger_thread* thread)
+{
+  int r;
+  r = rtems_debugger_target_read_regs(thread);
+  if (r >= 0) {
+    uint32_t* regs = &thread->registers[0];
+    return regs[REG_ESP];
+  }
+  return 0;
+}
+
+DB_UINT
+rtems_debugger_target_tcb_sp(rtems_debugger_thread* thread)
+{
+  return (DB_UINT) thread->tcb->Registers.esp;
+}
+
+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))) {
+    CPU_Exception_frame* frame = thread->frame;
+    /*
+     * Single step instructions with interrupts masked to avoid stepping into
+     * an interrupt handler.
+     */
+    if ((frame->eflags & EFLAGS_INTR_ENABLE) == 0)
+      thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED;
+    else
+      frame->eflags &= ~EFLAGS_INTR_ENABLE;
+    frame->eflags |= EFLAGS_TRAP;
+  }
+  return 0;
+}
+
+int
+rtems_debugger_target_exception_to_signal(CPU_Exception_frame* frame)
+{
+  int sig = RTEMS_DEBUGGER_SIGNAL_HUP;
+  switch (frame->idtIndex) {
+  case 1:  /* debug exception */
+  case 3:  /* breakpoint int3 */
+    sig = RTEMS_DEBUGGER_SIGNAL_TRAP;
+    break;
+  case 4:  /* int overflow    */
+  case 5:  /* out-of-bounds   */
+    sig = RTEMS_DEBUGGER_SIGNAL_URG;
+    break;
+  case 6:  /* invalid opcode  */
+    sig = RTEMS_DEBUGGER_SIGNAL_ILL;
+    break;
+  case 8:  /* double fault    */
+  case 16: /* fp error        */
+    sig = RTEMS_DEBUGGER_SIGNAL_EMT;
+    break;
+  case 0:  /* divide by zero  */
+  case 7:  /* FPU not avail.  */
+    sig = RTEMS_DEBUGGER_SIGNAL_FPE;
+    break;
+  case 9:  /* i387 seg overr. */
+  case 10: /* Invalid TSS     */
+  case 11: /* seg. not pres.  */
+  case 12: /* stack except.   */
+  case 13: /* general prot.   */
+  case 14: /* page fault      */
+  case 17: /* alignment check */
+    sig = RTEMS_DEBUGGER_SIGNAL_SEGV;
+    break;
+  case 2:  /* NMI             */
+  case 18: /* machine check   */
+    sig = RTEMS_DEBUGGER_SIGNAL_BUS;
+    break;
+  default:
+    break;
+  }
+  return sig;
+}
+
+int
+rtems_debugger_target_hwbreak_control(rtems_debugger_target_watchpoint wp,
+                                      bool                             insert,
+                                      DB_UINT                          addr,
+                                      DB_UINT                          kind)
+{
+  /*
+   * To do.
+   */
+  return 0;
+}
+
+int
+rtems_debugger_target_cache_sync(rtems_debugger_target_swbreak* swbreak)
+{
+  /*
+   * Nothing to do on an i386.
+   */
+  return 0;
+}
diff --git a/cpukit/libdebugger/rtems-debugger-remote-tcp.c b/cpukit/libdebugger/rtems-debugger-remote-tcp.c
new file mode 100644
index 0000000..ded51d6
--- /dev/null
+++ b/cpukit/libdebugger/rtems-debugger-remote-tcp.c
@@ -0,0 +1,342 @@
+/*
+ * 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <rtems/rtems-debugger.h>
+#include <rtems/debugger/rtems-debugger-server.h>
+#include <rtems/debugger/rtems-debugger-remote.h>
+
+#include "rtems-debugger-remote-tcp.h"
+
+/**
+ * Debugger default server port. 'RT' as ASCII.
+ */
+#define RTEMS_DB_PORT_DEFAULT (8284)
+
+/**
+ * TCP Remote data.
+ */
+typedef struct
+{
+  int fd;
+  int port;
+} rtems_debugger_remote_tcp;
+
+static rtems_debugger_remote_tcp*
+tcp_remote(rtems_debugger_remote* remote)
+{
+  rtems_debugger_remote_tcp* tcp = NULL;
+  rtems_debugger_lock();
+  if (remote != NULL && remote->data != NULL)
+      tcp = (rtems_debugger_remote_tcp*) remote->data;
+  rtems_debugger_unlock();
+  return tcp;
+}
+
+static int
+tcp_remote_begin(rtems_debugger_remote* remote, const char* device)
+{
+  rtems_debugger_remote_tcp* tcp;
+  int                        port;
+  char*                      end;
+
+  rtems_debugger_lock();
+
+  /*
+   * Parse the port number.
+   */
+  port = strtoul(device, &end, 10);
+  if (port == 0 || *end != '\0') {
+    rtems_debugger_printf("error: rtems-db: tcp remote: invalid port: %s\n", device);
+    return -1;
+  }
+
+  tcp = malloc(sizeof(rtems_debugger_remote_tcp));
+  if (tcp == NULL) {
+    errno = ENOMEM;
+    return -1;
+  }
+
+  remote->data = tcp;
+
+  tcp->fd = -1;
+  tcp->port = port;
+
+  rtems_debugger_unlock();
+
+  return 0;
+}
+
+static int
+tcp_remote_end(rtems_debugger_remote* remote)
+{
+  rtems_debugger_lock();
+
+  if (remote != NULL && remote->data != NULL) {
+    rtems_debugger_remote_tcp* tcp = (rtems_debugger_remote_tcp*) remote->data;
+    if (tcp != NULL) {
+      if (tcp->fd >= 0)
+        close(tcp->fd);
+      free(tcp);
+      remote->data = NULL;
+    }
+  }
+
+  rtems_debugger_unlock();
+
+  return 0;
+}
+
+static int
+tcp_remote_connect(rtems_debugger_remote* remote)
+{
+  int                        ld;
+  struct sockaddr_in         addr;
+  socklen_t                  opt;
+  socklen_t                  len;
+  bool                       running;
+  struct timeval             timeout;
+  rtems_debugger_remote_tcp* tcp = tcp_remote(remote);
+  int                        r;
+
+  if (rtems_debugger_verbose())
+    rtems_debugger_printf("error: rtems-db: tcp remote: connect\n");
+
+  ld = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (ld < 0) {
+    rtems_debugger_printf("error: rtems-db: tcp remote: socket: (%d) %s\n",
+                          errno, strerror(errno));
+    return -1;
+  }
+
+  opt = 1;
+  r = setsockopt(ld,
+                 SOL_SOCKET,
+                 SO_REUSEADDR,
+                 (char *) &opt,
+                 sizeof(opt));
+  if (r < 0) {
+    close(ld);
+    rtems_debugger_printf("error: rtems-db: tcp remote: setsocket: reuseaddr: (%d) %s\n",
+                          errno, strerror(errno));
+    return -1;
+  }
+
+  addr.sin_family = PF_INET;
+  addr.sin_port = htons(tcp->port);
+  addr.sin_addr.s_addr = INADDR_ANY;
+
+  r = bind(ld, (struct sockaddr *) &addr, sizeof(addr));
+  if (r < 0) {
+    close(ld);
+    rtems_debugger_printf("error: rtems-db: tcp remote: bind: (%d) %s\n",
+                          errno, strerror(errno));
+    return -1;
+  }
+
+  /*
+   * Backlog of 1 connection.
+   */
+  r = listen(ld, 1);
+  if (r < 0) {
+    close(ld);
+    rtems_debugger_printf("error: rtems-db: tcp remote: listen: (%d) %s\n",
+                          errno, strerror(errno));
+    return -1;
+  }
+
+  /*
+   * Use a random port if the port is 0.
+   */
+  if (tcp->port == 0) {
+    len = sizeof(addr);
+    r = getsockname(ld, (struct sockaddr *) &addr, &len);
+    if (r < 0 || len < sizeof(addr)) {
+      close(ld);
+      rtems_debugger_printf("error: rtems-db: tcp remote: getsockname: (%d) %s\n",
+                            errno, strerror(errno));
+      return -1;
+    }
+    tcp->port = ntohs(addr.sin_port);
+  }
+
+  rtems_debugger_printf("rtems-db: tcp remote: listing on port: %d\n",
+                        tcp->port);
+
+  len = sizeof(addr);
+  tcp->fd = accept(ld, (struct sockaddr *) &addr, &len);
+
+  running = rtems_debugger_server_running();
+
+  close(ld);
+
+  if (tcp->fd < 0) {
+    /*
+     * EBADF means the socket has been closed, ignore it.
+     */
+    if (errno != EBADF)
+      rtems_debugger_printf("error: rtems-db: accept: (%d) %s\n",
+                            errno, strerror(errno));
+    return -1;
+  }
+
+  if (!running) {
+    close(tcp->fd);
+    errno = EIO;
+    return -1;
+  }
+
+  opt = 1;
+  r = setsockopt(tcp->fd,
+                 SOL_SOCKET, SO_KEEPALIVE,
+                 (char*) &opt,
+                 sizeof(opt));
+  if (r < 0) {
+    int errno_ = errno;
+    close(tcp->fd);
+    rtems_debugger_printf("error: rtems-db: tcp remote: set keepalive: (%d) %s\n",
+                          errno, strerror(errno));
+    errno = errno_;
+    return -1;
+  }
+
+  opt = 1;
+  r = setsockopt(tcp->fd,
+                 IPPROTO_TCP, TCP_NODELAY,
+                 (char*) &opt, sizeof(opt));
+  if (r < 0) {
+    int errno_ = errno;
+    close(tcp->fd);
+    rtems_debugger_printf("error: rtems-db: tcp remote: set no-delay: (%d) %s\n",
+                          errno, strerror(errno));
+    errno = errno_;
+    return -1;
+  }
+
+  timeout.tv_sec = rtems_debugger->timeout;
+  timeout.tv_usec = 0;
+
+  r = setsockopt(tcp->fd,
+                 SOL_SOCKET, SO_RCVTIMEO,
+                 (char*) &timeout, sizeof(timeout));
+  if (r < 0) {
+    int errno_ = errno;
+    close(tcp->fd);
+    rtems_debugger_printf("error: rtems-db: tcp remote: set rcv-timeout: (%d) %s\n",
+                          errno, strerror(errno));
+    errno = errno_;
+    return -1;
+  }
+
+  rtems_debugger_printf("rtems-db: tcp remote: connect host: %s\n",
+                        inet_ntoa(addr.sin_addr));
+
+  return 0;
+}
+
+static int
+tcp_remote_disconnect(rtems_debugger_remote* remote)
+{
+  rtems_debugger_remote_tcp* tcp;
+
+  rtems_debugger_lock();
+
+  rtems_debugger_printf("rtems-db: tcp remote: disconnect host\n");
+
+  tcp = (rtems_debugger_remote_tcp*) remote->data;
+  close(tcp->fd);
+
+  rtems_debugger_unlock();
+
+  return 0;
+}
+
+static bool
+tcp_remote_isconnected(rtems_debugger_remote* remote)
+{
+  rtems_debugger_remote_tcp* tcp = tcp_remote(remote);
+  return tcp != NULL && tcp->fd >= 0;
+}
+
+static ssize_t
+tcp_remote_receive(rtems_debugger_remote* remote,
+                   void*                  buf,
+                   size_t                 nbytes)
+{
+  rtems_debugger_remote_tcp* tcp = tcp_remote(remote);
+  ssize_t                    len;
+  if (tcp != NULL) {
+    len = read(tcp->fd, buf, nbytes);
+  }
+  else {
+    errno = EIO;
+    len = -1;
+  }
+  return len;
+}
+
+static ssize_t
+tcp_remote_send(rtems_debugger_remote* remote,
+                const void*            buf,
+                size_t                 nbytes)
+{
+  rtems_debugger_remote_tcp* tcp = tcp_remote(remote);
+  ssize_t                    len;
+  if (tcp != NULL) {
+    len = write(tcp->fd, buf, nbytes);
+  }
+  else {
+    errno = EIO;
+    len = -1;
+  }
+  return len;
+}
+
+static rtems_debugger_remote remote_tcp =
+{
+  .name = "tcp",
+  .begin = tcp_remote_begin,
+  .end = tcp_remote_end,
+  .connect = tcp_remote_connect,
+  .disconnect = tcp_remote_disconnect,
+  .isconnected = tcp_remote_isconnected,
+  .read = tcp_remote_receive,
+  .write = tcp_remote_send
+};
+
+int
+rtems_debugger_register_tcp_remote(void)
+{
+  return rtems_debugger_remote_register(&remote_tcp);
+}
diff --git a/cpukit/libdebugger/rtems-debugger-remote-tcp.h b/cpukit/libdebugger/rtems-debugger-remote-tcp.h
new file mode 100644
index 0000000..d9d7fee
--- /dev/null
+++ b/cpukit/libdebugger/rtems-debugger-remote-tcp.h
@@ -0,0 +1,47 @@
+/*
+ * 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Debugger for RTEMS.
+ */
+
+#ifndef _RTEMS_DEBUGGER_REMOTE_TCP_h
+#define _RTEMS_DEBUGGER_REMOTE_TCP_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * Register a remote with the server.
+ */
+int rtems_debugger_register_tcp_remote(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif
diff --git a/cpukit/libdebugger/rtems-debugger-remote.c b/cpukit/libdebugger/rtems-debugger-remote.c
new file mode 100644
index 0000000..f9a104d
--- /dev/null
+++ b/cpukit/libdebugger/rtems-debugger-remote.c
@@ -0,0 +1,68 @@
+/*
+ * 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <rtems/rtems-debugger.h>
+#include <rtems/debugger/rtems-debugger-server.h>
+#include <rtems/debugger/rtems-debugger-remote.h>
+
+static rtems_debugger_remote* remotes[4];
+
+int
+rtems_debugger_remote_register(rtems_debugger_remote* remote)
+{
+  size_t r;
+  if (remote->begin == NULL || remote->end == NULL ||
+      remote->connect == NULL || remote->disconnect == NULL ||
+      remote->isconnected == NULL ||
+      remote->read == NULL || remote->write == NULL) {
+    errno = EINVAL;
+    return -1;
+  }
+  for (r = 0; r < RTEMS_DEBUGGER_NUMOF(remotes); ++r) {
+    if (remotes[r] == NULL) {
+      remotes[r] = remote;
+      return 0;
+    }
+  }
+  errno = ENOSPC;
+  return -1;
+}
+
+rtems_debugger_remote*
+rtems_debugger_remote_find(const char* name)
+{
+  size_t r;
+  for (r = 0; r < RTEMS_DEBUGGER_NUMOF(remotes); ++r) {
+    if (remotes[r] != NULL) {
+      if (strcasecmp(name, remotes[r]->name) == 0)
+        return remotes[r];
+    }
+  }
+  return NULL;
+}
diff --git a/cpukit/libdebugger/rtems-debugger-remote.h b/cpukit/libdebugger/rtems-debugger-remote.h
new file mode 100644
index 0000000..3ea2b14
--- /dev/null
+++ b/cpukit/libdebugger/rtems-debugger-remote.h
@@ -0,0 +1,71 @@
+/*
+ * 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Debugger for RTEMS.
+ */
+
+#ifndef _RTEMS_DEBUGGER_REMOTE_h
+#define _RTEMS_DEBUGGER_REMOTE_h
+
+#include <rtems/rtems-debugger.h>
+#include <rtems/debugger/rtems-debugger-server.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * Debugger remote.
+ */
+struct rtems_debugger_remote
+{
+  const char* name;
+  int         (*begin)(rtems_debugger_remote* remote, const char* device);
+  int         (*end)(rtems_debugger_remote* remote);
+  int         (*connect)(rtems_debugger_remote* remote);
+  int         (*disconnect)(rtems_debugger_remote* remote);
+  bool        (*isconnected)(rtems_debugger_remote* remote);
+  ssize_t     (*read)(rtems_debugger_remote* remote, void* buf, size_t nbytes);
+  ssize_t     (*write)(rtems_debugger_remote* remote, const void* buf, size_t nbytes);
+  void*       data;
+};
+
+/**
+ * Register a remote with the server.
+ */
+int rtems_debugger_remote_register(rtems_debugger_remote* remote);
+
+/**
+ * Find a remote by name.
+ */
+rtems_debugger_remote* rtems_debugger_remote_find(const char* name);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif
diff --git a/cpukit/libdebugger/rtems-debugger-server.c b/cpukit/libdebugger/rtems-debugger-server.c
new file mode 100644
index 0000000..8c20cf6
--- /dev/null
+++ b/cpukit/libdebugger/rtems-debugger-server.c
@@ -0,0 +1,1993 @@
+/*
+ * 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <rtems/rtems-debugger.h>
+#include <rtems/debugger/rtems-debugger-server.h>
+#include <rtems/debugger/rtems-debugger-remote.h>
+
+#include "rtems-debugger-target.h"
+#include "rtems-debugger-threads.h"
+
+/*
+ * GDB Debugger Remote Server for RTEMS.
+ */
+
+/*
+ * Hack to void including bsp.h. The reset needs a better API.
+ */
+extern void bsp_reset(void);
+
+/*
+ * Command lookup table.
+ */
+typedef int (*rtems_debugger_command)(uint8_t* buffer, int size);
+
+typedef struct rtems_debugger_packet
+{
+  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";
+
+/*
+ * Global Debugger.
+ *
+ * The server instance is allocated on the heap so memory is only used then the
+ * server is running. A global is used because:
+ *
+ *  1. There can only be a single instance at once.
+ *  2. The backend's need access to the data and holding pointers in the TCB
+ *     for each thread is mess.
+ *  3. The code is smaller and faster.
+ */
+rtems_debugger_server* rtems_debugger;
+
+int
+rtems_debugger_printf(const char* format, ...)
+{
+  int     len;
+  va_list ap;
+  va_start(ap, format);
+  len = rtems_vprintf(&rtems_debugger->printer, format, ap);
+  va_end(ap);
+  return len;
+}
+
+bool
+rtems_debugger_verbose(void)
+{
+  return rtems_debugger_server_flag(RTEMS_DEBUGGER_FLAG_VERBOSE);
+}
+
+static inline int
+hex_decode(uint8_t ch)
+{
+  int i;
+  if (ch >= '0' && ch <= '9')
+    i = (int) (ch - '0');
+  else if (ch >= 'a' && ch <= 'f')
+    i = (int) (ch - 'a') + 10;
+  else if (ch >= 'A' && ch <= 'F')
+    i = (int) (ch - 'A') + 10;
+  else
+    i = -1;
+  return i;
+}
+
+static inline uint8_t
+hex_encode(int val)
+{
+  return "0123456789abcdef"[val & 0xf];
+}
+
+static inline DB_UINT
+hex_decode_uint(const uint8_t* data)
+{
+  DB_UINT ui = 0;
+  size_t  i;
+  if (data[0] == '-') {
+    if (data[1] == '1')
+      ui = (DB_UINT) -1;
+  }
+  else {
+    for (i = 0; i < (sizeof(ui) * 2); ++i) {
+      int v = hex_decode(data[i]);
+      if (v < 0)
+        break;
+      ui = (ui << 4) | v;
+    }
+  }
+  return ui;
+}
+
+static inline int
+hex_decode_int(const uint8_t* data)
+{
+  return (int) hex_decode_uint(data);
+}
+
+static bool
+thread_id_decode(const char* data, DB_UINT* pid, DB_UINT* tid)
+{
+  bool is_extended = false;
+  if (*data == 'p') {
+    is_extended = true;
+    ++data;
+  }
+  *pid = *tid = hex_decode_uint((const uint8_t*) data);
+  if (is_extended) {
+    const char* stop = strchr(data, '.');
+    if (stop != NULL) {
+      *tid = hex_decode_uint((const uint8_t*) stop + 1);
+    }
+  }
+  return is_extended;
+}
+
+static inline bool
+check_pid(DB_UINT pid)
+{
+  return pid == 0|| rtems_debugger->pid == (pid_t) pid;
+}
+
+int
+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;
+}
+
+int
+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;
+}
+
+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;
+  }
+  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;
+}
+
+static int
+rtems_debugger_task_create(const char*         name,
+                           rtems_task_priority priority,
+                           size_t              stack_size,
+                           rtems_task_entry    entry_point,
+                           rtems_task_argument argument,
+                           rtems_id*           id)
+{
+  rtems_name        tname;
+  rtems_status_code sc;
+
+  tname = rtems_build_name(name[0], name[1], name[2], name[3]);
+
+  sc = rtems_task_create (tname,
+                          priority,
+                          stack_size,
+                          RTEMS_FLOATING_POINT | RTEMS_LOCAL,
+                          RTEMS_PREEMPT | RTEMS_NO_ASR,
+                          id);
+  if (sc != RTEMS_SUCCESSFUL) {
+    *id = 0;
+    rtems_debugger_printf("error: rtems-db: thread create: %s: %s\n",
+                          name, rtems_status_text(sc));
+    errno = EIO;
+    return -1;
+  }
+
+  sc = rtems_task_start(*id, entry_point, argument);
+  if (sc != RTEMS_SUCCESSFUL) {
+    rtems_debugger_printf("error: rtems-db: thread start: %s: %s\n",
+                          name, rtems_status_text(sc));
+    rtems_task_delete(*id);
+    *id = 0;
+    errno = EIO;
+    return -1;
+  }
+
+  return 0;
+}
+
+static int
+rtems_debugger_task_destroy(const char*    name,
+                            rtems_id       id,
+                            volatile bool* finished,
+                            int            timeout)
+{
+  while (timeout) {
+    bool has_finished;
+    rtems_debugger_lock();
+    has_finished = *finished;
+    rtems_debugger_unlock();
+
+    if (has_finished)
+      break;
+
+    usleep(RTEMS_DEBUGGER_POLL_WAIT);
+    if (timeout < RTEMS_DEBUGGER_POLL_WAIT)
+      timeout = 0;
+    else
+      timeout -= RTEMS_DEBUGGER_POLL_WAIT;
+  }
+
+  if (timeout == 0) {
+    rtems_debugger_printf("rtems-db: %s not stopping, killing\n", name);
+    rtems_task_delete(id);
+  }
+  return 0;
+}
+
+bool
+rtems_debugger_server_running(void)
+{
+  bool running;
+  rtems_debugger_lock();
+  running = rtems_debugger->server_running;
+  rtems_debugger_unlock();
+  return running;
+}
+
+rtems_debugger_remote*
+rtems_debugger_remote_handle(void)
+{
+  rtems_debugger_remote* remote;
+  rtems_debugger_lock();
+  remote = rtems_debugger->remote;
+  rtems_debugger_unlock();
+  return remote;
+}
+
+bool
+rtems_debugger_connected(void)
+{
+  bool isconnected = false;
+  rtems_debugger_lock();
+  if (rtems_debugger->remote != NULL)
+    isconnected = rtems_debugger->remote->isconnected(rtems_debugger->remote);
+  rtems_debugger_unlock();
+  return isconnected;
+}
+
+bool
+rtems_debugger_server_events_running(void)
+{
+  bool running;
+  rtems_debugger_lock();
+  running = rtems_debugger->events_running;
+  rtems_debugger_unlock();
+  return running;
+}
+
+int
+rtems_debugger_server_events_wake(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;
+}
+
+static int
+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;
+}
+
+static int
+rtems_debugger_remote_connect(void)
+{
+  rtems_debugger_remote* remote = rtems_debugger_remote_handle();
+  if (remote == NULL) {
+    errno = EIO;
+    return -1;
+  }
+  if (!remote->isconnected(remote))
+    return remote->connect(remote);
+}
+
+static int
+rtems_debugger_remote_disconnect(void)
+{
+  rtems_debugger_remote* remote = rtems_debugger_remote_handle();
+  if (remote == NULL) {
+    errno = EIO;
+    return -1;
+  }
+  if (remote->isconnected(remote))
+    return remote->disconnect(remote);
+}
+
+static int
+rtems_debugger_remote_receive(uint8_t* buffer, size_t size)
+{
+  rtems_debugger_remote* remote = rtems_debugger_remote_handle();
+  ssize_t len = remote->read(remote, buffer, size);
+  if (len < 0 && errno != EAGAIN)
+    rtems_debugger_printf("rtems-db: read: (%d) %s\n",
+                          errno, strerror(errno));
+  return (int) len;
+}
+
+static int
+rtems_debugger_remote_send(void)
+{
+  const uint8_t* buffer = rtems_debugger->output;
+  ssize_t        size = rtems_debugger->output_level;
+
+  if (rtems_debugger->output_level > RTEMS_DEBUGGER_BUFFER_SIZE) {
+    rtems_debugger_printf("rtems-db: write too big: %d\n",
+                          (int) rtems_debugger->output_level);
+    return -1;
+  }
+
+  if (rtems_debugger->remote_debug) {
+    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");
+  }
+
+  while (size) {
+    rtems_debugger_remote* remote = rtems_debugger_remote_handle();
+    ssize_t                w;
+    if (remote == NULL) {
+      errno = EIO;
+      return -1;
+    }
+    w = remote->write(remote, buffer, size);
+    if (w < 0 && errno != EINTR) {
+      rtems_debugger_printf("rtems-db: write: (%d) %s\n",
+                            errno, strerror(errno));
+      break;
+    }
+    else {
+      size -= w;
+      buffer += w;
+    }
+  }
+
+  return (int) rtems_debugger->output_level;
+}
+
+static int
+rtems_debugger_remote_send_ack(void)
+{
+  rtems_debugger->output[0] = '+';
+  rtems_debugger->output_level = 1;
+  return rtems_debugger_remote_send();
+}
+
+static int
+rtems_debugger_remote_send_nack(void)
+{
+  rtems_debugger->output[0] = '-';
+  rtems_debugger->output_level = 1;
+  return rtems_debugger_remote_send();
+}
+
+static int
+rtems_debugger_remote_packet_in(void)
+{
+  uint8_t buf[256];
+  uint8_t state;
+  int     in = 0;
+  uint8_t csum = 0;
+  uint8_t rx_csum = 0;
+  bool    junk = false;
+  bool    escaped = false;
+  bool    remote_debug_header = true;
+
+  /*
+   * States:
+   *  'H' : Looking for the start character '$', '-' or '+'.
+   *  'P' : Looking for the checksum character '#' else buffer data.
+   *  '1' : Looking for the first checksum character.
+   *  '2' : Looking for the second checksum character.
+   *  'F' : Finished.
+   */
+
+  state = 'H';
+
+  while (state != 'F') {
+    int r;
+    int i;
+
+    rtems_debugger_unlock();
+
+    r = rtems_debugger_remote_receive(buf, sizeof(buf));
+
+    rtems_debugger_lock();
+
+    if (r <= 0) {
+      /*
+       * Timeout?
+       */
+      if (r < 0 && errno == EAGAIN) {
+        if (rtems_debugger->ack_pending) {
+          rtems_debugger_remote_send();
+        }
+        continue;
+      }
+      if (r == 0)
+        rtems_debugger_printf("rtems-db: remote disconnected\n");
+      return -1;
+    }
+
+    i = 0;
+
+    while (i < r) {
+      uint8_t c = buf[i++];
+
+      if (rtems_debugger->remote_debug && remote_debug_header) {
+        rtems_debugger_printf("rtems-db: get:%4d: ", r);
+        remote_debug_header = false;
+      }
+
+      if (rtems_debugger->remote_debug)
+        rtems_debugger_printf("%c", c);
+
+      switch (state) {
+      case 'H':
+        switch (c) {
+        case '+':
+          if (rtems_debugger->remote_debug) {
+            rtems_debugger_printf(" [[ACK%s]]\n",
+                                  rtems_debugger->ack_pending ? "" : "?");
+            remote_debug_header = true;
+          }
+          rtems_debugger->ack_pending = false;
+          break;
+        case '-':
+          if (rtems_debugger->remote_debug) {
+            rtems_debugger_printf(" [[NACK]]\n");
+            remote_debug_header = true;
+          }
+          /*
+           * Resend.
+           */
+          rtems_debugger_remote_send();
+          break;
+        case '$':
+          state = 'P';
+          csum = 0;
+          in = 0;
+          if (junk && rtems_debugger->remote_debug) {
+            rtems_debugger_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->ack_pending = false;
+          rtems_debugger->input[0] =  '^';
+          rtems_debugger->input[1] =  'C';
+          rtems_debugger->input[2] =  '\0';
+          return 2;
+        default:
+          junk = true;
+          break;
+        }
+        break;
+      case 'P':
+        if (c == '{' && !escaped) {
+          escaped = true;
+        }
+        else if (c == '$' && !escaped) {
+          csum = 0;
+          in = 0;
+          if (rtems_debugger->remote_debug) {
+            rtems_debugger_printf("\n");
+            remote_debug_header = true;
+          }
+        }
+        else if (c == '#' && !escaped) {
+          rtems_debugger->input[in] = '\0';
+          rx_csum = 0;
+          state = '1';
+        }
+        else {
+          if (in >= (RTEMS_DEBUGGER_BUFFER_SIZE - 1)) {
+            rtems_debugger_printf("rtems-db: input buffer overflow\n");
+            return -1;
+          }
+          csum += c;
+          rtems_debugger->input[in++] = c;
+        }
+        break;
+      case '1':
+        rx_csum = (rx_csum << 4) | (uint8_t) hex_decode(c);
+        state = '2';
+        break;
+      case '2':
+        rx_csum = (rx_csum << 4) | (uint8_t) hex_decode(c);
+        if (csum == rx_csum) {
+          state = 'F';
+          if (rtems_debugger->remote_debug)
+            rtems_debugger_printf("\n");
+          rtems_debugger_remote_send_ack();
+        }
+        else {
+          if (rtems_debugger->remote_debug) {
+            rtems_debugger_printf(" [[invalid checksum]]\n");
+            remote_debug_header = true;
+            rtems_debugger_remote_send_nack();
+          }
+          state = 'H';
+        }
+        break;
+      case 'F':
+          if (rtems_debugger->remote_debug)
+            rtems_debugger_printf(" [[extra data: 0x%02x]]", (int) c);
+        break;
+      default:
+        rtems_debugger_printf("rtems-db: bad state\n");
+        rtems_debugger_remote_send_nack();
+        return -1;
+      }
+    }
+  }
+
+  return in;
+}
+
+static int
+rtems_debugger_remote_packet_in_hex(uint8_t*    addr,
+                                    const char* data,
+                                    size_t      size)
+{
+  size_t i;
+  for (i = 0; i < size; ++i) {
+    *addr = (hex_decode(*data++) << 4);
+    *addr++ |= hex_decode(*data++);
+  }
+  return 0;
+}
+
+#if KEEP_INCASE
+static void
+remote_packet_out_rewind(size_t size)
+{
+  size_t i = 0;
+  while (rtems_debugger->output_level > 0 && i < size) {
+    if (rtems_debugger->output_level > 1) {
+      if (rtems_debugger->output[rtems_debugger->output_level - 1] == '}') {
+        --rtems_debugger->output_level;
+      }
+    }
+    --rtems_debugger->output_level;
+    --i;
+  }
+}
+#endif
+
+static int
+remote_packet_out_append_buffer(const char* buffer, size_t size)
+{
+  size_t ol = rtems_debugger->output_level;
+  size_t i = 0;
+  while (i < size) {
+    char c = buffer[i++];
+    if (c == '#' || c == '$') {
+      if (rtems_debugger->output_level >= (RTEMS_DEBUGGER_BUFFER_SIZE - 1)) {
+        rtems_debugger->output_level = ol;
+        rtems_debugger_printf("rtems-db: output overflow\n");
+        return -1;
+      }
+      rtems_debugger->output[rtems_debugger->output_level++] = '}';
+      c ^= 0x20;
+    }
+    if (rtems_debugger->output_level >= (RTEMS_DEBUGGER_BUFFER_SIZE - 1)) {
+      rtems_debugger->output_level = ol;
+      rtems_debugger_printf("rtems-db: output overflow\n");
+      return -1;
+    }
+    rtems_debugger->output[rtems_debugger->output_level++] = c;
+  }
+  return 0;
+}
+
+static int
+remote_packet_out_append_hex(const uint8_t* data, size_t size)
+{
+  size_t ol = rtems_debugger->output_level;
+  size_t i = 0;
+  while (i < size) {
+    uint8_t byte = data[i++];
+    if (rtems_debugger->output_level >= (RTEMS_DEBUGGER_BUFFER_SIZE - 2)) {
+      rtems_debugger->output_level = ol;
+      rtems_debugger_printf("rtems-db: output overflow\n");
+      return -1;
+    }
+    rtems_debugger->output[rtems_debugger->output_level++] = hex_encode(byte >> 4);
+    rtems_debugger->output[rtems_debugger->output_level++] = hex_encode(byte);
+  }
+  return 0;
+}
+
+static int
+remote_packet_out_append_str(const char* str)
+{
+  return remote_packet_out_append_buffer(str, strlen(str));
+}
+
+static int
+remote_packet_out_append_vprintf(const char* fmt, va_list ap)
+{
+  int  len;
+  char buffer[64];
+  len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
+  return remote_packet_out_append_buffer(buffer, len);
+}
+
+static int
+remote_packet_out_append(const char* fmt, ...)
+{
+  va_list ap;
+  int     r;
+  va_start(ap, fmt);
+  r = remote_packet_out_append_vprintf(fmt, ap);
+  va_end(ap);
+  return r;
+}
+
+static void
+remote_packet_out_reset(void)
+{
+  rtems_debugger->output_level = 1;
+  rtems_debugger->output[0] = '$';
+}
+
+static int
+remote_packet_out_buffer(const char* buffer, size_t size)
+{
+  remote_packet_out_reset();
+  return remote_packet_out_append_buffer(buffer, size);
+}
+
+static int
+remote_packet_out_str(const char* str)
+{
+  remote_packet_out_reset();
+  return remote_packet_out_append_buffer(str, strlen(str));
+}
+
+static int
+remote_packet_out(const char* fmt, ...)
+{
+  va_list ap;
+  int     r;
+  va_start(ap, fmt);
+  remote_packet_out_reset();
+  r = remote_packet_out_append_vprintf(fmt, ap);
+  va_end(ap);
+  return r;
+}
+
+static int
+remote_packet_out_send(void)
+{
+  uint8_t csum = 0;
+  size_t  i = 1;
+
+  if (rtems_debugger->output_level >= (RTEMS_DEBUGGER_BUFFER_SIZE - 3)) {
+    rtems_debugger_printf("rtems-db: output overflow\n");
+    return -1;
+  }
+
+  while (i < rtems_debugger->output_level) {
+    csum += rtems_debugger->output[i++];
+  }
+
+  rtems_debugger->output[rtems_debugger->output_level++] = '#';
+  rtems_debugger->output[rtems_debugger->output_level++] = hex_encode((csum >> 4) & 0xf);
+  rtems_debugger->output[rtems_debugger->output_level++] = hex_encode(csum & 0xf);
+
+  rtems_debugger->ack_pending = true;;
+
+  return rtems_debugger_remote_send();
+}
+
+static int
+remote_packet_dispatch(const rtems_debugger_packet* packet,
+                       size_t                       packets,
+                       uint8_t*                     buffer,
+                       int                          size)
+{
+  const rtems_debugger_packet* p;
+  size_t                       i;
+  int                          r = -1;
+  for (i = 0, p = &packet[0]; i < packets; ++i, ++p) {
+    if (strncmp(p->label,
+                (const char*) &buffer[0],
+                strlen(p->label)) == 0) {
+      r = p->command(buffer, size);
+      break;
+    }
+  }
+  if (r < 0) {
+    remote_packet_out_buffer("", 0);
+    remote_packet_out_send();
+  }
+  return 0;
+}
+
+static int
+remote_detach(uint8_t* buffer, int size)
+{
+  remote_packet_out_str(r_OK);
+  remote_packet_out_send();
+  rtems_debugger_remote_disconnect();
+  return 0;
+}
+
+static int
+remote_ut_features(uint8_t* buffer, int size)
+{
+  return -1;
+}
+
+static int
+remote_ut_osdata(uint8_t* buffer, int size)
+{
+  return -1;
+}
+
+static const rtems_debugger_packet uninterpreted_transfer[] = {
+  { .label   = "qXfer:features",
+    .command = remote_ut_features },
+  { .label   = "qXfer:osdata",
+    .command = remote_ut_osdata },
+};
+
+#define REMOTE_UNINTERPRETED_TRANSFERS \
+  RTEMS_DEBUGGER_NUMOF(uninterpreted_transfer)
+
+static int
+remote_gq_uninterpreted_transfer(uint8_t* buffer, int size)
+{
+  return remote_packet_dispatch(uninterpreted_transfer,
+                                REMOTE_UNINTERPRETED_TRANSFERS,
+                                buffer, size);
+}
+
+static int
+remote_gq_thread_info_subsequent(uint8_t* buffer, int size)
+{
+  rtems_debugger_threads* threads = rtems_debugger->threads;
+  if (threads->next >= threads->current.level)
+    remote_packet_out_str("l");
+  else {
+    rtems_debugger_thread* current;
+    const char*            format = "p%d.%08lx";
+    current = rtems_debugger_thread_current(threads);
+    remote_packet_out_str("m");
+    while (threads->next < threads->current.level) {
+      int r;
+      r = remote_packet_out_append(format,
+                                   rtems_debugger->pid,
+                                   current[threads->next].id);
+      if (r < 0)
+        break;
+      format = ",p%d.%08lx";
+      ++threads->next;
+    }
+  }
+  remote_packet_out_send();
+  return 0;
+}
+
+static int
+remote_gq_thread_info_first(uint8_t* buffer, int size)
+{
+  rtems_debugger->threads->next = 0;
+  return remote_gq_thread_info_subsequent(buffer, size);
+}
+
+static int
+remote_gq_thread_extra_info(uint8_t* buffer, int size)
+{
+  const char* comma;
+  remote_packet_out_reset();
+  comma = strchr((const char*) buffer, ',');
+  if (comma != NULL) {
+    DB_UINT pid = 0;
+    DB_UINT tid = 0;
+    bool    extended;
+    extended = thread_id_decode(comma + 1, &pid, &tid);
+    if (!extended || (extended && check_pid(pid))) {
+      int r;
+      r = rtems_debugger_thread_find_index(tid);
+      if (r >= 0) {
+        rtems_debugger_threads* threads = rtems_debugger->threads;
+        rtems_debugger_thread*  current;
+        rtems_debugger_thread*  thread;
+        char                    buf[128];
+        char                    str[32];
+        size_t                  l;
+        current = rtems_debugger_thread_current(threads);
+        thread = &current[r];
+        l = snprintf(buf, sizeof(buf),
+                     "%4s (%08lx), ", thread->name, thread->id);
+        remote_packet_out_append_hex((const uint8_t*) buf, l);
+        l = snprintf(buf, sizeof(buf),
+                     "priority(c:%3d r:%3d), ",
+                     rtems_debugger_thread_current_priority(thread),
+                     rtems_debugger_thread_real_priority(thread));
+        remote_packet_out_append_hex((const uint8_t*) buf, l);
+        l = snprintf(buf, sizeof(buf),
+                     "stack(s:%6lu a:%p), ",
+                     rtems_debugger_thread_stack_size(thread),
+                     rtems_debugger_thread_stack_area(thread));
+        remote_packet_out_append_hex((const uint8_t*) buf, l);
+        rtems_debugger_thread_state_str(thread, str, sizeof(str));
+        l = snprintf(buf, sizeof(buf), "state(%s)", str);
+        remote_packet_out_append_hex((const uint8_t*) buf, l);
+      }
+    }
+  }
+  remote_packet_out_send();
+  return 0;
+}
+
+static int
+remote_gq_supported(uint8_t* buffer, int size)
+{
+  uint32_t    capabilities = rtems_debugger_target_capabilities();
+  const char* p;
+  bool        swbreak = false;
+  bool        hwbreak = false;
+  bool        vCont = false;
+  bool        no_resumed = false;
+  bool        multiprocess = false;
+  remote_packet_out("qSupported:PacketSize=%d;QNonStop-",
+                    RTEMS_DEBUGGER_BUFFER_SIZE);
+  p = strchr((const char*) buffer, ':');
+  if (p != NULL)
+    ++p;
+  while (p != NULL && p != '\0') {
+    bool  echo = false;
+    char* sc;
+    sc = strchr(p, ';');
+    if (sc != NULL) {
+      *sc++ = '\0';
+    }
+    if (strcmp(p, "swbreak+") == 0 &&
+        !swbreak && (capabilities & RTEMS_DEBUGGER_TARGET_CAP_SWBREAK) != 0) {
+      swbreak = true;
+      echo = true;
+    }
+    if (strcmp(p, "hwbreak+") == 0 &&
+        !hwbreak && (capabilities & RTEMS_DEBUGGER_TARGET_CAP_HWBREAK) != 0) {
+      hwbreak = true;
+      echo = true;
+    }
+    if (!vCont && strcmp(p, "vContSupported+") == 0) {
+      rtems_debugger->flags |= RTEMS_DEBUGGER_FLAG_VCONT;
+      vCont = true;
+      echo = true;
+    }
+    if (!no_resumed && strcmp(p, "no-resumed+") == 0) {
+      no_resumed = true;
+      echo = true;
+    }
+    if (!multiprocess && strcmp(p, "multiprocess+") == 0) {
+      rtems_debugger->flags |= RTEMS_DEBUGGER_FLAG_MULTIPROCESS;
+      multiprocess = true;
+      echo = true;
+    }
+
+    if (echo) {
+      remote_packet_out_append_str(";");
+      remote_packet_out_append_str(p);
+    }
+    else if (strncmp(p, "xmlRegisters", sizeof("xmlRegisters") - 1) == 0) {
+      /* ignore */
+    }
+    else {
+      remote_packet_out_append_str(";");
+      remote_packet_out_append_buffer(p, strlen(p) - 1);
+      remote_packet_out_append_str("-");
+    }
+    p = sc;
+  }
+  if (!swbreak && (capabilities & RTEMS_DEBUGGER_TARGET_CAP_SWBREAK) != 0) {
+    remote_packet_out_append_str("swbreak+;");
+  }
+  if (!hwbreak && (capabilities & RTEMS_DEBUGGER_TARGET_CAP_HWBREAK) != 0) {
+    remote_packet_out_append_str("hwbreak+;");
+  }
+  if (!vCont) {
+    remote_packet_out_append_str("vContSupported+;");
+  }
+  if (!no_resumed) {
+    remote_packet_out_append_str("no-resumed+;");
+  }
+  if (!multiprocess) {
+    remote_packet_out_append_str("multiprocess+;");
+  }
+  remote_packet_out_send();
+  return 0;
+}
+
+static int
+remote_gq_attached(uint8_t* buffer, int size)
+{
+  const char const* 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)
+      response = r_E01;
+  }
+  remote_packet_out_str(response);
+  remote_packet_out_send();
+  return 0;
+}
+
+static const rtems_debugger_packet general_query[] = {
+  { .label   = "qfThreadInfo",
+    .command = remote_gq_thread_info_first },
+  { .label   = "qsThreadInfo",
+    .command = remote_gq_thread_info_subsequent },
+  { .label   = "qThreadExtraInfo",
+    .command = remote_gq_thread_extra_info },
+  { .label   = "qSupported",
+    .command = remote_gq_supported },
+  { .label   = "qAttached",
+    .command = remote_gq_attached },
+  { .label   = "qXfer",
+    .command = remote_gq_uninterpreted_transfer },
+};
+
+#define REMOTE_GENERAL_QUERIES RTEMS_DEBUGGER_NUMOF(general_query)
+
+static int
+remote_general_query(uint8_t* buffer, int size)
+{
+  return remote_packet_dispatch(general_query, REMOTE_GENERAL_QUERIES,
+                                buffer, size);
+}
+
+static int
+remote_gs_non_stop(uint8_t* buffer, int size)
+{
+  const char const* response = r_E01;
+  char*       p = strchr((char*) buffer, ':');
+  if (p != NULL) {
+    ++p;
+    response = r_OK;
+    if (*p == '0') {
+      rtems_debugger->flags &= ~RTEMS_DEBUGGER_FLAG_NON_STOP;
+    }
+    else if (*p == '1') {
+      rtems_debugger->flags |= RTEMS_DEBUGGER_FLAG_NON_STOP;
+    }
+    else
+      response = r_E01;
+  }
+  remote_packet_out_str(response);
+  remote_packet_out_send();
+  return 0;
+}
+
+static const rtems_debugger_packet general_set[] = {
+  { .label   = "QNonStop",
+    .command = remote_gs_non_stop },
+};
+
+#define REMOTE_GENERAL_SETS RTEMS_DEBUGGER_NUMOF(general_set)
+
+static int
+remote_general_set(uint8_t* buffer, int size)
+{
+  return remote_packet_dispatch(general_set, REMOTE_GENERAL_SETS,
+                                buffer, size);
+}
+
+static int
+remote_v_stopped(uint8_t* buffer, int size)
+{
+  rtems_debugger_threads* threads = rtems_debugger->threads;
+  if (threads->next >= threads->stopped.level)
+    remote_packet_out_str(r_OK);
+  else {
+    rtems_id* stopped;
+    remote_packet_out("T%02x", rtems_debugger->signal);
+    stopped = rtems_debugger_thread_stopped(threads);
+    while (threads->next < threads->stopped.level) {
+      int r;
+      r = remote_packet_out_append("thread:p%d.%08lx;",
+                                   rtems_debugger->pid,
+                                   stopped[threads->next]);
+      if (r < 0)
+        break;
+      ++threads->next;
+    }
+  }
+  remote_packet_out_send();
+  return 0;
+}
+
+static int
+remote_stop_reason(uint8_t* buffer, int size)
+{
+  rtems_debugger->threads->next = 0;
+  return remote_v_stopped(buffer, size);
+}
+
+static int
+remote_v_continue(uint8_t* buffer, int size)
+{
+  buffer += 5;
+
+  if (buffer[0] == '?') {
+    /*
+     * You need to supply 'c' and 'C' or GDB says vCont is not supported. As
+     * Sammy-J says "Silly GDB".
+     */
+    remote_packet_out_str("vCont;c;C;s;r;");
+  }
+  else {
+    const char* semi = (const char*) &buffer[0];
+    bool        resume = false;
+    bool        ok = true;
+    while (ok && semi != NULL) {
+      const char* colon = strchr(semi + 1, ':');
+      const char  action = *(semi + 1);
+      DB_UINT     pid = 0;
+      DB_UINT     tid = 0;
+      bool        extended;
+      if (colon != NULL) {
+        int r = -1;
+        extended = thread_id_decode(colon + 1, &pid, &tid);
+        if (extended || check_pid(pid)) {
+          rtems_debugger_threads* threads = rtems_debugger->threads;
+          rtems_debugger_thread*  thread = NULL;
+          int                     index = 0;
+          if (tid != (DB_UINT) -1) {
+            rtems_debugger_thread* current;
+            current = rtems_debugger_thread_current(threads);
+            index = rtems_debugger_thread_find_index(tid);
+            if (index >= 0)
+              thread = &current[index];
+          }
+          switch (action) {
+          case 'c':
+          case 'C':
+            if (tid == (DB_UINT) -1) {
+              r = rtems_debugger_thread_continue_all();
+            }
+            else if (thread != NULL) {
+              r = rtems_debugger_thread_continue(thread);
+            }
+            if (r == 0)
+              resume = true;
+            break;
+          case 's':
+            if (thread != NULL) {
+              r = rtems_debugger_thread_step(thread);
+              if (r == 0)
+                resume = true;
+            }
+            break;
+          case 'r':
+            /*
+             * Range to step around inside: `r start,end`.
+             */
+            if (thread != NULL) {
+              const char* comma;
+              comma = strchr(semi + 2, ',');
+              if (comma != NULL) {
+                DB_UINT start;
+                DB_UINT end;
+                start = hex_decode_uint((const uint8_t*) semi + 2);
+                end = hex_decode_uint((const uint8_t*) comma + 1);
+                r = rtems_debugger_thread_stepping(thread, start, end);
+                if (r == 0)
+                  resume = true;
+              }
+              else {
+                ok = false;
+              }
+            }
+            break;
+          default:
+            ok = false;
+            break;
+          }
+          if (r < 0)
+            ok = false;
+        }
+      }
+      else {
+        ok = false;
+      }
+      semi = strchr(semi + 1, ';');
+    }
+
+    if (ok)
+      remote_packet_out_str(r_OK);
+    else
+      remote_packet_out_str(r_E01);
+
+    if (resume)
+      rtems_debugger_thread_system_resume(false);
+  }
+
+  remote_packet_out_send();
+
+  return 0;
+}
+
+static int
+remote_v_kill(uint8_t* buffer, int size)
+{
+  rtems_debugger->flags |= RTEMS_DEBUGGER_FLAG_RESET;
+  return remote_detach(buffer, size);
+}
+
+static const rtems_debugger_packet v_packets[] = {
+  { .label   = "vCont",
+    .command = remote_v_continue },
+  { .label   = "vStopped",
+    .command = remote_v_stopped },
+  { .label   = "vKill",
+    .command = remote_v_kill },
+};
+
+#define REMOTE_V_PACKETS RTEMS_DEBUGGER_NUMOF(v_packets)
+
+static int
+remote_v_packets(uint8_t* buffer, int size)
+{
+  return remote_packet_dispatch(v_packets, REMOTE_V_PACKETS,
+                                buffer, size);
+}
+
+static int
+remote_thread_select(uint8_t* buffer, int size)
+{
+  const char const* response = r_OK;
+  int*              index = NULL;
+
+  if (buffer[1] == 'g')
+    index = &rtems_debugger->threads->selector_gen;
+  else if (buffer[1] == 'c')
+    index = &rtems_debugger->threads->selector_cont;
+  else
+    response = r_E01;
+
+  if (index != NULL) {
+    DB_UINT pid = 0;
+    DB_UINT tid = 0;
+    bool    extended;
+    extended = thread_id_decode((const char*) &buffer[2], &pid, &tid);
+    if (extended && !check_pid(pid)) {
+      response = r_E01;
+    }
+    else {
+      if (tid == 0 || tid == (DB_UINT) -1)
+        *index = (int) tid;
+      else {
+        int r;
+        r = rtems_debugger_thread_find_index(tid);
+        if (r < 0) {
+          response = r_E01;
+          *index = -1;
+        }
+        else
+          *index = r;
+      }
+    }
+  }
+
+  remote_packet_out_str(response);
+  remote_packet_out_send();
+  return 0;
+}
+
+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;
+  extended = thread_id_decode((const char*) &buffer[1], &pid, &tid);
+  if (!extended || (extended && check_pid(pid))) {
+    int r;
+    r = rtems_debugger_thread_find_index(tid);
+    if (r >= 0)
+      response = r_OK;
+  }
+  remote_packet_out_str(response);
+  remote_packet_out_send();
+  return 0;
+}
+
+static int
+remote_argc_argv(uint8_t* buffer, int size)
+{
+  return -1;
+}
+
+static int
+remote_continue_at(uint8_t* buffer, int size)
+{
+  if (!rtems_debugger_server_flag(RTEMS_DEBUGGER_FLAG_VCONT)) {
+    char* vCont_c = "vCont;c:p1.-1";
+    return remote_v_continue((uint8_t*) vCont_c, strlen(vCont_c));
+  }
+  return -1;
+}
+
+static int
+remote_read_general_regs(uint8_t* buffer, int size)
+{
+  rtems_debugger_threads* threads = rtems_debugger->threads;
+  bool                    ok = false;
+  int                     r;
+  if (threads->selector_gen >= 0 &&
+      threads->selector_gen < (int) threads->current.level) {
+    rtems_debugger_thread* current;
+    rtems_debugger_thread* thread;
+    current = rtems_debugger_thread_current(threads);
+    thread = &current[threads->selector_gen];
+    r = rtems_debugger_target_read_regs(thread);
+    if (r >= 0) {
+      remote_packet_out_reset();
+      r = remote_packet_out_append_hex((const uint8_t*) &thread->registers[0],
+                                       rtems_debugger_target_reg_size());
+      if (r >= 0)
+        ok = true;
+    }
+  }
+  if (!ok)
+    remote_packet_out_str(r_E01);
+  remote_packet_out_send();
+  return 0;
+}
+
+static int
+remote_write_general_regs(uint8_t* buffer, int size)
+{
+  rtems_debugger_threads* threads = rtems_debugger->threads;
+  size_t                  reg_size = rtems_debugger_target_reg_size();
+  bool                    ok = false;
+  int                     r;
+  if (threads->selector_gen >= 0 &&
+      threads->selector_gen < (int) threads->current.level &&
+      ((size - 1) / 2) == (int) reg_size) {
+    rtems_debugger_thread* current;
+    rtems_debugger_thread* thread;
+    current = rtems_debugger_thread_current(threads);
+    thread = &current[threads->selector_gen];
+    r = rtems_debugger_target_read_regs(thread);
+    if (r >= 0) {
+      r = rtems_debugger_remote_packet_in_hex((uint8_t*) &thread->registers[0],
+                                              (const char*) &buffer[1],
+                                              reg_size);
+      if (r >= 0) {
+        thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
+        ok = true;
+      }
+    }
+  }
+  if (!ok)
+    remote_packet_out_str(r_E01);
+  remote_packet_out_send();
+  return 0;
+}
+
+static int
+remote_read_reg(uint8_t* buffer, int size)
+{
+  rtems_debugger_threads* threads = rtems_debugger->threads;
+  bool                    ok = false;
+  int                     r;
+  if (threads->selector_gen >= 0
+      && threads->selector_gen < (int) threads->current.level) {
+    size_t reg = hex_decode_int(&buffer[1]);
+    if (reg < rtems_debugger_target_reg_num()) {
+      rtems_debugger_thread* current;
+      rtems_debugger_thread* thread;
+      current = rtems_debugger_thread_current(threads);
+      thread = &current[threads->selector_gen];
+      r = rtems_debugger_target_read_regs(thread);
+      if (r >= 0) {
+        const uint8_t* addr = (const uint8_t*) &thread->registers[reg];
+        remote_packet_out_reset();
+        r = remote_packet_out_append_hex(addr, sizeof(thread->registers[0]));
+        if (r >= 0)
+          ok = true;
+      }
+    }
+  }
+  if (!ok)
+    remote_packet_out_str(r_E01);
+  remote_packet_out_send();
+  return 0;
+}
+
+static int
+remote_write_reg(uint8_t* buffer, int size)
+{
+  rtems_debugger_threads* threads = rtems_debugger->threads;
+  const char const*       response = r_E01;
+  if (threads->selector_gen >= 0
+      && threads->selector_gen < (int) threads->current.level) {
+    const char* equals;
+    equals = strchr((const char*) buffer, '=');
+    if (equals != NULL) {
+      size_t reg = hex_decode_int(&buffer[1]);
+      if (reg < rtems_debugger_target_reg_num()) {
+        rtems_debugger_thread* current;
+        rtems_debugger_thread* thread;
+        int                    r;
+        current = rtems_debugger_thread_current(threads);
+        thread = &current[threads->selector_gen];
+        r = rtems_debugger_target_read_regs(thread);
+        if (r >= 0) {
+          uint8_t* addr = (uint8_t*) &thread->registers[reg];
+          r = rtems_debugger_remote_packet_in_hex(addr,
+                                                  equals + 1,
+                                                  sizeof(thread->registers[reg]));
+          if (r == 0) {
+            thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
+            response = r_OK;
+          }
+        }
+      }
+    }
+  }
+  remote_packet_out_str(response);
+  remote_packet_out_send();
+  return 0;
+}
+
+static int
+remote_read_memory(uint8_t* buffer, int size)
+{
+  const char* comma;
+  comma = strchr((const char*) buffer, ',');
+  if (comma == NULL)
+    remote_packet_out_str(r_E01);
+  else {
+    DB_UINT addr;
+    DB_UINT length;
+    int     r;
+    addr = hex_decode_uint(&buffer[1]);
+    length = hex_decode_uint((const uint8_t*) comma + 1);
+    remote_packet_out_reset();
+    r = rtems_debugger_target_start_memory_access();
+    if (r == 0) {
+      /*
+       * There should be specific target access for 8, 16, 32 and 64 bit reads.
+       */
+      r = remote_packet_out_append_hex((const uint8_t*) addr, length);
+    }
+    rtems_debugger_target_end_memory_access();
+    if (r < 0)
+      remote_packet_out_str(r_E01);
+  }
+  remote_packet_out_send();
+  return 0;
+}
+
+static int
+remote_write_memory(uint8_t* buffer, int size)
+{
+  const char const* response = r_E01;
+  const char*       comma;
+  const char*       colon;
+  comma = strchr((const char*) buffer, ',');
+  colon = strchr((const char*) buffer, ':');
+  if (comma != NULL && colon != NULL) {
+    DB_UINT addr;
+    DB_UINT length;
+    int     r;
+    addr = hex_decode_uint(&buffer[1]);
+    length = hex_decode_uint((const uint8_t*) comma + 1);
+    r = rtems_debugger_target_start_memory_access();
+    if (r == 0) {
+      r = rtems_debugger_remote_packet_in_hex((uint8_t*) addr,
+                                              colon + 1,
+                                              length);
+    }
+    rtems_debugger_target_end_memory_access();
+    if (r == 0)
+      response = r_OK;
+  }
+  remote_packet_out_str(response);
+  remote_packet_out_send();
+  return 0;
+}
+
+static int
+remote_single_step(uint8_t* buffer, int size)
+{
+  if (!rtems_debugger_server_flag(RTEMS_DEBUGGER_FLAG_VCONT)) {
+    rtems_debugger_threads* threads = rtems_debugger->threads;
+    if (threads != NULL && rtems_debugger_thread_current(threads) != NULL) {
+      rtems_debugger_thread* current;
+      char                   vCont_s[32];
+      current = rtems_debugger_thread_current(threads);
+      snprintf(vCont_s, sizeof(vCont_s), "vCont;s:p1.%08lx;c:p1.-1",
+               current[threads->selector_cont].id);
+      return remote_v_continue((uint8_t*) vCont_s, strlen(vCont_s));
+    }
+    remote_packet_out_str(r_E01);
+    remote_packet_out_send();
+    return 0;
+  }
+  return -1;
+}
+
+static int
+remote_breakpoints(bool insert, uint8_t* buffer, int size)
+{
+  const char* comma1;
+  int         r = -1;
+  comma1 = strchr((const char*) buffer, ',');
+  if (comma1 != NULL) {
+    const char* comma2;
+    comma2 = strchr(comma1 + 1, ',');
+    if (comma2 != NULL) {
+      uint32_t capabilities;
+      DB_UINT  addr;
+      DB_UINT  kind;
+      addr = hex_decode_uint((const uint8_t*) comma1 + 1);
+      kind = hex_decode_uint((const uint8_t*)comma2 + 1);
+      capabilities = rtems_debugger_target_capabilities();
+      switch (buffer[1]) {
+      case '0':
+        if ((capabilities & RTEMS_DEBUGGER_TARGET_CAP_SWBREAK) != 0) {
+          r = rtems_debugger_target_swbreak_control(insert, addr, kind);
+        }
+        break;
+      case '1': /* execute */
+      case '2': /* write */
+      case '3': /* read */
+      case '4': /* access */
+        if ((capabilities & RTEMS_DEBUGGER_TARGET_CAP_HWWATCH) != 0) {
+          rtems_debugger_target_watchpoint type;
+          switch (buffer[1]) {
+          case '1':
+            type = rtems_debugger_target_hw_execute;
+            break;
+          case '2':
+            type = rtems_debugger_target_hw_write;
+            break;
+          case '3':
+            type = rtems_debugger_target_hw_read;
+            break;
+          case '4':
+          default:
+            type = rtems_debugger_target_hw_read_write;
+            break;
+          }
+          r = rtems_debugger_target_hwbreak_control(type, insert, addr, kind);
+        }
+        break;
+      default:
+        break;
+      }
+    }
+  }
+  remote_packet_out_str(r < 0 ?  r_E01 : r_OK);
+  remote_packet_out_send();
+  return 0;
+}
+
+static int
+remote_insert_breakpoint(uint8_t* buffer, int size)
+{
+  return remote_breakpoints(true, buffer, size);
+}
+
+static int
+remote_remove_breakpoint(uint8_t* buffer, int size)
+{
+  return remote_breakpoints(false, buffer, size);
+}
+
+static int
+remote_break(uint8_t* buffer, int size)
+{
+  int r;
+  r = rtems_debugger_thread_system_suspend();
+  if (r < 0) {
+    rtems_debugger_printf("error: rtems-db: suspend all on break\n");
+  }
+  return remote_stop_reason(buffer, size);
+}
+
+static const rtems_debugger_packet packets[] = {
+  { .label   = "q",
+    .command = remote_general_query },
+  { .label   = "Q",
+    .command = remote_general_set },
+  { .label   = "v",
+    .command = remote_v_packets },
+  { .label   = "H",
+    .command = remote_thread_select },
+  { .label   = "T",
+    .command = remote_thread_alive },
+  { .label   = "?",
+    .command = remote_stop_reason },
+  { .label   = "A",
+    .command = remote_argc_argv },
+  { .label   = "c",
+    .command = remote_continue_at },
+  { .label   = "g",
+    .command = remote_read_general_regs },
+  { .label   = "G",
+    .command = remote_write_general_regs },
+  { .label   = "p",
+    .command = remote_read_reg },
+  { .label   = "P",
+    .command = remote_write_reg },
+  { .label   = "m",
+    .command = remote_read_memory },
+  { .label   = "M",
+    .command = remote_write_memory },
+  { .label   = "s",
+    .command = remote_single_step },
+  { .label   = "Z",
+    .command = remote_insert_breakpoint },
+  { .label   = "z",
+    .command = remote_remove_breakpoint },
+  { .label   = "D",
+    .command = remote_detach },
+  { .label   = "k",
+    .command = remote_v_kill },
+  { .label   = "r",
+    .command = remote_v_kill },
+  { .label   = "R",
+    .command = remote_v_kill },
+  { .label   = "^C",
+    .command = remote_break },
+};
+
+#define REMOTE_PACKETS RTEMS_DEBUGGER_NUMOF(packets)
+
+static int
+remote_packets(uint8_t* buffer, size_t size)
+{
+  return remote_packet_dispatch(packets, REMOTE_PACKETS,
+                                buffer, size);
+}
+
+static void
+rtems_debugger_events(rtems_task_argument arg)
+{
+  int r;
+
+  if (rtems_debugger_verbose())
+    rtems_debugger_printf("rtems-db: events running\n");
+
+  /*
+   * Hold the lock until the thread blocks waiting for an event.
+   */
+  rtems_debugger_lock();
+
+  rtems_debugger_target_enable();
+
+  while (rtems_debugger_server_events_running()) {
+    r = rtems_debugger_server_events_wait();
+    if (r < 0)
+      break;
+    if (!rtems_debugger_server_events_running())
+      break;
+    r = rtems_debugger_thread_system_suspend();
+    if (r < 0)
+      break;
+    r = remote_stop_reason(NULL, 0);
+    if (r < 0)
+      break;
+  }
+
+  if (r < 0)
+    rtems_debugger_printf("rtems-db: error in events\n");
+
+  rtems_debugger_target_disable();
+
+  rtems_debugger->events_running = false;
+  rtems_debugger->events_finished = true;
+
+  rtems_debugger_unlock();
+
+  if (rtems_debugger_verbose())
+    rtems_debugger_printf("rtems-db: events finishing\n");
+
+  rtems_task_delete(RTEMS_SELF);
+}
+
+static int
+rtems_debugger_session(void)
+{
+  int r;
+  int rr;
+
+  if (rtems_debugger_verbose())
+    rtems_debugger_printf("rtems-db: remote running\n");
+
+  /*
+   * Hold the lock until the thread blocks on the remote input.
+   */
+  rtems_debugger_lock();
+
+  r = rtems_debugger_target_create();
+  if (r < 0) {
+    rtems_debugger_thread_destroy();
+    rtems_debugger_unlock();
+    return r;
+  }
+
+  r = rtems_debugger_thread_create();
+  if (r < 0) {
+    rtems_debugger_unlock();
+    return r;
+  }
+
+  rtems_debugger->events_running = true;
+  rtems_debugger->events_finished = false;
+
+  r = rtems_debugger_task_create("DBSe",
+                                 rtems_debugger->priority,
+                                 RTEMS_DEBUGGER_STACKSIZE,
+                                 rtems_debugger_events,
+                                 0,
+                                 &rtems_debugger->events_task);
+  if (r < 0) {
+    rtems_debugger_target_destroy();
+    rtems_debugger_thread_destroy();
+    rtems_debugger_unlock();
+    return r;
+  }
+
+  while (rtems_debugger_server_running() &&
+         rtems_debugger_connected()) {
+    r = rtems_debugger_remote_packet_in();
+    if (r < 0)
+      break;
+    if (r > 0) {
+      remote_packets(&rtems_debugger->input[0], r);
+    }
+  }
+
+  rtems_debugger->events_running = false;
+  rtems_debugger_server_events_wake();
+
+  rtems_debugger_unlock();
+
+  rr = rtems_debugger_task_destroy("DBSe",
+                                   rtems_debugger->events_task,
+                                   &rtems_debugger->events_finished,
+                                   RTEMS_DEBUGGER_TIMEOUT_STOP);
+  if (rr < 0 && r == 0)
+    r = rr;
+
+  rtems_debugger_lock();
+
+  rr = rtems_debugger_target_destroy();
+  if (rr < 0 && r == 0)
+    r = rr;
+
+  rr = rtems_debugger_thread_destroy();
+  if (rr < 0 && r == 0)
+    r = rr;
+
+  if (rtems_debugger_server_flag(RTEMS_DEBUGGER_FLAG_RESET)) {
+    rtems_debugger_printf("rtems-db: shutdown\n");
+    rtems_fatal_error_occurred(1122);
+  }
+
+  rtems_debugger->flags = 0;
+  rtems_debugger->ack_pending = false;
+
+  rtems_debugger_unlock();
+
+  if (rtems_debugger_verbose())
+    rtems_debugger_printf("rtems-db: remote finishing\n");
+
+  return r;
+}
+
+static int
+rtems_debugger_create(const char*          remote,
+                      const char*          device,
+                      rtems_task_priority  priority,
+                      int                  timeout,
+                      const rtems_printer* printer)
+{
+  int r;
+
+  if (rtems_debugger != NULL) {
+    rtems_printf(printer, "error: rtems-db: create: already active\n");
+    errno = EEXIST;
+    return -1;
+  }
+
+  rtems_debugger = malloc(sizeof(rtems_debugger_server));
+  if (rtems_debugger == NULL) {
+    rtems_printf(printer, "error: rtems-db: create: no memory\n");
+    errno = ENOMEM;
+    return -1;
+  }
+
+  memset(rtems_debugger, 0, sizeof(rtems_debugger_server));
+
+  /*
+   * These do not change with a session.
+   */
+  rtems_debugger->priority = priority;
+  rtems_debugger->timeout = timeout;
+  rtems_debugger->printer = *printer;
+  rtems_debugger->pid = getpid();
+  rtems_debugger->remote_debug = false;
+
+  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);
+    free(rtems_debugger);
+    rtems_debugger = NULL;
+    return -1;
+  }
+
+  r = rtems_debugger->remote->begin(rtems_debugger->remote, device);
+  if (r < 0) {
+    rtems_printf(printer, "error: rtems-db: remote begin: %s: %s\n",
+                 rtems_debugger->remote->name, strerror(errno));
+    free(rtems_debugger);
+    rtems_debugger = NULL;
+  }
+
+  /*
+   * Reset at the end of the session.
+   */
+  rtems_debugger->flags = 0;
+  rtems_debugger->ack_pending = false;
+
+  r = rtems_debugger_lock_create();
+  if (r < 0) {
+    free(rtems_debugger);
+    rtems_debugger = NULL;
+    return -1;
+  }
+
+  return 0;
+}
+
+static int
+rtems_debugger_destroy(void)
+{
+  int r;
+  int rr;
+
+  rtems_debugger_lock();
+  rtems_debugger->server_running = false;
+  rtems_debugger_unlock();
+
+  r = rtems_debugger_remote_disconnect();
+
+  rr = rtems_debugger->remote->end(rtems_debugger->remote);
+  if (rr < 0 && r == 0)
+    r = rr;
+
+  rr = rtems_debugger_task_destroy("DBSr",
+                                   rtems_debugger->server_task,
+                                   &rtems_debugger->server_finished,
+                                   RTEMS_DEBUGGER_TIMEOUT_STOP);
+  if (rr < 0 && r == 0)
+    r = rr;
+
+  rr = rtems_debugger_lock_destroy();
+  if (rr < 0 && r == 0)
+    r = rr;
+
+  free(rtems_debugger);
+  rtems_debugger = NULL;
+
+  return r;
+}
+
+static void
+rtems_debugger_main(rtems_task_argument arg)
+{
+  int r;
+
+  rtems_debugger_printf("rtems-db: remote running\n");
+
+  while (rtems_debugger_server_running()) {
+    r = rtems_debugger_remote_connect();
+    if (r < 0)
+      break;
+    rtems_debugger_session();
+    rtems_debugger_remote_disconnect();
+  }
+
+  rtems_debugger_printf("rtems-db: remote finishing\n");
+
+  rtems_debugger_lock();
+  rtems_debugger->server_running = false;
+  rtems_debugger->server_finished = true;
+  rtems_debugger_unlock();
+
+  rtems_task_delete(RTEMS_SELF);
+}
+
+int
+rtems_debugger_start(const char*          remote,
+                     const char*          device,
+                     int                  timeout,
+                     rtems_task_priority  priority,
+                     const rtems_printer* printer)
+{
+  int r;
+
+  r = rtems_debugger_create(remote, device, priority, timeout, printer);
+  if (r < 0)
+    return -1;
+
+  rtems_debugger_lock();
+  rtems_debugger->server_running = true;
+  rtems_debugger->server_finished = false;
+  rtems_debugger_unlock();
+
+  r = rtems_debugger_task_create("DBSs",
+                                 priority,
+                                 RTEMS_DEBUGGER_STACKSIZE,
+                                 rtems_debugger_main,
+                                 0,
+                                 &rtems_debugger->server_task);
+  if (r < 0) {
+    rtems_debugger_destroy();
+    return -1;
+  }
+
+  return 0;
+}
+
+int
+rtems_debugger_stop(void)
+{
+  return rtems_debugger_destroy();
+}
+
+bool
+rtems_debugger_running(void)
+{
+  return rtems_debugger != NULL;
+}
+
+void
+rtems_debugger_set_verbose(bool on)
+{
+  if (rtems_debugger_running()) {
+    if (on)
+      rtems_debugger->flags |= RTEMS_DEBUGGER_FLAG_VERBOSE;
+    else
+      rtems_debugger->flags &= ~RTEMS_DEBUGGER_FLAG_VERBOSE;
+  }
+}
+
+int
+rtems_debugger_remote_debug(bool state)
+{
+  rtems_debugger_lock();
+  rtems_debugger->remote_debug = state;
+  rtems_debugger_printf("rtems-db: remote-debug is %s\n",
+                        rtems_debugger->remote_debug ? "on" : "off");
+  rtems_debugger_unlock();
+  return 0;
+}
diff --git a/cpukit/libdebugger/rtems-debugger-server.h b/cpukit/libdebugger/rtems-debugger-server.h
new file mode 100644
index 0000000..0941933
--- /dev/null
+++ b/cpukit/libdebugger/rtems-debugger-server.h
@@ -0,0 +1,204 @@
+/*
+ * 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Debugger for RTEMS.
+ */
+
+#ifndef _RTEMS_DEBUGGER_SERVER_h
+#define _RTEMS_DEBUGGER_SERVER_h
+
+#include <rtems.h>
+#include <rtems/printer.h>
+
+#include <rtems/rtems-debugger.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * Debugger NUMOF macro.
+ */
+#define RTEMS_DEBUGGER_NUMOF(_d) (sizeof(_d) / sizeof(_d[0]))
+
+/**
+ * Machine specific size. Here for 64bit support.
+ */
+#define DB_UINT uint32_t
+
+/*
+ * Debugger signals.
+ */
+#define RTEMS_DEBUGGER_SIGNAL_HUP   1     /* Hangup */
+#define RTEMS_DEBUGGER_SIGNAL_INT   2     /* Interrupt */
+#define RTEMS_DEBUGGER_SIGNAL_QUIT  3     /* Quit */
+#define RTEMS_DEBUGGER_SIGNAL_ILL   4     /* Illegal instruction */
+#define RTEMS_DEBUGGER_SIGNAL_TRAP  5     /* Trace/breakpoint trap */
+#define RTEMS_DEBUGGER_SIGNAL_ABRT  6     /* Aborted */
+#define RTEMS_DEBUGGER_SIGNAL_EMT   7     /* Emulation trap */
+#define RTEMS_DEBUGGER_SIGNAL_FPE   8     /* Arithmetic exception */
+#define RTEMS_DEBUGGER_SIGNAL_KILL  9     /* Killed */
+#define RTEMS_DEBUGGER_SIGNAL_BUS   10    /* Bus error */
+#define RTEMS_DEBUGGER_SIGNAL_SEGV  11    /* Segmentation fault */
+#define RTEMS_DEBUGGER_SIGNAL_SYS   12    /* Bad system call */
+#define RTEMS_DEBUGGER_SIGNAL_PIPE  13    /* Broken pipe */
+#define RTEMS_DEBUGGER_SIGNAL_ALRM  14    /* Alarm clock */
+#define RTEMS_DEBUGGER_SIGNAL_TERM  15    /* Terminated */
+#define RTEMS_DEBUGGER_SIGNAL_URG   16    /* Urgent I/O condition */
+#define RTEMS_DEBUGGER_SIGNAL_STOP  17    /* Stopped (signal) */
+#define RTEMS_DEBUGGER_SIGNAL_TSTP  18    /* Stopped (user) */
+#define RTEMS_DEBUGGER_SIGNAL_CONT  19    /* Continued */
+
+/**
+ * Timeout period for the Debugger task to stop in usecs.
+ */
+#define RTEMS_DEBUGGER_TIMEOUT_STOP (5 * 1000 * 1000)
+
+/**
+ * Debugger poll wait timeout in usecs.
+ */
+#define RTEMS_DEBUGGER_POLL_WAIT (10000)
+
+/**
+ * Debugger task stack size.
+ */
+#define RTEMS_DEBUGGER_STACKSIZE (16 * 1024)
+
+/**
+ * Debugger output buffer size.
+ */
+#define RTEMS_DEBUGGER_BUFFER_SIZE (4 * 1024)
+
+/**
+ * Debugger flags.
+ */
+#define RTEMS_DEBUGGER_FLAG_VERBOSE      (1 << 0)
+#define RTEMS_DEBUGGER_FLAG_RESET        (1 << 1)
+#define RTEMS_DEBUGGER_FLAG_NON_STOP     (1 << 2)
+#define RTEMS_DEBUGGER_FLAG_VCONT        (1 << 3)
+#define RTEMS_DEBUGGER_FLAG_MULTIPROCESS (1 << 4)
+
+/**
+ * Forward decl for the threads and targets.
+ */
+typedef struct rtems_debugger_remote  rtems_debugger_remote;
+typedef struct rtems_debugger_threads rtems_debugger_threads;
+typedef struct rtems_debugger_target  rtems_debugger_target;
+
+/**
+ * Debugger data.
+ */
+typedef struct
+{
+  int                     port;
+  int                     timeout;
+  rtems_task_priority     priority;
+  rtems_id                lock;
+  rtems_id                lock_output;
+  rtems_debugger_remote*  remote;
+  rtems_id                server_task;
+  volatile bool           server_running;
+  volatile bool           server_finished;
+  rtems_id                events_task;
+  volatile bool           events_running;
+  volatile bool           events_finished;
+  rtems_printer           printer;
+  uint32_t                flags;
+  pid_t                   pid;
+  bool                    remote_debug;
+  bool                    ack_pending;
+  size_t                  output_level;
+  uint8_t                 input[RTEMS_DEBUGGER_BUFFER_SIZE];
+  uint8_t                 output[RTEMS_DEBUGGER_BUFFER_SIZE];
+  rtems_debugger_threads* threads;
+  int                     signal;
+  rtems_debugger_target*  target;
+} rtems_debugger_server;
+
+/**
+ * Debugger global variable.
+ */
+extern rtems_debugger_server* rtems_debugger;
+
+/**
+ * Debug server printer.
+ */
+extern int rtems_debugger_printf(const char* format, ...) RTEMS_PRINTFLIKE(1, 2);
+
+/**
+ * Lock the Debugger.
+ */
+extern int rtems_debugger_lock(void);
+
+/**
+ * Unlock the Debugger.
+ */
+extern int rtems_debugger_unlock(void);
+
+/**
+ * Is the server still running?
+ */
+bool rtems_debugger_server_running(void);
+
+/**
+ * Get the remote handle from the debugger.
+ */
+rtems_debugger_remote* rtems_debugger_remote_handle(void);
+
+/**
+ * Is the debugger connected?
+ */
+bool rtems_debugger_connected(void);
+
+/**
+ * Is the debugger events thread runnins?
+ */
+bool rtems_debugger_server_events_running(void);
+
+/**
+ * Wake events thread in the debug server.
+ */
+extern int rtems_debugger_server_events_wake(void);
+
+/**
+ * Check if verbose is on.
+ */
+extern bool rtems_debugger_verbose(void);
+
+/**
+ * Check a flag.
+ */
+static inline bool rtems_debugger_server_flag(uint32_t mask)
+{
+  return (rtems_debugger->flags & mask) != 0;
+}
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif
diff --git a/cpukit/libdebugger/rtems-debugger-target.c b/cpukit/libdebugger/rtems-debugger-target.c
new file mode 100644
index 0000000..cd15654
--- /dev/null
+++ b/cpukit/libdebugger/rtems-debugger-target.c
@@ -0,0 +1,400 @@
+/*
+ * 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define TARGET_DEBUG 0
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include <rtems.h>
+#include <rtems/score/threadimpl.h>
+
+#include "rtems-debugger-target.h"
+#include "rtems-debugger-threads.h"
+
+/**
+ * Frame signature.
+ */
+#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 };
+
+#if TARGET_DEBUG
+#include <rtems/bspIo.h>
+static void target_printk(const char* format, ...) RTEMS_PRINTFLIKE(1, 2);
+static void
+target_printk(const char* format, ...)
+{
+  va_list ap;
+  va_start(ap, format);
+  vprintk(format, ap);
+  va_end(ap);
+}
+#else
+#define target_printk(_fmt, ...)
+#endif
+
+int
+rtems_debugger_target_create(void)
+{
+  if (rtems_debugger->target == NULL) {
+    rtems_debugger_target* target;
+    int                    r;
+
+    target = calloc(1, sizeof(rtems_debugger_target));
+    if (target == NULL) {
+      errno = ENOMEM;
+      return -1;
+    }
+
+    r = rtems_debugger_target_configure(target);
+    if (r < 0) {
+      free(target);
+      return -1;
+    }
+
+    if (target->breakpoint_size > RTEMS_DEBUGGER_TARGET_SWBREAK_MAX_SIZE) {
+      free(target);
+      rtems_debugger_printf("error: rtems-db: target: breakpoint size too big\n");
+      return -1;
+    }
+
+    r = rtems_debugger_block_create(&target->swbreaks,
+                                    RTEMS_DEBUGGER_TARGET_SWBREAK_NUM,
+                                    sizeof(rtems_debugger_target_swbreak));
+    if (r < 0) {
+      free(target);
+      return -1;
+    }
+
+    rtems_debugger->target = target;
+  }
+
+  return 0;
+}
+
+int
+rtems_debugger_target_destroy(void)
+{
+  if (rtems_debugger->target != NULL) {
+    rtems_debugger_target* target = rtems_debugger->target;
+    rtems_debugger_target_swbreak_remove();
+    rtems_debugger_target_disable();
+    rtems_debugger_block_destroy(&target->swbreaks);
+    free(target);
+    rtems_debugger->target = NULL;
+  }
+  return 0;
+}
+
+uint32_t
+rtems_debugger_target_capabilities(void)
+{
+  if (rtems_debugger->target != NULL)
+
+    return rtems_debugger->target->capabilities;
+  return 0;
+}
+
+size_t
+rtems_debugger_target_reg_num(void)
+{
+  if (rtems_debugger->target != NULL)
+    return rtems_debugger->target->reg_num;
+  return 0;
+}
+
+size_t
+rtems_debugger_target_reg_size(void)
+{
+  if (rtems_debugger->target != NULL)
+    return rtems_debugger->target->reg_num * rtems_debugger->target->reg_size;
+  return 0;
+}
+
+int
+rtems_debugger_target_swbreak_control(bool insert, DB_UINT addr, DB_UINT kind)
+{
+  rtems_debugger_target*         target = rtems_debugger->target;
+  rtems_debugger_target_swbreak* swbreaks = target->swbreaks.block;
+  size_t                         swbreak_size;
+  uint8_t*                       loc = (void*) addr;
+  size_t                         i;
+  int                            r;
+
+  if (target == NULL || swbreaks == NULL || kind != target->breakpoint_size) {
+    errno = EIO;
+    return -1;
+  }
+
+  swbreak_size =
+    sizeof(rtems_debugger_target_swbreak) + target->breakpoint_size;
+
+  for (i = 0; i < target->swbreaks.level; ++i) {
+    if (loc == swbreaks[i].address) {
+      size_t remaining;
+      if (!insert) {
+        --target->swbreaks.level;
+        remaining = (target->swbreaks.level - i) * swbreak_size;
+        memmove(&swbreaks[i], &swbreaks[i + 1], remaining);
+      }
+      return 0;
+    }
+  }
+
+  if (!insert)
+    return 0;
+
+  r = rtems_debugger_block_resize(&target->swbreaks);
+  if (r < 0)
+    return -1;
+
+  swbreaks = target->swbreaks.block;
+
+  swbreaks[target->swbreaks.level].address = loc;
+  if (target->breakpoint_size > 4)
+    memcpy(&swbreaks[target->swbreaks.level].contents[0],
+           loc,
+           target->breakpoint_size);
+  else {
+    uint8_t* contents = &swbreaks[target->swbreaks.level].contents[0];
+    switch (target->breakpoint_size) {
+    case 4:
+      contents[3] = loc[3];
+    case 3:
+      contents[2] = loc[2];
+    case 2:
+      contents[1] = loc[1];
+    case 1:
+      contents[0] = loc[0];
+      break;
+    }
+  }
+  ++target->swbreaks.level;
+
+  return 0;
+}
+
+int
+rtems_debugger_target_swbreak_insert(void)
+{
+  rtems_debugger_target* target = rtems_debugger->target;
+  int                    r = -1;
+  if (target != NULL && target->swbreaks.block != NULL) {
+    rtems_debugger_target_swbreak* swbreaks = target->swbreaks.block;
+    size_t                         i;
+    r = 0;
+    for (i = 0; i < target->swbreaks.level; ++i) {
+      uint8_t* loc = swbreaks[i].address;
+      if (rtems_debugger_verbose())
+        rtems_debugger_printf("rtems-db:  bp:  in: %p\n", swbreaks[i].address);
+      if (target->breakpoint_size > 4)
+        memcpy(loc, &target->breakpoint[0], target->breakpoint_size);
+      else {
+        switch (target->breakpoint_size) {
+        case 4:
+          loc[3] = target->breakpoint[3];
+        case 3:
+          loc[2] = target->breakpoint[2];
+        case 2:
+          loc[1] = target->breakpoint[1];
+        case 1:
+          loc[0] = target->breakpoint[0];
+          break;
+        }
+      }
+      r = rtems_debugger_target_cache_sync(&swbreaks[i]);
+    }
+  }
+  return r;
+}
+
+int
+rtems_debugger_target_swbreak_remove(void)
+{
+  rtems_debugger_target* target = rtems_debugger->target;
+  int                    r = -1;
+  if (target != NULL && target->swbreaks.block != NULL) {
+    rtems_debugger_target*         target = rtems_debugger->target;
+    rtems_debugger_target_swbreak* swbreaks = target->swbreaks.block;
+    size_t                         i;
+    r = 0;
+    for (i = 0; i < target->swbreaks.level; ++i) {
+      uint8_t* loc = swbreaks[i].address;
+      uint8_t* contents = &swbreaks[i].contents[0];
+      if (rtems_debugger_verbose())
+        rtems_debugger_printf("rtems-db:  bp: out: %p\n", swbreaks[i].address);
+      if (target->breakpoint_size > 4)
+        memcpy(loc, contents, target->breakpoint_size);
+      else {
+        switch (target->breakpoint_size) {
+        case 4:
+          loc[3] = contents[3];
+        case 3:
+          loc[2] = contents[2];
+        case 2:
+          loc[1] = contents[1];
+        case 1:
+          loc[0] = contents[0];
+          break;
+        }
+      }
+      r = rtems_debugger_target_cache_sync(&swbreaks[i]);
+    }
+  }
+  return r;
+}
+
+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;
+    Thread_Control*                      thread = _Thread_Executing;
+    rtems_id*                            excludes;
+    const rtems_id                       tid = thread->Object.id;
+    DB_UINT                              pc;
+    const rtems_debugger_thread_stepper* stepper;
+    size_t                               i;
+
+    target_printk("[} tid:%08" PRIx32 ": thread:%08" PRIxPTR
+                  " frame:%08" PRIxPTR "\n",
+                  tid, (intptr_t) thread, (intptr_t) frame);
+
+    /*
+     * If the thread is the debugger recover.
+     */
+    if (tid == rtems_debugger->server_task) {
+      if (rtems_debugger->target->memory_access) {
+        target_printk("[} server access fault\n");
+        rtems_debugger->target->memory_access = true;
+        longjmp(rtems_debugger->target->access_return, -1);
+      }
+      target_printk("[} server exception\n");
+      return rtems_debugger_target_exc_cascade;
+    }
+
+    /*
+     * See if the thread is excluded.
+     */
+    excludes = rtems_debugger_thread_excludes(threads);
+    for (i = 0; i < threads->excludes.level; ++i) {
+      if (tid == excludes[i]) {
+        /*
+         * We do nothing with this condition and cascade the exception.
+         *
+         * @todo: if this is a hwbreak carry on, if this is a swbreak replace
+         *        the contents of the instruction, step then return the
+         *        swbreak's contents.
+         */
+        target_printk("[} tid:%08lx: excluded\n", tid);
+        return rtems_debugger_target_exc_cascade;
+      }
+    }
+
+    /*
+     * See if the thread is inside the stepping a range.
+     */
+    pc = rtems_debugger_target_frame_pc(frame);
+    stepper = rtems_debugger_thread_is_stepping(tid, pc);
+    if (stepper != NULL) {
+      stepper->thread->frame = frame;
+      rtems_debugger_target_thread_stepping(stepper->thread);
+      target_printk("[} tid:%08lx: stepping\n", tid);
+      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.
+     */
+    _Thread_Set_state(thread, STATES_DEBUGGER);
+    rtems_debugger_server_events_wake();
+    rtems_task_suspend(tid);
+
+    target_printk("[} tid:%08lx: resuming\n", tid);
+
+    return rtems_debugger_target_exc_consumed;
+  }
+
+  target_printk("[} cascade, in interrupt\n");
+
+  return rtems_debugger_target_exc_cascade;
+}
+
+int
+rtems_debugger_target_set_exception_frame(rtems_debugger_thread* thread)
+{
+  int r = 0;
+  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_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
+rtems_debugger_target_start_memory_access(void)
+{
+  rtems_debugger_target* target = rtems_debugger->target;
+  target->memory_access = true;
+  return setjmp(target->access_return);
+}
+
+void
+rtems_debugger_target_end_memory_access(void)
+{
+  rtems_debugger->target->memory_access = false;
+}
diff --git a/cpukit/libdebugger/rtems-debugger-target.h b/cpukit/libdebugger/rtems-debugger-target.h
new file mode 100644
index 0000000..82230e8
--- /dev/null
+++ b/cpukit/libdebugger/rtems-debugger-target.h
@@ -0,0 +1,237 @@
+/*
+ * 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Debugger for RTEMS.
+ */
+
+#ifndef _RTEMS_DEBUGGER_TARGET_h
+#define _RTEMS_DEBUGGER_TARGET_h
+
+#include <setjmp.h>
+
+#include <rtems/rtems-debugger.h>
+
+#include "rtems-debugger-threads.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*
+ * Software breakpoint block size.
+ */
+#define RTEMS_DEBUGGER_TARGET_SWBREAK_NUM 64
+
+/**
+ * Target capabilities mask.
+ */
+#define RTEMS_DEBUGGER_TARGET_CAP_SWBREAK   (1 << 0)
+#define RTEMS_DEBUGGER_TARGET_CAP_HWBREAK   (1 << 1)
+#define RTEMS_DEBUGGER_TARGET_CAP_HWWATCH   (1 << 2)
+
+/**
+ * Types of hardware breakpoints.
+ */
+typedef enum rtems_debugger_target_watchpoint
+{
+  rtems_debugger_target_hw_read,
+  rtems_debugger_target_hw_write,
+  rtems_debugger_target_hw_read_write,
+  rtems_debugger_target_hw_execute
+} rtems_debugger_target_watchpoint;
+
+/**
+ * Target exception actions.
+ */
+typedef enum rtems_debugger_target_exc_action
+{
+  rtems_debugger_target_exc_consumed, /*<< The exception has been consumed. */
+  rtems_debugger_target_exc_cascade,  /*<< Cascade to a previous handler. */
+  rtems_debugger_target_exc_step,     /*<< Step an instruction. */
+} rtems_debugger_target_exc_action;
+
+/**
+ * Memory breakpoint. We use thumb mode BKPT which is 2 bytes.
+ */
+#define RTEMS_DEBUGGER_TARGET_SWBREAK_MAX_SIZE (4)
+typedef struct rtems_debugger_target_swbreak {
+  void*   address;
+  uint8_t contents[RTEMS_DEBUGGER_TARGET_SWBREAK_MAX_SIZE];
+} rtems_debugger_target_swbreak;
+
+/**
+ * The target data.
+ */
+typedef struct rtems_debugger_target {
+  int                  capabilities;     /*<< The capabilities to report. */
+  size_t               reg_num;          /*<< The number of registers. */
+  size_t               reg_size;         /*<< The size of a register. */
+  const uint8_t*       breakpoint;       /*<< The breakpoint instruction(s). */
+  size_t               breakpoint_size;  /*<< The breakpoint size. */
+  rtems_debugger_block swbreaks;         /*<< The software breakpoint block. */
+  bool                 memory_access;    /*<< Accessing target memory. */
+  jmp_buf              access_return;    /*<< Return from an access fault. */
+} rtems_debugger_target;
+
+/**
+ * Create the target.
+ */
+extern int rtems_debugger_target_create(void);
+
+/**
+ * Destroy the target.
+ */
+extern int rtems_debugger_target_destroy(void);
+
+/**
+ * Configure the target. This is architecture specific.
+ */
+extern int rtems_debugger_target_configure(rtems_debugger_target* target);
+
+/**
+ * Enable the target.
+ */
+extern int rtems_debugger_target_enable(void);
+
+/**
+ * Disable the target.
+ */
+extern int rtems_debugger_target_disable(void);
+
+/**
+ * Return the capabilities mask for the target.
+ */
+extern uint32_t rtems_debugger_target_capabilities(void);
+
+/**
+ * Return the number of regisers.
+ */
+extern size_t rtems_debugger_target_reg_num(void);
+
+/**
+ * Return the size of the regisers in bytes.
+ */
+extern size_t rtems_debugger_target_reg_size(void);
+
+/**
+ * Read the regosters.
+ */
+extern int rtems_debugger_target_read_regs(rtems_debugger_thread* thread);
+
+/**
+ * Write the regosters.
+ */
+extern int rtems_debugger_target_write_regs(rtems_debugger_thread* thread);
+
+/**
+ * Return the thread's program counter (PC).
+ */
+extern DB_UINT rtems_debugger_target_reg_pc(rtems_debugger_thread* thread);
+
+/**
+ * Return the frame's program counter (PC).
+ */
+extern DB_UINT rtems_debugger_target_frame_pc(CPU_Exception_frame* frame);
+
+/**
+ * Return the thread's stack pointer (SP).
+ */
+extern DB_UINT rtems_debugger_target_reg_sp(rtems_debugger_thread* thread);
+
+/**
+ * Return the thread's TCB stack pointer (SP).
+ */
+extern DB_UINT rtems_debugger_target_tcb_sp(rtems_debugger_thread* thread);
+
+/**
+ * The thread is stepping. Setup the thread to step an instruction.
+ */
+extern int rtems_debugger_target_thread_stepping(rtems_debugger_thread* thread);
+
+/**
+ * Return the signal for the exception.
+ */
+extern int rtems_debugger_target_exception_to_signal(CPU_Exception_frame* frame);
+
+/**
+ * Software breakpoints. These are also referred to as memory breakpoints.
+ */
+extern int rtems_debugger_target_swbreak_control(bool    insert,
+                                                 DB_UINT addr,
+                                                 DB_UINT kind);
+
+/**
+ * Insert software breakpoints into the memory.
+ */
+extern int rtems_debugger_target_swbreak_insert(void);
+
+/**
+ * Remove software breakpoints from the memory.
+ */
+extern int rtems_debugger_target_swbreak_remove(void);
+
+/**
+ * Hardware breakpoints.
+ */
+extern int rtems_debugger_target_hwbreak_control(rtems_debugger_target_watchpoint type,
+                                                 bool                             insert,
+                                                 DB_UINT                          addr,
+                                                 DB_UINT                          kind);
+
+/**
+ * Target exception processor.
+ */
+extern rtems_debugger_target_exc_action
+rtems_debugger_target_exception(CPU_Exception_frame* frame);
+
+/**
+ * Set the thread's exception stack frame pointer.
+ */
+extern int rtems_debugger_target_set_exception_frame(rtems_debugger_thread* thread);
+
+/**
+ * Target instruction cache sync. This depends on the target but it normally
+ * means a data cache flush and an instruction cache invalidate.
+ */
+extern int rtems_debugger_target_cache_sync(rtems_debugger_target_swbreak* swbreak);
+
+/**
+ * Start a target memory access. If 0 is return the access can proceed and if
+ * -1 is return the access has failed.
+ */
+extern int rtems_debugger_target_start_memory_access(void);
+
+/**
+ * End a target memory access.
+ */
+extern void rtems_debugger_target_end_memory_access(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif
diff --git a/cpukit/libdebugger/rtems-debugger-threads.c b/cpukit/libdebugger/rtems-debugger-threads.c
new file mode 100644
index 0000000..89c1b9e
--- /dev/null
+++ b/cpukit/libdebugger/rtems-debugger-threads.c
@@ -0,0 +1,577 @@
+/*
+ * 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <rtems.h>
+#include <rtems/score/statesimpl.h>
+#include <rtems/score/threadimpl.h>
+
+#include <rtems/debugger/rtems-debugger-server.h>
+
+#include "rtems-debugger-target.h"
+#include "rtems-debugger-threads.h"
+
+static const char const* excludes_defaults[] =
+{
+  "TIME",
+  "_BSD",
+  "IRQS",
+  "DBSs",
+  "DBSe",
+};
+
+static void
+rtems_debugger_thread_free(rtems_debugger_threads* threads)
+{
+  rtems_debugger_block_destroy(&threads->current);
+  rtems_debugger_block_destroy(&threads->registers);
+  rtems_debugger_block_destroy(&threads->excludes);
+  rtems_debugger_block_destroy(&threads->stopped);
+  rtems_debugger_block_destroy(&threads->steppers);
+  threads->next = 0;
+}
+
+int
+rtems_debugger_thread_create(void)
+{
+  rtems_debugger_threads* threads;
+  int                     r;
+
+  threads = calloc(1, sizeof(rtems_debugger_threads));
+  if (threads == NULL) {
+    errno = ENOMEM;
+    rtems_debugger_printf("error: rtems-db: thread: threads alloc: (%d) %s\n",
+                          errno, strerror(errno));
+    return -1;
+  }
+
+  r = rtems_debugger_block_create(&threads->current,
+                                  RTEMS_DEBUGGER_THREAD_BLOCK_SIZE,
+                                  sizeof(rtems_debugger_thread));
+  if (r < 0) {
+    rtems_debugger_thread_free(threads);
+    free(threads);
+    rtems_debugger_printf("error: rtems-db: thread: current alloc: (%d) %s\n",
+                          errno, strerror(errno));
+    return -1;
+  }
+
+  r = rtems_debugger_block_create(&threads->registers,
+                                  RTEMS_DEBUGGER_THREAD_BLOCK_SIZE,
+                                  rtems_debugger_target_reg_size());
+  if (r < 0) {
+    rtems_debugger_thread_free(threads);
+    free(threads);
+    rtems_debugger_printf("error: rtems-db: thread: registers alloc: (%d) %s\n",
+                          errno, strerror(errno));
+    return -1;
+  }
+
+  r = rtems_debugger_block_create(&threads->excludes,
+                                  RTEMS_DEBUGGER_THREAD_BLOCK_SIZE,
+                                  sizeof(rtems_id));
+  if (r < 0) {
+    rtems_debugger_thread_free(threads);
+    free(threads);
+    rtems_debugger_printf("error: rtems-db: thread: exlcudes alloc: (%d) %s\n",
+                          errno, strerror(errno));
+    return -1;
+  }
+
+  r = rtems_debugger_block_create(&threads->stopped,
+                                  RTEMS_DEBUGGER_THREAD_BLOCK_SIZE,
+                                  sizeof(rtems_id));
+  if (r < 0) {
+    rtems_debugger_thread_free(threads);
+    free(threads);
+    rtems_debugger_printf("error: rtems-db: thread: stopped alloc: (%d) %s\n",
+                          errno, strerror(errno));
+    return -1;
+  }
+
+  r = rtems_debugger_block_create(&threads->steppers,
+                                  RTEMS_DEBUGGER_THREAD_BLOCK_SIZE,
+                                  sizeof(rtems_debugger_thread_stepper));
+  if (r < 0) {
+    rtems_debugger_thread_free(threads);
+    free(threads);
+    rtems_debugger_printf("error: rtems-db: thread: steppers alloc: (%d) %s\n",
+                          errno, strerror(errno));
+    return -1;
+  }
+
+  rtems_debugger->threads = threads;
+
+  return rtems_debugger_thread_system_suspend();
+}
+
+int
+rtems_debugger_thread_destroy(void)
+{
+  rtems_debugger_threads* threads = rtems_debugger->threads;
+  rtems_debugger_thread_system_resume(true);
+  rtems_debugger_thread_free(threads);
+  free(threads);
+  rtems_debugger->threads = NULL;
+  return 0;
+}
+
+int
+rtems_debugger_thread_find_index(rtems_id id)
+{
+  rtems_debugger_threads* threads = rtems_debugger->threads;
+  rtems_debugger_thread*  current = rtems_debugger_thread_current(threads);
+  int                     r = -1;
+  if (threads != NULL) {
+    size_t i;
+    for (i = 0; i < threads->current.level; ++i) {
+      if (id == 0 || current[i].id == id) {
+        r = i;
+        break;
+      }
+    }
+  }
+  return r;
+}
+
+static bool
+snapshot_thread(rtems_tcb* tcb, void* arg)
+{
+  rtems_debugger_threads* threads = rtems_debugger->threads;
+  rtems_id                id = tcb->Object.id;
+  char                    name[RTEMS_DEBUGGER_THREAD_NAME_SIZE];
+  bool                    exclude = false;
+  size_t                  i;
+
+  /*
+   * The only time the threads pointer is NULL is a realloc error so we stop
+   * processing threads. There is no way to stop the iterator.
+   */
+  if (rtems_debugger_thread_current(threads) == NULL)
+    return true;
+
+  /*
+   * Filter the threads.
+   */
+  switch (rtems_object_id_get_api(id)) {
+  case OBJECTS_NO_API:
+  case OBJECTS_INTERNAL_API:
+    exclude = true;
+    break;
+  default:
+    rtems_object_get_name(id, sizeof(name), (char*) &name[0]);
+    for (i = 0; i < RTEMS_DEBUGGER_NUMOF(excludes_defaults); ++i) {
+      if (strcmp(excludes_defaults[i], name) == 0) {
+        exclude = true;
+        break;
+      }
+    }
+    break;
+  }
+
+  if (exclude) {
+    rtems_id* excludes;
+    int       r;
+    r = rtems_debugger_block_resize(&threads->excludes);
+    if (r < 0) {
+      rtems_debugger_thread_free(threads);
+      return true;
+    }
+    excludes = rtems_debugger_thread_excludes(threads);
+    excludes[threads->excludes.level++] = id;
+  }
+  else {
+    rtems_debugger_thread* current;
+    DB_UINT*               registers;
+    rtems_debugger_thread* thread;
+    int                    r;
+
+    r = rtems_debugger_block_resize(&threads->current);
+    if (r < 0) {
+      rtems_debugger_thread_free(threads);
+      return true;
+    }
+    r = rtems_debugger_block_resize(&threads->registers);
+    if (r < 0) {
+      rtems_debugger_thread_free(threads);
+      return true;
+    }
+
+    current = rtems_debugger_thread_current(threads);
+    registers = rtems_debugger_thread_registers(threads);
+
+    thread = &current[threads->current.level++];
+    thread->registers =
+        &registers[threads->registers.level++ * rtems_debugger_target_reg_num()];
+
+    thread->tcb    = tcb;
+    thread->id     = id;
+    thread->flags  = 0;
+    thread->signal = 0;
+    thread->frame  = NULL;
+    memcpy((void*) &thread->name[0], &name[0], sizeof(thread->name));
+
+    /*
+     * 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);
+
+    /*
+     * Debugger threads are stopped for breakpoint, segv or other errors have
+     * the RTEMS_DEBUGGER_THREAD_FLAG_DEBUGGING set.
+     */
+    if (rtems_debugger_thread_flag(thread,
+                                   RTEMS_DEBUGGER_THREAD_FLAG_DEBUGGING)) {
+      rtems_id* stopped;
+      r = rtems_debugger_block_resize(&threads->stopped);
+      if (r < 0) {
+        rtems_debugger_thread_free(threads);
+        return true;
+      }
+      stopped = rtems_debugger_thread_stopped(threads);
+      stopped[threads->stopped.level++] = id;
+    }
+    else {
+      rtems_status_code sc;
+      sc = rtems_task_suspend(id);
+      if (sc != RTEMS_SUCCESSFUL && sc != RTEMS_ALREADY_SUSPENDED) {
+        rtems_debugger_printf("error: rtems-db: thread: suspend: %08lx: %s\n",
+                              id, rtems_status_text(sc));
+        r = -1;
+      }
+    }
+
+    if (rtems_debugger_server_flag(RTEMS_DEBUGGER_FLAG_VERBOSE))
+      rtems_debugger_printf("rtems-db: sys: thd: %08lx: signal: %d\n",
+                            id, thread->signal);
+
+    /*
+     * Pick up the first non-zero signal.
+     */
+    if (rtems_debugger->signal == 0) {
+      rtems_debugger->signal = thread->signal;
+    }
+  }
+
+  return false;
+}
+
+int
+rtems_debugger_thread_system_suspend(void)
+{
+  rtems_debugger_threads* threads = rtems_debugger->threads;
+  int                     r = -1;
+  if (threads != NULL && rtems_debugger_thread_current(threads) != NULL) {
+    if (rtems_debugger_verbose())
+      rtems_debugger_printf("rtems-db: sys:    : suspending\n");
+    r = rtems_debugger_target_swbreak_remove();
+    if (r == 0) {
+      rtems_debugger_thread* current;
+      threads->current.level = 0;
+      threads->registers.level = 0;
+      threads->stopped.level = 0;
+      threads->excludes.level = 0;
+      threads->steppers.level = 0;
+      rtems_task_iterate(snapshot_thread, NULL);
+      current = rtems_debugger_thread_current(threads);
+      if (current == NULL) {
+        rtems_debugger_printf("error: rtems-db: thread: snapshot: (%d) %s\n",
+                              errno, strerror(errno));
+        r = -1;
+      }
+      else {
+        rtems_id* stopped;
+        /*
+         * If there are no stopped threads pick the first one in the current
+         * table and return that.
+         */
+        threads->selector_gen = 0;
+        threads->selector_cont = 0;
+        stopped = rtems_debugger_thread_stopped(threads);
+        if (threads->stopped.level == 0 && threads->current.level > 0) {
+          stopped[threads->stopped.level++] = current[0].id;
+        }
+        if (threads->stopped.level > 0) {
+          threads->selector_gen =
+            rtems_debugger_thread_find_index(stopped[0]);
+          if (threads->selector_gen < 0)
+            threads->selector_gen = 0;
+        }
+      }
+    }
+    else {
+      errno = EIO;
+    }
+  }
+  return r;
+}
+
+int
+rtems_debugger_thread_system_resume(bool detaching)
+{
+  rtems_debugger_threads* threads = rtems_debugger->threads;
+  rtems_debugger_thread*  current;
+  int                     r = 0;
+  current = rtems_debugger_thread_current(threads);
+  if (threads != NULL && current != NULL) {
+    size_t i;
+    if (rtems_debugger_verbose())
+      rtems_debugger_printf("rtems-db: sys:    : resuming\n");
+    if (!detaching)
+      r = rtems_debugger_target_swbreak_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.
+         */
+        if (detaching ||
+            rtems_debugger_thread_flag(thread,
+                                       RTEMS_DEBUGGER_THREAD_FLAG_RESUME)) {
+          if (!detaching) {
+            rr = rtems_debugger_target_write_regs(thread);
+            if (rr < 0 && r == 0)
+              r = rr;
+            if (rtems_debugger_thread_flag(thread,
+                                           RTEMS_DEBUGGER_THREAD_FLAG_STEP_INSTR)) {
+              rr = rtems_debugger_target_thread_stepping(thread);
+              if (rr < 0 && r == 0)
+                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));
+          }
+          thread->flags &= ~(RTEMS_DEBUGGER_THREAD_FLAG_CONTINUE |
+                             RTEMS_DEBUGGER_THREAD_FLAG_STEP);
+          thread->signal = 0;
+        }
+      }
+      /*
+       * Excludes are not cleared so the exception handler can find the
+       * excluded thread.
+       */
+      threads->current.level = 0;
+      threads->registers.level = 0;
+      threads->stopped.level = 0;
+    }
+    else {
+      r = -1;
+      errno = EIO;
+    }
+  }
+  return r;
+}
+
+int
+rtems_debugger_thread_continue(rtems_debugger_thread* thread)
+{
+  thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_CONTINUE;
+  return 0;
+}
+
+int
+rtems_debugger_thread_continue_all(void)
+{
+  rtems_debugger_threads* threads = rtems_debugger->threads;
+  rtems_debugger_thread*  current;
+  int                     r = 0;
+  current = rtems_debugger_thread_current(threads);
+  if (threads != NULL && current != NULL) {
+    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;
+    }
+  }
+  else {
+    r = -1;
+    errno = EIO;
+  }
+  return r;
+}
+
+int
+rtems_debugger_thread_step(rtems_debugger_thread* thread)
+{
+  thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_STEP;
+  return 0;
+}
+
+int
+rtems_debugger_thread_stepping(rtems_debugger_thread* thread,
+                               DB_UINT                start,
+                               DB_UINT                end)
+{
+  /* add lock */
+  rtems_debugger_threads*        threads = rtems_debugger->threads;
+  rtems_debugger_thread_stepper* stepper;
+  int                            r;
+  /*
+   * The resize will automatically extend the block when we are full. The
+   * steppers are cleared in suspend by setting the level to 0.
+   */
+  r = rtems_debugger_block_resize(&threads->steppers);
+  if (r < 0) {
+    rtems_debugger_thread_free(threads);
+    return -1;
+  }
+  stepper = rtems_debugger_thread_steppers(threads);
+  stepper = &stepper[threads->steppers.level];
+  stepper->thread = thread;
+  stepper->start = start;
+  stepper->end = end;
+  threads->steppers.level++;
+  thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_STEPPING;
+  return 0;
+}
+
+const rtems_debugger_thread_stepper*
+rtems_debugger_thread_is_stepping(rtems_id id, DB_UINT pc)
+{
+  /* add lock */
+  rtems_debugger_threads*        threads = rtems_debugger->threads;
+  rtems_debugger_thread_stepper* stepper;
+  size_t                         i;
+  stepper = rtems_debugger_thread_steppers(threads);
+  for (i = 0; i < threads->steppers.level; ++i, ++stepper) {
+    if (stepper->thread->id == id) {
+      if (pc == stepper->start || (pc > stepper->start && pc < stepper->end))
+        return stepper;
+      break;
+    }
+  }
+  return NULL;
+}
+
+int
+rtems_debugger_thread_current_priority(rtems_debugger_thread* thread)
+{
+  return _Thread_Get_priority(thread->tcb);
+}
+
+int
+rtems_debugger_thread_real_priority(rtems_debugger_thread* thread)
+{
+  return thread->tcb->Real_priority.priority;
+}
+
+int
+rtems_debugger_thread_state(rtems_debugger_thread* thread)
+{
+  return thread->tcb->current_state;
+}
+
+int
+rtems_debugger_thread_state_str(rtems_debugger_thread* thread,
+                                char*                  buffer,
+                                size_t                 size)
+{
+  struct mapper {
+    const char const* label;
+    DB_UINT           mask;
+  };
+  const struct mapper map[] = {
+    { "DELAY",  STATES_DELAYING },
+    { "DORM",   STATES_DORMANT },
+    { "LIFE",   STATES_LIFE_IS_CHANGING },
+    { "SUSP",   STATES_SUSPENDED },
+    { "Wbar",   STATES_WAITING_FOR_BARRIER },
+    { "Wbuf",   STATES_WAITING_FOR_BUFFER },
+    { "Wcvar",  STATES_WAITING_FOR_CONDITION_VARIABLE },
+    { "Wevnt",  STATES_WAITING_FOR_EVENT },
+    { "Wisig",  STATES_INTERRUPTIBLE_BY_SIGNAL },
+    { "Wjatx",  STATES_WAITING_FOR_JOIN_AT_EXIT },
+    { "Wjoin",  STATES_WAITING_FOR_JOIN },
+    { "Wmsg" ,  STATES_WAITING_FOR_MESSAGE },
+    { "Wmutex", STATES_WAITING_FOR_MUTEX },
+    { "WRATE",  STATES_WAITING_FOR_PERIOD },
+    { "Wrpc",   STATES_WAITING_FOR_RPC_REPLY },
+    { "Wrwlk",  STATES_WAITING_FOR_RWLOCK },
+    { "Wseg",   STATES_WAITING_FOR_SEGMENT },
+    { "Wsem",   STATES_WAITING_FOR_SEMAPHORE },
+    { "Wsig",   STATES_WAITING_FOR_SIGNAL },
+    { "Wslcnd", STATES_WAITING_FOR_SYS_LOCK_CONDITION },
+    { "Wslftx", STATES_WAITING_FOR_SYS_LOCK_FUTEX },
+    { "Wslmtx", STATES_WAITING_FOR_SYS_LOCK_MUTEX },
+    { "Wslsem", STATES_WAITING_FOR_SYS_LOCK_SEMAPHORE },
+    { "Wsysev", STATES_WAITING_FOR_SYSTEM_EVENT },
+    { "Wtime",  STATES_WAITING_FOR_TIME },
+    { "Wwkup",  STATES_WAITING_FOR_BSD_WAKEUP },
+    { "ZOMBI",  STATES_ZOMBIE },
+  };
+  DB_UINT state = thread->tcb->current_state;
+  if (state == STATES_READY) {
+    strcpy(buffer, "READY");
+  }
+  else {
+    char*  start = buffer;
+    size_t i;
+    buffer[0] = '\0';
+    buffer[size - 1] = '\0';
+    for (i = 0; size > 0 && i < RTEMS_DEBUGGER_NUMOF(map); ++i) {
+      if ((map[i].mask & state) != 0) {
+        size_t l = snprintf(buffer, size - 1, "%s ", map[i].label);
+        buffer += l;
+        size -= l;
+      }
+    }
+    if (buffer != start)
+      *(buffer - 1) = '\0';
+  }
+  return 0;
+}
+
+unsigned long
+rtems_debugger_thread_stack_size(rtems_debugger_thread* thread)
+{
+  return thread->tcb->Start.Initial_stack.size;
+}
+
+void*
+rtems_debugger_thread_stack_area(rtems_debugger_thread* thread)
+{
+  return thread->tcb->Start.Initial_stack.area;
+}
diff --git a/cpukit/libdebugger/rtems-debugger-threads.h b/cpukit/libdebugger/rtems-debugger-threads.h
new file mode 100644
index 0000000..563b402
--- /dev/null
+++ b/cpukit/libdebugger/rtems-debugger-threads.h
@@ -0,0 +1,272 @@
+/*
+ * 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Debugger for RTEMS.
+ */
+
+#ifndef _RTEMS_DEBUGGER_THREADS_h
+#define _RTEMS_DEBUGGER_THREADS_h
+
+#include <rtems/debugger/rtems-debugger-server.h>
+
+#include "rtems-debugger-block.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * Debugger thread name size, fixed size. ASCIIZ format.
+ */
+#define RTEMS_DEBUGGER_THREAD_NAME_SIZE (5)
+
+/**
+ * Debugger thread allocation block size.
+ */
+#define RTEMS_DEBUGGER_THREAD_BLOCK_SIZE (32)
+
+/**
+ * Debugger thread flags.
+ */
+#define RTEMS_DEBUGGER_THREAD_FLAG_DEBUGGING      (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)
+#define RTEMS_DEBUGGER_THREAD_FLAG_STEP           (1 << 4)
+#define RTEMS_DEBUGGER_THREAD_FLAG_STEPPING       (1 << 5)
+#define RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED  (1 << 6)
+/* Target specific flags for use by the target backend. */
+#define RTEMS_DEBUGGER_THREAD_FLAG_TARGET_BASE    (24)
+#define RTEMS_DEBUGGER_THREAD_FLAG_TARGET_MASK    (0xff << RTEMS_DEBUGGER_THREAD_FLAG_TARGET_BASE)
+
+/**
+ * Resume this thread.
+ */
+#define RTEMS_DEBUGGER_THREAD_FLAG_RESUME \
+  (RTEMS_DEBUGGER_THREAD_FLAG_CONTINUE | \
+   RTEMS_DEBUGGER_THREAD_FLAG_STEP | \
+   RTEMS_DEBUGGER_THREAD_FLAG_STEPPING)
+
+/**
+ * Step an instruction.
+ */
+#define RTEMS_DEBUGGER_THREAD_FLAG_STEP_INSTR \
+  (RTEMS_DEBUGGER_THREAD_FLAG_STEP | \
+   RTEMS_DEBUGGER_THREAD_FLAG_STEPPING)
+
+/**
+ * Debugger thread.
+ */
+typedef struct rtems_debugger_thread
+{
+  uint32_t        flags;
+  const char      name[RTEMS_DEBUGGER_THREAD_NAME_SIZE];
+  Thread_Control* tcb;
+  rtems_id        id;
+  int             cpu;
+  DB_UINT*        registers;
+  int             signal;
+  void*           frame;
+} rtems_debugger_thread;
+
+/**
+ * Debugger stepping thread. This is a thread that steps while inside an
+ * address range.
+ */
+typedef struct rtems_debugger_thread_stepper
+{
+  rtems_debugger_thread* thread;
+  DB_UINT                start;
+  DB_UINT                end;
+} rtems_debugger_thread_stepper;
+
+/**
+ * Debugger thread control.
+ */
+struct rtems_debugger_threads
+{
+  rtems_debugger_block current;       /**< The threads currently available. */
+  rtems_debugger_block registers;     /**< The threads that have stopped. */
+  rtems_debugger_block excludes;      /**< The threads we cannot touch. */
+  rtems_debugger_block stopped;       /**< The threads that have stopped. */
+  rtems_debugger_block steppers;      /**< The threads that are stepping. */
+  size_t               next;          /**< An iterator. */
+  int                  selector_gen;  /**< General thread selector. */
+  int                  selector_cont; /**< Continue thread selector. */
+};
+
+/**
+ * Create the thread support.
+ */
+extern int rtems_debugger_thread_create(void);
+
+/**
+ * Destroy the thread support.
+ */
+extern int rtems_debugger_thread_destroy(void);
+
+/**
+ * Find the index in the thread table for the ID.
+ */
+extern int rtems_debugger_thread_find_index(rtems_id id);
+
+/**
+ * Suspend the system.
+ */
+extern int rtems_debugger_thread_system_suspend(void);
+
+/**
+ * Resume the system.
+ */
+extern int rtems_debugger_thread_system_resume(bool detaching);
+
+/**
+ * Continue all threads.
+ */
+extern int rtems_debugger_thread_continue_all(void);
+
+/**
+ * Continue a thread.
+ */
+extern int rtems_debugger_thread_continue(rtems_debugger_thread* thread);
+
+/**
+ * Step a thread.
+ */
+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);
+
+/**
+ * Thread's PC in the stepping range? Returns the stepper is in range else
+ * NULL.
+ */
+extern const rtems_debugger_thread_stepper*
+rtems_debugger_thread_is_stepping(rtems_id id, DB_UINT pc);
+
+/**
+ * Return the thread's current priority/
+ */
+extern int rtems_debugger_thread_current_priority(rtems_debugger_thread* thread);
+
+/**
+ * Return the thread's real priority.
+ */
+extern int rtems_debugger_thread_real_priority(rtems_debugger_thread* thread);
+
+/**
+ * Return the thread's state.
+ */
+extern int rtems_debugger_thread_state(rtems_debugger_thread* thread);
+
+/**
+ * Return the thread's state.
+ */
+//extern bool rtems_debugger_thread_state_debugger(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);
+
+/**
+ * Return the thread's stack size.
+ */
+extern unsigned long rtems_debugger_thread_stack_size(rtems_debugger_thread* thread);
+
+/**
+ * Return the thread's stack area address.
+ */
+extern void* rtems_debugger_thread_stack_area(rtems_debugger_thread* thread);
+
+/**
+ * Check a thread's flag and return true if any of the bits in the mask are
+ * set.
+ */
+static inline bool
+rtems_debugger_thread_flag(rtems_debugger_thread* thread,
+			   uint32_t               mask)
+{
+  return (thread->flags & mask) != 0;
+}
+
+/**
+ * Get the current threads.
+ */
+static inline rtems_debugger_thread*
+rtems_debugger_thread_current(rtems_debugger_threads* threads)
+{
+  return threads->current.block;
+}
+
+/**
+ * Get the registers.
+ */
+static inline DB_UINT*
+rtems_debugger_thread_registers(rtems_debugger_threads* threads)
+{
+  return threads->registers.block;
+}
+
+/**
+ * Get the excludes.
+ */
+static inline rtems_id*
+rtems_debugger_thread_excludes(rtems_debugger_threads* threads)
+{
+  return threads->excludes.block;
+}
+
+/**
+ * Get the stopped.
+ */
+static inline rtems_id*
+rtems_debugger_thread_stopped(rtems_debugger_threads* threads)
+{
+  return threads->stopped.block;
+}
+
+/**
+ * Get the steppers.
+ */
+static inline rtems_debugger_thread_stepper*
+rtems_debugger_thread_steppers(rtems_debugger_threads* threads)
+{
+  return threads->steppers.block;
+}
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
diff --git a/cpukit/libdebugger/rtems-debugger.h b/cpukit/libdebugger/rtems-debugger.h
new file mode 100644
index 0000000..1fc8b3d
--- /dev/null
+++ b/cpukit/libdebugger/rtems-debugger.h
@@ -0,0 +1,81 @@
+/*
+ * 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Debugger for RTEMS.
+ */
+
+#ifndef _RTEMS_DEBUGGER_h
+#define _RTEMS_DEBUGGER_h
+
+#include <stdbool.h>
+
+#include <rtems.h>
+#include <rtems/printer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * Timeout period for an ack
+ */
+#define RTEMS_DEBUGGER_TIMEOUT (3)
+
+/**
+ * Start the Debugger.
+ */
+extern int rtems_debugger_start(const char*          remote,
+                                const char*          device,
+                                int                  timeout,
+                                rtems_task_priority  priority,
+                                const rtems_printer* printer);
+
+/**
+ * Stop the Debugger.
+ */
+extern int rtems_debugger_stop(void);
+
+/**
+ * Is the Debugger running?.
+ */
+extern bool rtems_debugger_running(void);
+
+/**
+ * Verbose control.
+ */
+extern void rtems_debugger_set_verbose(bool on);
+
+/**
+ * Control remote debug printing.
+ */
+extern int rtems_debugger_remote_debug(bool state);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif
diff --git a/cpukit/preinstall.am b/cpukit/preinstall.am
index 9514390..f4b6529 100644
--- a/cpukit/preinstall.am
+++ b/cpukit/preinstall.am
@@ -233,6 +233,24 @@ $(PROJECT_INCLUDE)/rtems/rtl/rap-shell.h: libdl/rap-shell.h $(PROJECT_INCLUDE)/r
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtl/rap-shell.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtl/rap-shell.h
 endif
+if LIBDEBUGGER
+$(PROJECT_INCLUDE)/rtems/rtems-debugger.h: libdebugger/rtems-debugger.h $(PROJECT_INCLUDE)/rtems/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtems-debugger.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtems-debugger.h
+
+$(PROJECT_INCLUDE)/rtems/debugger/$(dirstamp):
+	@$(MKDIR_P) $(PROJECT_INCLUDE)/rtems/debugger
+	@: > $(PROJECT_INCLUDE)/rtems/debugger/$(dirstamp)
+PREINSTALL_DIRS += $(PROJECT_INCLUDE)/rtems/debugger/$(dirstamp)
+
+$(PROJECT_INCLUDE)/rtems/debugger/rtems-debugger-server.h: libdebugger/rtems-debugger-server.h $(PROJECT_INCLUDE)/rtems/debugger/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/debugger/rtems-debugger-server.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/debugger/rtems-debugger-server.h
+
+$(PROJECT_INCLUDE)/rtems/debugger/rtems-debugger-remote.h: libdebugger/rtems-debugger-remote.h $(PROJECT_INCLUDE)/rtems/debugger/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/debugger/rtems-debugger-remote.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/debugger/rtems-debugger-remote.h
+endif
 $(PROJECT_INCLUDE)/rtems/bspIo.h: include/rtems/bspIo.h $(PROJECT_INCLUDE)/rtems/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/bspIo.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/bspIo.h
diff --git a/cpukit/wrapup/Makefile.am b/cpukit/wrapup/Makefile.am
index 768a903..47ffd24 100644
--- a/cpukit/wrapup/Makefile.am
+++ b/cpukit/wrapup/Makefile.am
@@ -95,6 +95,10 @@ if LIBDL
 TMP_LIBS += ../libdl/libdl.a
 endif
 
+if LIBDEBUGGER
+TMP_LIBS += ../libdebugger/libdebugger.a
+endif
+
 librtemscpu.a: $(TMP_LIBS)
 	rm -f $@
 	$(MKDIR_P) $(ARCH)
diff --git a/testsuites/libtests/Makefile.am b/testsuites/libtests/Makefile.am
index c00916a..9ff4394 100644
--- a/testsuites/libtests/Makefile.am
+++ b/testsuites/libtests/Makefile.am
@@ -53,5 +53,9 @@ _SUBDIRS += dl04 dl05
 endif
 endif
 
+if DEBUGGERTESTS
+_SUBDIRS += debugger01
+endif
+
 include $(top_srcdir)/../automake/test-subdirs.am
 include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/libtests/configure.ac b/testsuites/libtests/configure.ac
index 430c509..8e74b3e 100644
--- a/testsuites/libtests/configure.ac
+++ b/testsuites/libtests/configure.ac
@@ -80,6 +80,17 @@ AS_IF([test x"$TEST_LIBDL" = x"yes"],[
 
 AM_CONDITIONAL(DLTESTS,[test x"$TEST_LIBDL" = x"yes"])
 
+# Must match the list in cpukit.
+AC_MSG_CHECKING([whether CPU supports libdebugger])
+case $RTEMS_CPU in
+  arm | i386)
+   TEST_LIBDEBUGGER=yes ;;
+  *)
+   TEST_LIBDEBUGGER=no ;;
+esac
+AC_MSG_RESULT([$TEST_LIBDEBUGGER])
+AM_CONDITIONAL(DEBUGGERTESTS,[test x"$TEST_LIBDEBUGGER" = x"yes"])
+
 # Explicitly list all Makefiles here
 AC_CONFIG_FILES([Makefile
 networking01/Makefile
@@ -169,5 +180,6 @@ math/Makefile
 mathf/Makefile
 mathl/Makefile
 complex/Makefile
+debugger01/Makefile
 ])
 AC_OUTPUT
diff --git a/testsuites/libtests/debugger01/Makefile.am b/testsuites/libtests/debugger01/Makefile.am
new file mode 100644
index 0000000..d0bf0f8
--- /dev/null
+++ b/testsuites/libtests/debugger01/Makefile.am
@@ -0,0 +1,21 @@
+
+rtems_tests_PROGRAMS = debugger01
+debugger01_SOURCES = init.c remote.c system.h
+
+dist_rtems_tests_DATA = debugger01.scn
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP at .cfg
+include $(top_srcdir)/../automake/compile.am
+include $(top_srcdir)/../automake/leaf.am
+
+
+AM_CPPFLAGS += -I$(top_srcdir)/../support/include
+
+LINK_OBJS = $(debugger01_OBJECTS)
+LINK_LIBS = $(debugger01_LDLIBS)
+
+debugger01$(EXEEXT): $(debugger01_OBJECTS) $(debugger01_DEPENDENCIES)
+	@rm -f debugger01$(EXEEXT)
+	$(make-exe)
+
+include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/libtests/debugger01/debugger01.doc b/testsuites/libtests/debugger01/debugger01.doc
new file mode 100644
index 0000000..2cdd48b
--- /dev/null
+++ b/testsuites/libtests/debugger01/debugger01.doc
@@ -0,0 +1,18 @@
+# Copyright (c) 2016 Chris Johns <chrisj at rtems.org>
+#
+# The license and distribution terms for this file may be
+# found in the file LICENSE in this distribution or at
+# http://www.rtems.org/license/LICENSE.
+#
+
+This file describes the directives and concepts tested by this test set.
+
+test set name: debugger01
+
+directives:
+
+  rtems_debugger_start
+
+concepts:
+
++ Starts a debugging session with the test remote backend.
diff --git a/testsuites/libtests/debugger01/debugger01.scn b/testsuites/libtests/debugger01/debugger01.scn
new file mode 100644
index 0000000..7d221fd
--- /dev/null
+++ b/testsuites/libtests/debugger01/debugger01.scn
@@ -0,0 +1,188 @@
+
+*** BEGIN OF TEST DEBUGGER01 ***
+error: rtems-db: remote not found: test
+error: rtems-db: test remote: begin
+rtems-db: remote-debug is on
+rtems-db: remote running
+rtems-db: test remote: isconnected: not-connected
+error: rtems-db: test remote: connect
+rtems-db: remote running
+rtems-db: arm debug: (v3.0) ARMv7 [v7, all CP14 registers] breakpoints:5
+watchpoints:3
+rtems-db: sys:    : suspending
+rtems-db: sys: thd: 0a010001: signal: 0
+rtems-db: test remote: isconnected: connected
+ remote: rx: message=0 length=1
+ remote: rx: +
+rtems-db: get:   1: + [[ACK?]]
+ remote: rx: message=1 length=5
+ remote: rx: xxxxx
+ remote: rx: message=2 length=5
+ remote: rx: $x#aa
+rtems-db: get:   5: xxxxx [[junk dropped]]
+rtems-db: get:   : $x#aa [[invalid checksum]]
+rtems-db: put:   1: -
+ remote: tx: message=0 length=1
+ remote: tx: -
+ remote: rx: message=3 length=141
+ remote: rx: $qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+#df
+rtems-db: get: 141:  [[junk dropped]]
+rtems-db: get:   : $qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+#df
+rtems-db: put:   1: +
+ remote: tx: message=1 length=1
+ remote: tx: +
+rtems-db: put: 167: $qSupported:PacketSize=4096;QNonStop-;multiprocess+;swbreak+;hwbreak-;qRelocInsn-;fork-events-;vfork-events-;exec-events-;vContSupported+;QThreadEvents-;no-resumed+#b3
+ remote: tx: message=2 length=167
+ remote: tx: $qSupported:PacketSize=4096;QNonStop-;multiprocess+;swbreak+;hwbreak-;qRelocInsn-;fork-events-;vfork-events-;exec-events-;vContSupported+;QThreadEvents-;no-resumed+#b3
+rtems-db: test remote: isconnected: connected
+ remote: rx: message=4 length=19
+ remote: rx: $vMustReplyEmpty#3a
+rtems-db: get:  19: $vMustReplyEmpty#3a
+rtems-db: put:   1: +
+ remote: tx: message=3 length=1
+ remote: tx: +
+rtems-db: put:   4: $#00
+ remote: tx: message=4 length=4
+ remote: tx: $#00
+rtems-db: test remote: isconnected: connected
+ remote: rx: message=5 length=1
+ remote: rx: +
+rtems-db: get:   1: + [[ACK]]
+ remote: rx: message=6 length=10
+ remote: rx: $Hgp0.0#ad
+rtems-db: get:  10: $Hgp0.0#ad
+rtems-db: put:   1: +
+ remote: tx: message=5 length=1
+ remote: tx: +
+rtems-db: put:   6: $OK#9a
+ remote: tx: message=6 length=6
+ remote: tx: $OK#9a
+rtems-db: test remote: isconnected: connected
+ remote: rx: message=7 length=1
+ remote: rx: +
+rtems-db: get:   1: + [[ACK]]
+ remote: rx: message=8 length=12
+ remote: rx: $qTStatus#49
+rtems-db: get:  12: $qTStatus#49
+rtems-db: put:   1: +
+ remote: tx: message=7 length=1
+ remote: tx: +
+rtems-db: put:   4: $#00
+ remote: tx: message=8 length=4
+ remote: tx: $#00
+rtems-db: test remote: isconnected: connected
+ remote: rx: message=9 length=1
+ remote: rx: +
+rtems-db: get:   1: + [[ACK]]
+ remote: rx: message=10 length=5
+ remote: rx: $?#3f
+rtems-db: get:   5: $?#3f
+rtems-db: put:   1: +
+ remote: tx: message=9 length=1
+ remote: tx: +
+rtems-db: put:  26: $T00thread:p1.0a010001;#23
+ remote: tx: message=10 length=26
+ remote: tx: $T00thread:p1.0a010001;#23
+rtems-db: test remote: isconnected: connected
+ remote: rx: message=11 length=1
+ remote: rx: +
+rtems-db: get:   1: + [[ACK]]
+ remote: rx: message=12 length=16
+ remote: rx: $qfThreadInfo#bb
+rtems-db: get:  16: $qfThreadInfo#bb
+rtems-db: put:   1: +
+ remote: tx: message=11 length=1
+ remote: tx: +
+rtems-db: put:  16: $mp1.0a010001#ef
+ remote: tx: message=12 length=2
+ remote: tx: $mp1.0a010001#ef
+rtems-db: test remote: isconnected: connected
+ remote: rx: message=13 length=1
+ remote: rx: +
+rtems-db: get:   1: + [[ACK]]
+ remote: rx: message=14 length=16
+ remote: rx: $qsThreadInfo#c8
+rtems-db: get:  16: $qsThreadInfo#c8
+rtems-db: put:   1: +
+ remote: tx: message=13 length=1
+ remote: tx: +
+rtems-db: put:   5: $l#6c
+ remote: tx: message=14 length=5
+ remote: tx: $l#6c
+rtems-db: test remote: isconnected: connected
+ remote: rx: message=15 length=1
+ remote: rx: -
+rtems-db: get:   1: - [[NACK]]
+rtems-db: put:   5: $l#6c
+ remote: tx: message=15 length=5
+ remote: tx: $l#6c
+ remote: rx: message=16 length=1
+ remote: rx: +
+rtems-db: get:   1: + [[ACK]]
+ remote: rx: message=17 length=15
+ remote: rx: $qAttached:1#fa
+rtems-db: get:  15: $qAttached:1#fa
+rtems-db: put:   1: +
+ remote: tx: message=16 length=1
+ remote: tx: +
+rtems-db: put:   5: $1#31
+ remote: tx: message=17 length=5
+ remote: tx: $1#31
+rtems-db: test remote: isconnected: connected
+ remote: rx: message=18 length=1
+ remote: rx: +
+rtems-db: get:   1: + [[ACK]]
+ remote: rx: message=19 length=8
+ remote: rx: $Hc-1#09
+rtems-db: get:   8: $Hc-1#09
+rtems-db: put:   1: +
+ remote: tx: message=18 length=1
+ remote: tx: +
+rtems-db: put:   6: $OK#9a
+ remote: tx: message=19 length=6
+ remote: tx: $OK#9a
+rtems-db: test remote: isconnected: connected
+ remote: rx: message=20 length=1
+ remote: rx: +
+rtems-db: get:   1: + [[ACK]]
+ remote: rx: message=21 length=12
+ remote: rx: $qOffsets#4b
+rtems-db: get:  12: $qOffsets#4b
+rtems-db: put:   1: +
+ remote: tx: message=20 length=1
+ remote: tx: +
+rtems-db: put:   4: $#00
+ remote: tx: message=21 length=4
+ remote: tx: $#00
+rtems-db: test remote: isconnected: connected
+ remote: rx: message=22 length=1
+ remote: rx: +
+rtems-db: get:   1: + [[ACK]]
+ remote: rx: message=23 length=6
+ remote: rx: $g#67+
+rtems-db: get:   6: $g#67
+rtems-db: put:   1: +
+ remote: tx: message=22 length=1
+ remote: tx: +
++ [[extra data: 0x2b]]rtems-db: put: 212: $cc381200cc381200cc381200cc3812004c162000a83f2000704520004c16200040362000481620000000000020ee1100cc38120028a2200089dc100089dc1000cc381200cc381200cc381200cc381200cc381200cc381200cc381200cc381200cc381200cc381200#95
+ remote: tx: message=23 length=2
+ remote: tx: $cc381200cc381200cc381200cc3812004c162000a83f2000704520004c16200040362000481620000000000020ee1100cc38120028a2200089dc100089dc1000cc381200cc381200cc381200cc381200cc381200cc381200cc381200cc381200cc3812g00cc381200#95
+rtems-db: test remote: isconnected: connected
+ remote: rx: message=24 length=7
+ remote: rx: $D;1#b0
+rtems-db: get:   7: $D;1#b0
+rtems-db: put:   1: +
+ remote: tx: message=24 length=1
+ remote: tx: +
+rtems-db: put:   6: $OK#9a
+ remote: tx: message=25 length=6
+ remote: tx: $OK#9a
+rtems-db: test remote: isconnected: connected
+rtems-db: test remote: disconnect host
+rtems-db: test remote: isconnected: not-connected
+rtems-db: events running
+rtems-db: events finishing
+rtems-db: sys:    : resuming
+rtems-db: test remote: isconnected: not-connected
+rtems-db: test remote: isconnected: not-connected
+*** END OF TEST DEBUGGER01 ***
diff --git a/testsuites/libtests/debugger01/init.c b/testsuites/libtests/debugger01/init.c
new file mode 100644
index 0000000..e243d42
--- /dev/null
+++ b/testsuites/libtests/debugger01/init.c
@@ -0,0 +1,53 @@
+/*
+ *  Debugger test.
+ *
+ *  Copyright (c) 2016 Chris Johns (chrisj at rtems.org)
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define CONFIGURE_INIT
+#include "system.h"
+
+#include "tmacros.h"
+
+#include <rtems/rtems-debugger.h>
+
+#include "system.h"
+
+static void test(void)
+{
+  rtems_printer printer;
+
+  rtems_print_printer_fprintf(&printer, stdout);
+  rtems_test_assert(rtems_debugger_start("test", "something",
+                                         3, 10, &printer) < 0);
+  rtems_test_assert(rtems_debugger_register_test_remote() == 0);
+  rtems_test_assert(rtems_debugger_start("test", "something",
+                                         3, 10, &printer) == 0);
+  rtems_debugger_set_verbose(true);
+  rtems_test_assert(rtems_debugger_remote_debug(true) == 0);
+
+  /*
+   * This thread is suspended when the debugger is active until the debugger
+   * disconnects.
+   */
+  sleep(1);
+}
+
+const char rtems_test_name[] = "DEBUGGER01";
+
+rtems_task Init(rtems_task_argument argument)
+{
+  TEST_BEGIN();
+
+  test();
+
+  TEST_END();
+}
diff --git a/testsuites/libtests/debugger01/remote.c b/testsuites/libtests/debugger01/remote.c
new file mode 100644
index 0000000..1c8c4d0
--- /dev/null
+++ b/testsuites/libtests/debugger01/remote.c
@@ -0,0 +1,321 @@
+/*
+ *  Debugger test remote.
+ *
+ *  Copyright (c) 2016 Chris Johns (chrisj at rtems.org)
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+  #include "config.h"
+#endif
+
+#include "tmacros.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <rtems/rtems-debugger.h>
+#include <rtems/debugger/rtems-debugger-server.h>
+#include <rtems/debugger/rtems-debugger-remote.h>
+
+#include "system.h"
+
+/**
+ * Remote data.
+ */
+typedef struct
+{
+  int    connect_count;
+  bool   connected;
+  size_t out;
+  size_t in;
+} rtems_debugger_remote_test;
+
+static const char* out[] =
+{
+  "+",
+  "xxxxx",
+  "$x#aa",
+
+  "$qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;"
+  "vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+#df",
+
+  "$vMustReplyEmpty#3a",
+  "+",
+
+  "$Hgp0.0#ad",
+  "+",
+
+  "$qTStatus#49",
+  "+",
+
+  "$?#3f",
+  "+",
+
+  "$qfThreadInfo#bb",
+  "+",
+
+  "$qsThreadInfo#c8",
+  "-",
+  "+",
+
+  "$qAttached:1#fa",
+  "+",
+
+  "$Hc-1#09",
+  "+",
+
+  "$qOffsets#4b",
+  "+",
+
+  "$g#67"
+  "+",
+
+  "$D;1#b0",
+  "+"
+};
+
+static const char* in[] =
+{
+  /*  0 */
+  "-",
+
+  /*  1 */
+  "+",
+  "$qSupported:PacketSize=4096;QNonStop-;multiprocess+;swbreak+;hwbreak-;"
+  "qRelocInsn-;fork-events-;vfork-events-;exec-events-;vContSupported+;"
+  "QThreadEvents-;no-resumed+#b3",
+
+  /*  3 */
+  "+",
+  "$#00",
+
+  /*  5 */
+  "+",
+  "$OK#9a",
+
+  /*  7 */
+  "+",
+  "$#00",
+
+  /*  9 */
+  "+",
+  "$T00thread:p1.0a010001;#23",
+
+  /* 11 */
+  "+",
+  "**",
+
+  /* 13 */
+  "+",
+  "$l#6c",
+  "$l#6c",
+
+  /* 16 */
+  "+",
+  "$1#31",
+
+  /* 18 */
+  "+",
+  "$OK#9a",
+
+  /* 20 */
+  "+",
+  "$#00",
+
+  /* 22 */
+  "+",
+  "**",
+
+  "+",
+  "$OK#9a"
+};
+
+static int
+test_remote_begin(rtems_debugger_remote* remote, const char* device)
+{
+  rtems_debugger_remote_test* test;
+
+  rtems_debugger_printf("error: rtems-db: test remote: begin\n");
+
+  rtems_debugger_lock();
+
+  /*
+   * Check the device.
+   */
+  rtems_test_assert(strcmp(device, "something") == 0);
+
+  test = malloc(sizeof(rtems_debugger_remote_test));
+  rtems_test_assert(test != NULL);
+
+  remote->data = test;
+
+  test->connect_count = 0;
+  test->connected = false;
+  test->out = 0;
+  test->in = 0;
+
+  rtems_debugger_unlock();
+
+  return 0;
+}
+
+static int
+test_remote_end(rtems_debugger_remote* remote)
+{
+  rtems_debugger_remote_test* test;
+
+  rtems_debugger_printf("error: rtems-db: test remote: end\n");
+
+  rtems_debugger_lock();
+
+  rtems_test_assert(remote != NULL);
+  rtems_test_assert(remote->data != NULL);
+  test = (rtems_debugger_remote_test*) remote->data;
+
+  test->connected = false;
+
+  free(test);
+
+  rtems_debugger_unlock();
+
+  return 0;
+}
+
+static int
+test_remote_connect(rtems_debugger_remote* remote)
+{
+  rtems_debugger_remote_test* test;
+
+  rtems_test_assert(remote != NULL);
+  rtems_test_assert(remote->data != NULL);
+  test = (rtems_debugger_remote_test*) remote->data;
+
+  if (test->connect_count > 0) {
+    rtems_event_set out = 0;
+    rtems_test_assert(rtems_event_receive(RTEMS_EVENT_1,
+                                          RTEMS_EVENT_ALL | RTEMS_WAIT,
+                                          RTEMS_NO_TIMEOUT,
+                                          &out) == RTEMS_SUCCESSFUL);
+  }
+
+  rtems_debugger_printf("error: rtems-db: test remote: connect\n");
+
+  ++test->connect_count;
+  test->connected = true;
+  test->out = 0;
+  test->in = 0;
+
+  return 0;
+}
+
+static int
+test_remote_disconnect(rtems_debugger_remote* remote)
+{
+  rtems_debugger_remote_test* test;
+
+  rtems_test_assert(remote != NULL);
+  rtems_test_assert(remote->data != NULL);
+  test = (rtems_debugger_remote_test*) remote->data;
+
+  rtems_debugger_printf("rtems-db: test remote: disconnect host\n");
+
+  rtems_debugger_lock();
+
+  rtems_test_assert(test->connected == true);
+
+  test->connected = false;
+
+  rtems_debugger_unlock();
+
+  return 0;
+}
+
+static bool
+test_remote_isconnected(rtems_debugger_remote* remote)
+{
+  rtems_debugger_remote_test* test;
+  bool                        isconnected;
+  rtems_test_assert(remote != NULL);
+  rtems_test_assert(remote->data != NULL);
+  test = (rtems_debugger_remote_test*) remote->data;
+  isconnected = test != NULL && test->connected;
+  rtems_debugger_printf("rtems-db: test remote: isconnected: %s\n",
+                        isconnected ? "connected" : "not-connected");
+  return isconnected;
+}
+
+static void
+test_remote_print(const char* label, const char* buf, size_t size)
+{
+  printf(" remote: %s: ", label);
+  while (size-- > 0) {
+    printf("%c", *buf++);
+  }
+  printf("\n");
+}
+
+static ssize_t
+test_remote_receive(rtems_debugger_remote* remote,
+                    void*                  buf,
+                    size_t                 nbytes)
+{
+  rtems_debugger_remote_test* test;
+  size_t                      len;
+  rtems_test_assert(remote != NULL);
+  rtems_test_assert(remote->data != NULL);
+  test = (rtems_debugger_remote_test*) remote->data;
+  rtems_test_assert(test->out < RTEMS_DEBUGGER_NUMOF(out));
+  len = strlen(out[test->out]);
+  printf(" remote: rx: message=%zu length=%zu\n", test->out, len);
+  test_remote_print("rx", out[test->out], len);
+  rtems_test_assert(len < nbytes);
+  memcpy(buf, out[test->out++], len);
+  return len;
+}
+
+static ssize_t
+test_remote_send(rtems_debugger_remote* remote,
+                const void*            buf,
+                size_t                 nbytes)
+{
+  rtems_debugger_remote_test* test;
+  size_t                      len;
+  bool                        no_match;
+  rtems_test_assert(remote != NULL);
+  rtems_test_assert(remote->data != NULL);
+  test = (rtems_debugger_remote_test*) remote->data;
+  rtems_test_assert(test->in < RTEMS_DEBUGGER_NUMOF(in));
+  len = strlen(in[test->in]);
+  no_match = len == 2 && strcmp(in[test->in], "**") == 0;
+  printf(" remote: tx: message=%zu length=%zu\n", test->in, len);
+  if (!no_match)
+    rtems_test_assert(len == nbytes);
+  test_remote_print("tx", buf, nbytes);
+  if (!no_match)
+    rtems_test_assert(memcmp(buf, in[test->in], nbytes) == 0);
+  test->in++;
+  return nbytes;
+}
+
+static rtems_debugger_remote remote_test =
+{
+  .name = "test",
+  .begin = test_remote_begin,
+  .end = test_remote_end,
+  .connect = test_remote_connect,
+  .disconnect = test_remote_disconnect,
+  .isconnected = test_remote_isconnected,
+  .read = test_remote_receive,
+  .write = test_remote_send
+};
+
+int
+rtems_debugger_register_test_remote(void)
+{
+  return rtems_debugger_remote_register(&remote_test);
+}
diff --git a/testsuites/libtests/debugger01/system.h b/testsuites/libtests/debugger01/system.h
new file mode 100644
index 0000000..c38283c
--- /dev/null
+++ b/testsuites/libtests/debugger01/system.h
@@ -0,0 +1,37 @@
+/*  system.h
+ *
+ *  This include file contains information that is included in every
+ *  function in the test set.
+ *
+ *  COPYRIGHT (c) 1989-1999.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <tmacros.h>
+
+/* functions */
+
+rtems_task Init(rtems_task_argument argument);
+
+int rtems_debugger_register_test_remote(void);
+void test_wake(void);
+
+/* configuration information */
+
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+
+#define CONFIGURE_MAXIMUM_USER_EXTENSIONS     1
+#define CONFIGURE_MAXIMUM_TASKS               10
+#define CONFIGURE_MAXIMUM_SEMAPHORES          10
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#include <rtems/confdefs.h>
+
+/* end of include file */




More information about the vc mailing list