Rename RdbClient to RdbResponse

This commit is contained in:
Simon Gellis 2024-10-07 22:18:42 -04:00
parent 1b273171ad
commit 6ea396a974
9 changed files with 201 additions and 199 deletions

113
client.c
View File

@ -1,113 +0,0 @@
#include <client.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
static bool write_char(RdbClient *self, char out) {
if (self->len >= RDB_CLIENT_BUFLEN) {
return false;
}
if (out == '#' || out == '$' || out == '}' || out == '*') {
self->full_buf[self->len++] = '}';
self->chk += '}';
if (self->len >= RDB_CLIENT_BUFLEN) {
return false;
}
out ^= 0x20;
}
self->full_buf[self->len++] = out;
self->chk += out;
return true;
}
bool char_to_hex_digit(char in, char *out) {
if (in & 0xf0) {
return false;
}
in &= 0x0f;
if (in > 9) {
*out = 'a' + in - 10;
} else {
*out = '0' + in;
}
return true;
}
bool char_to_hex_digits(char in, char *hi, char *lo) {
return char_to_hex_digit((in & 0xf0) >> 4, hi)
&& char_to_hex_digit(in & 0x0f, lo);
}
void rdb_client_init(RdbClient *self, int connfd) {
self->connfd = connfd;
self->len = 0;
self->chk = 0;
self->should_ack = true;
}
void rdb_client_begin_packet(RdbClient *self) {
self->len = 0;
self->chk = 0;
if (self->should_ack) {
self->full_buf[self->len++] = '+';
}
self->full_buf[self->len++] = '$';
}
bool rdb_client_write_str(RdbClient *self, const char *str) {
size_t len = strlen(str);
for (size_t i = 0; i < len; ++i) {
if (!write_char(self, str[i])) {
return false;
}
}
return true;
}
bool rdb_client_write_str_hex(RdbClient *self, const char *str) {
size_t len = strlen(str);
for (size_t i = 0; i < len; ++i) {
char hi, lo;
if (!char_to_hex_digits(str[i], &hi, &lo)
|| !write_char(self, hi)
|| !write_char(self, lo)) {
return false;
}
}
return true;
}
bool rdb_client_write_i8_hex(RdbClient *self, uint8_t value) {
char hi, lo;
return char_to_hex_digits(value, &hi, &lo)
&& write_char(self, hi)
&& write_char(self, lo);
}
bool rdb_client_write_i32_hex(RdbClient *self, uint32_t value) {
return rdb_client_write_i8_hex(self, (uint8_t) value)
&& rdb_client_write_i8_hex(self, (uint8_t) (value >> 8))
&& rdb_client_write_i8_hex(self, (uint8_t) (value >> 16))
&& rdb_client_write_i8_hex(self, (uint8_t) (value >> 24));
}
int rdb_client_send_packet(RdbClient *self) {
if (self->len + 3 > RDB_CLIENT_BUFLEN) {
return -1;
}
self->full_buf[self->len++] = '#';
char hi, lo;
if (!char_to_hex_digits(self->chk, &hi, &lo)) {
return -1;
}
self->full_buf[self->len++] = hi;
self->full_buf[self->len++] = lo;
printf("sending command \"%.*s\" %d\n", (int) self->len, self->full_buf, (int)self->len);
ssize_t rwrite = write(self->connfd, self->full_buf, self->len);
if (rwrite == -1) {
return -1;
}
return 0;
}

View File

@ -1,27 +0,0 @@
#ifndef RDBSERVER_CLIENT_H_
#define RDBSERVER_CLIENT_H_
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
#define RDB_CLIENT_BUFLEN 8096
typedef struct RdbClient {
int connfd;
char full_buf[RDB_CLIENT_BUFLEN];
size_t len;
char chk;
bool should_ack;
} RdbClient;
void rdb_client_init(RdbClient *self, int connfd);
void rdb_client_begin_packet(RdbClient *self);
bool rdb_client_write_str(RdbClient *self, const char *str);
bool rdb_client_write_str_hex(RdbClient *self, const char *str);
bool rdb_client_write_i8_hex(RdbClient *self, uint8_t value);
bool rdb_client_write_i32_hex(RdbClient *self, uint32_t value);
int rdb_client_send_packet(RdbClient *self);
#endif

View File

@ -35,7 +35,7 @@ typedef struct RdbRequest {
char chk; char chk;
} RdbRequest; } RdbRequest;
void rdb_request_init(RdbRequest *req, int connfd, char *cmd, size_t cmdlen); void rdb_request_init(RdbRequest *req, int connfd, char *buf, size_t buflen);
void rdb_request_reset(RdbRequest *req); void rdb_request_reset(RdbRequest *req);
void rdb_request_set_blocking(RdbRequest *req, bool blocking); void rdb_request_set_blocking(RdbRequest *req, bool blocking);
rdb_read_result_t rdb_request_read(RdbRequest *req, CommandBuf *cmd); rdb_read_result_t rdb_request_read(RdbRequest *req, CommandBuf *cmd);

26
include/response.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef RDBSERVER_RESPONSE_H_
#define RDBSERVER_RESPONSE_H_
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
typedef struct RdbResponse {
int connfd;
char *buf;
size_t buflen;
size_t len;
char chk;
bool should_ack;
} RdbResponse;
void rdb_response_init(RdbResponse *self, int connfd, char *buf, size_t buflen);
void rdb_response_begin_packet(RdbResponse *self);
bool rdb_response_write_str(RdbResponse *self, const char *str);
bool rdb_response_write_str_hex(RdbResponse *self, const char *str);
bool rdb_response_write_i8_hex(RdbResponse *self, uint8_t value);
bool rdb_response_write_i32_hex(RdbResponse *self, uint32_t value);
int rdb_response_send_packet(RdbResponse *self);
#endif

View File

@ -1,11 +1,11 @@
#ifndef RDBSERVER_SERVER_H_ #ifndef RDBSERVER_SERVER_H_
#define RDBSERVER_SERVER_H_ #define RDBSERVER_SERVER_H_
#include <client.h>
#include <cmdbuf.h> #include <cmdbuf.h>
#include <response.h>
#include <stdbool.h> #include <stdbool.h>
#include <vb.h> #include <vb.h>
int handle_command(RdbClient *client, CommandBuf *cmd, VB *sim, bool *running); int handle_command(RdbResponse *res, CommandBuf *cmd, VB *sim, bool *running);
#endif #endif

17
main.c
View File

@ -1,6 +1,6 @@
#include <client.h>
#include <cmdbuf.h> #include <cmdbuf.h>
#include <request.h> #include <request.h>
#include <response.h>
#include <server.h> #include <server.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -12,11 +12,12 @@ const size_t BUFLEN = 8096;
int server(int connfd, VB *sim) { int server(int connfd, VB *sim) {
RdbRequest req; RdbRequest req;
RdbClient client; RdbResponse res;
char buf[BUFLEN]; char reqbuf[BUFLEN];
char resbuf[BUFLEN];
rdb_request_init(&req, connfd, buf, BUFLEN); rdb_request_init(&req, connfd, reqbuf, BUFLEN);
rdb_client_init(&client, connfd); rdb_response_init(&res, connfd, resbuf, BUFLEN);
bool running = false; bool running = false;
@ -37,9 +38,9 @@ int server(int connfd, VB *sim) {
} else { } else {
printf("received command \"%.*s\"\n", (int) cmd.len, cmd.buf); printf("received command \"%.*s\"\n", (int) cmd.len, cmd.buf);
fflush(stdout); fflush(stdout);
int res = handle_command(&client, &cmd, sim, &running); int result = handle_command(&res, &cmd, sim, &running);
if (res != 0) { if (result != 0) {
return res; return result;
} }
rdb_request_set_blocking(&req, !running); rdb_request_set_blocking(&req, !running);
rdb_request_reset(&req); rdb_request_reset(&req);

View File

@ -1,6 +1,6 @@
build: build:
@mkdir -p build @mkdir -p build
@gcc main.c client.c cmdbuf.c hex.c request.c server.c ../vbtest/vb.c \ @gcc main.c cmdbuf.c hex.c request.c response.c server.c ../vbtest/vb.c \
-I include -I ../vbtest \ -I include -I ../vbtest \
-Werror -Wall -Wextra -Wpedantic \ -Werror -Wall -Wextra -Wpedantic \
-Wno-unused-parameter -Wno-unused-function \ -Wno-unused-parameter -Wno-unused-function \

115
response.c Normal file
View File

@ -0,0 +1,115 @@
#include <response.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
static bool write_char(RdbResponse *res, char out) {
if (res->len >= res->buflen) {
return false;
}
if (out == '#' || out == '$' || out == '}' || out == '*') {
res->buf[res->len++] = '}';
res->chk += '}';
if (res->len >= res->buflen) {
return false;
}
out ^= 0x20;
}
res->buf[res->len++] = out;
res->chk += out;
return true;
}
bool char_to_hex_digit(char in, char *out) {
if (in & 0xf0) {
return false;
}
in &= 0x0f;
if (in > 9) {
*out = 'a' + in - 10;
} else {
*out = '0' + in;
}
return true;
}
bool char_to_hex_digits(char in, char *hi, char *lo) {
return char_to_hex_digit((in & 0xf0) >> 4, hi)
&& char_to_hex_digit(in & 0x0f, lo);
}
void rdb_response_init(RdbResponse *res, int connfd, char *buf, size_t buflen) {
res->connfd = connfd;
res->buf = buf;
res->buflen = buflen;
res->len = 0;
res->chk = 0;
res->should_ack = true;
}
void rdb_response_begin_packet(RdbResponse *res) {
res->len = 0;
res->chk = 0;
if (res->should_ack) {
res->buf[res->len++] = '+';
}
res->buf[res->len++] = '$';
}
bool rdb_response_write_str(RdbResponse *res, const char *str) {
size_t len = strlen(str);
for (size_t i = 0; i < len; ++i) {
if (!write_char(res, str[i])) {
return false;
}
}
return true;
}
bool rdb_response_write_str_hex(RdbResponse *res, const char *str) {
size_t len = strlen(str);
for (size_t i = 0; i < len; ++i) {
char hi, lo;
if (!char_to_hex_digits(str[i], &hi, &lo)
|| !write_char(res, hi)
|| !write_char(res, lo)) {
return false;
}
}
return true;
}
bool rdb_response_write_i8_hex(RdbResponse *res, uint8_t value) {
char hi, lo;
return char_to_hex_digits(value, &hi, &lo)
&& write_char(res, hi)
&& write_char(res, lo);
}
bool rdb_response_write_i32_hex(RdbResponse *res, uint32_t value) {
return rdb_response_write_i8_hex(res, (uint8_t) value)
&& rdb_response_write_i8_hex(res, (uint8_t) (value >> 8))
&& rdb_response_write_i8_hex(res, (uint8_t) (value >> 16))
&& rdb_response_write_i8_hex(res, (uint8_t) (value >> 24));
}
int rdb_response_send_packet(RdbResponse *res) {
if (res->len + 3 > res->buflen) {
return -1;
}
res->buf[res->len++] = '#';
char hi, lo;
if (!char_to_hex_digits(res->chk, &hi, &lo)) {
return -1;
}
res->buf[res->len++] = hi;
res->buf[res->len++] = lo;
printf("sending command \"%.*s\" %d\n", (int) res->len, res->buf, (int)res->len);
ssize_t rwrite = write(res->connfd, res->buf, res->len);
if (rwrite == -1) {
return -1;
}
return 0;
}

View File

@ -69,81 +69,81 @@ const uint32_t SYSTEM_REGISTERS[] = {
const uint32_t PC_INDEX = 32 + 13; const uint32_t PC_INDEX = 32 + 13;
int handle_command(RdbClient *client, CommandBuf *cmd, VB *sim, bool *running) { int handle_command(RdbResponse *res, CommandBuf *cmd, VB *sim, bool *running) {
rdb_client_begin_packet(client); rdb_response_begin_packet(res);
if (cmd_match_only_str(cmd, "QStartNoAckMode")) { if (cmd_match_only_str(cmd, "QStartNoAckMode")) {
// The debugger is asking us to no longer ACK messages. // The debugger is asking us to no longer ACK messages.
// Note that we ack THIS response, because we already called rdb_client_begin_packet. // Note that we ack THIS response, because we already called rdb_response_begin_packet.
client->should_ack = false; res->should_ack = false;
rdb_client_write_str(client, "OK"); rdb_response_write_str(res, "OK");
return rdb_client_send_packet(client); return rdb_response_send_packet(res);
} }
if (cmd_match_str(cmd, "qSupported")) { if (cmd_match_str(cmd, "qSupported")) {
// The debugger is asking for a list of features we support. // The debugger is asking for a list of features we support.
rdb_client_write_str(client, "no-resumed+;multiprocess;vContSupported;QNonStop+"); rdb_response_write_str(res, "no-resumed+;multiprocess;vContSupported;QNonStop+");
return rdb_client_send_packet(client); return rdb_response_send_packet(res);
} }
if (cmd_match_only_str(cmd, "QThreadSuffixSupported")) { if (cmd_match_only_str(cmd, "QThreadSuffixSupported")) {
// The debugger is asking us to include the current thread as a suffix to some responses. // The debugger is asking us to include the current thread as a suffix to some responses.
rdb_client_write_str(client, "OK"); rdb_response_write_str(res, "OK");
return rdb_client_send_packet(client); return rdb_response_send_packet(res);
} }
if (cmd_match_only_str(cmd, "QListThreadsInStopReply")) { if (cmd_match_only_str(cmd, "QListThreadsInStopReply")) {
// The debugger is asking us to list all threads whenever we stop running. // The debugger is asking us to list all threads whenever we stop running.
rdb_client_write_str(client, "OK"); rdb_response_write_str(res, "OK");
return rdb_client_send_packet(client); return rdb_response_send_packet(res);
} }
if (cmd_match_only_str(cmd, "qHostInfo")) { if (cmd_match_only_str(cmd, "qHostInfo")) {
// The debugger is asking us to describe the "host machine" getting debugged. // The debugger is asking us to describe the "host machine" getting debugged.
rdb_client_write_str(client, "triple:"); rdb_response_write_str(res, "triple:");
rdb_client_write_str_hex(client, "v810-unknown-vb"); rdb_response_write_str_hex(res, "v810-unknown-vb");
rdb_client_write_str(client, ";endian:little;ptrsize:4;"); rdb_response_write_str(res, ";endian:little;ptrsize:4;");
return rdb_client_send_packet(client); return rdb_response_send_packet(res);
} }
if (cmd_match_only_str(cmd, "qProcessInfo")) { if (cmd_match_only_str(cmd, "qProcessInfo")) {
// The debugger is asking us to describe the "process" getting debugged. // The debugger is asking us to describe the "process" getting debugged.
// We make up a process with id 1. // We make up a process with id 1.
rdb_client_write_str(client, "pid:1;triple:"); rdb_response_write_str(res, "pid:1;triple:");
rdb_client_write_str_hex(client, "v810-unknown-vb"); rdb_response_write_str_hex(res, "v810-unknown-vb");
rdb_client_write_str(client, "endian:little;ptrsize:4;"); rdb_response_write_str(res, "endian:little;ptrsize:4;");
return rdb_client_send_packet(client); return rdb_response_send_packet(res);
} }
if (cmd_match_str(cmd, "qRegisterInfo")) { if (cmd_match_str(cmd, "qRegisterInfo")) {
// The debugger is asking for information about a specific register. // The debugger is asking for information about a specific register.
uint32_t reg_no; uint32_t reg_no;
if (!cmd_match_hex_number(cmd, &reg_no)) return 1; if (!cmd_match_hex_number(cmd, &reg_no)) return 1;
if (reg_no <= PC_INDEX) { if (reg_no <= PC_INDEX) {
rdb_client_write_str(client, REGISTERS[reg_no]); rdb_response_write_str(res, REGISTERS[reg_no]);
} }
return rdb_client_send_packet(client); return rdb_response_send_packet(res);
} }
if (cmd_match_only_str(cmd, "qfThreadInfo")) { if (cmd_match_only_str(cmd, "qfThreadInfo")) {
// The debugger is asking us to list all threads. Return a list with "thread 1". // The debugger is asking us to list all threads. Return a list with "thread 1".
rdb_client_write_str(client, "mp1.t1"); rdb_response_write_str(res, "mp1.t1");
return rdb_client_send_packet(client); return rdb_response_send_packet(res);
} }
if (cmd_match_only_str(cmd, "qsThreadInfo")) { if (cmd_match_only_str(cmd, "qsThreadInfo")) {
// The debugger is asking us to list all threads. // The debugger is asking us to list all threads.
rdb_client_write_str(client, "l"); rdb_response_write_str(res, "l");
return rdb_client_send_packet(client); return rdb_response_send_packet(res);
} }
if (cmd_match_only_str(cmd, "vCont?")) { if (cmd_match_only_str(cmd, "vCont?")) {
// The debugger is asking which vCont commands we support. // The debugger is asking which vCont commands we support.
rdb_client_write_str(client, "c;C;s;S"); rdb_response_write_str(res, "c;C;s;S");
return rdb_client_send_packet(client); return rdb_response_send_packet(res);
} }
if (cmd_match_only_str(cmd, "qC")) { if (cmd_match_only_str(cmd, "qC")) {
// The debugger is asking for the current thread id. Return "thread 1". // The debugger is asking for the current thread id. Return "thread 1".
rdb_client_write_str(client, "QCp1.t1"); rdb_response_write_str(res, "QCp1.t1");
return rdb_client_send_packet(client); return rdb_response_send_packet(res);
} }
if (cmd_match_str(cmd, "p")) { if (cmd_match_str(cmd, "p")) {
// read a register. // read a register.
uint32_t reg_no; uint32_t reg_no;
if (!cmd_match_hex_number(cmd, &reg_no)) return 1; if (!cmd_match_hex_number(cmd, &reg_no)) return 1;
if (reg_no > PC_INDEX) { if (reg_no > PC_INDEX) {
return rdb_client_send_packet(client); return rdb_response_send_packet(res);
} }
int32_t reg_value; int32_t reg_value;
@ -154,8 +154,8 @@ int handle_command(RdbClient *client, CommandBuf *cmd, VB *sim, bool *running) {
} else { } else {
reg_value = vbGetProgramRegister(sim, reg_no); reg_value = vbGetProgramRegister(sim, reg_no);
} }
rdb_client_write_i32_hex(client, reg_value); rdb_response_write_i32_hex(res, reg_value);
return rdb_client_send_packet(client); return rdb_response_send_packet(res);
} }
if (cmd_match_str(cmd, "P")) { if (cmd_match_str(cmd, "P")) {
// write a register. // write a register.
@ -171,7 +171,7 @@ int handle_command(RdbClient *client, CommandBuf *cmd, VB *sim, bool *running) {
((uint32_t) reg_bytes[0]); ((uint32_t) reg_bytes[0]);
if (reg_no > PC_INDEX) { if (reg_no > PC_INDEX) {
return rdb_client_send_packet(client); return rdb_response_send_packet(res);
} }
if (reg_no == PC_INDEX) { if (reg_no == PC_INDEX) {
vbSetProgramCounter(sim, reg_value); vbSetProgramCounter(sim, reg_value);
@ -180,13 +180,13 @@ int handle_command(RdbClient *client, CommandBuf *cmd, VB *sim, bool *running) {
} else { } else {
vbSetProgramRegister(sim, reg_no, reg_value); vbSetProgramRegister(sim, reg_no, reg_value);
} }
rdb_client_write_str(client, "OK"); rdb_response_write_str(res, "OK");
return rdb_client_send_packet(client); return rdb_response_send_packet(res);
} }
if (cmd_match_str(cmd, "Hc-1")) { if (cmd_match_str(cmd, "Hc-1")) {
// Set the "current thread" for future commands to all threads (thread -1). // Set the "current thread" for future commands to all threads (thread -1).
rdb_client_write_str(client, "OK"); rdb_response_write_str(res, "OK");
return rdb_client_send_packet(client); return rdb_response_send_packet(res);
} }
if (cmd_match_only_str(cmd, "c")) { if (cmd_match_only_str(cmd, "c")) {
// The debugger has told us to run until we are stopped. // The debugger has told us to run until we are stopped.
@ -198,15 +198,15 @@ int handle_command(RdbClient *client, CommandBuf *cmd, VB *sim, bool *running) {
// Received an ETX, indicating that the server wants to cancel the "c" command from before. // Received an ETX, indicating that the server wants to cancel the "c" command from before.
*running = false; *running = false;
// Send the response to the "c" command from before. // Send the response to the "c" command from before.
rdb_client_write_str(client, "T05thread:p1.t1;threads:p1.t1"); rdb_response_write_str(res, "T05thread:p1.t1;threads:p1.t1");
return rdb_client_send_packet(client); return rdb_response_send_packet(res);
} }
if (cmd_match_only_str(cmd, "?")) { if (cmd_match_only_str(cmd, "?")) {
// The debugger has asked us why we stopped // The debugger has asked us why we stopped
rdb_client_write_str(client, "T"); rdb_response_write_str(res, "T");
rdb_client_write_str(client, *running ? "00" : "05"); rdb_response_write_str(res, *running ? "00" : "05");
rdb_client_write_str(client, "thread:p1.t1;threads:p1.t1;"); rdb_response_write_str(res, "thread:p1.t1;threads:p1.t1;");
return rdb_client_send_packet(client); return rdb_response_send_packet(res);
} }
if (cmd_match_str(cmd, "m")) { if (cmd_match_str(cmd, "m")) {
// read memory // read memory
@ -218,11 +218,11 @@ int handle_command(RdbClient *client, CommandBuf *cmd, VB *sim, bool *running) {
for (uint32_t i = 0; i < len; ++i) { for (uint32_t i = 0; i < len; ++i) {
uint8_t byte = vbRead(sim, address + i, VB_U8); uint8_t byte = vbRead(sim, address + i, VB_U8);
rdb_client_write_i8_hex(client, byte); rdb_response_write_i8_hex(res, byte);
} }
return rdb_client_send_packet(client); return rdb_response_send_packet(res);
} }
fprintf(stderr, "Unrecognized command.\n"); fprintf(stderr, "Unrecognized command.\n");
return rdb_client_send_packet(client); return rdb_response_send_packet(res);
} }