@@ -52,6 +52,12 @@ extern "C"
5252// Thread syncronization flag used to indicate that a debug event has occured.
5353#define MRI_THREAD_DEBUG_EVENT_FLAG (1 << 0 )
5454
55+ // Lower nibble of EXC_RETURN in LR will have one of these values if interrupted code was running in thread mode.
56+ // Using PSP.
57+ #define EXC_RETURN_THREADMODE_PROCESSSTACK 0xD
58+ // Using MSP.
59+ #define EXC_RETURN_THREADMODE_MAINSTACK 0x9
60+
5561
5662// Assert routine that will dump error text to GDB connection before entering infinite loop. If user is logging MRI
5763// remote communications then they will see the error text in the log before debug stub becomes unresponseive.
@@ -73,9 +79,6 @@ extern "C"
7379// Flag to verify that only one ThreadMRI object has been initialized.
7480static bool g_alreadyInitialized;
7581
76- // The ID of the mriMain() thread.
77- static osThreadId_t g_mriThreadId;
78-
7982// The ID of the halted thread being debugged.
8083static volatile osThreadId_t g_haltedThreadId;
8184
@@ -88,7 +91,10 @@ static uint32_t g_threadCount;
8891
8992// This flag is set to a non-zero value if the DebugMon handler is to re-enable DWT watchpoints and FPB breakpoints
9093// after being disabled by the HardFault handler when a debug event is encounted in handler mode.
91- static volatile uint32_t g_enableDWTandFPB;
94+ static volatile uint32_t g_enableDWTandFPB;
95+
96+ // The ID of the mriMain() thread.
97+ volatile osThreadId_t mriThreadId;
9298
9399// If non-NULL, this is the thread that we want to single step.
94100// If NULL, single stepping is not enabled.
@@ -132,11 +138,20 @@ static void resumeApplicationThreads();
132138static void readThreadContext (osThreadId_t thread);
133139static void switchRtxHandlersToDebugStubsForSingleStepping ();
134140static void restoreRtxHandlers ();
141+ static void setDebugActiveFlag ();
142+ static void clearDebugActiveFlag ();
143+ static bool isThreadMode (uint32_t excReturn);
135144static bool hasEncounteredDebugEvent ();
136145static void recordAndClearFaultStatusBits ();
137146static void wakeMriMainToDebugCurrentThread ();
138147static void stopSingleStepping ();
139148static void recordAndSwitchFaultHandlersToDebugger ();
149+ static bool isDebugThreadActive ();
150+ static void setFaultDetectedFlag ();
151+ static bool isImpreciseBusFault ();
152+ static void advancePCToNextInstruction (uint32_t excReturn, uint32_t psp, uint32_t msp);
153+ static uint32_t * threadSP (uint32_t excReturn, uint32_t psp, uint32_t msp);
154+ static bool isInstruction32Bit (uint16_t firstWordOfInstruction);
140155
141156
142157
@@ -166,8 +181,8 @@ bool ThreadMRI::begin()
166181 .stack_size = sizeof (stack),
167182 .priority = osPriorityNormal
168183 };
169- g_mriThreadId = osThreadNew (mriMain, NULL , &threadAttr);
170- if (g_mriThreadId == NULL ) {
184+ mriThreadId = osThreadNew (mriMain, NULL , &threadAttr);
185+ if (mriThreadId == NULL ) {
171186 return false ;
172187 }
173188 g_alreadyInitialized = true ;
@@ -189,11 +204,13 @@ static __NO_RETURN void mriMain(void *pv)
189204 if (Platform_IsSingleStepping ()) {
190205 restoreRtxHandlers ();
191206 }
207+ setDebugActiveFlag ();
192208
193209 osThreadSetPriority (osThreadGetId (), osPriorityNormal);
194210 mriDebugException ();
195211 osThreadSetPriority (osThreadGetId (), osPriorityRealtime7);
196212
213+ clearDebugActiveFlag ();
197214 if (Platform_IsSingleStepping ()) {
198215 mriThreadSingleStepThreadId = g_haltedThreadId;
199216 switchRtxHandlersToDebugStubsForSingleStepping ();
@@ -214,7 +231,7 @@ static void suspendAllApplicationThreads()
214231 osThreadId_t thread = g_suspendedThreads[i];
215232 const char * pThreadName = osThreadGetName (thread);
216233
217- if (thread != g_mriThreadId && strcmp (pThreadName, " rtx_idle" ) != 0 ) {
234+ if (thread != mriThreadId && strcmp (pThreadName, " rtx_idle" ) != 0 ) {
218235 osThreadSuspend (thread);
219236 }
220237 else {
@@ -298,6 +315,15 @@ static void restoreRtxHandlers()
298315 NVIC_SetVector (SysTick_IRQn, mriThreadOrigSysTick);
299316}
300317
318+ static void setDebugActiveFlag ()
319+ {
320+ mriCortexMState.flags |= CORTEXM_FLAGS_ACTIVE_DEBUG;
321+ }
322+
323+ static void clearDebugActiveFlag ()
324+ {
325+ mriCortexMState.flags &= ~CORTEXM_FLAGS_ACTIVE_DEBUG;
326+ }
301327
302328
303329
@@ -427,9 +453,7 @@ int Semihost_HandleSemihostRequest(void)
427453// ---------------------------------------------------------------------------------------------------------------------
428454extern " C" void mriDebugMonitorHandler (uint32_t excReturn)
429455{
430- excReturn &= 0xF ;
431- bool isThreadMode = (excReturn == 0xD || excReturn == 0x9 );
432- while (!isThreadMode) {
456+ while (!isThreadMode (excReturn)) {
433457 // DebugMon is running at such low priority that we should be getting ready to return to thread mode.
434458 }
435459
@@ -461,11 +485,20 @@ extern "C" void mriDebugMonitorHandler(uint32_t excReturn)
461485
462486// This function is called if a fault (hard, mem, bus, usage) has occurred while running code in thread mode.
463487// It is also called when a debug event has forced a hard fault while running code in handler mode.
464- extern " C" void mriFaultHandler (uint32_t excReturn)
488+ extern " C" void mriFaultHandler (uint32_t excReturn, uint32_t psp, uint32_t msp )
465489{
466- excReturn &= 0xF ;
467- bool isThreadMode = (excReturn == 0xD || excReturn == 0x9 );
468- if (isThreadMode) {
490+ if (isThreadMode (excReturn)) {
491+ if (isDebugThreadActive ()) {
492+ // Encountered memory fault when GDB attempted to access an invalid address.
493+ // Set flag to let debugger thread know that its access failed and advance past the faulting instruction
494+ // if it was a precise bus fault so that it doesn't just occur again on return.
495+ setFaultDetectedFlag ();
496+ if (!isImpreciseBusFault ()) {
497+ advancePCToNextInstruction (excReturn, psp, msp);
498+ }
499+ return ;
500+ }
501+
469502 // A crash has been detected in thread mode. Wake debugger thread to debug it.
470503 recordAndClearFaultStatusBits ();
471504 stopSingleStepping ();
@@ -483,6 +516,12 @@ extern "C" void mriFaultHandler(uint32_t excReturn)
483516 setMonitorPending ();
484517}
485518
519+ static bool isThreadMode (uint32_t excReturn)
520+ {
521+ excReturn &= 0xF ;
522+ return excReturn == EXC_RETURN_THREADMODE_PROCESSSTACK || excReturn == EXC_RETURN_THREADMODE_MAINSTACK;
523+ }
524+
486525static bool hasEncounteredDebugEvent ()
487526{
488527 return SCB->DFSR != 0 ;
@@ -509,11 +548,61 @@ static void wakeMriMainToDebugCurrentThread()
509548 disableSingleStep ();
510549 g_debugThreadId = osThreadGetId ();
511550 g_haltedThreadId = g_debugThreadId; // UNDONE: osThreadGetId();
512- osThreadFlagsSet (g_mriThreadId , MRI_THREAD_DEBUG_EVENT_FLAG);
551+ osThreadFlagsSet (mriThreadId , MRI_THREAD_DEBUG_EVENT_FLAG);
513552}
514553
515554static void stopSingleStepping ()
516555{
517556 disableSingleStep ();
518557 mriThreadSingleStepThreadId = NULL ;
519558}
559+
560+ static bool isDebugThreadActive ()
561+ {
562+ return (mriCortexMState.flags & CORTEXM_FLAGS_ACTIVE_DEBUG) && mriThreadId == osThreadGetId ();
563+ }
564+
565+ static void setFaultDetectedFlag ()
566+ {
567+ mriCortexMState.flags |= CORTEXM_FLAGS_FAULT_DURING_DEBUG;
568+ }
569+
570+ static bool isImpreciseBusFault ()
571+ {
572+ return SCB->CFSR & SCB_CFSR_IMPRECISERR_Msk;
573+ }
574+
575+ static void advancePCToNextInstruction (uint32_t excReturn, uint32_t psp, uint32_t msp)
576+ {
577+ uint32_t * pSP = threadSP (excReturn, psp, msp);
578+ uint32_t * pPC = pSP + 7 ;
579+ uint16_t currentInstruction = *(uint16_t *)pPC;
580+ if (isInstruction32Bit (currentInstruction)) {
581+ *pPC += sizeof (uint32_t );
582+ } else {
583+ *pPC += sizeof (uint16_t );
584+ }
585+ }
586+
587+ static uint32_t * threadSP (uint32_t excReturn, uint32_t psp, uint32_t msp)
588+ {
589+ uint32_t sp;
590+ if ((excReturn & 0xF ) == EXC_RETURN_THREADMODE_PROCESSSTACK) {
591+ sp = psp;
592+ } else {
593+ sp = msp;
594+ }
595+ return (uint32_t *)sp;
596+ }
597+
598+
599+ static bool isInstruction32Bit (uint16_t firstWordOfInstruction)
600+ {
601+ uint16_t maskedOffUpper5BitsOfWord = firstWordOfInstruction & 0xF800 ;
602+
603+ // 32-bit instructions start with 0b11101, 0b11110, 0b11111 according to page A5-152 of the
604+ // ARMv7-M Architecture Manual.
605+ return (maskedOffUpper5BitsOfWord == 0xE800 ||
606+ maskedOffUpper5BitsOfWord == 0xF000 ||
607+ maskedOffUpper5BitsOfWord == 0xF800 );
608+ }
0 commit comments