summaryrefslogtreecommitdiff
path: root/gdbremote.cpp
blob: eb0fed817c4dabab348b1713c283e1ad9946909b (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
120
121
122
123
124
125
126
127
128
129
130
/* SPDX-License-Identifier: Unlicense
 */

#include "gdbremote_parser.hpp"

#include <cstdlib>
#include <cstdio>
#include <cstdint>
#include <cstring>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

#define MESSAGE_BUFFER_SIZE 1

char msg_buf[MESSAGE_BUFFER_SIZE];

static int set_socket_reuseaddr(int socket_fd)
{
    const int val = 1;
    const socklen_t len = sizeof(val);
    return setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, (void*)&val, len);
}

static inline struct sockaddr_in sockaddr_in_any_ip_with_port(uint16_t port) {
    struct sockaddr_in server{};
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(port);
    return server;
}

static int setup_socket(uint16_t port)
{
    // This creates the socket - or quits
    const int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (socket_fd == -1) {
        perror("Could not create socket");
        return -1;
    }
    // Make TCP port reusable in case of kill or crash.
    // Deliberate explanation: https://stackoverflow.com/a/3233022
    if (set_socket_reuseaddr(socket_fd) == -1) {
        perror("setsockopt failed");
        close(socket_fd);
        return -1;
    }
    puts("Socket created");
    const struct sockaddr_in server = sockaddr_in_any_ip_with_port(port);
    if (bind(socket_fd, (struct sockaddr *)&server, sizeof(server)) == -1) {
        perror("Bind failed");
        close(socket_fd);
        return -1;
    }
    printf("Binding to 0.0.0.0:%u done\n", port);
    return socket_fd;
}

static std::string CreateResponse(const GDBRemote::Packet& packet)
{
    using namespace GDBRemote;
    if (0) {
    } else if (packet.type == PacketType::kQueryHaltReason) {
        return "S05";
    } else if (packet.type == PacketType::kSetThreadForCont) {
        return "OK";
    } else if (packet.type == PacketType::kQueryAttached) {
        return "1";
    } else if (packet.type == PacketType::kInterrupt) {
        return "OK";
    } else if (packet.type == PacketType::kReadGeneralRegisters) {
        return std::string(2*4*17, '0') + "00000200"; // 17 registers + PC
    }
    return "";
}

int main(int argc, char *argv[])
{
    const int port = argc > 1 ? atoi(argv[1]) : 3333;
    const int socket_fd = setup_socket(port);
    if (socket_fd == -1)
        return EXIT_FAILURE;
    printf("Listening TCP 0.0.0.0:%u\n", port);
    listen(socket_fd, 4); // Mark socket as listener
    struct sockaddr client_address;
    socklen_t address_len;
    const int conn_fd = accept(socket_fd, &client_address, &address_len);
    if (conn_fd == -1) {
        perror("Accept failed");
        close(socket_fd);
        return EXIT_FAILURE;
    }
    puts("Connection accepted");
    GDBRemote::ExchangeContext exchange_ctx{};
    ssize_t read_size;
    while ((read_size = recv(conn_fd, msg_buf, MESSAGE_BUFFER_SIZE, 0)) > 0) {
        for (size_t i = 0; i < static_cast<size_t>(read_size); i++) {
            const auto res = exchange_ctx.Consume(msg_buf[i]);
            if (res == nullptr) continue;
            if (res->packet.length() > 0) {
                if (0) printf("<- \"%s\"\n", res->packet.c_str());
                printf("<- \"%s\"\n", exchange_ctx.GetLastPacket().c_str());
                const auto packet = GDBRemote::Packet::Parse(res->packet);
                printf(
                        "   Packet type: \"%s\"\n",
                        GDBRemote::Packet::PacketTypeToString(packet.type));
            }
            if (res->ack.length() > 0) {
                printf("-> \"%s\"\n", res->ack.c_str());
                if (send(conn_fd, &res->ack[0], res->ack.length(), 0) == -1)
                    perror("Send failed (ack/nak)");
            }
            if (res->packet.length() > 0) {
                const auto packet = GDBRemote::Packet::Parse(res->packet);
                const auto response =
                    exchange_ctx.WrapDataToSend(CreateResponse(packet));
                printf("-> \"%s\"\n", response.c_str());
                if (send(conn_fd, &response[0], response.length(), 0) == -1)
                    perror("Send failed (response)");
            }
        }
        memset(msg_buf, '\0', MESSAGE_BUFFER_SIZE);
    }
    if (read_size == 0) {
        puts("Client disconnected");
    } else if (read_size == -1) {
        perror("Recv failed");
    }
    close(socket_fd);
}