229 lines
11 KiB
C
229 lines
11 KiB
C
#include <server.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
|
|
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(RdbResponse *res, CommandBuf *cmd, VB *sim, bool *running) {
|
|
rdb_response_begin_packet(res);
|
|
|
|
if (cmd_match_str(cmd, "QStartNoAckMode")) {
|
|
// The debugger is asking us to no longer ACK messages.
|
|
// Note that we ack THIS response, because we already called rdb_response_begin_packet.
|
|
res->should_ack = false;
|
|
rdb_response_write_str(res, "OK");
|
|
return rdb_response_send_packet(res);
|
|
}
|
|
if (cmd_match_str(cmd, "qSupported")) {
|
|
// The debugger is asking for a list of features we support.
|
|
rdb_response_write_str(res, "no-resumed+;multiprocess;vContSupported;QNonStop+");
|
|
return rdb_response_send_packet(res);
|
|
}
|
|
if (cmd_match_str(cmd, "QThreadSuffixSupported")) {
|
|
// The debugger is asking us to include the current thread as a suffix to some responses.
|
|
rdb_response_write_str(res, "OK");
|
|
return rdb_response_send_packet(res);
|
|
}
|
|
if (cmd_match_str(cmd, "QListThreadsInStopReply")) {
|
|
// The debugger is asking us to list all threads whenever we stop running.
|
|
rdb_response_write_str(res, "OK");
|
|
return rdb_response_send_packet(res);
|
|
}
|
|
if (cmd_match_str(cmd, "qHostInfo")) {
|
|
// The debugger is asking us to describe the "host machine" getting debugged.
|
|
rdb_response_write_str(res, "triple:");
|
|
rdb_response_write_str_hex(res, "v810-unknown-vb");
|
|
rdb_response_write_str(res, ";endian:little;ptrsize:4;");
|
|
return rdb_response_send_packet(res);
|
|
}
|
|
if (cmd_match_str(cmd, "qProcessInfo")) {
|
|
// The debugger is asking us to describe the "process" getting debugged.
|
|
// We make up a process with id 1.
|
|
rdb_response_write_str(res, "pid:1;triple:");
|
|
rdb_response_write_str_hex(res, "v810-unknown-vb");
|
|
rdb_response_write_str(res, "endian:little;ptrsize:4;");
|
|
return rdb_response_send_packet(res);
|
|
}
|
|
if (cmd_match_str(cmd, "qRegisterInfo")) {
|
|
// The debugger is asking for information about a specific register.
|
|
uint32_t reg_no;
|
|
if (!cmd_match_hex_number(cmd, ®_no)) return 1;
|
|
if (reg_no <= PC_INDEX) {
|
|
rdb_response_write_str(res, REGISTERS[reg_no]);
|
|
}
|
|
return rdb_response_send_packet(res);
|
|
}
|
|
if (cmd_match_str(cmd, "qfThreadInfo")) {
|
|
// The debugger is asking us to list all threads. Return a list with "thread 1".
|
|
rdb_response_write_str(res, "mp1.t1");
|
|
return rdb_response_send_packet(res);
|
|
}
|
|
if (cmd_match_str(cmd, "qsThreadInfo")) {
|
|
// The debugger is asking us to list all threads.
|
|
rdb_response_write_str(res, "l");
|
|
return rdb_response_send_packet(res);
|
|
}
|
|
if (cmd_match_str(cmd, "vCont?")) {
|
|
// The debugger is asking which vCont commands we support.
|
|
rdb_response_write_str(res, "c;C;s;S");
|
|
return rdb_response_send_packet(res);
|
|
}
|
|
if (cmd_match_str(cmd, "qC")) {
|
|
// The debugger is asking for the current thread id. Return "thread 1".
|
|
rdb_response_write_str(res, "QCp1.t1");
|
|
return rdb_response_send_packet(res);
|
|
}
|
|
if (cmd_match_str(cmd, "p")) {
|
|
// read a register.
|
|
uint32_t reg_no;
|
|
if (!cmd_match_hex_number(cmd, ®_no)) return 1;
|
|
if (reg_no > PC_INDEX) {
|
|
return rdb_response_send_packet(res);
|
|
}
|
|
|
|
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_response_write_i32_hex(res, reg_value);
|
|
return rdb_response_send_packet(res);
|
|
}
|
|
if (cmd_match_str(cmd, "P")) {
|
|
// write a register.
|
|
uint32_t reg_no;
|
|
uint8_t 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) {
|
|
return rdb_response_send_packet(res);
|
|
}
|
|
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_response_write_str(res, "OK");
|
|
return rdb_response_send_packet(res);
|
|
}
|
|
if (cmd_match_str(cmd, "Hc-1")) {
|
|
// Set the "current thread" for future commands to all threads (thread -1).
|
|
rdb_response_write_str(res, "OK");
|
|
return rdb_response_send_packet(res);
|
|
}
|
|
if (cmd_match_str(cmd, "c")) {
|
|
// The debugger has told us to run until we are stopped.
|
|
// Don't send a response to this until we receive an ETX (when the debugger pauses us).
|
|
*running = true;
|
|
return 0;
|
|
}
|
|
if (cmd_match_str(cmd, "\x03")) {
|
|
// Received an ETX, indicating that the server wants to cancel the "c" command from before.
|
|
*running = false;
|
|
// Send the response to the "c" command from before.
|
|
rdb_response_write_str(res, "T05thread:p1.t1;threads:p1.t1");
|
|
return rdb_response_send_packet(res);
|
|
}
|
|
if (cmd_match_str(cmd, "?")) {
|
|
// The debugger has asked us why we stopped
|
|
rdb_response_write_str(res, "T");
|
|
rdb_response_write_str(res, *running ? "00" : "05");
|
|
rdb_response_write_str(res, "thread:p1.t1;threads:p1.t1;");
|
|
return rdb_response_send_packet(res);
|
|
}
|
|
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;
|
|
|
|
for (uint32_t i = 0; i < len; ++i) {
|
|
uint8_t byte = vbRead(sim, address + i, VB_U8);
|
|
rdb_response_write_i8_hex(res, byte);
|
|
}
|
|
return rdb_response_send_packet(res);
|
|
}
|
|
fprintf(stderr, "Unrecognized command.\n");
|
|
return rdb_response_send_packet(res);
|
|
}
|
|
|