#include #include #include #include #include #include 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; }