diff options
Diffstat (limited to 'gdbremote_parser.hpp')
-rw-r--r-- | gdbremote_parser.hpp | 133 |
1 files changed, 133 insertions, 0 deletions
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 <cstdint> +#include <string> +#include <vector> +#include <memory> + +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<Feature> features{}; + virtual ~PacketDataSupportedFeatures() {} +}; + +struct Packet { + const PacketType type{}; + const std::unique_ptr<PacketData> 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<ExchangeResult> Nak(std::string data=std::string{}) + { + return std::make_unique<ExchangeResult>(data, std::string{"-"}); + } + + static std::unique_ptr<ExchangeResult> Ack(std::string data=std::string{}) + { + return std::make_unique<ExchangeResult>(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<ExchangeResult> 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{}; +}; + +} |