Software breakpoints seem to work.
authorTim Newsome <tim@sifive.com>
Thu, 10 Mar 2016 20:29:29 +0000 (12:29 -0800)
committerTim Newsome <tim@sifive.com>
Mon, 23 May 2016 19:12:09 +0000 (12:12 -0700)
riscv/execute.cc
riscv/gdbserver.cc
riscv/gdbserver.h
riscv/processor.cc

index b6326004dca14a2a678bf4f40cdc0aabf71cd489..4bfaf4a9d693bc1919271565e2581d48c0fe76d2 100644 (file)
@@ -59,11 +59,8 @@ void processor_t::step(size_t n)
     halted = false;
     n = 1;
   }
-  if (halted) {
-    return;
-  }
 
-  while (run && n > 0) {
+  while (run && !halted && n > 0) {
     size_t instret = 0;
     reg_t pc = state.pc;
     mmu_t* _mmu = mmu;
index e8517aed63d3ec5c986cada36bc8856f17cc72bc..83bc01387dc04aa25a3d26f88de9233f83cfaed6 100644 (file)
@@ -17,6 +17,9 @@
 #include "gdbserver.h"
 #include "mmu.h"
 
+#define C_EBREAK        0x9002
+#define EBREAK          0x00100073
+
 template <typename T>
 unsigned int circular_buffer_t<T>::size() const
 {
@@ -96,6 +99,12 @@ gdbserver_t::gdbserver_t(uint16_t port, sim_t *sim) :
   }
 
   fcntl(socket_fd, F_SETFL, O_NONBLOCK);
+  int reuseaddr = 1;
+  if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
+        sizeof(int)) == -1) {
+    fprintf(stderr, "failed setsockopt: %s (%d)\n", strerror(errno), errno);
+    abort();
+  }
 
   struct sockaddr_in addr;
   memset(&addr, 0, sizeof(addr));
@@ -346,7 +355,7 @@ void gdbserver_t::handle_register_read(const std::vector<uint8_t> &packet)
   std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
   unsigned int n = consume_hex_number(iter, packet.end());
   if (*iter != '#')
-    return send_packet("E16"); // EINVAL
+    return send_packet("E01");
 
   processor_t *p = sim->get_core(0);
   send("$");
@@ -356,7 +365,7 @@ void gdbserver_t::handle_register_read(const std::vector<uint8_t> &packet)
   } else if (n == 0x20) {
     send(p->state.pc);
   } else {
-    send("E16");        // EINVAL
+    send("E02");
   }
 
   send_running_checksum();
@@ -369,11 +378,11 @@ void gdbserver_t::handle_memory_read(const std::vector<uint8_t> &packet)
   std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
   reg_t address = consume_hex_number(iter, packet.end());
   if (*iter != ',')
-    return send_packet("E16"); // EINVAL
+    return send_packet("E10");
   iter++;
   reg_t length = consume_hex_number(iter, packet.end());
   if (*iter != '#')
-    return send_packet("E16"); // EINVAL
+    return send_packet("E11");
 
   send("$");
   running_checksum = 0;
@@ -394,18 +403,18 @@ void gdbserver_t::handle_memory_binary_write(const std::vector<uint8_t> &packet)
   std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
   reg_t address = consume_hex_number(iter, packet.end());
   if (*iter != ',')
-    return send_packet("E16"); // EINVAL
+    return send_packet("E20");
   iter++;
   reg_t length = consume_hex_number(iter, packet.end());
   if (*iter != ':')
-    return send_packet("E16"); // EINVAL
+    return send_packet("E21");
   iter++;
 
   processor_t *p = sim->get_core(0);
   mmu_t* mmu = sim->debug_mmu;
   for (unsigned int i = 0; i < length; i++) {
     if (iter == packet.end()) {
-      return send_packet("E16"); // EINVAL
+      return send_packet("E22");
     }
     mmu->store_uint8(address + i, *iter);
     iter++;
@@ -424,7 +433,7 @@ void gdbserver_t::handle_continue(const std::vector<uint8_t> &packet)
     std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
     p->state.pc = consume_hex_number(iter, packet.end());
     if (*iter != '#')
-      return send_packet("E16"); // EINVAL
+      return send_packet("E30");
   }
 
   p->set_halted(false);
@@ -439,7 +448,7 @@ void gdbserver_t::handle_step(const std::vector<uint8_t> &packet)
     std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
     p->state.pc = consume_hex_number(iter, packet.end());
     if (*iter != '#')
-      return send_packet("E16"); // EINVAL
+      return send_packet("E40");
   }
 
   p->set_single_step(true);
@@ -462,6 +471,65 @@ void gdbserver_t::handle_extended(const std::vector<uint8_t> &packet)
   extended_mode = true;
 }
 
+void software_breakpoint_t::insert(mmu_t* mmu)
+{
+  if (size == 2) {
+    instruction = mmu->load_uint16(address);
+    mmu->store_uint16(address, C_EBREAK);
+  } else {
+    instruction = mmu->load_uint32(address);
+    mmu->store_uint32(address, EBREAK);
+  }
+}
+
+void software_breakpoint_t::remove(mmu_t* mmu)
+{
+  if (size == 2) {
+    mmu->store_uint16(address, instruction);
+  } else {
+    mmu->store_uint32(address, instruction);
+  }
+}
+
+void gdbserver_t::handle_breakpoint(const std::vector<uint8_t> &packet)
+{
+  // insert: Z type,addr,kind
+  // remove: z type,addr,kind
+
+  software_breakpoint_t bp;
+  bool insert = (packet[1] == 'Z');
+  std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
+  int type = consume_hex_number(iter, packet.end());
+  if (*iter != ',')
+    return send_packet("E50");
+  iter++;
+  bp.address = consume_hex_number(iter, packet.end());
+  if (*iter != ',')
+    return send_packet("E51");
+  iter++;
+  bp.size = consume_hex_number(iter, packet.end());
+  // There may be more options after a ; here, but we don't support that.
+  if (*iter != '#')
+    return send_packet("E52");
+
+  if (bp.size != 2 && bp.size != 4) {
+    return send_packet("E53");
+  }
+
+  processor_t *p = sim->get_core(0);
+  mmu_t* mmu = sim->debug_mmu;
+  if (insert) {
+    bp.insert(mmu);
+    breakpoints[bp.address] = bp;
+
+  } else {
+    bp = breakpoints[bp.address];
+    bp.remove(mmu);
+    breakpoints.erase(bp.address);
+  }
+  return send_packet("OK");
+}
+
 void gdbserver_t::handle_packet(const std::vector<uint8_t> &packet)
 {
   if (compute_checksum(packet) != extract_checksum(packet)) {
@@ -497,6 +565,9 @@ void gdbserver_t::handle_packet(const std::vector<uint8_t> &packet)
       return handle_continue(packet);
     case 's':
       return handle_step(packet);
+    case 'z':
+    case 'Z':
+      return handle_breakpoint(packet);
   }
 
   // Not supported.
index 178003d59718d9ede8d44c5e5945c2cb6a89ef31..67ae6d069de0a3cb10d5b5ec4e7cde16b95fde32 100644 (file)
@@ -42,6 +42,18 @@ public:
   void append(const T *src, unsigned int count);
 };
 
+// Class to track software breakpoints that we set.
+class software_breakpoint_t
+{
+public:
+  reg_t address;
+  unsigned int size;
+  uint32_t instruction;
+
+  void insert(mmu_t* mmu);
+  void remove(mmu_t* mmu);
+};
+
 class gdbserver_t
 {
 public:
@@ -55,6 +67,7 @@ public:
   void handle_packet(const std::vector<uint8_t> &packet);
   void handle_interrupt();
 
+  void handle_breakpoint(const std::vector<uint8_t> &packet);
   void handle_continue(const std::vector<uint8_t> &packet);
   void handle_extended(const std::vector<uint8_t> &packet);
   void handle_general_registers_read(const std::vector<uint8_t> &packet);
@@ -78,6 +91,8 @@ private:
   // but it isn't, we need to tell gdb about it.
   bool running;
 
+  std::map <reg_t, software_breakpoint_t> breakpoints;
+
   // Read pending data from the client.
   void read();
   void write();
index 05fdb1c6f824be51e31e2531bd19190b9bd84a77..1c539866466e2db12c98f416af1395d4db58ade7 100644 (file)
@@ -208,6 +208,12 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
     fprintf(stderr, "core %3d: exception %s, epc 0x%016" PRIx64 "\n",
             id, t.name(), epc);
 
+  if (t.cause() == CAUSE_BREAKPOINT) {
+    // TODO: Only do this if there is a debugger attached.
+    halted = true;
+    return;
+  }
+
   // by default, trap to M-mode, unless delegated to S-mode
   reg_t bit = t.cause();
   reg_t deleg = state.medeleg;