/* SPDX-License-Identifier: Unlicense */ #include "gdbremote_parser.hpp" #include #include #include #include #include #include #include #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(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); }