initial version from before
This commit is contained in:
commit
bf969e72b4
|
@ -0,0 +1 @@
|
|||
build
|
|
@ -0,0 +1,214 @@
|
|||
#include <client.h>
|
||||
#include <stdio.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 hex_digit_to_char(char in, char *out) {
|
||||
if (in >= '0' && in <= '9') {
|
||||
*out = in - '0';
|
||||
return true;
|
||||
}
|
||||
if (in >= 'a' && in <= 'f') {
|
||||
*out = in - 'a' + 10;
|
||||
return true;
|
||||
}
|
||||
if (in >= 'A' && in <= 'F') {
|
||||
*out = in - 'A' + 10;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#define BUFFER_LEN 8096
|
||||
|
||||
typedef struct Buffer {
|
||||
char buf[BUFFER_LEN];
|
||||
size_t len;
|
||||
size_t index;
|
||||
} Buffer;
|
||||
|
||||
static Buffer INBUF = {
|
||||
.len = 0,
|
||||
.index = 0,
|
||||
};
|
||||
|
||||
static ssize_t read_next_char(int connfd, char *in) {
|
||||
if (INBUF.index >= INBUF.len) {
|
||||
ssize_t inlen = read(connfd, INBUF.buf, BUFFER_LEN);
|
||||
if (inlen < 1) {
|
||||
// either we got an error (-1) or the connection closed (0)
|
||||
return inlen;
|
||||
}
|
||||
INBUF.index = 0;
|
||||
INBUF.len = inlen;
|
||||
}
|
||||
*in = INBUF.buf[INBUF.index++];
|
||||
return 1;
|
||||
}
|
||||
|
||||
ssize_t rdb_client_read(RdbClient *self, char *buf, size_t len) {
|
||||
// read any acknowledgements and continue
|
||||
char in;
|
||||
do {
|
||||
ssize_t res = read_next_char(self->connfd, &in);
|
||||
if (res < 1) return res;
|
||||
} while (in == '+');
|
||||
|
||||
if (in == '\x03') {
|
||||
// interrupt from the server
|
||||
*buf = in;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (in == '-') {
|
||||
// we don't handle resending right now
|
||||
return -1;
|
||||
}
|
||||
|
||||
// now, expect to be at the start of a packet
|
||||
if (in != '$') {
|
||||
fprintf(stderr, "unexpected packet start \"%c\"", in);
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t outlen = 0;
|
||||
char chk = 0;
|
||||
while (1) {
|
||||
ssize_t res = read_next_char(self->connfd, &in);
|
||||
if (res < 1) return res;
|
||||
|
||||
if (in == '#') {
|
||||
// end of packet, checksum next
|
||||
break;
|
||||
}
|
||||
if (outlen >= len) {
|
||||
// ran out of room in the buffer
|
||||
fprintf(stderr, "packet too big for buffer\n");
|
||||
return -1;
|
||||
}
|
||||
if (in == '}') {
|
||||
// escape sequence
|
||||
chk += in;
|
||||
res = read_next_char(self->connfd, &in);
|
||||
if (res < 1) return res;
|
||||
chk += in;
|
||||
buf[outlen++] = in ^ 0x20;
|
||||
} else {
|
||||
chk += in;
|
||||
buf[outlen++] = in;
|
||||
}
|
||||
};
|
||||
|
||||
// validate the checksum
|
||||
char hi, lo;
|
||||
|
||||
ssize_t res = read_next_char(self->connfd, &in);
|
||||
if (res < 1) return res;
|
||||
if (!hex_digit_to_char(in, &hi)) return -1;
|
||||
|
||||
res = read_next_char(self->connfd, &in);
|
||||
if (res < 1) return res;
|
||||
if (!hex_digit_to_char(in, &lo)) return -1;
|
||||
|
||||
char real_chk = (hi << 4) | lo;
|
||||
if (real_chk != chk) {
|
||||
fprintf(stderr, "invalid checksum\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return outlen;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef RDBSERVER_CLIENT_H_
|
||||
#define RDBSERVER_CLIENT_H_
|
||||
|
||||
#include <stdbool.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);
|
||||
ssize_t rdb_client_read(RdbClient *self, char *buf, size_t len);
|
||||
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);
|
||||
int rdb_client_send_packet(RdbClient *self);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,286 @@
|
|||
#include <client.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
|
||||
const size_t BUFLEN = 8096;
|
||||
|
||||
const char* REGISTERS[] = {
|
||||
"name:r0;bitsize:32;offset:0;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:r1;bitsize:32;offset:4;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:fp;alt-name:r2;bitsize:32;offset:8;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0;generic:fp",
|
||||
"name:sp;alt-name:r3;bitsize:32;offset:12;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0;generic:sp",
|
||||
"name:gp;alt-name:r4;bitsize:32;offset:16;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:tp;alt-name:r5;bitsize:32;offset:20;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:r6;bitsize:32;offset:24;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0;generic:arg1",
|
||||
"name:r7;bitsize:32;offset:28;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0;generic:arg2",
|
||||
"name:r8;bitsize:32;offset:32;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0;generic:arg3",
|
||||
"name:r9;bitsize:32;offset:36;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0;generic:arg4",
|
||||
"name:r10;bitsize:32;offset:40;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:r11;bitsize:32;offset:44;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:r12;bitsize:32;offset:48;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:r13;bitsize:32;offset:52;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:r14;bitsize:32;offset:56;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:r15;bitsize:32;offset:60;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:r16;bitsize:32;offset:64;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:r17;bitsize:32;offset:68;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:r18;bitsize:32;offset:72;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:r19;bitsize:32;offset:76;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:r20;bitsize:32;offset:80;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:r21;bitsize:32;offset:84;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:r22;bitsize:32;offset:88;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:r23;bitsize:32;offset:92;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:r24;bitsize:32;offset:96;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:r25;bitsize:32;offset:100;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:r26;bitsize:32;offset:104;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:r27;bitsize:32;offset:108;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:r28;bitsize:32;offset:112;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:r29;bitsize:32;offset:116;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:r30;bitsize:32;offset:120;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
|
||||
"name:lp;alt-name:r31;bitsize:32;offset:124;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0;generic:ra",
|
||||
"name:pc;bitsize:32;offset:128;encoding:uint;format:hex;set:Special Registers;dwarf:0;generic:pc",
|
||||
};
|
||||
|
||||
bool read_hex_digit(char digit, char *out) {
|
||||
if (digit >= '0' && digit <= '9') {
|
||||
*out = digit - '0';
|
||||
return true;
|
||||
}
|
||||
if (digit >= 'a' && digit <= 'f') {
|
||||
*out = digit - 'a' + 10;
|
||||
return true;
|
||||
}
|
||||
if (digit >= 'A' && digit <= 'F') {
|
||||
*out = digit - 'A' + 10;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool read_hex(char *buf, int len, int *out) {
|
||||
*out = 0;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
char outdigit;
|
||||
if (!read_hex_digit(buf[i], &outdigit)) return false;
|
||||
*out = (*out << 4) | (int) outdigit;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool read_hex_byte(char *buf, char *val) {
|
||||
char digit1, digit2;
|
||||
if (!read_hex_digit(buf[0], &digit1) || !read_hex_digit(buf[1], &digit2)) {
|
||||
return false;
|
||||
}
|
||||
*val = (digit1 << 4) | digit2;
|
||||
return true;
|
||||
}
|
||||
|
||||
int handle_command(RdbClient *client, char *cmd, size_t cmdlen) {
|
||||
rdb_client_begin_packet(client);
|
||||
|
||||
if (!strncmp(cmd, "\x03", cmdlen)) {
|
||||
rdb_client_write_str(client, "T05thread:p1.t1;threads:p1.t1;thread-pcs:07000000;00:00000000;01:00000001;20;07000000");
|
||||
return rdb_client_send_packet(client);
|
||||
}
|
||||
|
||||
if (!strncmp(cmd, "QStartNoAckMode", cmdlen)) {
|
||||
client->should_ack = false;
|
||||
rdb_client_write_str(client, "OK");
|
||||
return rdb_client_send_packet(client);
|
||||
}
|
||||
if (!strncmp(cmd, "qSupported", 10)) {
|
||||
rdb_client_write_str(client, "no-resumed+;multiprocess;vContSupported;QNonStop+");
|
||||
return rdb_client_send_packet(client);
|
||||
}
|
||||
if (!strncmp(cmd, "QThreadSuffixSupported", cmdlen)) {
|
||||
rdb_client_write_str(client, "OK");
|
||||
return rdb_client_send_packet(client);
|
||||
}
|
||||
if (!strncmp(cmd, "QListThreadsInStopReply", cmdlen)) {
|
||||
rdb_client_write_str(client, "OK");
|
||||
return rdb_client_send_packet(client);
|
||||
}
|
||||
if (!strncmp(cmd, "qHostInfo", cmdlen)) {
|
||||
rdb_client_write_str(client, "triple:");
|
||||
rdb_client_write_str_hex(client, "v810-unknown-vb");
|
||||
rdb_client_write_str(client, ";endian:little;ptrsize:4;");
|
||||
return rdb_client_send_packet(client);
|
||||
}
|
||||
if (!strncmp(cmd, "qProcessInfo", cmdlen)) {
|
||||
rdb_client_write_str(client, "pid:1;triple:");
|
||||
rdb_client_write_str_hex(client, "v810-unknown-vb");
|
||||
rdb_client_write_str(client, "endian:little;ptrsize:4;");
|
||||
return rdb_client_send_packet(client);
|
||||
}
|
||||
if (!strncmp(cmd, "qRegisterInfo", 13)) {
|
||||
char reg;
|
||||
if (cmdlen == 14) {
|
||||
if (!read_hex_digit(cmd[13], ®)) return 1;
|
||||
} else {
|
||||
if (!read_hex_byte(cmd + 13, ®)) return 1;
|
||||
}
|
||||
if (reg < 33) {
|
||||
rdb_client_write_str(client, REGISTERS[(size_t) reg]);
|
||||
}
|
||||
return rdb_client_send_packet(client);
|
||||
}
|
||||
if (!strncmp(cmd, "qfThreadInfo", cmdlen)) {
|
||||
rdb_client_write_str(client, "mp1.t1");
|
||||
return rdb_client_send_packet(client);
|
||||
}
|
||||
if (!strncmp(cmd, "qsThreadInfo", cmdlen)) {
|
||||
rdb_client_write_str(client, "l");
|
||||
return rdb_client_send_packet(client);
|
||||
}
|
||||
if (!strncmp(cmd, "vCont?", cmdlen)) {
|
||||
rdb_client_write_str(client, "c;C;s;S");
|
||||
return rdb_client_send_packet(client);
|
||||
}
|
||||
if (!strncmp(cmd, "qVAttachOrWaitSupported", cmdlen)) {
|
||||
return rdb_client_send_packet(client);
|
||||
}
|
||||
if (!strncmp(cmd, "qC", cmdlen)) {
|
||||
rdb_client_write_str(client, "QCp1.t1");
|
||||
return rdb_client_send_packet(client);
|
||||
}
|
||||
if (!strncmp(cmd, "p", 1)) {
|
||||
rdb_client_write_str(client, "00000000");
|
||||
return rdb_client_send_packet(client);
|
||||
}
|
||||
if (!strncmp(cmd, "Hc-1", 1)) {
|
||||
rdb_client_write_str(client, "OK");
|
||||
return rdb_client_send_packet(client);
|
||||
}
|
||||
if (!strncmp(cmd, "c", cmdlen)) {
|
||||
printf("running until we hit a breakpoint or the server stops us\n");
|
||||
return 0;
|
||||
}
|
||||
if (!strncmp(cmd, "?", cmdlen)) {
|
||||
rdb_client_write_str(client, "T00thread:p1.t1;threads:p1.t1;thread-pcs:00000007;");
|
||||
return rdb_client_send_packet(client);
|
||||
}
|
||||
if (!strncmp(cmd, "qMemoryRegionInfo:", 18)) {
|
||||
rdb_client_write_str(client, "start:0;size:100000000;permissions:rx;name:");
|
||||
rdb_client_write_str_hex(client, "ROM");
|
||||
rdb_client_write_str(client, ";");
|
||||
return rdb_client_send_packet(client);
|
||||
}
|
||||
if (!strncmp(cmd, "m7000000,100", cmdlen)) {
|
||||
// hard-coded fake memory region
|
||||
const char *fake = "80bc000784a0e002a0bc0005a5a00000c0bc0005c6a0000000a81000";
|
||||
size_t fakelen = strlen(fake) / 2;
|
||||
rdb_client_write_str(client, fake);
|
||||
for (size_t i = fakelen; i < 256; ++i) {
|
||||
rdb_client_write_str(client, "00");
|
||||
}
|
||||
return rdb_client_send_packet(client);
|
||||
}
|
||||
if (*cmd == 'm') {
|
||||
// all other memory is 0
|
||||
int commapos = -1;
|
||||
for (size_t i = 2; i < cmdlen; ++i) {
|
||||
if (cmd[i] == ',') {
|
||||
commapos = (int) i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (commapos == -1) {
|
||||
fprintf(stderr, "malformed memory read");
|
||||
return -1;
|
||||
}
|
||||
int address, len;
|
||||
if (!read_hex(cmd + 1, commapos - 1, &address) ||
|
||||
!read_hex(cmd + commapos + 1, cmdlen - commapos - 1, &len)) {
|
||||
fprintf(stderr, "malformed memory read");
|
||||
return -1;
|
||||
}
|
||||
printf("read %d bytes from %d\n", len, address);
|
||||
for (int i = 0; i < len; ++i) {
|
||||
rdb_client_write_str(client, "00");
|
||||
}
|
||||
return rdb_client_send_packet(client);
|
||||
}
|
||||
fprintf(stderr, "Unrecognized command %.*s\n", (int) cmdlen, cmd);
|
||||
return rdb_client_send_packet(client);
|
||||
}
|
||||
|
||||
|
||||
int server(int connfd) {
|
||||
RdbClient client;
|
||||
rdb_client_init(&client, connfd);
|
||||
|
||||
char buf[BUFLEN];
|
||||
while (1) {
|
||||
ssize_t len = rdb_client_read(&client, buf, BUFLEN);
|
||||
if (len < 0) {
|
||||
perror("could not read data");
|
||||
return -len;
|
||||
} else if (len == 0) {
|
||||
printf("client has disconnected\n");
|
||||
return 0;
|
||||
} else {
|
||||
printf("received command \"%.*s\"\n", (int) len, buf);
|
||||
fflush(stdout);
|
||||
int res = handle_command(&client, buf, len);
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
// +$QStartNoAckMode#b0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
short port;
|
||||
if (argc > 1) {
|
||||
char *end;
|
||||
port = (short) strtol(argv[1], &end, 10);
|
||||
if (argv[1] == end) {
|
||||
perror("could not parse port");
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
port = 8080;
|
||||
}
|
||||
|
||||
int fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (fd == -1) {
|
||||
perror("could not open socket");
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
|
||||
perror("could not bind socket");
|
||||
return 1;
|
||||
}
|
||||
if (listen(fd, 1) == -1) {
|
||||
perror("could not listen on socket");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("connecting\n");
|
||||
int connfd;
|
||||
struct sockaddr_in cliaddr;
|
||||
socklen_t cliaddrlen = sizeof(cliaddr);
|
||||
connfd = accept(fd, (struct sockaddr *) &cliaddr, &cliaddrlen);
|
||||
if (connfd == -1) {
|
||||
perror("could not accept connection");
|
||||
return 1;
|
||||
}
|
||||
printf("connected\n");
|
||||
|
||||
int response = server(connfd);
|
||||
return close(connfd)
|
||||
|| close(fd)
|
||||
|| response;
|
||||
}
|
Loading…
Reference in New Issue