risc-v-tlm/src/Debug.cpp

251 lines
6.7 KiB
C++

/*!
\file Debug.cpp
\brief GDB connector
\author Màrius Montón
\date February 2021
*/
// SPDX-License-Identifier: GPL-3.0-or-later
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <sys/socket.h>
#include <netinet/in.h>
#include <boost/algorithm/string.hpp>
#include "Debug.h"
constexpr char nibble_to_hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
Debug::Debug(CPU *cpu, Memory* mem): sc_module(std::string("Debug")) {
dbg_cpu = cpu;
dbg_mem = mem;
int sock = socket(AF_INET, SOCK_STREAM, 0);
int optval = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval,
sizeof(optval));
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(1234);
bind(sock, (struct sockaddr *) &addr, sizeof(addr));
listen(sock, 1);
socklen_t len = sizeof(addr);
conn = accept(sock, (struct sockaddr *) &addr, &len);
handle_gdb_loop();
}
Debug::~Debug() {
}
void Debug::send_packet(int conn, const std::string &msg) {
std::string frame = "+$" + msg + "#" + compute_checksum_string(msg);
memcpy(iobuf, frame.c_str(), frame.size());
::send(conn, iobuf, frame.size(), 0);
}
std::string Debug::receive_packet() {
int nbytes = ::recv(conn, iobuf, bufsize, 0);
if (nbytes == 0) {
return "";
} else if (nbytes == 1) {
return std::string("+");
} else {
char *start = strchr(iobuf, '$');
char *end = strchr(iobuf, '#');
std::string message(start + 1, end - (start + 1));
return message;
}
}
void Debug::handle_gdb_loop() {
std::cout << "Handle_GDB_Loop\n";
Registers *register_bank = dbg_cpu->getRegisterBank();
while (true) {
std::string msg = receive_packet();
if (msg.size() == 0) {
std::cout << "remote connection seems to be closed, terminating ..."
<< std::endl;
break;
} else if (msg == "+") {
// NOTE: just ignore this message, nothing to do in this case
} else if (boost::starts_with(msg, "qSupported")) {
send_packet(conn, "PacketSize=256;swbreak+;hwbreak+;vContSupported+;multiprocess-");
} else if (msg == "vMustReplyEmpty") {
send_packet(conn, "");
} else if (msg == "Hg0") {
send_packet(conn, "OK");
} else if (msg == "Hc0") {
send_packet(conn, "");
} else if (msg == "qTStatus") {
send_packet(conn, "");
} else if (msg == "?") {
send_packet(conn, "S05");
} else if (msg == "qfThreadInfo") {
send_packet(conn, "");
} else if (boost::starts_with(msg, "qL")) {
send_packet(conn, "");
} else if (msg == "Hc-1") {
send_packet(conn, "OK");
} else if (msg == "qC") {
send_packet(conn, "-1");
} else if (msg == "qAttached") {
send_packet(conn, "0"); // 0 process started, 1 attached to process
} else if (msg == "g") {
std::stringstream stream;
stream << std::setfill('0') << std::hex;
for (int i = 1; i < 32; i++) {
stream << std::setw(8) << register_bank->getValue(i);
}
send_packet(conn, stream.str());
} else if (boost::starts_with(msg, "p")) {
long n = strtol(msg.c_str() + 1, 0, 16);
int reg_value;
if (n < 32) {
reg_value = register_bank->getValue(n);
} else if (n == 32) {
reg_value = register_bank->getPC();
} else {
// see: https://github.com/riscv/riscv-gnu-toolchain/issues/217
// risc-v register 834
reg_value = register_bank->getCSR(n - 65);
}
std::stringstream stream;
stream << std::setfill('0') << std::hex;
stream << std::setw(8) << htonl(reg_value);
send_packet(conn, stream.str());
} else if (boost::starts_with(msg, "P")) {
char * pEnd;
long reg = strtol(msg.c_str() + 1, &pEnd, 16);
int val = strtol(pEnd + 1, 0, 16);
register_bank->setValue(reg + 1, val);
send_packet(conn, "OK");
} else if (boost::starts_with(msg, "m")) {
char * pEnd;
long addr = strtol(msg.c_str() + 1, &pEnd, 16);;
int len = strtol(pEnd + 1, &pEnd, 16);
dbg_trans.set_data_ptr(pyld_array);
dbg_trans.set_command(tlm::TLM_READ_COMMAND);
dbg_trans.set_address(addr);
dbg_trans.set_data_length(len);
dbg_mem->transport_dbg(dbg_trans);
std::stringstream stream;
stream << std::setfill('0') << std::hex;
for (auto &c : pyld_array) {
stream << std::setw(2) << (0xFF & c);
}
send_packet(conn, stream.str());
} else if (boost::starts_with(msg, "M")) {
printf("M TBD\n");
send_packet(conn, "OK");
} else if (boost::starts_with(msg, "X")) {
send_packet(conn, ""); // binary data unsupported
} else if (msg == "qOffsets") {
send_packet(conn, "Text=0;Data=0;Bss=0");
} else if (msg == "qSymbol::") {
send_packet(conn, "OK");
} else if (msg == "vCont?") {
send_packet(conn, "vCont;cs");
} else if (msg == "c") {
bool breakpoint_hit = false;
bool bkpt = false;
do {
bkpt = dbg_cpu->CPU_step();
uint32_t currentPC = register_bank->getPC();
auto search = breakpoints.find(currentPC);
if (search != breakpoints.end()) {
breakpoint_hit = true;
}
} while ((breakpoint_hit == false) && (bkpt == false));
std::cout << "Breakpoint hit at 0x" << std::hex << register_bank->getPC() << std::endl;
send_packet(conn, "S05");
} else if (msg == "s") {
bool breakpoint;
dbg_cpu->CPU_step();
uint32_t currentPC = register_bank->getPC();
auto search = breakpoints.find(currentPC);
if (search != breakpoints.end()) {
breakpoint = true;
} else {
breakpoint = false;
}
if (breakpoint) {
send_packet(conn, "S03");
} else {
send_packet(conn, "S05");
}
} else if (boost::starts_with(msg, "vKill")) {
send_packet(conn, "OK");
break;
} else if (boost::starts_with(msg, "Z1")) {
char * pEnd;
long addr = strtol(msg.c_str() + 3, &pEnd, 16);;
breakpoints.insert(addr);
std::cout << "Breakpoint set to address 0x"<< std::hex << addr << std::endl;
send_packet(conn, "OK");
} else if (boost::starts_with(msg, "z1")) {
char * pEnd;
long addr = strtol(msg.c_str() + 3, &pEnd, 16);;
breakpoints.erase(addr);
send_packet(conn, "OK");
} else if (boost::starts_with(msg, "z0")) {
char * pEnd;
long addr = strtol(msg.c_str() + 3, &pEnd, 16);;
breakpoints.erase(addr);
send_packet(conn, "");
} else if (boost::starts_with(msg, "Z0")) {
char * pEnd;
long addr = strtol(msg.c_str() + 3, &pEnd, 16);;
breakpoints.insert(addr);
std::cout << "Breakpoint set to address 0x"<< std::hex << addr << std::endl;
send_packet(conn, "OK");
} else {
std::cout << "unsupported message '" << msg
<< "' detected, terminating ..." << std::endl;
break;
}
}
}
std::string Debug::compute_checksum_string(const std::string &msg) {
unsigned sum = 0;
for (auto c : msg) {
sum += unsigned(c);
}
sum = sum % 256;
char low = nibble_to_hex[sum & 0xf];
char high = nibble_to_hex[(sum & (0xf << 4)) >> 4];
return {high, low};
}