/* SPDX-License-Identifier: Unlicense */ #include "gdbremote_parser.hpp" using namespace GDBRemote; static inline bool is_hex_digit(uint8_t byte) { return byte >= '0' && byte <= '9' || byte >= 'A' && byte < 'F' || byte >= 'a' && byte <= 'f'; } static inline uint8_t parseChecksumFromHexChars(uint8_t first, uint8_t second) { // Assume, that given bytes are valid hex digits in ASCII first = ((first & 0x40) ? (first + 9) : first) & 0x0f; second = ((second & 0x40) ? (second + 9) : second) & 0x0f; return ((first << 4) | second) & 0xff; } std::unique_ptr ExchangeContext::Consume(uint8_t byte) { switch (_parsing_state) { case ParsingState::kIdle: if (byte == '$') { transit(ParsingState::kPacketData); } break; case ParsingState::kPacketData: if (byte == '#') { transit(ParsingState::kChecksum1); } else { _checksum = (_checksum + byte) & 0xff; _packet_data += byte; } break; case ParsingState::kPacketDataBinSecond: // TODO escaped and binary data break; case ParsingState::kChecksum1: if (is_hex_digit(byte)) { transit(ParsingState::kChecksum2); _given_checksum_first_byte = byte; } else { transit(ParsingState::kIdle); return ExchangeResult::Nak(); } break; case ParsingState::kChecksum2: const uint8_t checksum = _checksum; std::string packet_data(std::move(_packet_data)); transit(ParsingState::kIdle); if (is_hex_digit(byte)) { const uint8_t given_checksum = parseChecksumFromHexChars(_given_checksum_first_byte, byte); if (given_checksum == checksum) { return ExchangeResult::Ack(packet_data); } else { printf( "Checksum mismatch received: %02X, expected: %02X\n", given_checksum, checksum); printf("Packet data: \"%s\"\n", packet_data.c_str()); return ExchangeResult::Nak(); } } else { return ExchangeResult::Nak(); } break; } return nullptr; } std::string ExchangeContext::WrapDataToSend(Packet packet) { (void) packet; return std::string{}; } void ExchangeContext::transit(ParsingState new_state) { printf( "GDBRemote ParsingState: %s -> %s\n", parsingStateToString(_parsing_state), parsingStateToString(new_state)); switch (new_state) { case ParsingState::kIdle: _checksum = 0; _packet_data.clear(); break; case ParsingState::kPacketData: break; case ParsingState::kPacketDataBinSecond: break; case ParsingState::kChecksum1: break; case ParsingState::kChecksum2: break; } _parsing_state = new_state; } const char* ExchangeContext::parsingStateToString(ParsingState state) { switch (state) { case ParsingState::kIdle: return "Idle"; case ParsingState::kPacketData: return "PacketData"; case ParsingState::kPacketDataBinSecond: return "PacketDataBinSecond"; case ParsingState::kChecksum1: return "Checksum1"; case ParsingState::kChecksum2: return "Checksum2"; } return "?"; }