Skip to content

Commit 25d4290

Browse files
committed
Add detach and monitor support
The "detach" command allows GDB to detach from a running program linked with MRI. It causes the debuggee to resume execution and then the user can exit GDB with the program on the embedded device in a running state whereas today it would remain halted when GDB disconnects. Added support for the following "monitor" commands: * "monitor help" - Lists the currently supported monitor commands to the GDB console. Issuing an unknown monitor command will also display this help list. * "monitor showfault" - This command will dump information about the current fault to the GDB console just like what happens if already connected when the fault occurs. This is useful if you are attaching GDB after the fault happens. * "monitor reset" - After issuing this command in GDB the microcontroller will reset on the next "continue" or "detach". This doesn't work well when using USBSerial as the debug interface since the reset will cause the TTY device being used by GDB to briefly disappear during the reset, causing GDB to disconnect. The user needs to reissue the appropriate "target remote /dev/tty*" to make the connection again. I needed to implement mriPlatform_CommHasTransmitCompleted() API for both ThreadDebug and KernelDebug to indicate if the last text transmitted has been sent. This is needed to make sure that the ack for the "continue" command is sent back to GDB before the device is actually reset or GDB gets confused.
1 parent cdfd2a1 commit 25d4290

File tree

16 files changed

+298
-61
lines changed

16 files changed

+298
-61
lines changed

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

+17
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ extern "C" {
3333

3434
// Globals that describe the KernelDebug singleton.
3535
static mbed::UnbufferedSerial* g_pSerial;
36+
static uint32_t g_baudRate;
3637
static IRQn_Type g_irq;
3738
static bool g_breakInSetup;
3839

@@ -72,6 +73,7 @@ arduino::KernelDebug::KernelDebug(PinName txPin, PinName rxPin, IRQn_Type irq, u
7273
if (g_pSerial != NULL) {
7374
return;
7475
}
76+
g_baudRate = baudRate;
7577
g_irq = irq;
7678
g_breakInSetup = breakInSetup;
7779
g_pSerial = &_serial;
@@ -175,6 +177,21 @@ uint32_t Platform_CommHasReceiveData(void)
175177
return g_pSerial->readable();
176178
}
177179

180+
uint32_t Platform_CommHasTransmitCompleted(void)
181+
{
182+
// This function is called by MRI to make sure that last GDB command has been ACKed before it executes a reset
183+
// request. We will busy wait in here until that has happened and then always return true.
184+
while (!g_pSerial->writable()) {
185+
// Wait until transmit data register is empty.
186+
}
187+
188+
// Might still have one byte in output shift register so wait 10 bit times to be safe.
189+
uint32_t microsecondsForOneByte = (10 * 1000000) / g_baudRate;
190+
delayMicroseconds(microsecondsForOneByte);
191+
192+
return 1;
193+
}
194+
178195
int Platform_CommReceiveChar(void)
179196
{
180197
while (!Platform_CommHasReceiveData()) {

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
*/
4747
#define CORTEXM_DEBUGGER_STACK_FILL 0xDEADBEEF
4848
#if MRI_DEVICE_HAS_FPU
49-
#define CORTEXM_DEBUGGER_STACK_SIZE 90
49+
#define CORTEXM_DEBUGGER_STACK_SIZE 180
5050
#else
5151
#define CORTEXM_DEBUGGER_STACK_SIZE 45
5252
#endif

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

+5
Original file line numberDiff line numberDiff line change
@@ -1182,6 +1182,11 @@ const char* Platform_GetTargetXml(void)
11821182
}
11831183

11841184

1185+
void Platform_ResetDevice(void)
1186+
{
1187+
NVIC_SystemReset();
1188+
}
1189+
11851190

11861191

11871192
#if !MRI_THREAD_MRI

Diff for: libraries/MRI/src/core/buffer.c

+60-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright 2014 Adam Green (https://github.com/adamgreen/)
1+
/* Copyright 2020 Adam Green (https://github.com/adamgreen/)
22
33
Licensed under the Apache License, Version 2.0 (the "License");
44
you may not use this file except in compliance with the License.
@@ -368,17 +368,32 @@ static void advanceToNextChar(Buffer* pBuffer)
368368
}
369369

370370

371+
typedef struct CompareParams
372+
{
373+
int (*compareFuncPtr)(Buffer* pBuffer, const char* pDesiredString, size_t stringLength);
374+
size_t charLength;
375+
} CompareParams;
376+
377+
static int matchesString(CompareParams* pParams, Buffer* pBuffer, const char* pString, size_t stringLength);
371378
static int doesBufferContainThisString(Buffer* pBuffer, const char* pDesiredString, size_t stringLength);
379+
static int doesBufferContainThisHexString(Buffer* pBuffer, const char* pDesiredString, size_t stringLength);
380+
static int hexStringCompare(Buffer* pBuffer, const char* pDesiredString, size_t stringLength);
372381
int Buffer_MatchesString(Buffer* pBuffer, const char* pString, size_t stringLength)
382+
{
383+
CompareParams params = { doesBufferContainThisString, 1 };
384+
return matchesString(&params, pBuffer, pString, stringLength);
385+
}
386+
387+
static int matchesString(CompareParams* pParams, Buffer* pBuffer, const char* pString, size_t stringLength)
373388
{
374389
__try
375-
throwExceptionIfBufferLeftIsSmallerThan(pBuffer, stringLength);
390+
throwExceptionIfBufferLeftIsSmallerThan(pBuffer, stringLength * pParams->charLength);
376391
__catch
377392
__rethrow_and_return(0);
378393

379-
if(doesBufferContainThisString(pBuffer, pString, stringLength))
394+
if(pParams->compareFuncPtr(pBuffer, pString, stringLength))
380395
{
381-
pBuffer->pCurrent += stringLength;
396+
pBuffer->pCurrent += stringLength * pParams->charLength;
382397
return 1;
383398
}
384399

@@ -391,5 +406,45 @@ static int doesBufferContainThisString(Buffer* pBuffer, const char* pDesiredStri
391406

392407
return (strncmp(pBufferString, pDesiredString, stringLength) == 0) &&
393408
(Buffer_BytesLeft(pBuffer) == stringLength ||
394-
pBufferString[stringLength] == ':');
409+
pBufferString[stringLength] == ':' ||
410+
pBufferString[stringLength] == ',');
411+
}
412+
413+
414+
int Buffer_MatchesHexString(Buffer* pBuffer, const char* pString, size_t stringLength)
415+
{
416+
CompareParams params = { doesBufferContainThisHexString, 2 };
417+
return matchesString(&params, pBuffer, pString, stringLength);
418+
}
419+
420+
static int doesBufferContainThisHexString(Buffer* pBuffer, const char* pDesiredString, size_t stringLength)
421+
{
422+
return (hexStringCompare(pBuffer, pDesiredString, stringLength) == 0) &&
423+
(Buffer_BytesLeft(pBuffer) == stringLength*2 ||
424+
(Buffer_BytesLeft(pBuffer) >= (stringLength+1)*2 &&
425+
pBuffer->pCurrent[stringLength*2] == '2' &&
426+
pBuffer->pCurrent[stringLength*2+1] == '0'));
427+
}
428+
429+
static int hexStringCompare(Buffer* pBuffer, const char* pDesiredString, size_t stringLength)
430+
{
431+
char* pOrig = pBuffer->pCurrent;
432+
int result = 0;
433+
size_t i;
434+
for (i = 0 ; i < stringLength ; i++)
435+
{
436+
uint8_t byte = Buffer_ReadByteAsHex(pBuffer);
437+
if (byte < (uint8_t)pDesiredString[i])
438+
{
439+
result = -1;
440+
break;
441+
}
442+
if (byte > (uint8_t)pDesiredString[i])
443+
{
444+
result = 1;
445+
break;
446+
}
447+
}
448+
pBuffer->pCurrent = pOrig;
449+
return result;
395450
}

Diff for: libraries/MRI/src/core/buffer.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright 2012 Adam Green (https://github.com/adamgreen/)
1+
/* Copyright 2020 Adam Green (https://github.com/adamgreen/)
22
33
Licensed under the Apache License, Version 2.0 (the "License");
44
you may not use this file except in compliance with the License.
@@ -47,6 +47,7 @@ int32_t mriBuffer_ReadIntegerAsHex(Buffer* pBuffer);
4747
void mriBuffer_WriteIntegerAsHex(Buffer* pBuffer, int32_t value);
4848
int mriBuffer_IsNextCharEqualTo(Buffer* pBuffer, char thisChar);
4949
int mriBuffer_MatchesString(Buffer* pBuffer, const char* pString, size_t stringLength);
50+
int mriBuffer_MatchesHexString(Buffer* pBuffer, const char* pString, size_t stringLength);
5051

5152
/* Macroes which allow code to drop the mri namespace prefix. */
5253
#define Buffer_Init mriBuffer_Init
@@ -68,5 +69,6 @@ int mriBuffer_MatchesString(Buffer* pBuffer, const char* pString, size_t st
6869
#define Buffer_WriteIntegerAsHex mriBuffer_WriteIntegerAsHex
6970
#define Buffer_IsNextCharEqualTo mriBuffer_IsNextCharEqualTo
7071
#define Buffer_MatchesString mriBuffer_MatchesString
72+
#define Buffer_MatchesHexString mriBuffer_MatchesHexString
7173

7274
#endif /* BUFFER_H_ */

Diff for: libraries/MRI/src/core/cmd_common.h

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright 2012 Adam Green (https://github.com/adamgreen/)
1+
/* Copyright 2020 Adam Green (https://github.com/adamgreen/)
22
33
Licensed under the Apache License, Version 2.0 (the "License");
44
you may not use this file except in compliance with the License.
@@ -23,9 +23,10 @@
2323
/* The bits that can be set in the return value from a command handler to indicate if the caller should return
2424
immediately or send the prepared response back to gdb. It also indicates whether program execution should be
2525
resumed for commands like continue and single step. */
26-
#define HANDLER_RETURN_RESUME_PROGRAM 1
27-
#define HANDLER_RETURN_RETURN_IMMEDIATELY 2
28-
#define HANDLER_RETURN_SKIPPED_OVER_BREAK 4
26+
#define HANDLER_RETURN_RESUME_PROGRAM (1 << 0)
27+
#define HANDLER_RETURN_RETURN_IMMEDIATELY (1 << 1)
28+
#define HANDLER_RETURN_SKIPPED_OVER_BREAK (1 << 2)
29+
#define HANDLER_RETURN_HANDLED (1 << 31)
2930

3031
typedef struct
3132
{

Diff for: libraries/MRI/src/core/cmd_continue.c

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright 2017 Adam Green (https://github.com/adamgreen/)
1+
/* Copyright 2020 Adam Green (https://github.com/adamgreen/)
22
33
Licensed under the Apache License, Version 2.0 (the "License");
44
you may not use this file except in compliance with the License.
@@ -109,3 +109,17 @@ uint32_t HandleContinueWithSignalCommand(void)
109109

110110
return (returnValue | HANDLER_RETURN_RESUME_PROGRAM | HANDLER_RETURN_RETURN_IMMEDIATELY);
111111
}
112+
113+
114+
/* Handle the 'D' command which is sent from gdb to resume execution before it detaches and exits.
115+
116+
Command Format: D
117+
Response Format: OK
118+
119+
*/
120+
uint32_t HandleDetachCommand(void)
121+
{
122+
skipHardcodedBreakpoint();
123+
PrepareStringResponse("OK");
124+
return HANDLER_RETURN_RESUME_PROGRAM;
125+
}

Diff for: libraries/MRI/src/core/cmd_continue.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright 2017 Adam Green (https://github.com/adamgreen/)
1+
/* Copyright 2020 Adam Green (https://github.com/adamgreen/)
22
33
Licensed under the Apache License, Version 2.0 (the "License");
44
you may not use this file except in compliance with the License.
@@ -21,9 +21,11 @@
2121
/* Real name of functions are in mri namespace. */
2222
uint32_t mriCmd_HandleContinueCommand(void);
2323
uint32_t mriCmd_HandleContinueWithSignalCommand(void);
24+
uint32_t mriCmd_HandleDetachCommand(void);
2425

2526
/* Macroes which allow code to drop the mri namespace prefix. */
2627
#define HandleContinueCommand mriCmd_HandleContinueCommand
2728
#define HandleContinueWithSignalCommand mriCmd_HandleContinueWithSignalCommand
29+
#define HandleDetachCommand mriCmd_HandleDetachCommand
2830

2931
#endif /* CMD_CONTINUE_H_ */

Diff for: libraries/MRI/src/core/cmd_query.c

+72-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright 2014 Adam Green (https://github.com/adamgreen/)
1+
/* Copyright 2020 Adam Green (https://github.com/adamgreen/)
22
33
Licensed under the Apache License, Version 2.0 (the "License");
44
you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
2020
#include <core/mri.h>
2121
#include <core/cmd_common.h>
2222
#include <core/cmd_query.h>
23+
#include <core/gdb_console.h>
2324

2425

2526
typedef struct
@@ -40,6 +41,10 @@ static void validateAnnexIsNull(const char* pAnnex);
4041
static void handleQueryTransferReadCommand(AnnexOffsetLength* pArguments);
4142
static uint32_t handleQueryTransferFeaturesCommand(void);
4243
static void validateAnnexIs(const char* pAnnex, const char* pExpected);
44+
static uint32_t handleMonitorCommand(void);
45+
static uint32_t handleMonitorResetCommand(void);
46+
static uint32_t handleMonitorShowFaultCommand(void);
47+
static uint32_t handleMonitorHelpCommand(void);
4348
/* Handle the 'q' command used by gdb to communicate state to debug monitor and vice versa.
4449
4550
Command Format: qSSS
@@ -50,6 +55,7 @@ uint32_t HandleQueryCommand(void)
5055
Buffer* pBuffer = GetBuffer();
5156
static const char qSupportedCommand[] = "Supported";
5257
static const char qXferCommand[] = "Xfer";
58+
static const char qRcmdCommand[] = "Rcmd";
5359

5460
if (Buffer_MatchesString(pBuffer, qSupportedCommand, sizeof(qSupportedCommand)-1))
5561
{
@@ -59,6 +65,10 @@ uint32_t HandleQueryCommand(void)
5965
{
6066
return handleQueryTransferCommand();
6167
}
68+
else if (Buffer_MatchesString(pBuffer, qRcmdCommand, sizeof(qRcmdCommand)-1))
69+
{
70+
return handleMonitorCommand();
71+
}
6272
else
6373
{
6474
PrepareEmptyResponseForUnknownCommand();
@@ -268,3 +278,64 @@ static void validateAnnexIs(const char* pAnnex, const char* pExpected)
268278
if (pAnnex == NULL || 0 != strcmp(pAnnex, pExpected))
269279
__throw(invalidArgumentException);
270280
}
281+
282+
/* Handle the "qRcmd" command used by gdb to send "monitor" commands to the stub.
283+
284+
Command Format: qRcmd,XXYY...
285+
Where XXYY... are the hexadecimal representation of the ASCII command text.
286+
*/
287+
static uint32_t handleMonitorCommand(void)
288+
{
289+
Buffer* pBuffer =GetBuffer();
290+
static const char reset[] = "reset";
291+
static const char showfault[] = "showfault";
292+
static const char help[] = "help";
293+
294+
if (!Buffer_IsNextCharEqualTo(pBuffer, ','))
295+
{
296+
PrepareStringResponse(MRI_ERROR_INVALID_ARGUMENT);
297+
return 0;
298+
}
299+
300+
if (Buffer_MatchesHexString(pBuffer, reset, sizeof(reset)-1))
301+
{
302+
return handleMonitorResetCommand();
303+
}
304+
else if (Buffer_MatchesHexString(pBuffer, showfault, sizeof(showfault)-1))
305+
{
306+
return handleMonitorShowFaultCommand();
307+
}
308+
else if (Buffer_MatchesHexString(pBuffer, help, sizeof(help)-1))
309+
{
310+
return handleMonitorHelpCommand();
311+
}
312+
else
313+
{
314+
WriteStringToGdbConsole("Unrecognized monitor command!\r\n");
315+
return handleMonitorHelpCommand();
316+
}
317+
}
318+
319+
static uint32_t handleMonitorResetCommand(void)
320+
{
321+
RequestResetOnNextContinue();
322+
WriteStringToGdbConsole("Will reset on next continue.\r\n");
323+
PrepareStringResponse("OK");
324+
return 0;
325+
}
326+
327+
static uint32_t handleMonitorShowFaultCommand(void)
328+
{
329+
Platform_DisplayFaultCauseToGdbConsole();
330+
PrepareStringResponse("OK");
331+
return 0;
332+
}
333+
334+
static uint32_t handleMonitorHelpCommand(void)
335+
{
336+
WriteStringToGdbConsole("Supported monitor commands:\r\n");
337+
WriteStringToGdbConsole("reset\r\n");
338+
WriteStringToGdbConsole("showfault\r\n");
339+
PrepareStringResponse("OK");
340+
return 0;
341+
}

Diff for: libraries/MRI/src/core/core.h

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ int mriCore_WasSemihostCallCancelledByGdb(void);
3535
void mriCore_FlagSemihostCallAsHandled(void);
3636
int mriCore_IsFirstException(void);
3737
int mriCore_WasSuccessfullyInit(void);
38+
void mriCore_RequestResetOnNextContinue(void);
3839

3940
void mriCore_SetSignalValue(uint8_t signalValue);
4041
uint8_t mriCore_GetSignalValue(void);
@@ -60,6 +61,7 @@ int mriCore_SetTempBreakpoint(uint32_t breakpointAddress, TempBreakpointCall
6061
#define FlagSemihostCallAsHandled mriCore_FlagSemihostCallAsHandled
6162
#define IsFirstException mriCore_IsFirstException
6263
#define WasSuccessfullyInit mriCore_WasSuccessfullyInit
64+
#define RequestResetOnNextContinue mriCore_RequestResetOnNextContinue
6365
#define SetSignalValue mriCore_SetSignalValue
6466
#define GetSignalValue mriCore_GetSignalValue
6567
#define SetSemihostReturnValues mriCore_SetSemihostReturnValues

0 commit comments

Comments
 (0)