--- /dev/null
+/* Copyright 2011 Adam Green (http://mbed.org/users/AdamGreen/)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef _DEBUG_CM3_H_
+#define _DEBUG_CM3_H_
+
+/* Data Watchpoint and Trace Registers */
+typedef struct
+{
+ /* Control register. */
+ __IO uint32_t CTRL;
+ /* Cycle Count register. */
+ __IO uint32_t CYCCNT;
+ /* CPI Count register. */
+ __IO uint32_t CPICNT;
+ /* Exception Overhead Count register. */
+ __IO uint32_t EXCCNT;
+ /* Sleep Count register. */
+ __IO uint32_t SLEEPCNT;
+ /* Load Store Count register. */
+ __IO uint32_t LSUCNT;
+ /* Folded-instruction Count register. */
+ __IO uint32_t FOLDCNT;
+ /* Program Counter Sample register. */
+ __I uint32_t PCSR;
+} DWT_Type;
+
+typedef struct
+{
+ /* Comparator register. */
+ __IO uint32_t COMP;
+ /* Comparator Mask register. */
+ __IO uint32_t MASK;
+ /* Comparator Function register. */
+ __IO uint32_t FUNCTION;
+ /* Reserved 4 bytes to pad struct size out to 16 bytes. */
+ __I uint32_t Reserved;
+} DWT_COMP_Type;
+
+/* Flash Patch and Breakpoint Registers */
+typedef struct
+{
+ /* FlashPatch Control Register. */
+ __IO uint32_t CTRL;
+ /* FlashPatch Remap Register. */
+ __IO uint32_t REMAP;
+} FPB_Type;
+
+
+/* Memory mapping of Cortex-M3 Debug Hardware */
+#define DWT_BASE (0xE0001000)
+#define DWT_COMP_BASE (0xE0001020)
+#define DWT ((DWT_Type *) DWT_BASE)
+#define DWT_COMP_ARRAY ((DWT_COMP_Type*) DWT_COMP_BASE)
+#define FPB_BASE (0xE0002000)
+#define FPB_COMP_BASE (0xE0002008)
+#define FPB ((FPB_Type*) FPB_BASE)
+#define FPB_COMP_ARRAY ((uint32_t*) FPB_COMP_BASE)
+
+
+/* Debug Halting Control and Status Register Bits */
+/* Enable halt mode debug. If set to 1 then JTAG debugging is being used. */
+#define CoreDebug_DHCSR_C_DEBUGEN (1 << 0)
+
+/* Debug Exception and Monitor Control Registers Bits */
+/* Monitor Single Step. Set to 1 to single step instruction when exiting monitor. */
+#define CoreDebug_DEMCR_MON_STEP (1 << 18)
+/* Monitor Pending. Set to 1 to pend a monitor exception. */
+#define CoreDebug_DEMCR_MON_PEND (1 << 17)
+/* Monitor Enable. Set to 1 to enable the debug monitor exception. */
+#define CoreDebug_DEMCR_MON_END (1 << 16)
+
+/* Debug Fault Status Register Bits. Clear a bit by writing a 1 to it. */
+/* Indicates that EDBGRQ was asserted. */
+#define SCB_DFSR_EXTERNAL (1 << 4)
+/* Indicates that a vector catch was triggered. */
+#define SCB_DFSR_VCATCH (1 << 3)
+/* Indicates that a DWT debug event was triggered. */
+#define SCB_DFSR_DWTTRAP (1 << 2)
+/* Indicates a BKPT instruction or FPB match was encountered. */
+#define SCB_DFSR_BKPT (1 << 1)
+/* Indicates that a single step has occurred. */
+#define SCB_DFSR_HALTED 1
+
+static __INLINE int IsDebuggerAttached(void)
+{
+ return (CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN);
+}
+
+static __INLINE int WaitForDebuggerToDetach(unsigned int TimeOut)
+{
+ while (TimeOut-- > 0 && IsDebuggerAttached())
+ {
+ }
+
+ return IsDebuggerAttached();
+}
+
+static __INLINE void EnableDebugMonitorAtPriority0(void)
+{
+ NVIC_SetPriority(DebugMonitor_IRQn, 0);
+ CoreDebug->DEMCR |= CoreDebug_DEMCR_MON_END;
+}
+
+static __INLINE void DisableSingleStep(void)
+{
+ CoreDebug->DEMCR &= ~CoreDebug_DEMCR_MON_STEP;
+}
+
+static void EnableSingleStep(void)
+{
+ CoreDebug->DEMCR |= CoreDebug_DEMCR_MON_STEP;
+}
+
+static __INLINE void ClearMonitorPending(void)
+{
+ CoreDebug->DEMCR &= ~CoreDebug_DEMCR_MON_PEND;
+}
+
+
+/* Data Watchpoint and Trace Comparator Function Bits. */
+/* Matched. Read-only. Set to 1 to indicate that this comparator has been matched. Cleared on read. */
+#define DWT_COMP_FUNCTION_MATCHED (1 << 24)
+/* Data Value Match. Set to 0 for address compare and 1 for data value compare. */
+#define DWT_COMP_FUNCTION_DATAVMATCH (1 << 8)
+/* Cycle Count Match. Set to 1 for enabling cycle count match and 0 otherwise. Only valid on comparator 0. */
+#define DWT_COMP_FUNCTION_CYCMATCH (1 << 7)
+/* Enable Data Trace Address offset packets. 0 to disable. */
+#define DWT_COMP_FUNCTION_EMITRANGE (1 << 5)
+/* Selects action to be taken on match. */
+#define DWT_COMP_FUNCTION_FUNCTION_MASK 0xF
+/* Disabled */
+#define DWT_COMP_FUNCTION_FUNCTION_DISABLED 0x0
+/* Instruction Watchpoint */
+#define DWT_COMP_FUNCTION_FUNCTION_INSTRUCTION 0x4
+/* Data Read Watchpoint */
+#define DWT_COMP_FUNCTION_FUNCTION_DATA_READ 0x5
+/* Data Write Watchpoint */
+#define DWT_COMP_FUNCTION_FUNCTION_DATA_WRITE 0x6
+/* Data Read/Write Watchpoint */
+#define DWT_COMP_FUNCTION_FUNCTION_DATE_READWRITE 0x7
+
+/* DWT - Data Watchpoint Trace Routines */
+static __INLINE unsigned int GetDWTComparatorCount(void)
+{
+ return (DWT->CTRL >> 28);
+}
+
+static __INLINE void ClearDWTComparator(DWT_COMP_Type* pComparatorStruct)
+{
+ pComparatorStruct->COMP = 0;
+ pComparatorStruct->MASK = 0;
+ pComparatorStruct->FUNCTION &= ~(DWT_COMP_FUNCTION_DATAVMATCH |
+ DWT_COMP_FUNCTION_CYCMATCH |
+ DWT_COMP_FUNCTION_EMITRANGE |
+ DWT_COMP_FUNCTION_FUNCTION_MASK);
+}
+
+static __INLINE void ClearDWTComparators(void)
+{
+ unsigned int ComparatorCount;
+ unsigned int i;
+ DWT_COMP_Type* pComparatorStruct = DWT_COMP_ARRAY;
+
+ ComparatorCount = GetDWTComparatorCount();
+
+ for (i = 0 ; i < ComparatorCount ; i++)
+ {
+ ClearDWTComparator(pComparatorStruct);
+ pComparatorStruct++;
+ }
+}
+
+static __INLINE void InitDWT(void)
+{
+ ClearDWTComparators();
+}
+
+
+/* FlashPatch Control Register Bits. */
+/* Most significant bits of number of instruction address comparators. Read-only */
+#define FP_CTRL_NUM_CODE_MSB_SHIFT 12
+#define FP_CTRL_NUM_CODE_MSB_MASK (0x7 << FP_CTRL_NUM_CODE_MSB_SHIFT)
+/* Least significant bits of number of instruction address comparators. Read-only */
+#define FP_CTRL_NUM_CODE_LSB_SHIFT 4
+#define FP_CTRL_NUM_CODE_LSB_MASK (0xF << FP_CTRL_NUM_CODE_LSB_SHIFT)
+/* Number of instruction literal address comparators. Read only */
+#define FP_CTRL_NUM_LIT_SHIFT 8
+#define FP_CTRL_NUM_LIT_MASK (0xF << FP_CTRL_NUM_LIT_SHIFT)
+/* This Key field must be set to 1 when writing or the write will be ignored. */
+#define FP_CTRL_KEY (1 << 1)
+/* Enable bit for the FPB. Set to 1 to enable FPB. */
+#define FP_CTRL_ENABLE 1
+
+/* FlashPatch Comparator Register Bits. */
+/* Defines the behaviour for code address comparators. */
+#define FP_COMP_REPLACE_SHIFT 30
+#define FP_COMP_REPLACE_MASK (0x3 << FP_COMP_REPLACE_SHIFT)
+/* Remap to specified address in SRAM. */
+#define FP_COMP_REPLACE_REMAP (0x0 << FP_COMP_REPLACE_SHIFT)
+/* Breakpoint on lower halfword. */
+#define FP_COMP_REPLACE_BREAK_LOWER (0x1 << FP_COMP_REPLACE_SHIFT)
+/* Breakpoint on upper halfword. */
+#define FP_COMP_REPLACE_BREAK_UPPER (0x2 << FP_COMP_REPLACE_SHIFT)
+/* Breakpoint on word. */
+#define FP_COMP_REPLACE_BREAK (0x3 << FP_COMP_REPLACE_SHIFT)
+/* Specified bits 28:2 of the address to be use for match on this comparator. */
+#define FP_COMP_COMP_SHIFT 2
+#define FP_COMP_COMP_MASK (0x07FFFFFF << FP_COMP_COMP_SHIFT)
+/* Enables this comparator. Set to 1 to enable. */
+#define FP_COMP_ENABLE 1
+
+/* FPB - Flash Patch Breakpoint Routines. */
+static __INLINE unsigned int GetFPBCodeComparatorCount(void)
+{
+ uint32_t ControlValue = FPB->CTRL;
+ return (((ControlValue & FP_CTRL_NUM_CODE_MSB_MASK) >> 8) |
+ ((ControlValue & FP_CTRL_NUM_CODE_LSB_MASK) >> 4));
+}
+
+static __INLINE unsigned int GetFPBLiteralComparatorCount(void)
+{
+ uint32_t ControlValue = FPB->CTRL;
+ return ((ControlValue & FP_CTRL_NUM_LIT_MASK) >> FP_CTRL_NUM_LIT_SHIFT);
+}
+
+static __INLINE void ClearFPBComparator(uint32_t* pComparator)
+{
+ *pComparator = 0;
+}
+
+static __INLINE int32_t IsAddressInUpperHalfGig(uint32_t Address)
+{
+ return (Address & 0xE0000000);
+}
+
+static __INLINE int32_t IsAddressOdd(uint32_t Address)
+{
+ return (Address & 0x1);
+}
+
+static __INLINE int32_t IsBreakpointAddressInvalid(uint32_t BreakpointAddress)
+{
+ return (IsAddressInUpperHalfGig(BreakpointAddress) || IsAddressOdd(BreakpointAddress));
+}
+
+static __INLINE uint32_t IsAddressInUpperHalfword(uint32_t Address)
+{
+ return (Address & 0x2);
+}
+
+static __INLINE uint32_t CalculateFPBComparatorReplaceValue(uint32_t BreakpointAddress, int32_t Is32BitInstruction)
+{
+ if (Is32BitInstruction)
+ {
+ return FP_COMP_REPLACE_BREAK;
+ }
+ else if (IsAddressInUpperHalfword(BreakpointAddress))
+ {
+ return FP_COMP_REPLACE_BREAK_UPPER;
+ }
+ else
+ {
+ return FP_COMP_REPLACE_BREAK_LOWER;
+ }
+}
+
+static __INLINE uint32_t CalculateFPBComparatorValue(uint32_t BreakpointAddress, int32_t Is32BitInstruction)
+{
+ uint32_t ComparatorValue;
+
+ if (IsBreakpointAddressInvalid(BreakpointAddress))
+ {
+ /* Can only set a breakpoint on addresses where the upper 3-bits are all 0 (upper 0.5GB is off limits) and
+ the address is half-word aligned */
+ return ~0UL;
+ }
+
+ ComparatorValue = (BreakpointAddress & FP_COMP_COMP_MASK);
+ ComparatorValue |= FP_COMP_ENABLE;
+ ComparatorValue |= CalculateFPBComparatorReplaceValue(BreakpointAddress, Is32BitInstruction);
+
+ return ComparatorValue;
+}
+
+static __INLINE uint32_t MaskOffFPBComparatorReservedBits(uint32_t ComparatorValue)
+{
+ return (ComparatorValue & (FP_COMP_REPLACE_MASK | FP_COMP_COMP_MASK | FP_COMP_ENABLE));
+}
+
+static __INLINE uint32_t IsFPBComparatorEnabled(uint32_t Comparator)
+{
+ return (Comparator & FP_COMP_ENABLE);
+}
+
+static __INLINE uint32_t* FindFPBBreakpointComparator(uint32_t BreakpointAddress, int32_t Is32BitInstruction)
+{
+ uint32_t* pCurrentComparator = FPB_COMP_ARRAY;
+ uint32_t ComparatorValueForThisBreakpoint;
+ unsigned int CodeComparatorCount;
+ unsigned int i;
+
+ ComparatorValueForThisBreakpoint = CalculateFPBComparatorValue(BreakpointAddress, Is32BitInstruction);
+ CodeComparatorCount = GetFPBCodeComparatorCount();
+
+ for (i = 0 ; i < CodeComparatorCount ; i++)
+ {
+ uint32_t MaskOffReservedBits;
+
+ MaskOffReservedBits = MaskOffFPBComparatorReservedBits(*pCurrentComparator);
+ if (ComparatorValueForThisBreakpoint == MaskOffReservedBits)
+ {
+ return pCurrentComparator;
+ }
+ pCurrentComparator++;
+ }
+
+ /* Return NULL if no FPB comparator is already enabled for this breakpoint. */
+ return NULL;
+}
+
+static __INLINE uint32_t* FindFreeFPBBreakpointComparator(void)
+{
+ uint32_t* pCurrentComparator = FPB_COMP_ARRAY;
+ unsigned int CodeComparatorCount;
+ unsigned int i;
+
+ CodeComparatorCount = GetFPBCodeComparatorCount();
+
+ for (i = 0 ; i < CodeComparatorCount ; i++)
+ {
+ if (!IsFPBComparatorEnabled(*pCurrentComparator))
+ {
+ return pCurrentComparator;
+ }
+ pCurrentComparator++;
+ }
+
+ /* Return NULL if no FPB breakpoint comparators are free. */
+ return NULL;
+}
+
+static __INLINE uint32_t* EnableFPBBreakpoint(uint32_t BreakpointAddress, int32_t Is32BitInstruction)
+{
+ uint32_t* pExistingFPBBreakpoint;
+ uint32_t* pFreeFPBBreakpointComparator;
+
+ pExistingFPBBreakpoint = FindFPBBreakpointComparator(BreakpointAddress, Is32BitInstruction);
+ if (pExistingFPBBreakpoint)
+ {
+ /* This breakpoint is already set to just return pointer to existing comparator. */
+ return pExistingFPBBreakpoint;
+ }
+
+ pFreeFPBBreakpointComparator = FindFreeFPBBreakpointComparator();
+ if (!pFreeFPBBreakpointComparator)
+ {
+ /* All FPB breakpoint comparator slots are used so return NULL as error indicator. */
+ return NULL;
+ }
+
+
+ *pFreeFPBBreakpointComparator = CalculateFPBComparatorValue(BreakpointAddress, Is32BitInstruction);
+ return pFreeFPBBreakpointComparator;
+}
+
+static __INLINE uint32_t* DisableFPBBreakpointComparator(uint32_t BreakpointAddress, int32_t Is32BitInstruction)
+{
+ uint32_t* pExistingFPBBreakpoint;
+
+ pExistingFPBBreakpoint = FindFPBBreakpointComparator(BreakpointAddress, Is32BitInstruction);
+ if (pExistingFPBBreakpoint)
+ {
+ ClearFPBComparator(pExistingFPBBreakpoint);
+ }
+
+ return pExistingFPBBreakpoint;
+}
+
+static __INLINE void ClearFPBComparators(void)
+{
+ unsigned int CodeComparatorCount;
+ unsigned int LiteralComparatorCount;
+ unsigned int TotalComparatorCount;
+ unsigned int i;
+ uint32_t* pCurrentComparator = FPB_COMP_ARRAY;
+
+ CodeComparatorCount = GetFPBCodeComparatorCount();
+ LiteralComparatorCount = GetFPBLiteralComparatorCount();
+ TotalComparatorCount = CodeComparatorCount + LiteralComparatorCount;
+
+ for (i = 0 ; i < TotalComparatorCount ; i++)
+ {
+ ClearFPBComparator(pCurrentComparator);
+ pCurrentComparator++;
+ }
+}
+
+static __INLINE void EnableFPB(void)
+{
+ FPB->CTRL |= (FP_CTRL_KEY | FP_CTRL_ENABLE);
+}
+
+static __INLINE void InitFPB(void)
+{
+ ClearFPBComparators();
+ EnableFPB();
+}
+
+
+/* Memory Protection Unit Type Register Bits. */
+/* Number of instruction regions supported by MPU. 0 for Cortex-M3 */
+#define MPU_TYPE_IREGION_SHIFT 16
+#define MPU_TYPE_IREGION_MASK (0xFF << MPU_TYPE_IREGION_SHIFT)
+/* Number of data regions supported by MPU. */
+#define MPU_TYPE_DREGION_SHIFT 8
+#define MPU_TYPE_DREGION_MASK (0xFF << MPU_TYPE_DREGION_SHIFT)
+/* Are instruction and data regions configured separately? 1 for yes and 0 otherwise. */
+#define MPU_TYPE_SEPARATE 0x1
+
+/* Memory Protection Unit Control Register Bits. */
+/* Default memory map as background region for privileged access. 1 enables. */
+#define MPU_CTRL_PRIVDEFENA (1 << 2)
+/* Hard fault and NMI exceptions to use MPU. 0 disables MPU for these handlers. */
+#define MPU_CTRL_HFNMIENA (1 << 1)
+/* MPU Enable. 1 enables and disabled otherwise. */
+#define MPU_CTRL_ENABLE 1
+
+/* MPU - Memory Protection Unit Routines. */
+static __INLINE unsigned int GetMPUControlValue(void)
+{
+ return (MPU->CTRL);
+}
+
+static __INLINE void SetMPUControlValue(unsigned int NewControlValue)
+{
+ MPU->CTRL = NewControlValue;
+}
+
+static __INLINE void DisableMPU(void)
+{
+ MPU->CTRL &= ~MPU_CTRL_ENABLE;
+}
+
+
+/* Program Status Register Bits. */
+/* Was the stack 8-byte aligned during auto stacking. */
+#define PSR_STACK_ALIGN (1 << 9)
+
+
+#endif /* _DEBUG_CM3_H_ */
--- /dev/null
+/* Copyright 2011 Adam Green (http://mbed.org/users/AdamGreen/)\r
+\r
+ This program is free software: you can redistribute it and/or modify\r
+ it under the terms of the GNU Lesser General Public License as published\r
+ by the Free Software Foundation, either version 3 of the License, or\r
+ (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU Lesser General Public License for more details.\r
+\r
+ You should have received a copy of the GNU Lesser General Public License\r
+ along with this program. If not, see <http://www.gnu.org/licenses/>. \r
+*/\r
+/* Monitor for Remote Inspection\r
+\r
+ Stub implementation to allow Cortex based mbed microcontrollers to be\r
+ debugged from gdb, the GNU debugger.\r
+*/\r
+#include <string.h>\r
+#include <signal.h>\r
+#include <mbed.h>\r
+#include "mri.h"\r
+#include "mriasm.h"\r
+#include "debug_cm3.h"\r
+\r
+\r
+/*********************/\r
+/* Type Declarations */\r
+/*********************/\r
+/* NOTE: The MriExceptionHandler function definition in mriasm.S is dependent on the layout of this structure. It\r
+ is also dictated by the version of gdb which supports the ARM processors. It should only be changed if the\r
+ gdb ARM support code is modified and then the context saving and restoring code will need to be modified to\r
+ use the correct offsets as well. \r
+*/\r
+typedef struct\r
+{\r
+ unsigned int R0;\r
+ unsigned int R1;\r
+ unsigned int R2;\r
+ unsigned int R3;\r
+ unsigned int R4;\r
+ unsigned int R5;\r
+ unsigned int R6;\r
+ unsigned int R7;\r
+ unsigned int R8;\r
+ unsigned int R9;\r
+ unsigned int R10;\r
+ unsigned int R11;\r
+ unsigned int R12;\r
+ unsigned int SP;\r
+ unsigned int LR;\r
+ unsigned int PC;\r
+ /* Reserve room for 8 96-bit floats. */\r
+ unsigned int Floats[8 * 3];\r
+ unsigned int FPS;\r
+ unsigned int CPSR;\r
+} SContext;\r
+\r
+typedef struct\r
+{\r
+ char* pStart;\r
+ char* pEnd;\r
+ char* pCurrent;\r
+ int BufferOverrunDetected;\r
+} SBuffer;\r
+\r
+typedef struct\r
+{\r
+ unsigned int Address;\r
+ int Is32BitInstruction;\r
+ char Type;\r
+} SBreakpointWatchpointArguments;\r
+\r
+/* NOTE: The largest buffer is required for receiving the 'G' command which receives the contents of the registers from \r
+ the debugger as two hex digits per byte. Also need a character for the 'G' command and NULL terminator. */\r
+#define MRI_INPUT_OUTPUT_BUFFER_SIZE (1 + 2 * sizeof(SContext))\r
+\r
+typedef struct\r
+{\r
+ SBuffer Buffer;\r
+ unsigned int OriginalPC;\r
+ unsigned int OriginalPSRBitsToMaintain;\r
+ unsigned int MPUControlValueBeforeDisabling;\r
+ int SignalValue;\r
+ char InputOutputBuffer[MRI_INPUT_OUTPUT_BUFFER_SIZE];\r
+} SMriState;\r
+\r
+\r
+\r
+\r
+/********************************************/\r
+/* RAM based globals used by debug monitor. */\r
+/********************************************/\r
+/* Register context of interrupted program state is stored in this global. */\r
+SContext g_MriContext;\r
+\r
+/* Bitmask of MRI_FLAGS_* bits listed below in Constant Definitions sections. */\r
+volatile unsigned int g_MriFlags = 0;\r
+\r
+/* UID feteched from mbed interface chip before disabling it. */\r
+unsigned char g_MriMbedUid[36];\r
+\r
+/* UNDONE: Move to stack later when debugger has its own stack. */\r
+/* Tracks state for debugging the current exception. */\r
+static SMriState g_MriState;\r
+\r
+static Serial g_Serial(USBTX, USBRX);\r
+\r
+\r
+\r
+/************************/\r
+/* Constant Definitions */\r
+/************************/\r
+/* g_MriFlags bit definitions. */\r
+/* NOTE: These flag definitions must match the equivalent .equ's in mriasm.S */\r
+#define MRI_FLAGS_ACTIVE_DEBUG 1\r
+#define MRI_FLAGS_FAULT_DURING_DEBUG 2\r
+#define MRI_FLAGS_FAILED_MBED_DISABLE 4\r
+#define MRI_FLAGS_MBED_DETECTED 8\r
+\r
+/* Error strings to be returned to GDB. */\r
+#define MRI_ERROR_INVALID_ARGUMENT "E01" /* Encountered error when parsing command arguments. */\r
+#define MRI_ERROR_MEMORY_ACCESS_FAILURE "E03" /* Couldn't access requested memory. */\r
+#define MRI_ERROR_BUFFER_OVERRUN "E04" /* Overflowed internal input/output buffer. */\r
+#define MRI_ERROR_NO_FREE_BREAKPOINT "E05" /* No free FPB breakpoint comparator slots. */\r
+\r
+/* The bits that can be set in the return value from a command handler to indicate if the caller should return\r
+ immediately or send the prepared response back to gdb. It also indicates whether program execution should be\r
+ resumed for commands like continue and single step. */\r
+#define HANDLER_RETURN_RESUME_PROGRAM 1\r
+#define HANDLER_RETURN_RETURN_IMMEDIATELY 2\r
+\r
+\r
+\r
+/***********/\r
+/* Macroes */\r
+/***********/\r
+/* Calculates the number of items in a static array at compile time. */\r
+#define ARRAY_SIZE(X) (sizeof(X)/sizeof(X[0]))\r
+\r
+/* Macro to provide index for specified register in the SContext structure. */\r
+#define CONTEXT_MEMBER_INDEX(MEMBER) (offsetof(SContext, MEMBER)/sizeof(unsigned int))\r
+\r
+/* Macros to extract upper and lower 4-bit nibbles from 8-bit value. */\r
+#define HI_NIBBLE(X) (((X) >> 4) & 0xF)\r
+#define LO_NIBBLE(X) ((X) & 0xF)\r
+\r
+\r
+\r
+/************************/\r
+/* Function Prototypes. */\r
+/************************/\r
+static void ClearDebuggerActiveFlag(void);\r
+\r
+\r
+\r
+/***************************************************************/\r
+/* External low-level support routines required by debug stub. */\r
+/***************************************************************/\r
+/* UNDONE: Make these configurable to run different UARTs and at different baud rates. \r
+ Also move out to a mbed target platform specific file. */\r
+void MriTargetSendChar(int Character)\r
+{\r
+ g_Serial.putc(Character);\r
+}\r
+\r
+int MriTargetReceiveChar(void)\r
+{\r
+ return g_Serial.getc();\r
+}\r
+\r
+int ControlCDetected(void)\r
+{\r
+ static const char ControlC = 0x03;\r
+ char Char;\r
+ \r
+ while (g_Serial.readable())\r
+ {\r
+ Char = g_Serial.getc();\r
+ if (Char == ControlC)\r
+ {\r
+ return 1;\r
+ }\r
+ }\r
+ \r
+ return 0;\r
+}\r
+\r
+static void ConfigureNVICForUartInterrupt(void)\r
+{\r
+ NVIC_SetPriority(UART0_IRQn, 0);\r
+ NVIC_EnableIRQ(UART0_IRQn);\r
+}\r
+\r
+static void EnableUartToInterruptOnReceivedChar(void)\r
+{\r
+ static const uint32_t EnableFIFO_DisableDMA_SetReceiveInterruptThresholdTo0 = 0x01;\r
+ static const uint32_t BaudDivisorLatchBit = (1 << 7);\r
+ static const uint32_t EnableReceiveDataInterrupt = (1 << 0);\r
+ uint32_t OriginalLCR;\r
+ \r
+ LPC_UART0->FCR = EnableFIFO_DisableDMA_SetReceiveInterruptThresholdTo0;\r
+ OriginalLCR = LPC_UART0->LCR;\r
+ LPC_UART0->LCR &= ~BaudDivisorLatchBit;\r
+ LPC_UART0->IER = EnableReceiveDataInterrupt;\r
+ LPC_UART0->LCR = OriginalLCR;\r
+}\r
+\r
+static void InitUart(void)\r
+{\r
+ g_Serial.baud(115200);\r
+ EnableUartToInterruptOnReceivedChar();\r
+ ConfigureNVICForUartInterrupt();\r
+}\r
+\r
+\r
+\r
+/************************************/\r
+/* Hexadecimal Conversion Routines. */\r
+/************************************/\r
+/* Used to convert 4-bit nibble values to hex digit. */\r
+static const char NibbleToHexChar[16] = { '0', '1', '2', '3', '4', '5', '6', '7',\r
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };\r
+\r
+static int HexCharToNibble(unsigned char HexChar)\r
+{\r
+ if (HexChar >= 'a' && HexChar <= 'f')\r
+ {\r
+ return HexChar - 'a' + 10;\r
+ }\r
+ if (HexChar >= 'A' && HexChar <= 'F')\r
+ {\r
+ return HexChar - 'A' + 10;\r
+ }\r
+ if (HexChar >= '0' && HexChar <= '9')\r
+ {\r
+ return HexChar - '0';\r
+ }\r
+ \r
+ /* NOTE: Returns -1 if HexChar isn't a valid hex digit. */\r
+ return -1;\r
+}\r
+\r
+\r
+\r
+/***************************************/\r
+/* Character buffer handling routines. */\r
+/***************************************/\r
+static void SBuffer_Reset(SBuffer* pBuffer)\r
+{\r
+ pBuffer->pCurrent = pBuffer->pStart;\r
+ pBuffer->BufferOverrunDetected = 0;\r
+}\r
+\r
+static void SBuffer_Init(SBuffer* pBuffer, char* pBufferStart, size_t BufferSize)\r
+{\r
+ pBuffer->pStart = pBufferStart;\r
+ pBuffer->pEnd = pBufferStart + BufferSize;\r
+ SBuffer_Reset(pBuffer);\r
+}\r
+\r
+static size_t SBuffer_BytesLeft(SBuffer* pBuffer)\r
+{\r
+ int BytesLeft = pBuffer->pEnd - pBuffer->pCurrent;\r
+ \r
+ if (BytesLeft < 0)\r
+ {\r
+ pBuffer->BufferOverrunDetected = 1;\r
+ return 0;\r
+ }\r
+ else\r
+ {\r
+ return (size_t)BytesLeft;\r
+ }\r
+}\r
+\r
+static void SBuffer_PushBackLastChar(SBuffer* pBuffer)\r
+{\r
+ if (pBuffer->pCurrent > pBuffer->pStart)\r
+ {\r
+ pBuffer->pCurrent--;\r
+ }\r
+}\r
+\r
+static int SBuffer_BufferOverrunDetected(SBuffer* pBuffer)\r
+{\r
+ return pBuffer->BufferOverrunDetected;\r
+}\r
+\r
+static int SBuffer_WriteChar(SBuffer* pBuffer, char Char)\r
+{\r
+ if (SBuffer_BytesLeft(pBuffer) < 1)\r
+ {\r
+ pBuffer->BufferOverrunDetected = 1;\r
+ return 0;\r
+ }\r
+ else\r
+ {\r
+ *(pBuffer->pCurrent++) = Char;\r
+ return 1;\r
+ }\r
+}\r
+\r
+static int SBuffer_ReadChar(SBuffer* pBuffer, char* pChar)\r
+{\r
+ if (SBuffer_BytesLeft(pBuffer) < 1)\r
+ {\r
+ pBuffer->BufferOverrunDetected = 1;\r
+ *pChar = '\0';\r
+ return 0;\r
+ }\r
+ else\r
+ {\r
+ *pChar = *(pBuffer->pCurrent++);\r
+ return 1;\r
+ }\r
+}\r
+\r
+static int SBuffer_WriteByteAsHex(SBuffer* pBuffer, unsigned char Byte)\r
+{\r
+ if (SBuffer_BytesLeft(pBuffer) < 2)\r
+ {\r
+ pBuffer->BufferOverrunDetected = 1;\r
+ return 0;\r
+ }\r
+ else\r
+ {\r
+ *(pBuffer->pCurrent++) = NibbleToHexChar[HI_NIBBLE(Byte)];\r
+ *(pBuffer->pCurrent++) = NibbleToHexChar[LO_NIBBLE(Byte)];\r
+ return 1;\r
+ }\r
+}\r
+\r
+static int SBuffer_ReadByteAsHex(SBuffer* pBuffer, unsigned char* pByte)\r
+{\r
+ if (SBuffer_BytesLeft(pBuffer) < 2)\r
+ {\r
+ pBuffer->BufferOverrunDetected = 1;\r
+ return 0;\r
+ }\r
+ else\r
+ {\r
+ unsigned char Byte;\r
+ \r
+ Byte = HexCharToNibble(*(pBuffer->pCurrent++)) << 4;\r
+ Byte |= HexCharToNibble(*(pBuffer->pCurrent++));\r
+ *pByte = Byte;\r
+ return 1;\r
+ }\r
+}\r
+\r
+static int SBuffer_WriteString(SBuffer* pBuffer, const char* pString)\r
+{\r
+ int Result = 0;\r
+ \r
+ while (*pString)\r
+ {\r
+ Result = SBuffer_WriteChar(pBuffer, *pString++);\r
+ if (!Result)\r
+ {\r
+ return Result;\r
+ }\r
+ }\r
+ \r
+ return 1;\r
+}\r
+\r
+static int SBuffer_WriteSizedString(SBuffer* pBuffer, const char* pString, size_t Length)\r
+{\r
+ int Result = 0;\r
+ \r
+ while (Length--)\r
+ {\r
+ Result = SBuffer_WriteChar(pBuffer, *pString++);\r
+ if (!Result)\r
+ {\r
+ return Result;\r
+ }\r
+ }\r
+ \r
+ return 1;\r
+}\r
+\r
+static int SBuffer_ReadUIntegerAsHex(SBuffer* pBuffer, unsigned int* pUIntegerResult)\r
+{\r
+ int HexDigitsParsed = 0;\r
+ unsigned int UInteger = 0;\r
+ char Char; \r
+\r
+ while (SBuffer_ReadChar(pBuffer, &Char))\r
+ {\r
+ int DigitValue;\r
+ \r
+ DigitValue = HexCharToNibble(Char);\r
+ if (DigitValue < 0)\r
+ {\r
+ /* A character which wasn't a hex digit was encountered so end of hex string has been passed. */\r
+ SBuffer_PushBackLastChar(pBuffer);\r
+ break;\r
+ }\r
+\r
+ UInteger = (UInteger << 4) + DigitValue;\r
+ HexDigitsParsed++;\r
+ }\r
+\r
+ *pUIntegerResult = UInteger;\r
+ return HexDigitsParsed;\r
+}\r
+\r
+static int SBuffer_WriteUIntegerAsHex(SBuffer* pBuffer, unsigned int Value)\r
+{\r
+ unsigned char* pSrc = ((unsigned char*)&Value) + 3;\r
+ int NonZero = 0;\r
+ unsigned int i;\r
+ \r
+ for (i = 0 ; i < sizeof(Value) ; i++)\r
+ {\r
+ unsigned char Byte = *pSrc--;\r
+ \r
+ if (NonZero || Byte)\r
+ {\r
+ SBuffer_WriteByteAsHex(pBuffer, Byte);\r
+ NonZero = 1;\r
+ }\r
+ }\r
+ \r
+ if (!NonZero)\r
+ {\r
+ SBuffer_WriteByteAsHex(pBuffer, 0);\r
+ }\r
+ \r
+ return !SBuffer_BufferOverrunDetected(pBuffer);\r
+}\r
+\r
+static int SBuffer_IsNextCharEqualTo(SBuffer* pBuffer, char ThisChar)\r
+{\r
+ char NextChar;\r
+ \r
+ if (!SBuffer_ReadChar(pBuffer, &NextChar))\r
+ {\r
+ /* There are no more characters in buffer so it can't be ThisChar. */\r
+ return 0;\r
+ }\r
+ else\r
+ {\r
+ return (ThisChar == NextChar);\r
+ }\r
+}\r
+\r
+static int SBuffer_MatchesString(SBuffer* pBuffer, const char* pString, size_t StringLength)\r
+{\r
+ size_t BytesLeft = SBuffer_BytesLeft(pBuffer);\r
+ \r
+ if (BytesLeft < StringLength)\r
+ {\r
+ /* Buffer contents aren't long enough to contain this string so return false. */\r
+ return 0;\r
+ }\r
+ \r
+ if(0 == strncmp(pBuffer->pCurrent, pString, StringLength) &&\r
+ (BytesLeft == StringLength ||\r
+ pBuffer->pCurrent[StringLength] == ':'))\r
+ {\r
+ pBuffer->pCurrent += StringLength;\r
+ return 1;\r
+ }\r
+ else\r
+ {\r
+ return 0;\r
+ }\r
+}\r
+\r
+\r
+\r
+/********************************************************************************************/\r
+/* Routines to send and receive character based checksummed packets to/from the gdb client. */\r
+/********************************************************************************************/\r
+static void SendByteAsHex(unsigned char Byte)\r
+{\r
+ MriTargetSendChar(NibbleToHexChar[HI_NIBBLE(Byte)]);\r
+ MriTargetSendChar(NibbleToHexChar[LO_NIBBLE(Byte)]);\r
+}\r
+\r
+static void WaitForStartOfNextPacket(char LastChar)\r
+{\r
+ char Char = LastChar;\r
+ \r
+ /* Wait for the packet start character, '$', and ignore all other characters. */\r
+ while (Char != '$')\r
+ {\r
+ Char = MriTargetReceiveChar();\r
+ }\r
+}\r
+\r
+static int GetPacketDataAndChecksum(char* pBuffer, size_t BufferSize, unsigned char* pChecksum, char* pLastChar)\r
+{\r
+ char* pEnd = pBuffer + BufferSize - 1;\r
+ char Char = '\0';\r
+ unsigned char Checksum;\r
+ char* pDest;\r
+\r
+ /* Read data characters until end of packet character ('#') is encountered, start of next packet character ('$') is\r
+ unexpectedly received or the buffer is unexpectedly filled. */\r
+ pDest = pBuffer;\r
+ Checksum = 0;\r
+ Char = MriTargetReceiveChar();\r
+ while (pDest < pEnd && Char != '$' && Char != '#')\r
+ {\r
+ Checksum = Checksum + (unsigned char)Char;\r
+ *pDest++ = Char;\r
+\r
+ Char = MriTargetReceiveChar();\r
+ }\r
+ *pDest = '\0';\r
+ *pChecksum = Checksum;\r
+ *pLastChar = Char;\r
+ \r
+ /* Return success if the expected end of packet character, '#', was received. */\r
+ return (Char == '#');\r
+}\r
+\r
+static int ValidatePacketChecksum(unsigned char CalculatedChecksum)\r
+{\r
+ char ExpectedChecksumString[2];\r
+ unsigned char ExpectedChecksum;\r
+ SBuffer Buffer;\r
+ \r
+ ExpectedChecksumString[0] = MriTargetReceiveChar();\r
+ ExpectedChecksumString[1] = MriTargetReceiveChar();\r
+ SBuffer_Init(&Buffer, ExpectedChecksumString, sizeof(ExpectedChecksumString));\r
+ \r
+ SBuffer_ReadByteAsHex(&Buffer, &ExpectedChecksum);\r
+ \r
+ return (ExpectedChecksum == CalculatedChecksum);\r
+}\r
+\r
+static void SendACKToGDB(void)\r
+{\r
+ MriTargetSendChar('+');\r
+}\r
+\r
+static void SendNAKToGDB(void)\r
+{\r
+ MriTargetSendChar('-');\r
+}\r
+\r
+static int AttemptToGetPacketData(char* pBuffer, size_t BufferSize, char** pStartOfPacket)\r
+{\r
+ char LastChar = '\0';\r
+ unsigned char Checksum;\r
+ int GoodPacket;\r
+ \r
+ do\r
+ {\r
+ WaitForStartOfNextPacket(LastChar);\r
+ GoodPacket = GetPacketDataAndChecksum(pBuffer, BufferSize, &Checksum, &LastChar);\r
+ } while (!GoodPacket);\r
+ \r
+ if (ValidatePacketChecksum(Checksum))\r
+ {\r
+ SendACKToGDB();\r
+ *pStartOfPacket = &pBuffer[0];\r
+ return 1;\r
+ }\r
+ else\r
+ {\r
+ SendNAKToGDB();\r
+ return 0;\r
+ }\r
+}\r
+\r
+static char* _GetPacketFromGDB(char* pBuffer, size_t BufferSize)\r
+{\r
+ int PacketChecksumGood;\r
+ char* StartOfPacket;\r
+ \r
+ do\r
+ {\r
+ PacketChecksumGood = AttemptToGetPacketData(pBuffer, BufferSize, &StartOfPacket);\r
+ } while(!PacketChecksumGood);\r
+ \r
+ return StartOfPacket;\r
+}\r
+\r
+static void _SendPacketToGDB(SBuffer* pBuffer)\r
+{\r
+ char* pEnd = pBuffer->pCurrent;\r
+ \r
+ /* Keeps looping until GDB sends back the '+' packet acknowledge character. */\r
+ do\r
+ {\r
+ unsigned char Checksum = 0;\r
+ char* pCurrent = pBuffer->pStart;\r
+ \r
+ /* Send packet of format: "$<DataInHex>#<1ByteChecksumInHex> */\r
+ MriTargetSendChar('$');\r
+ while (pCurrent < pEnd)\r
+ {\r
+ char Char = *pCurrent;\r
+ \r
+ MriTargetSendChar(Char);\r
+ Checksum += (unsigned char)Char;\r
+ pCurrent++;\r
+ }\r
+\r
+ MriTargetSendChar('#');\r
+ SendByteAsHex(Checksum);\r
+ } while (MriTargetReceiveChar() != '+');\r
+}\r
+\r
+\r
+\r
+/**************************************************************************************/\r
+/* Routines used to determine cause of exception trap and extract useful information. */\r
+/**************************************************************************************/\r
+static unsigned int GetCurrentlyExecutingExceptionNumber(void)\r
+{\r
+ return (MriGetIPSR() & 0xFF);\r
+}\r
+\r
+static unsigned char DetermineCauseOfDebugEvent(void)\r
+{\r
+ struct\r
+ {\r
+ unsigned int StatusBit;\r
+ unsigned char SignalToReturn;\r
+ } static const DebugEventToSignalMap[] =\r
+ {\r
+ {SCB_DFSR_EXTERNAL, SIGSTOP},\r
+ {SCB_DFSR_DWTTRAP, SIGTRAP},\r
+ {SCB_DFSR_BKPT, SIGTRAP},\r
+ {SCB_DFSR_HALTED, SIGTRAP}\r
+ };\r
+ unsigned int DebugFaultStatus = SCB->DFSR;\r
+ size_t i;\r
+ \r
+ for (i = 0 ; i < sizeof(DebugEventToSignalMap)/sizeof(DebugEventToSignalMap[0]) ; i++)\r
+ {\r
+ if (DebugFaultStatus & DebugEventToSignalMap[i].StatusBit)\r
+ {\r
+ SCB->DFSR = DebugEventToSignalMap[i].StatusBit;\r
+ return DebugEventToSignalMap[i].SignalToReturn;\r
+ }\r
+ }\r
+ \r
+ /* NOTE: Default catch all signal is SIGSTOP. */\r
+ return SIGSTOP;\r
+}\r
+\r
+static unsigned char DetermineCauseOfException(void)\r
+{\r
+ unsigned int ExceptionNumber = GetCurrentlyExecutingExceptionNumber();\r
+ \r
+ /* UNDONE: Might want to look at Fault Status Registers to better disambiguate cause of faults. For example you\r
+ can get a UsageFault for divide by 0 errors but today this code just returns SIGILL. */\r
+ switch(ExceptionNumber)\r
+ {\r
+ case 2:\r
+ /* NMI */\r
+ return SIGINT;\r
+ case 3:\r
+ /* HardFault */\r
+ return SIGSEGV;\r
+ case 4:\r
+ /* MemManage */\r
+ return SIGSEGV;\r
+ case 5:\r
+ /* BusFault */\r
+ return SIGBUS;\r
+ case 6:\r
+ /* UsageFault */\r
+ return SIGILL;\r
+ case 12:\r
+ /* Debug Monitor */\r
+ return DetermineCauseOfDebugEvent();\r
+ case 21:\r
+ /* UART0 */\r
+ return SIGINT;\r
+ default:\r
+ /* NOTE: Catch all signal will be SEGSTOP. */\r
+ return SIGSTOP;\r
+ }\r
+}\r
+\r
+static unsigned int IsUartInterrupt(void)\r
+{\r
+ return (21 == GetCurrentlyExecutingExceptionNumber());\r
+}\r
+\r
+\r
+\r
+/*********************************************/\r
+/* Routines to manipulate MRI state objects. */\r
+/*********************************************/\r
+static void SMriState_Init(SMriState* pState)\r
+{\r
+ memset(pState, 0, sizeof(*pState));\r
+ pState->SignalValue = DetermineCauseOfException();\r
+ pState->OriginalPC = g_MriContext.PC;\r
+ pState->OriginalPSRBitsToMaintain = g_MriContext.CPSR & PSR_STACK_ALIGN;\r
+ pState->MPUControlValueBeforeDisabling = GetMPUControlValue();\r
+}\r
+\r
+static void SMriState_InitBuffer(SMriState* pState)\r
+{\r
+ SBuffer_Init(&pState->Buffer, pState->InputOutputBuffer, sizeof(pState->InputOutputBuffer));\r
+}\r
+\r
+static void SMriState_PrepareStringResponse(SMriState* pState, const char* pErrorString)\r
+{\r
+ SMriState_InitBuffer(pState);\r
+ SBuffer_WriteString(&pState->Buffer, pErrorString);\r
+}\r
+\r
+static void SMriState_SendPacketToGDB(SMriState* pState)\r
+{\r
+ if (SBuffer_BufferOverrunDetected(&pState->Buffer))\r
+ {\r
+ SMriState_InitBuffer(pState);\r
+ SBuffer_WriteString(&pState->Buffer, MRI_ERROR_BUFFER_OVERRUN);\r
+ }\r
+\r
+ _SendPacketToGDB(&pState->Buffer);\r
+}\r
+\r
+static void SMriState_GetPacketFromGDB(SMriState* pState)\r
+{\r
+ char* pStartOfPacket;\r
+ \r
+ pStartOfPacket = _GetPacketFromGDB(pState->InputOutputBuffer, sizeof(pState->InputOutputBuffer));\r
+ SBuffer_Init(&pState->Buffer, pStartOfPacket, strlen(pStartOfPacket));\r
+}\r
+\r
+static void SMriState_PrepareForRestart(SMriState* pState)\r
+{\r
+ SetMPUControlValue(pState->MPUControlValueBeforeDisabling);\r
+ ClearDebuggerActiveFlag();\r
+}\r
+\r
+static int SMriState_IsDebugTrap(SMriState* pState)\r
+{\r
+ return (pState->SignalValue == SIGTRAP);\r
+}\r
+\r
+\r
+\r
+/*********************************************/\r
+/* Routines to handle hardcoded breakpoints. */\r
+/*********************************************/\r
+static int IsPCUnchanged(SMriState* pState)\r
+{\r
+ return (g_MriContext.PC == pState->OriginalPC);\r
+}\r
+\r
+static int DoesPCPointToHardCodedBreakpoint(void)\r
+{\r
+ static const unsigned short HardCodedBreakpointMachineCode = 0xbe00;\r
+ const unsigned short* pCurrentInstruction = (const unsigned short*)g_MriContext.PC;\r
+ \r
+ return (HardCodedBreakpointMachineCode == *pCurrentInstruction);\r
+}\r
+\r
+static int ShouldSkipHardcodedBreakpoint(SMriState* pState)\r
+{\r
+ return (IsPCUnchanged(pState) && DoesPCPointToHardCodedBreakpoint());\r
+}\r
+\r
+static int IsInstruction32Bit(unsigned short FirstWordOfInstruction)\r
+{\r
+ unsigned short MaskedOffUpper5BitsOfWord = FirstWordOfInstruction & 0xF800;\r
+ \r
+ /* 32-bit instructions start with 0b11101, 0b11110, 0b11111 according to page A5-152 of the \r
+ ARMv7-M Architecture Manual. */\r
+ if (MaskedOffUpper5BitsOfWord == 0xE800 ||\r
+ MaskedOffUpper5BitsOfWord == 0xF000 ||\r
+ MaskedOffUpper5BitsOfWord == 0xF800)\r
+ {\r
+ return 1;\r
+ }\r
+ else\r
+ {\r
+ return 0;\r
+ }\r
+}\r
+\r
+static void AdvanceToNextInstruction(void)\r
+{\r
+ unsigned short* pCurrentInstruction;\r
+ unsigned short FirstWordOfCurrentInstruction;\r
+ \r
+ pCurrentInstruction = (unsigned short*)g_MriContext.PC;\r
+ FirstWordOfCurrentInstruction = *pCurrentInstruction;\r
+ \r
+ if (IsInstruction32Bit(FirstWordOfCurrentInstruction))\r
+ {\r
+ /* 32-bit Instruction. */\r
+ g_MriContext.PC += 4;\r
+ }\r
+ else\r
+ {\r
+ /* 16-bit Instruction. */\r
+ g_MriContext.PC += 2;\r
+ }\r
+}\r
+\r
+\r
+\r
+/***************************************************/\r
+/* Routines to handle mbed semihost functionality. */\r
+/***************************************************/\r
+static int DoesPCPointToSemihostBreakpoint(void)\r
+{\r
+ static const unsigned short SemihostBreakpointMachineCode = 0xbeab;\r
+ const unsigned short* pCurrentInstruction = (const unsigned short*)g_MriContext.PC;\r
+ \r
+ return (SemihostBreakpointMachineCode == *pCurrentInstruction);\r
+}\r
+\r
+extern "C" int semihost_uid(unsigned char* pOutputBuffer);\r
+\r
+static int FetchAndSaveMbedUID(void)\r
+{\r
+ return semihost_uid(g_MriMbedUid);\r
+}\r
+\r
+static int HandleSemihostUidRequest(void)\r
+{\r
+ struct SUidParameters\r
+ {\r
+ unsigned char* pBuffer;\r
+ unsigned int BufferSize;\r
+ };\r
+ const SUidParameters* pParameters;\r
+ unsigned int CopySize;\r
+ \r
+ pParameters = (const SUidParameters*)g_MriContext.R1;\r
+ CopySize = pParameters->BufferSize;\r
+ if (CopySize > sizeof(g_MriMbedUid))\r
+ {\r
+ CopySize = sizeof(g_MriMbedUid);\r
+ }\r
+ memcpy(pParameters->pBuffer, g_MriMbedUid, CopySize);\r
+\r
+ return 0;\r
+}\r
+\r
+static int HandleSemihostRequest(void)\r
+{\r
+ unsigned int OpCode;\r
+ int ReturnCode;\r
+ \r
+ OpCode = g_MriContext.R0;\r
+ switch (OpCode)\r
+ {\r
+ case 257:\r
+ ReturnCode = HandleSemihostUidRequest();\r
+ break;\r
+ default:\r
+ return 0;\r
+ }\r
+ \r
+ AdvanceToNextInstruction();\r
+ \r
+ g_MriContext.R0 = ReturnCode;\r
+ return (ReturnCode != -1);\r
+}\r
+\r
+\r
+/***************************************************************************************************/\r
+/* Routines to read/write memory and detect any faults that might occur while attempting to do so. */\r
+/***************************************************************************************************/\r
+static void SetDebuggerActiveFlag(void)\r
+{\r
+ g_MriFlags |= MRI_FLAGS_ACTIVE_DEBUG;\r
+}\r
+\r
+static void ClearDebuggerActiveFlag(void)\r
+{\r
+ g_MriFlags &= ~MRI_FLAGS_ACTIVE_DEBUG;\r
+}\r
+\r
+static void ClearFaultDetectionFlag(void)\r
+{\r
+ g_MriFlags &= ~MRI_FLAGS_FAULT_DURING_DEBUG;\r
+}\r
+\r
+static int WasFaultDetected(void)\r
+{\r
+ return (g_MriFlags & MRI_FLAGS_FAULT_DURING_DEBUG);\r
+}\r
+\r
+static int ReadMemoryIntoHexBuffer(SBuffer* pBuffer,\r
+ const void* pvMemory, \r
+ int ReadByteCount)\r
+{\r
+ const volatile unsigned char* pMemory = (const volatile unsigned char*) pvMemory;\r
+ \r
+ ClearFaultDetectionFlag();\r
+\r
+ while (ReadByteCount-- > 0)\r
+ {\r
+ unsigned char Byte;\r
+ \r
+ Byte = *pMemory++;\r
+ if (WasFaultDetected())\r
+ {\r
+ /* Return false when memory access error is encountered. */\r
+ return 0;\r
+ }\r
+\r
+ SBuffer_WriteByteAsHex(pBuffer, Byte);\r
+ }\r
+\r
+ /* Return true on success. If pBuffer was overflown, SendPacketToGDB() will detect and return appropriate error. */\r
+ return 1;\r
+}\r
+\r
+static int WriteHexBufferToMemory(SBuffer* pBuffer, \r
+ void* pvMemory, \r
+ int WriteByteCount)\r
+{\r
+ volatile unsigned char* pMemory = (volatile unsigned char*)pvMemory;\r
+\r
+ ClearFaultDetectionFlag();\r
+\r
+ while (WriteByteCount-- > 0)\r
+ {\r
+ unsigned char Byte;\r
+ \r
+ if (!SBuffer_ReadByteAsHex(pBuffer, &Byte))\r
+ {\r
+ /* Return false when input hex buffer overflow is detected. */\r
+ return 0;\r
+ }\r
+\r
+ *pMemory++ = Byte;\r
+ if (WasFaultDetected())\r
+ {\r
+ /* Return false when memory access error is encountered. */\r
+ return 0;\r
+ }\r
+ }\r
+\r
+ /* Return true on successful write. */\r
+ return 1;\r
+}\r
+\r
+\r
+\r
+/***************************************************************/\r
+/* Routines to disable the debug interface on the mbed device. */\r
+/***************************************************************/\r
+static void DisableMbedInterface(void)\r
+{\r
+ static const unsigned int DebugDetachWaitTimeout = 5000;\r
+ \r
+ if (!IsDebuggerAttached())\r
+ {\r
+ /* mbed interface exists on JTAG bus so if no debugger, then no potential for mbed interface. */\r
+ return;\r
+ }\r
+ \r
+ FetchAndSaveMbedUID();\r
+ MriDisableMbed();\r
+ \r
+ if (WaitForDebuggerToDetach(DebugDetachWaitTimeout))\r
+ {\r
+ printf("Failed to disable mbed debug interface.\n");\r
+ g_MriFlags |= MRI_FLAGS_FAILED_MBED_DISABLE;\r
+ }\r
+ else\r
+ {\r
+ g_MriFlags |= MRI_FLAGS_MBED_DETECTED;\r
+ }\r
+}\r
+\r
+static int IsMbedDisabled(void)\r
+{\r
+ return !(g_MriFlags & MRI_FLAGS_FAILED_MBED_DISABLE);\r
+}\r
+\r
+\r
+\r
+/**********************************/\r
+/* GDB Command Handling Routines. */\r
+/**********************************/\r
+static void SendRegisterFor_T_Response(SBuffer* pBuffer, unsigned char RegisterOffset, unsigned int RegisterValue)\r
+{\r
+ SBuffer_WriteByteAsHex(pBuffer, RegisterOffset);\r
+ SBuffer_WriteChar(pBuffer, ':');\r
+ ReadMemoryIntoHexBuffer(pBuffer, &RegisterValue, sizeof(RegisterValue));\r
+ SBuffer_WriteChar(pBuffer, ';');\r
+}\r
+\r
+static void PrepareEmptyResponseForUnknownCommand(SMriState* pState)\r
+{\r
+ SMriState_InitBuffer(pState);\r
+}\r
+\r
+/* Sent when an exception occurs while program is executing because of previous 'c' (Continue) or 's' (Step) commands.\r
+\r
+ Data Format: Tssii:xxxxxxxx;ii:xxxxxxxx;...\r
+ \r
+ Where ss is the hex value of the signal which caused the exception.\r
+ ii is the hex offset of the 32-bit register value following the ':' The offset is relative to the register\r
+ contents in the g response packet and the SContext structure.\r
+ xxxxxxxx is the 32-bit value of the specified register in hex format.\r
+ The above ii:xxxxxxxx; patterns can be repeated for whichever register values should be sent with T repsonse.\r
+*/\r
+static unsigned int Send_T_StopResponse(SMriState* pState)\r
+{\r
+ SBuffer* pBuffer = &pState->Buffer;\r
+ \r
+ SMriState_InitBuffer(pState);\r
+ SBuffer_WriteChar(pBuffer, 'T');\r
+ SBuffer_WriteByteAsHex(pBuffer, pState->SignalValue);\r
+\r
+ SendRegisterFor_T_Response(pBuffer, CONTEXT_MEMBER_INDEX(R12), g_MriContext.R12);\r
+ SendRegisterFor_T_Response(pBuffer, CONTEXT_MEMBER_INDEX(SP), g_MriContext.SP);\r
+ SendRegisterFor_T_Response(pBuffer, CONTEXT_MEMBER_INDEX(LR), g_MriContext.LR);\r
+ SendRegisterFor_T_Response(pBuffer, CONTEXT_MEMBER_INDEX(PC), g_MriContext.PC);\r
+\r
+ SMriState_SendPacketToGDB(pState);\r
+\r
+ return HANDLER_RETURN_RETURN_IMMEDIATELY;\r
+}\r
+\r
+/* Handle the 'g' command which is to send the contents of the registers back to gdb.\r
+\r
+ Command Format: g\r
+ Response Format: xxxxxxxxyyyyyyyy...\r
+ \r
+ Where xxxxxxxx is the hexadecimal representation of the 32-bit R0 register.\r
+ yyyyyyyy is the hexadecimal representation of the 32-bit R1 register.\r
+ ... and so on through the members of the SContext structure.\r
+*/\r
+static unsigned int HandleRegisterReadCommand(SMriState* pState)\r
+{\r
+ SBuffer* pBuffer = &pState->Buffer;\r
+\r
+ SMriState_InitBuffer(pState);\r
+ ReadMemoryIntoHexBuffer(pBuffer, &g_MriContext, sizeof(g_MriContext));\r
+ return 0;\r
+}\r
+\r
+/* Handle the 'G' command which is to receive the new contents of the registers from gdb for the program to use when\r
+ it resumes execution.\r
+ \r
+ Command Format: Gxxxxxxxxyyyyyyyy...\r
+ Response Format: OK\r
+ \r
+ Where xxxxxxxx is the hexadecimal representation of the 32-bit R0 register.\r
+ yyyyyyyy is the hexadecimal representation of the 32-bit R1 register.\r
+ ... and so on through the members of the SContext structure.\r
+*/\r
+static unsigned int HandleRegisterWriteCommand(SMriState* pState)\r
+{\r
+ SBuffer* pBuffer = &pState->Buffer;\r
+ int Result;\r
+ unsigned int NewPSR;\r
+ \r
+ Result = WriteHexBufferToMemory(pBuffer, &g_MriContext, sizeof(g_MriContext));\r
+ NewPSR = g_MriContext.CPSR & (~PSR_STACK_ALIGN);\r
+ g_MriContext.CPSR = NewPSR | pState->OriginalPSRBitsToMaintain;\r
+ \r
+ SMriState_InitBuffer(pState);\r
+ if (!Result)\r
+ {\r
+ SBuffer_WriteString(pBuffer, MRI_ERROR_BUFFER_OVERRUN); \r
+ }\r
+ else\r
+ {\r
+ SBuffer_WriteString(pBuffer, "OK");\r
+ }\r
+ return 0;\r
+}\r
+\r
+/* Handle the 'm' command which is to read the specified address range from memory.\r
+\r
+ Command Format: mAAAAAAAA,LLLLLLLL\r
+ Response Format: xx...\r
+ \r
+ Where AAAAAAAA is the hexadecimal representation of the address where the read is to start.\r
+ LLLLLLLL is the hexadecimal representation of the length (in bytes) of the read to be conducted.\r
+ xx is the hexadecimal representation of the first byte read from the specified location.\r
+ ... continue returning the rest of LLLLLLLL-1 bytes in hexadecimal format.\r
+*/\r
+static unsigned int HandleMemoryReadCommand(SMriState* pState)\r
+{\r
+ SBuffer* pBuffer = &pState->Buffer;\r
+ unsigned int Address;\r
+ unsigned int Length;\r
+\r
+ if (SBuffer_ReadUIntegerAsHex(pBuffer, &Address) &&\r
+ SBuffer_IsNextCharEqualTo(pBuffer, ',') &&\r
+ SBuffer_ReadUIntegerAsHex(pBuffer, &Length))\r
+ {\r
+ SMriState_InitBuffer(pState);\r
+ if (!ReadMemoryIntoHexBuffer(pBuffer, (unsigned char *)Address, Length))\r
+ {\r
+ /* Received an exception while attempting to read from memory. */\r
+ SMriState_PrepareStringResponse(pState, MRI_ERROR_MEMORY_ACCESS_FAILURE);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ /* Failed parsing the m command arguments. */\r
+ SMriState_PrepareStringResponse(pState, MRI_ERROR_INVALID_ARGUMENT);\r
+ }\r
+ return 0;\r
+}\r
+\r
+/* Handle the 'm' command which is to read the specified address range from memory.\r
+\r
+ Command Format: mAAAAAAAA,LLLLLLLL\r
+ Response Format: xx...\r
+ \r
+ Where AAAAAAAA is the hexadecimal representation of the address where the read is to start.\r
+ LLLLLLLL is the hexadecimal representation of the length (in bytes) of the read to be conducted.\r
+ xx is the hexadecimal representation of the first byte read from the specified location.\r
+ ... continue returning the rest of LLLLLLLL-1 bytes in hexadecimal format.\r
+*/\r
+static unsigned int HandleMemoryWriteCommand(SMriState* pState)\r
+{\r
+ SBuffer* pBuffer = &pState->Buffer;\r
+ unsigned int Address;\r
+ unsigned int Length;\r
+\r
+ if (SBuffer_ReadUIntegerAsHex(pBuffer, &Address) &&\r
+ SBuffer_IsNextCharEqualTo(pBuffer, ',') &&\r
+ SBuffer_ReadUIntegerAsHex(pBuffer, &Length) &&\r
+ SBuffer_IsNextCharEqualTo(pBuffer, ':'))\r
+ {\r
+ if (WriteHexBufferToMemory(pBuffer, (unsigned char *)Address, Length))\r
+ {\r
+ /* Successfully wrote to memory so return OK response. */\r
+ SMriState_PrepareStringResponse(pState, "OK");\r
+ }\r
+ else\r
+ {\r
+ /* Received an exception while attempting to write to memory. */\r
+ SMriState_PrepareStringResponse(pState, MRI_ERROR_MEMORY_ACCESS_FAILURE);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ SMriState_PrepareStringResponse(pState, MRI_ERROR_INVALID_ARGUMENT);\r
+ }\r
+ return 0;\r
+}\r
+\r
+/* Handle the 'c' command which is sent from gdb to tell the debugger to continue execution of the currently halted\r
+ program.\r
+ \r
+ Command Format: cAAAAAAAA\r
+ Response Format: Blank until the next exception, at which time a 'T' stop response packet will be sent.\r
+\r
+ Where AAAAAAAA is an optional value to be used for the Program Counter when restarting the program.\r
+*/\r
+static unsigned int HandleContinueCommand(SMriState* pState)\r
+{\r
+ SBuffer* pBuffer = &pState->Buffer;\r
+ unsigned int Address;\r
+\r
+ if (ShouldSkipHardcodedBreakpoint(pState))\r
+ {\r
+ AdvanceToNextInstruction();\r
+ }\r
+\r
+ /* Try to read optional parameter, pc unchanged if no parm */\r
+ if (SBuffer_ReadUIntegerAsHex(pBuffer, &Address))\r
+ {\r
+ /* Update PC register with new address. */\r
+ g_MriContext.PC = Address;\r
+ }\r
+\r
+ return (HANDLER_RETURN_RESUME_PROGRAM | HANDLER_RETURN_RETURN_IMMEDIATELY);\r
+}\r
+\r
+/* Handle the "qSupported" command used by gdb to communicate state to debug monitor and vice versa.\r
+\r
+ Reponse Format: qXfer:memory-map:read+;PacketSize==SSSSSSSS\r
+ Where SSSSSSSS is the hexadecimal representation of the maximum packet size support by this stub.\r
+*/\r
+static unsigned int HandleQuerySupportedCommand(SMriState* pState)\r
+{\r
+ /* gdb includes # and 2 chars of checksum that are not placed in our buffer. */\r
+ static const unsigned int PacketSize = sizeof(SContext) + 3;\r
+ static const char QuerySupportResponse[] = "qXfer:memory-map:read+;PacketSize=";\r
+ SBuffer* pBuffer = &pState->Buffer;\r
+\r
+ SMriState_InitBuffer(pState);\r
+ SBuffer_WriteString(pBuffer, QuerySupportResponse);\r
+ SBuffer_WriteUIntegerAsHex(pBuffer, PacketSize);\r
+ \r
+ return 0;\r
+}\r
+\r
+/* Handle the "qXfer:memory-map" command used by gdb to read the device memory map from the stub.\r
+\r
+ Command Format: qXfer:memory-map:read::offset,length\r
+*/\r
+static unsigned int HandleQueryTransferMemoryMapCommand(SMriState* pState)\r
+{\r
+ SBuffer* pBuffer = &pState->Buffer;\r
+ unsigned int Offset;\r
+ unsigned int Length;\r
+ static const char ReadCommand[] = "read";\r
+ static const char MemoryMapXML[] = "<?xml version=\"1.0\"?>"\r
+ "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\" \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"\r
+ "<memory-map>"\r
+ "<memory type=\"flash\" start=\"0x0\" length=\"0x10000\"> <property name=\"blocksize\">0x1000</property></memory>" \r
+ "<memory type=\"flash\" start=\"0x10000\" length=\"0x70000\"> <property name=\"blocksize\">0x8000</property></memory>" \r
+ "<memory type=\"ram\" start=\"0x10000000\" length=\"0x8000\"> </memory>" \r
+ "<memory type=\"ram\" start=\"0x2007C000\" length=\"0x8000\"> </memory>" \r
+ "</memory-map>";\r
+ \r
+ if (SBuffer_IsNextCharEqualTo(pBuffer, ':') &&\r
+ SBuffer_MatchesString(pBuffer, ReadCommand, sizeof(ReadCommand)-1) &&\r
+ SBuffer_IsNextCharEqualTo(pBuffer, ':') &&\r
+ SBuffer_IsNextCharEqualTo(pBuffer, ':') &&\r
+ SBuffer_ReadUIntegerAsHex(pBuffer, &Offset) &&\r
+ SBuffer_IsNextCharEqualTo(pBuffer, ',') &&\r
+ SBuffer_ReadUIntegerAsHex(pBuffer, &Length))\r
+ {\r
+ char DataPrefixChar = 'm';\r
+ unsigned int OutputBufferSize;\r
+ unsigned int ValidMemoryMapBytes;\r
+ \r
+ if (Offset >= (sizeof(MemoryMapXML) - 1))\r
+ {\r
+ /* Attempt to read past end of XML content so flag with a l only packet. */\r
+ DataPrefixChar = 'l';\r
+ Length = 0;\r
+ ValidMemoryMapBytes = 0;\r
+ }\r
+ else\r
+ {\r
+ ValidMemoryMapBytes = (sizeof(MemoryMapXML) - 1) - Offset;\r
+ }\r
+ \r
+ SMriState_InitBuffer(pState);\r
+ OutputBufferSize = SBuffer_BytesLeft(pBuffer);\r
+\r
+ if (Length > OutputBufferSize)\r
+ {\r
+ Length = OutputBufferSize;\r
+ }\r
+ if (Length > ValidMemoryMapBytes)\r
+ {\r
+ DataPrefixChar = 'l';\r
+ Length = ValidMemoryMapBytes;\r
+ }\r
+ \r
+ SBuffer_WriteChar(pBuffer, DataPrefixChar);\r
+ SBuffer_WriteSizedString(pBuffer, &MemoryMapXML[Offset], Length);\r
+\r
+ return 0;\r
+ }\r
+ else\r
+ {\r
+ SMriState_PrepareStringResponse(pState, MRI_ERROR_INVALID_ARGUMENT);\r
+ return 0;\r
+ }\r
+}\r
+\r
+/* Handle the "qXfer" command used by gdb to transfer data to and from the stub for special functionality.\r
+\r
+ Command Format: qXfer:object:read:annex:offset,length\r
+ Where supported objects are currently:\r
+ memory-map\r
+*/\r
+static unsigned int HandleQueryTransferCommand(SMriState* pState)\r
+{\r
+ SBuffer* pBuffer = &pState->Buffer;\r
+ static const char MemoryMapObject[] = "memory-map";\r
+ \r
+ if (!SBuffer_IsNextCharEqualTo(pBuffer, ':'))\r
+ {\r
+ SMriState_PrepareStringResponse(pState, MRI_ERROR_INVALID_ARGUMENT);\r
+ return 0;\r
+ }\r
+ \r
+ if (SBuffer_MatchesString(pBuffer, MemoryMapObject, sizeof(MemoryMapObject)-1))\r
+ {\r
+ return HandleQueryTransferMemoryMapCommand(pState);\r
+ }\r
+ else\r
+ {\r
+ PrepareEmptyResponseForUnknownCommand(pState);\r
+ return 0;\r
+ }\r
+}\r
+\r
+/* Handle the 'q' command used by gdb to communicate state to debug monitor and vice versa.\r
+\r
+ Command Format: qSSS\r
+ Where SSS is a variable length string indicating which query command is being sent to the stub.\r
+*/\r
+static unsigned int HandleQueryCommand(SMriState* pState)\r
+{\r
+ SBuffer* pBuffer = &pState->Buffer;\r
+ static const char qSupportedCommand[] = "Supported";\r
+ static const char qXferCommand[] = "Xfer";\r
+ \r
+ if (SBuffer_MatchesString(pBuffer, qSupportedCommand, sizeof(qSupportedCommand)-1))\r
+ {\r
+ return HandleQuerySupportedCommand(pState);\r
+ }\r
+ else if (SBuffer_MatchesString(pBuffer, qXferCommand, sizeof(qXferCommand)-1))\r
+ {\r
+ return HandleQueryTransferCommand(pState);\r
+ }\r
+ else\r
+ {\r
+ PrepareEmptyResponseForUnknownCommand(pState);\r
+ return 0;\r
+ }\r
+}\r
+\r
+static int Is32BitInstructionKind(char Kind, int* pIs32BitInstruction)\r
+{\r
+ switch (Kind)\r
+ {\r
+ case '2':\r
+ *pIs32BitInstruction = 0;\r
+ return 1;\r
+ case '3':\r
+ case '4':\r
+ *pIs32BitInstruction = 1;\r
+ return 1;\r
+ default:\r
+ *pIs32BitInstruction = 0;\r
+ return 0;\r
+ }\r
+}\r
+\r
+static int ParseBreakpointWatchpointCommandArguments(SMriState* pState, SBreakpointWatchpointArguments* pArguments)\r
+{\r
+ SBuffer* pBuffer = &pState->Buffer;\r
+ char Kind;\r
+ \r
+ if (SBuffer_ReadChar(pBuffer, &pArguments->Type) &&\r
+ SBuffer_IsNextCharEqualTo(pBuffer, ',') &&\r
+ SBuffer_ReadUIntegerAsHex(pBuffer, &pArguments->Address) &&\r
+ SBuffer_IsNextCharEqualTo(pBuffer, ',') &&\r
+ SBuffer_ReadChar(pBuffer, &Kind) &&\r
+ Is32BitInstructionKind(Kind, &pArguments->Is32BitInstruction))\r
+ {\r
+ return 1;\r
+ }\r
+ else\r
+ {\r
+ SMriState_PrepareStringResponse(pState, MRI_ERROR_INVALID_ARGUMENT);\r
+ return 0;\r
+ }\r
+}\r
+\r
+/* Handle the '"Z0" command used by gdb to set hardware breakpoints.\r
+\r
+ Command Format: Z0,AAAAAAAA,K\r
+ Response Format: OK\r
+ Where AAAAAAAA is the hexadecimal representation of the address on which the breakpoint should be set.\r
+ K is either 2: 16-bit Thumb instruction.\r
+ 3: 32-bit Thumb2 instruction.\r
+ 4: 32-bit ARM insruction.\r
+*/\r
+static void HandleHardwareBreakpointSetCommand(SMriState* pState, SBreakpointWatchpointArguments* pArguments)\r
+{\r
+ SBuffer* pBuffer = &pState->Buffer;\r
+ uint32_t* pFPBBreakpointComparator;\r
+ \r
+ SMriState_InitBuffer(pState);\r
+\r
+ pFPBBreakpointComparator = EnableFPBBreakpoint(pArguments->Address, pArguments->Is32BitInstruction);\r
+ if (!pFPBBreakpointComparator)\r
+ {\r
+ SBuffer_WriteString(pBuffer, MRI_ERROR_NO_FREE_BREAKPOINT);\r
+ }\r
+ else\r
+ {\r
+ SBuffer_WriteString(pBuffer, "OK");\r
+ }\r
+}\r
+\r
+/* Handle the '"z0" command used by gdb to remove hardware breakpoints.\r
+\r
+ Command Format: z0,AAAAAAAA,K\r
+ Response Format: OK\r
+ Where AAAAAAAA is the hexadecimal representation of the address on which the breakpoint should be removed.\r
+ K is either 2: 16-bit Thumb instruction.\r
+ 3: 32-bit Thumb2 instruction.\r
+ 4: 32-bit ARM insruction.\r
+*/\r
+static void HandleHardwareBreakpointRemoveCommand(SMriState* pState, SBreakpointWatchpointArguments* pArguments)\r
+{\r
+ DisableFPBBreakpointComparator(pArguments->Address, pArguments->Is32BitInstruction);\r
+ SMriState_PrepareStringResponse(pState, "OK");\r
+}\r
+\r
+/* Handle the Z* commands which can be used to set breakpoints and watchpoints. */\r
+static unsigned int HandleBreakpointWatchpointSetCommand(SMriState* pState)\r
+{\r
+ SBreakpointWatchpointArguments Arguments;\r
+ \r
+ if (!ParseBreakpointWatchpointCommandArguments(pState, &Arguments))\r
+ {\r
+ return 0;\r
+ }\r
+ \r
+ switch(Arguments.Type)\r
+ {\r
+ case '1':\r
+ HandleHardwareBreakpointSetCommand(pState, &Arguments);\r
+ break;\r
+ default:\r
+ PrepareEmptyResponseForUnknownCommand(pState);\r
+ break;\r
+ }\r
+ \r
+ return 0;\r
+}\r
+\r
+/* Handle the z* commands which can be used to remove breakpoints and watchpoints. */\r
+static unsigned int HandleBreakpointWatchpointRemoveCommand(SMriState* pState)\r
+{\r
+ SBreakpointWatchpointArguments Arguments;\r
+ \r
+ if (!ParseBreakpointWatchpointCommandArguments(pState, &Arguments))\r
+ {\r
+ return 0;\r
+ }\r
+ \r
+ switch(Arguments.Type)\r
+ {\r
+ case '1':\r
+ HandleHardwareBreakpointRemoveCommand(pState, &Arguments);\r
+ break;\r
+ default:\r
+ PrepareEmptyResponseForUnknownCommand(pState);\r
+ break;\r
+ }\r
+ \r
+ return 0;\r
+}\r
+\r
+/* Handle the 's' command which is sent from gdb to tell the debugger to single step over the next instruction in the\r
+ currently halted program.\r
+ \r
+ Command Format: sAAAAAAAA\r
+ Response Format: Blank until the next exception, at which time a 'T' stop response packet will be sent.\r
+\r
+ Where AAAAAAAA is an optional value to be used for the Program Counter when restarting the program.\r
+*/\r
+static unsigned int HandleSingleStepCommand(SMriState* pState)\r
+{\r
+ /* Single step is pretty much like continue except processor is told to only execute 1 instruction. */\r
+ HandleContinueCommand(pState);\r
+ EnableSingleStep();\r
+\r
+ return (HANDLER_RETURN_RESUME_PROGRAM | HANDLER_RETURN_RETURN_IMMEDIATELY);\r
+}\r
+\r
+static int HandleGDBCommand(SMriState* pState)\r
+{\r
+ SBuffer* pBuffer = &pState->Buffer;\r
+ unsigned int HandlerResult = 0;\r
+ char CommandChar;\r
+ size_t i;\r
+ static const struct\r
+ {\r
+ unsigned int (*Handler)(SMriState*);\r
+ char CommandChar;\r
+ } CommandTable[] =\r
+ {\r
+ {Send_T_StopResponse, '?'},\r
+ {HandleContinueCommand, 'c'},\r
+ {HandleRegisterReadCommand, 'g'},\r
+ {HandleRegisterWriteCommand, 'G'},\r
+ {HandleMemoryReadCommand, 'm'},\r
+ {HandleMemoryWriteCommand, 'M'},\r
+ {HandleQueryCommand, 'q'},\r
+ {HandleSingleStepCommand, 's'},\r
+ {HandleBreakpointWatchpointRemoveCommand, 'z'},\r
+ {HandleBreakpointWatchpointSetCommand, 'Z'}\r
+ };\r
+ \r
+ SMriState_GetPacketFromGDB(pState);\r
+ \r
+ SBuffer_ReadChar(pBuffer, &CommandChar);\r
+ for (i = 0 ; i < ARRAY_SIZE(CommandTable) ; i++)\r
+ {\r
+ if (CommandTable[i].CommandChar == CommandChar)\r
+ {\r
+ HandlerResult = CommandTable[i].Handler(pState);\r
+ if (HandlerResult & HANDLER_RETURN_RETURN_IMMEDIATELY)\r
+ {\r
+ return HandlerResult & HANDLER_RETURN_RESUME_PROGRAM;\r
+ }\r
+ else\r
+ {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ if (ARRAY_SIZE(CommandTable) == i)\r
+ {\r
+ PrepareEmptyResponseForUnknownCommand(pState);\r
+ }\r
+\r
+ SMriState_SendPacketToGDB(pState);\r
+ return (HandlerResult & HANDLER_RETURN_RESUME_PROGRAM);\r
+}\r
+\r
+\r
+\r
+/********************/\r
+/* Public routines. */\r
+/********************/\r
+extern "C" void MriInit(void)\r
+{\r
+ DisableMbedInterface();\r
+ if (!IsMbedDisabled())\r
+ {\r
+ /* UNDONE: Remove and flag as subsequent error on gdb commands */\r
+ printf("Exiting MriInit() because of failure to disable mbed device.\n");\r
+ return;\r
+ }\r
+ \r
+ /* UNDONE: Do I need to enable TRACE in the DEMCR to use the DWT or just for it to trace? */\r
+ InitDWT();\r
+ InitFPB();\r
+ \r
+ DisableSingleStep();\r
+ ClearMonitorPending();\r
+ EnableDebugMonitorAtPriority0();\r
+ InitUart();\r
+}\r
+\r
+\r
+extern "C" void MriDebugException(void)\r
+{\r
+ int StartDebuggeeUpAgain;\r
+ \r
+ SetDebuggerActiveFlag();\r
+ if (IsUartInterrupt() && !ControlCDetected())\r
+ {\r
+ /* Just return to active program if gdb sent characters which weren't CTRL+C */\r
+ ClearDebuggerActiveFlag();\r
+ return;\r
+ }\r
+ \r
+ DisableSingleStep();\r
+ ClearMonitorPending();\r
+ SMriState_Init(&g_MriState);\r
+ DisableMPU();\r
+ \r
+ if (SMriState_IsDebugTrap(&g_MriState) && \r
+ DoesPCPointToSemihostBreakpoint() && \r
+ HandleSemihostRequest())\r
+ {\r
+ SMriState_PrepareForRestart(&g_MriState);\r
+ return;\r
+ }\r
+ \r
+ Send_T_StopResponse(&g_MriState);\r
+ do\r
+ {\r
+ StartDebuggeeUpAgain = HandleGDBCommand(&g_MriState);\r
+ } while (!StartDebuggeeUpAgain);\r
+\r
+ SMriState_PrepareForRestart(&g_MriState);\r
+}\r