summaryrefslogtreecommitdiff
path: root/gdbremote_parser.cpp
blob: e3f4aae0ae08483615fa485f8f066bcc3e3d98e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/* 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<ExchangeResult> 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 "?";
}