/* Handle the 'M' command which is to write to the specified address range in memory. Command Format: MAAAAAAAA,LLLLLLLL:xx... Response Format: OK Where AAAAAAAA is the hexadecimal representation of the address where the write is to start. LLLLLLLL is the hexadecimal representation of the length (in bytes) of the write to be conducted. xx is the hexadecimal representation of the first byte to be written to the specified location. ... continue returning the rest of LLLLLLLL-1 bytes in hexadecimal format. */ uint32_t HandleMemoryWriteCommand(void) { Buffer* pBuffer = GetBuffer(); AddressLength addressLength; __try { ReadAddressAndLengthArgumentsWithColon(pBuffer, &addressLength); } __catch { PrepareStringResponse(MRI_ERROR_INVALID_ARGUMENT); return 0; } if (WriteHexBufferToMemory(pBuffer, ADDR32_TO_POINTER(addressLength.address), addressLength.length)) { PrepareStringResponse("OK"); } else { if (Buffer_OverrunDetected(pBuffer)) PrepareStringResponse( MRI_ERROR_BUFFER_OVERRUN); else PrepareStringResponse(MRI_ERROR_MEMORY_ACCESS_FAILURE); } return 0; }
/* Handle the 'G' command which is to receive the new contents of the registers from gdb for the program to use when it resumes execution. Command Format: Gxxxxxxxxyyyyyyyy... Response Format: OK Where xxxxxxxx is the hexadecimal representation of the 32-bit R0 register. yyyyyyyy is the hexadecimal representation of the 32-bit R1 register. ... and so on through the members of the SContext structure. */ uint32_t HandleRegisterWriteCommand(void) { Buffer* pBuffer = GetBuffer(); Platform_CopyContextFromBuffer(pBuffer); if (Buffer_OverrunDetected(pBuffer)) PrepareStringResponse(MRI_ERROR_BUFFER_OVERRUN); else PrepareStringResponse("OK"); return 0; }
/* Handle the '"Z*" commands used by gdb to set hardware breakpoints/watchpoints. Command Format: Z*,AAAAAAAA,K Response Format: OK Where * is 1 for hardware breakpoint. 2 for write watchpoint. 3 for read watchpoint. 4 for read/write watchpoint. AAAAAAAA is the hexadecimal representation of the address on which the breakpoint should be set. K is either 2: 16-bit Thumb instruction. 3: 32-bit Thumb2 instruction. 4: 32-bit ARM insruction. value: byte size for data watchpoint. */ uint32_t HandleBreakpointWatchpointSetCommand(void) { BreakpointWatchpointArguments arguments; __try { parseBreakpointWatchpointCommandArguments(&arguments); } __catch { PrepareStringResponse(MRI_ERROR_INVALID_ARGUMENT); return 0; } switch(arguments.type) { case '1': handleHardwareBreakpointSetCommand(&arguments); break; case '2': handleWatchpointSetCommand(MRI_PLATFORM_WRITE_WATCHPOINT, &arguments); break; case '3': handleWatchpointSetCommand(MRI_PLATFORM_READ_WATCHPOINT, &arguments); break; case '4': handleWatchpointSetCommand(MRI_PLATFORM_READWRITE_WATCHPOINT, &arguments); break; default: PrepareEmptyResponseForUnknownCommand(); break; } return 0; }
/* Handle the 'C' command which is sent from gdb to tell the debugger to continue execution of the currently halted program. It is similar to the 'c' command but it also provides a signal level, which MRI ignores. Command Format: cAA;BBBBBBBB Response Format: Blank until the next exception, at which time a 'T' stop response packet will be sent. Where AA is the signal to be set, and BBBBBBBB is an optional value to be used for the Program Counter when restarting the program. */ uint32_t HandleContinueWithSignalCommand(void) { Buffer* pBuffer = GetBuffer(); uint32_t returnValue = 0; uint32_t newPC; returnValue |= skipHardcodedBreakpoint(); __try { /* Fetch signal value but ignore it. */ __throwing_func( ReadUIntegerArgument(pBuffer) ); if (Buffer_BytesLeft(pBuffer) && Buffer_IsNextCharEqualTo(pBuffer, ';')) { __throwing_func( newPC = ReadUIntegerArgument(pBuffer) ); Platform_SetProgramCounter(newPC); } } __catch { PrepareStringResponse(MRI_ERROR_INVALID_ARGUMENT); return 0; } return (returnValue | HANDLER_RETURN_RESUME_PROGRAM | HANDLER_RETURN_RETURN_IMMEDIATELY); }
/* Handle the "qXfer" command used by gdb to transfer data to and from the stub for special functionality. Command Format: qXfer:object:read:annex:offset,length Where supported objects are currently: memory-map */ static uint32_t handleQueryTransferCommand(void) { Buffer* pBuffer =GetBuffer(); static const char memoryMapObject[] = "memory-map"; static const char featureObject[] = "features"; if (!Buffer_IsNextCharEqualTo(pBuffer, ':')) { PrepareStringResponse(MRI_ERROR_INVALID_ARGUMENT); return 0; } if (Buffer_MatchesString(pBuffer, memoryMapObject, sizeof(memoryMapObject)-1)) { return handleQueryTransferMemoryMapCommand(); } else if (Buffer_MatchesString(pBuffer, featureObject, sizeof(featureObject)-1)) { return handleQueryTransferFeaturesCommand(); } else { PrepareEmptyResponseForUnknownCommand(); return 0; } }
/* Handle the 'm' command which is to read the specified address range from memory. Command Format: mAAAAAAAA,LLLLLLLL Response Format: xx... Where AAAAAAAA is the hexadecimal representation of the address where the read is to start. LLLLLLLL is the hexadecimal representation of the length (in bytes) of the read to be conducted. xx is the hexadecimal representation of the first byte read from the specified location. ... continue returning the rest of LLLLLLLL-1 bytes in hexadecimal format. */ uint32_t HandleMemoryReadCommand(void) { Buffer* pBuffer = GetBuffer(); AddressLength addressLength; __try { ReadAddressAndLengthArguments(pBuffer, &addressLength); } __catch { PrepareStringResponse(MRI_ERROR_INVALID_ARGUMENT); return 0; } InitBuffer(); ReadMemoryIntoHexBuffer(pBuffer, ADDR32_TO_POINTER(addressLength.address), addressLength.length); return 0; }
/* Handle the "qXfer:features" command used by gdb to read the target XML from the stub. Command Format: qXfer:features:read:target.xml:offset,length */ static uint32_t handleQueryTransferFeaturesCommand(void) { Buffer* pBuffer = GetBuffer(); AnnexOffsetLength arguments; __try { __throwing_func( readQueryTransferReadArguments(pBuffer, &arguments) ); __throwing_func( validateAnnexIs(arguments.pAnnex, "target.xml") ); } __catch { PrepareStringResponse(MRI_ERROR_INVALID_ARGUMENT); return 0; } arguments.pAnnex = Platform_GetTargetXml(); arguments.annexSize = Platform_GetTargetXmlSize(); handleQueryTransferReadCommand(&arguments); return 0; }