summaryrefslogtreecommitdiff
path: root/gdbremote_parser.hpp
diff options
context:
space:
mode:
authorOxore <oxore@protonmail.com>2022-08-27 15:12:08 +0300
committerOxore <oxore@protonmail.com>2022-08-27 15:13:13 +0300
commit9580a9a8daa4426914f396a694903ab880ecd3f2 (patch)
tree46394ea036316ffccf3357bcc35f1c18635ae890 /gdbremote_parser.hpp
parent903b8dbcaad887f6e14cc8cffc22ddda08dc9f85 (diff)
Add initial gdbremote implementation
Diffstat (limited to 'gdbremote_parser.hpp')
-rw-r--r--gdbremote_parser.hpp133
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{};
+};
+
+}