Index: cpukit/libdebugger/rtems-debugger-arm.c
===================================================================
--- cpukit/libdebugger/rtems-debugger-arm.c	(revision a0d4e9933c57693f99203da358bb8aaa8a5d50d9)
+++ cpukit/libdebugger/rtems-debugger-arm.c	(revision a0d4e9933c57693f99203da358bb8aaa8a5d50d9)
@@ -0,0 +1,1193 @@
+/*
+ * Copyright (c) 2016 Chris Johns <chrisj@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;
+}
