#include #include #include #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:eipc;alt-name:sr0;bitsize:32;offset:128;encoding:uint;format:hex;set:Special Registers;dwarf:0", "name:eipsw;alt-name:sr1;bitsize:32;offset:132;encoding:uint;format:hex;set:Special Registers;dwarf:0", "name:fepc;alt-name:sr2;bitsize:32;offset:136;encoding:uint;format:hex;set:Special Registers;dwarf:0", "name:fepsw;alt-name:sr3;bitsize:32;offset:140;encoding:uint;format:hex;set:Special Registers;dwarf:0", "name:ecr;alt-name:sr4;bitsize:32;offset:144;encoding:uint;format:hex;set:Special Registers;dwarf:0", "name:psw;alt-name:sr5;bitsize:32;offset:148;encoding:uint;format:hex;set:Special Registers;dwarf:0;generic:flags", "name:pir;alt-name:sr6;bitsize:32;offset:152;encoding:uint;format:hex;set:Special Registers;dwarf:0", "name:tkcw;alt-name:sr7;bitsize:32;offset:156;encoding:uint;format:hex;set:Special Registers;dwarf:0", "name:chcw;alt-name:sr24;bitsize:32;offset:160;encoding:uint;format:hex;set:Special Registers;dwarf:0", "name:adtre;alt-name:sr25;bitsize:32;offset:164;encoding:uint;format:hex;set:Special Registers;dwarf:0", "name:sr29;bitsize:32;offset:168;encoding:uint;format:hex;set:Special Registers;dwarf:0", "name:sr30;bitsize:32;offset:172;encoding:uint;format:hex;set:Special Registers;dwarf:0", "name:sr31;bitsize:32;offset:176;encoding:uint;format:hex;set:Special Registers;dwarf:0", "name:pc;bitsize:32;offset:180;encoding:uint;format:hex;set:Special Registers;dwarf:0;generic:pc", }; const uint32_t SYSTEM_REGISTERS[] = { VB_EIPC, VB_EIPSW, VB_FEPC, VB_FEPSW, VB_ECR, VB_PSW, VB_PIR, VB_TKCW, VB_CHCW, VB_ADTRE, 29, 30, 31, }; const uint32_t PC_INDEX = 32 + 13; int handle_command(RdbClient *client, CommandBuf *cmd, VB *sim) { rdb_client_begin_packet(client); if (cmd_match_only_str(cmd, "\x03")) { rdb_client_write_str(client, "T05thread:p1.t1;threads:p1.t1"); return rdb_client_send_packet(client); } if (cmd_match_only_str(cmd, "QStartNoAckMode")) { client->should_ack = false; rdb_client_write_str(client, "OK"); return rdb_client_send_packet(client); } if (cmd_match_str(cmd, "qSupported")) { rdb_client_write_str(client, "no-resumed+;multiprocess;vContSupported;QNonStop+"); return rdb_client_send_packet(client); } if (cmd_match_only_str(cmd, "QThreadSuffixSupported")) { rdb_client_write_str(client, "OK"); return rdb_client_send_packet(client); } if (cmd_match_only_str(cmd, "QListThreadsInStopReply")) { rdb_client_write_str(client, "OK"); return rdb_client_send_packet(client); } if (cmd_match_only_str(cmd, "qHostInfo")) { 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 (cmd_match_only_str(cmd, "qProcessInfo")) { 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 (cmd_match_str(cmd, "qRegisterInfo")) { uint32_t reg_no; if (!cmd_match_hex_number(cmd, ®_no)) return 1; if (reg_no <= PC_INDEX) { rdb_client_write_str(client, REGISTERS[reg_no]); } return rdb_client_send_packet(client); } if (cmd_match_only_str(cmd, "qfThreadInfo")) { rdb_client_write_str(client, "mp1.t1"); return rdb_client_send_packet(client); } if (cmd_match_only_str(cmd, "qsThreadInfo")) { rdb_client_write_str(client, "l"); return rdb_client_send_packet(client); } if (cmd_match_only_str(cmd, "vCont?")) { rdb_client_write_str(client, "c;C;s;S"); return rdb_client_send_packet(client); } if (cmd_match_only_str(cmd, "qVAttachOrWaitSupported")) { return rdb_client_send_packet(client); } if (cmd_match_only_str(cmd, "qC")) { rdb_client_write_str(client, "QCp1.t1"); return rdb_client_send_packet(client); } if (cmd_match_str(cmd, "p")) { uint32_t reg_no; if (!cmd_match_hex_number(cmd, ®_no)) return 1; int32_t reg_value; if (reg_no == PC_INDEX) { reg_value = vbGetProgramCounter(sim); } else if (reg_no > 31) { reg_value = vbGetSystemRegister(sim, SYSTEM_REGISTERS[reg_no - 32]); } else { reg_value = vbGetProgramRegister(sim, reg_no); } rdb_client_write_i32_hex(client, reg_value); return rdb_client_send_packet(client); } if (cmd_match_str(cmd, "P")) { uint32_t reg_no; char reg_bytes[4]; if (!cmd_match_hex_number(cmd, ®_no)) return -1; if (!cmd_match_str(cmd, "=")) return -1; if (!cmd_match_hex_bytes(cmd, 4, reg_bytes)) return -1; int32_t reg_value = ((uint32_t) (reg_bytes[3]) << 24) | ((uint32_t) (reg_bytes[2]) << 16) | ((uint32_t) (reg_bytes[1]) << 8) | ((uint32_t) reg_bytes[0]); if (reg_no == PC_INDEX) { vbSetProgramCounter(sim, reg_value); } else if (reg_no > 31) { vbSetSystemRegister(sim, SYSTEM_REGISTERS[reg_no - 32], reg_value); } else { vbSetProgramRegister(sim, reg_no, reg_value); } rdb_client_write_str(client, "OK"); return rdb_client_send_packet(client); } if (cmd_match_str(cmd, "Hc-1")) { rdb_client_write_str(client, "OK"); return rdb_client_send_packet(client); } if (cmd_match_only_str(cmd, "c")) { printf("running until we hit a breakpoint or the server stops us\n"); return 0; } if (cmd_match_only_str(cmd, "?")) { rdb_client_write_str(client, "T00thread:p1.t1;threads:p1.t1;"); return rdb_client_send_packet(client); } if (cmd_match_str(cmd, "qMemoryRegionInfo:")) { 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 (cmd_match_str(cmd, "m")) { // read memory uint32_t address; uint32_t len; if (!cmd_match_hex_number(cmd, &address)) return -1; if (!cmd_match_str(cmd, ",")) return -1; if (!cmd_match_hex_number(cmd, &len)) return -1; printf("read %d bytes from %d\n", len, address); for (uint32_t i = 0; i < len; ++i) { uint8_t byte = vbRead(sim, address + i, VB_U8); rdb_client_write_i8_hex(client, byte); } return rdb_client_send_packet(client); } fprintf(stderr, "Unrecognized command."); return rdb_client_send_packet(client); } int server(int connfd, VB *sim) { 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); CommandBuf cmd; cmd.buf = buf; cmd.len = len; int res = handle_command(&client, &cmd, sim); if (res != 0) { return res; } // +$QStartNoAckMode#b0 } } } int readROM(VB *sim, char *filename) { FILE *file = fopen(filename, "rb"); long size; if (!file) { perror("could not open file"); return 1; } if (fseek(file, 0, SEEK_END)) { perror("could not seek file end"); return 1; } size = ftell(file); if (size == -1) { perror("could not read file size"); return 1; } if (fseek(file, 0, SEEK_SET)) { perror("could not seek file start"); return 1; } uint8_t *rom = malloc(size); if (!rom) { perror("could not allocate ROM"); return 1; } fread(rom, 1, size, file); if (ferror(file)) { perror("could not read file"); return 1; } if (fclose(file)) { perror("could not close file"); return 1; } vbSetCartROM(sim, rom, size); return 0; } int main(int argc, char** argv) { if (argc < 2) { fprintf(stderr, "Please pass a ROM file\n"); return 1; } VB *sim = malloc(vbSizeOf()); if (!sim) { return 1; } vbInit(sim); if (readROM(sim, argv[1])) { return 1; } vbSetProgramCounter(sim, 0x07000000); short port; if (argc > 2) { char *end; port = (short) strtol(argv[2], &end, 10); if (argv[2] == 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, sim); return close(connfd) || close(fd) || response; }