#include "CommandPacketFactory.hpp" #include #include #include namespace Bloom::DebugServers::Gdb { using CommandPackets::CommandPacket; std::vector> CommandPacketFactory::extractRawPackets( std::vector buffer ) { std::vector> output; std::size_t bufferIndex; std::size_t bufferSize = buffer.size(); unsigned char byte; for (bufferIndex = 0; bufferIndex < bufferSize; bufferIndex++) { byte = buffer[bufferIndex]; if (byte == 0x03) { /* * This is an interrupt packet - it doesn't carry any of the usual packet frame bytes, so we'll just * add them here, in order to keep things consistent. * * Because we're effectively faking the packet frame, we can use any value for the checksum. */ output.push_back({'$', byte, '#', 'F', 'F'}); } else if (byte == '$') { // Beginning of packet std::vector rawPacket; rawPacket.push_back('$'); auto packetIndex = bufferIndex; bool validPacket = false; bool isByteEscaped = false; for (packetIndex++; packetIndex < bufferSize; packetIndex++) { byte = buffer[packetIndex]; if (byte == '}' && !isByteEscaped) { isByteEscaped = true; continue; } if (byte == '$' && !isByteEscaped) { // Unexpected end of packet validPacket = false; break; } if (byte == '#' && !isByteEscaped) { // End of packet data if ((bufferSize - 1) < (packetIndex + 2)) { // There should be at least two more bytes in the buffer, for the checksum. break; } rawPacket.push_back(byte); // Add the checksum bytes and break the loop rawPacket.push_back(buffer[++packetIndex]); rawPacket.push_back(buffer[++packetIndex]); validPacket = true; break; } if (isByteEscaped) { // Escaped bytes are XOR'd with a 0x20 mask. byte ^= 0x20; isByteEscaped = false; } rawPacket.push_back(byte); } if (validPacket) { output.push_back(rawPacket); bufferIndex = packetIndex; } } } return output; } std::unique_ptr CommandPacketFactory::create(std::vector rawPacket) { if (rawPacket.size() == 5 && rawPacket[1] == 0x03) { // This is an interrupt request - create a fake packet for it return std::make_unique(rawPacket); } auto rawPacketString = std::string(rawPacket.begin(), rawPacket.end()); if (rawPacketString.size() >= 2) { /* * First byte of the raw packet will be 0x24 ('$'), so find() should return 1, not 0, when * looking for a command identifier string. */ if (rawPacketString.find("qSupported") == 1) { return std::make_unique(rawPacket); } if (rawPacketString[1] == 'g' || rawPacketString[1] == 'p') { return std::make_unique(rawPacket); } if (rawPacketString[1] == 'P') { return std::make_unique(rawPacket); } if (rawPacketString[1] == 'c') { return std::make_unique(rawPacket); } if (rawPacketString[1] == 's') { return std::make_unique(rawPacket); } if (rawPacketString[1] == 'm') { return std::make_unique(rawPacket); } if (rawPacketString[1] == 'M') { return std::make_unique(rawPacket); } if (rawPacketString[1] == 'Z') { return std::make_unique(rawPacket); } if (rawPacketString[1] == 'z') { return std::make_unique(rawPacket); } } return std::make_unique(rawPacket); } }