Skip to content

Commit 1dbfa6a

Browse files
committed
Fix vCont multi-threading support
Updates MRI core to version 1.1-20200510-0. Refactored the vCont multi-threading support again to better handle any combination of continue and/or stepping actions that are sent from GDB in a single vCont command. This includes a modification to requirements for ports implementing Platform_RtosSetThreadState() to now support a thread-id of MRI_PLATFORM_ALL_FROZEN_THREADS. This new special thread-id indicates to the port that it should update the state of any threads still in the initial frozen state after the previously parsed vCont actions have been applied. Ports now also have to implement a Platform_RtosRestorePrevThreadState() API to restore the state of the threads to match the way they were configured after the last exit from mriDebugException(). This is used to restore the thawed/single-stepping state of threads while stepping through a range of addresses. This pushes the responsibility to know how each thread was configured at the beginning of a ranged single step onto the port instead of the MRI core where it tried to maintain it unsuccessfully before. The big change in this commit is that vCont now parses its parameters twice when a port supports Platform_RtosSetThreadState(). On the first pass it is checking for parsing errors and determining the most specific continue or single step action to apply to the currently halted thread. This action is used to determine if the halted thread should be advanced past a hard coded breakpoint and if single stepping over a hardcoded breakpoint on the halted thread, it is enough to send GDB a T packet and continue GDB command handling rather than actually continuing execution in single step mode. The second pass is used to call the Platform_RtosSetThreadState() for each action encountered in the vCont command from GDB, letting the port's implementation manage the resulting list of states for all of the threads and the MRI core only needs to remember if it needs to enable single stepping or not. This makes it much easier to handle an arbirary list of actions sent from GDB and the core now needs to make very few assumptions about the nature of the action lists (the count, order, combination of continue and single step, etc). I did need to increase the size of the mriDebuggerStack as the vCont handler itself now uses 100 bytes of stack while parsing the action list sent by GDB. Only fill mriCortexMDebuggerStack @ init. Was previously filling it before every entry into MRI but really only needs to be done once from mriCortexMInit(). I also made some other KernelDebug/ThreadDebug updates while code reviewing and running a test pass on the latest MRI updates: * Renamed the DEBUG_*_BREAK_ON_SETUP defines to DEBUG_*_BREAK_IN_SETUP. * Cleaned up some comments in the ThreadDebug sources. * I decreased IDLE_THREAD_STACK_SIZE to free up space that was found to not be required by mriIdle() thread while running the test pass. * Switched ThreadList::findThreadId() to use a binary search instead of a linear search. * mriDebugMonitorHandler() always checks to see if it needs to re-enable DTW/FPB. There is no reason to skip this check. * Added a g_controlC flag in addition to the control C flag in MRI itself since the flag in MRI doesn't get cleared until leaving mriDebugException(). There were race conditions that as breakpoints were enabled by GDB, they would fire and mriDebugMonitorHandler() would think that CTRL+C had just been sent when it hadn't. * Related to the previous item, I updated mriDebugMonitorHandler() to ignore debug events that occur while inside MRI since GDB itself may read from addresses on which it has read watchpoints and we want to ignore such debug events.
1 parent c045878 commit 1dbfa6a

File tree

15 files changed

+266
-149
lines changed

15 files changed

+266
-149
lines changed

Diff for: libraries/KernelDebug/examples/KernelDebug/KernelDebug.ino

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
#include <KernelDebug.h>
77

8-
KernelDebug kernelDebug(SERIAL1_TX, SERIAL1_RX, USART1_IRQn, 230400, DEBUG_BREAK_ON_SETUP);
8+
KernelDebug kernelDebug(SERIAL1_TX, SERIAL1_RX, USART1_IRQn, 230400, DEBUG_BREAK_IN_SETUP);
99

1010
void setup() {
1111

Diff for: libraries/KernelDebug/src/KernelDebug.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -612,3 +612,7 @@ int Platform_RtosIsSetThreadStateSupported(void)
612612
void Platform_RtosSetThreadState(uint32_t threadId, PlatformThreadState state)
613613
{
614614
}
615+
616+
void Platform_RtosRestorePrevThreadState(void)
617+
{
618+
}

Diff for: libraries/KernelDebug/src/KernelDebug.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,17 @@
3636
namespace arduino {
3737

3838
// Pass as breakInSetup parameter of constructor to halt in setup().
39-
#define DEBUG_BREAK_ON_SETUP true
39+
#define DEBUG_BREAK_IN_SETUP true
4040
// Pass as breakInSetup parameter of constructors to NOT halt in setup().
41-
#define DEBUG_NO_BREAK_ON_SETUP false
41+
#define DEBUG_NO_BREAK_IN_SETUP false
4242

4343

4444
class KernelDebug {
4545
public:
4646
// You must declare your KernelDebug object as a global.
4747
// Example:
4848
// KernelDebug debug(SERIAL1_TX, SERIAL1_RX, USART1_IRQn, 230400, DEBUG_BREAK_ON_SETUP);
49-
KernelDebug(PinName txPin, PinName rxPin, IRQn_Type irq, uint32_t baudRate=230400, bool breakInSetup=DEBUG_BREAK_ON_SETUP);
49+
KernelDebug(PinName txPin, PinName rxPin, IRQn_Type irq, uint32_t baudRate=230400, bool breakInSetup=DEBUG_BREAK_IN_SETUP);
5050

5151
// You should never let your DebugSerial object go out of scope. Make it global or static. To warn you if you do
5252
// let it go out of scope by mistake, this destructor will break into GDB and then enter an infinite loop.

Diff for: libraries/KernelDebug/src/armv7-m_asm.S

+4-10
Original file line numberDiff line numberDiff line change
@@ -109,20 +109,14 @@ mriExceptionHandler:
109109
bl mriCortexHandleDebuggerFault
110110
pop {r1, pc}
111111

112-
/* Fill debugger stack with 0xDEADBEEF before switching MSP to it. */
112+
/* Point R0 to the top of the debugger stack, where MSP should be pointed. */
113113
1$: ldr r0, =mriCortexMDebuggerStack
114-
ldr r1, =CORTEXM_DEBUGGER_STACK_FILL
115-
mov r2, r1
116-
ldr r3, =CORTEXM_DEBUGGER_STACK_SIZE
117-
2$: cbz r3, 3$
118-
strd r1, r2, [r0], #8
119-
subs r3, #1
120-
b 2$
121-
/* R0 is now pointing to top of stack, where MSP should be pointed to. */
114+
ldr r1, =CORTEXM_DEBUGGER_STACK_SIZE * 8
115+
add r0, r0, r1
122116

123117
/* Save away copy of MSP value at the time of the fault into R0. */
124118
3$: mrs r1, msp
125-
/* Set MSP to top of debugger stack returned from mriCortexMDebuggerStack. */
119+
/* Set MSP to top of debugger stack. */
126120
msr msp, r0
127121

128122
/* Saving integer registers to debugger stack. */

Diff for: libraries/MRI/src/architectures/armv7-m/armv7-m.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@
4646
*/
4747
#define CORTEXM_DEBUGGER_STACK_FILL 0xDEADBEEF
4848
#if MRI_DEVICE_HAS_FPU
49-
#define CORTEXM_DEBUGGER_STACK_SIZE 180
49+
#define CORTEXM_DEBUGGER_STACK_SIZE 193
5050
#else
51-
#define CORTEXM_DEBUGGER_STACK_SIZE 45
51+
#define CORTEXM_DEBUGGER_STACK_SIZE 58
5252
#endif
5353

5454

Diff for: libraries/MRI/src/architectures/armv7-m/armv7-m.x

+11
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ static const char g_targetXml[] =
131131
void mriExceptionHandler(void);
132132

133133

134+
static void fillDebuggerStack(void);
134135
static void clearState(void);
135136
static void determineSubPriorityBitCount(void);
136137
static void configureDWTandFPB(void);
@@ -147,6 +148,7 @@ void mriCortexMInit(Token* pParameterTokens, uint8_t debugMonPriority, IRQn_Type
147148
}
148149
(void)pParameterTokens;
149150

151+
fillDebuggerStack();
150152
clearState();
151153
determineSubPriorityBitCount();
152154
configureDWTandFPB();
@@ -163,6 +165,15 @@ void mriCortexMInit(Token* pParameterTokens, uint8_t debugMonPriority, IRQn_Type
163165
enableDebugMonitorAtSpecifiedPriority(debugMonPriority);
164166
}
165167

168+
static void fillDebuggerStack(void)
169+
{
170+
uint64_t fillValue = ((uint64_t)CORTEXM_DEBUGGER_STACK_FILL << 32) | (uint64_t)CORTEXM_DEBUGGER_STACK_FILL;
171+
size_t i;
172+
173+
for (i = 0 ; i < sizeof(mriCortexMDebuggerStack)/sizeof(mriCortexMDebuggerStack[0]) ; i++)
174+
mriCortexMDebuggerStack[i] = fillValue;
175+
}
176+
166177
static void clearState(void)
167178
{
168179
memset(&mriCortexMState, 0, sizeof(mriCortexMState));

0 commit comments

Comments
 (0)