gdb can now read spike memory.
[riscv-isa-sim.git] / riscv / gdbserver.cc
index e2481bca0670f32f95b2bcd03c4cfba56b253d17..40ee4b2572aa8a95cae8d9ff142369fe85da56c1 100644 (file)
@@ -12,6 +12,8 @@
 #include <cstdio>
 #include <vector>
 
+#include "disasm.h"
+#include "sim.h"
 #include "gdbserver.h"
 
 template <typename T>
@@ -82,7 +84,8 @@ void circular_buffer_t<T>::append(const T *src, unsigned int count)
 
 // Code inspired by/copied from OpenOCD server/server.c.
 
-gdbserver_t::gdbserver_t(uint16_t port) :
+gdbserver_t::gdbserver_t(uint16_t port, sim_t *sim) :
+  sim(sim),
   client_fd(0),
   recv_buf(64 * 1024), send_buf(64 * 1024)
 {
@@ -222,7 +225,7 @@ uint8_t character_hex_value(uint8_t character)
     return 10 + character - 'a';
   if (character >= 'A' && character <= 'F')
     return 10 + character - 'A';
-  return 0;
+  return 0xff;
 }
 
 uint8_t extract_checksum(const std::vector<uint8_t> &packet)
@@ -274,19 +277,78 @@ void gdbserver_t::process_requests()
   }
 }
 
-void gdbserver_t::handle_set_threadid(const std::vector<uint8_t> &packet)
+void gdbserver_t::handle_halt_reason(const std::vector<uint8_t> &packet)
 {
-  if (packet[2] == 'g' && packet[3] == '0') {
-    // Use thread 0 for all operations.
-    send("OK");
-  } else {
-    send("$#00");
+  send_packet("S00");
+}
+
+void gdbserver_t::handle_read_general_registers(const std::vector<uint8_t> &packet)
+{
+  // Register order that gdb expects is:
+  //   "x0",  "x1",  "x2",  "x3",  "x4",  "x5",  "x6",  "x7",
+  //   "x8",  "x9",  "x10", "x11", "x12", "x13", "x14", "x15",
+  //   "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
+  //   "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31",
+  //   "pc",
+  //   "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
+  //   "f8",  "f9",  "f10", "f11", "f12", "f13", "f14", "f15",
+  //   "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+  //   "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
+
+  send("$");
+  running_checksum = 0;
+  char buffer[17];
+  processor_t *p = sim->get_core(0);
+  for (int r = 0; r < 32; r++) {
+    sprintf(buffer, "%08lx", p->state.XPR[r]);
+    send(buffer);
   }
+  send_running_checksum();
+  expect_ack = true;
 }
 
-void gdbserver_t::handle_halt_reason(const std::vector<uint8_t> &packet)
+uint64_t consume_hex_number(std::vector<uint8_t>::const_iterator &iter,
+    std::vector<uint8_t>::const_iterator end)
 {
-  send_packet("S00");
+  uint64_t value = 0;
+
+  while (iter != end) {
+    uint8_t c = *iter;
+    uint64_t c_value = character_hex_value(c);
+    if (c_value > 15)
+      break;
+    iter++;
+    value <<= 4;
+    value += c_value;
+  }
+  return value;
+}
+
+void gdbserver_t::handle_read_memory(const std::vector<uint8_t> &packet)
+{
+  // m addr,length
+  std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
+  reg_t address = consume_hex_number(iter, packet.end());
+  printf("address=%lx %c\n", address, *iter);
+  if (*iter != ',')
+    return send_packet("E16"); // EINVAL
+  iter++;
+  reg_t length = consume_hex_number(iter, packet.end());
+  printf("length=%lx %c\n", length, *iter);
+  if (*iter != '#')
+    return send_packet("E16"); // EINVAL
+
+  send("$");
+  running_checksum = 0;
+  char buffer[3];
+  processor_t *p = sim->get_core(0);
+  mmu_t* mmu = sim->debug_mmu;
+
+  for (reg_t i = 0; i < length; i++) {
+    sprintf(buffer, "%02x", mmu->load_uint8(address + i));
+    send(buffer);
+  }
+  send_running_checksum();
 }
 
 void gdbserver_t::handle_packet(const std::vector<uint8_t> &packet)
@@ -304,10 +366,12 @@ void gdbserver_t::handle_packet(const std::vector<uint8_t> &packet)
   send("+");
 
   switch (packet[1]) {
-    case 'H':
-      return handle_set_threadid(packet);
     case '?':
       return handle_halt_reason(packet);
+    case 'g':
+      return handle_read_general_registers(packet);
+    case 'm':
+      return handle_read_memory(packet);
   }
 
   // Not supported.
@@ -330,21 +394,23 @@ void gdbserver_t::handle()
 void gdbserver_t::send(const char* msg)
 {
   unsigned int length = strlen(msg);
+  for (const char *c = msg; *c; c++)
+    running_checksum += *c;
   send_buf.append((const uint8_t *) msg, length);
 }
 
 void gdbserver_t::send_packet(const char* data)
 {
   send("$");
+  running_checksum = 0;
   send(data);
-  send("#");
+  send_running_checksum();
+  expect_ack = true;
+}
 
-  uint8_t checksum = 0;
-  for ( ; *data; data++) {
-    checksum += *data;
-  }
-  char checksum_string[3];
-  sprintf(checksum_string, "%02x", checksum);
+void gdbserver_t::send_running_checksum()
+{
+  char checksum_string[4];
+  sprintf(checksum_string, "#%02x", running_checksum);
   send(checksum_string);
-  expect_ack = true;
 }