From 9580a9a8daa4426914f396a694903ab880ecd3f2 Mon Sep 17 00:00:00 2001 From: Oxore Date: Sat, 27 Aug 2022 15:12:08 +0300 Subject: Add initial gdbremote implementation --- gdbremote_parser.hpp | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 gdbremote_parser.hpp (limited to 'gdbremote_parser.hpp') diff --git a/gdbremote_parser.hpp b/gdbremote_parser.hpp new file mode 100644 index 0000000..0e2f375 --- /dev/null +++ b/gdbremote_parser.hpp @@ -0,0 +1,133 @@ +/* SPDX-License-Identifier: Unlicense + */ + +#pragma once + +#include +#include +#include +#include + +namespace GDBRemote { + +enum class FeatureSupportMark: uint8_t { + kNone = 0, + kPlus, + kMinus, + kQuestion, +}; + +enum class FeatureName: int { + kUnknown = 0, + kMultiprocess, + kSoftwareBreak, + kHardwareBreak, + kQRelocInsn, + kForkEvents, + kVForkEvents, + kExecEvents, + kVContSuppurted, + kQThreadEvents, + kNoResumed, + kMemoryTagging, + kPacketSize, +}; + +struct Feature { + const FeatureName name{}; + const FeatureSupportMark mark{}; + const bool has_value{}; + const int value{}; + const std::string raw{}; +}; + +enum class PacketType: int { + kNone = 0, + kQuerySupported, + kQueryC, + kQueryFThreadInfo, + kQuerySThreadInfo, + kH, + kMustReplyEmpty, +}; + +struct PacketData { + PacketData() = delete; + PacketData(const PacketData&) = delete; + PacketData(PacketData&&) = delete; + virtual ~PacketData() {} +}; + +struct PacketDataSupportedFeatures: public PacketData { + std::vector features{}; + virtual ~PacketDataSupportedFeatures() {} +}; + +struct Packet { + const PacketType type{}; + const std::unique_ptr data; + + /** Convert raw packet data into a Packet + * + * Packet data is the data extracted by ExchangeContext::Consume function. + */ + static Packet Parse(std::string packet_data); +}; + +struct ExchangeResult { + const std::string packet{}; + const std::string response{}; + + ExchangeResult(std::string a_packet, std::string a_response) + : packet(a_packet), response(a_response) {} + + static std::unique_ptr Nak(std::string data=std::string{}) + { + return std::make_unique(data, std::string{"-"}); + } + + static std::unique_ptr Ack(std::string data=std::string{}) + { + return std::make_unique(data, std::string{"+"}); + } +}; + +class ExchangeContext { +public: + /** Consume next byte from input stream from GDB client + * + * Returns packet data and acknowledge response in case if a valid packet + * fully received. + * + * Returns nullptr if is in progress. + */ + std::unique_ptr Consume(uint8_t byte); + + /** Creates raw packet from packet data to be sent into socket directly + * + * It is not static nor const because after sending a packet an + * ExchangeContext must be set into awaiting acknowledge response state + * (i.e. '+' or '-'). Otherwise we will be unable to resend packet in case + * if '-' negative acknowledge is received. + */ + std::string WrapDataToSend(Packet packet=Packet{}); + +private: + enum class ParsingState { + kIdle, + kPacketData, + kPacketDataBinSecond, + kChecksum1, + kChecksum2, + }; + + void transit(ParsingState); + static const char* parsingStateToString(ParsingState state); + + ParsingState _parsing_state{ParsingState::kIdle}; + std::string _packet_data{}; + uint8_t _checksum{}; + uint8_t _given_checksum_first_byte{}; +}; + +} -- cgit v1.2.3