Software breakpoints sort of work.
authorTim Newsome <tim@sifive.com>
Wed, 4 May 2016 20:14:46 +0000 (13:14 -0700)
committerTim Newsome <tim@sifive.com>
Mon, 23 May 2016 19:12:12 +0000 (12:12 -0700)
riscv/debug_module.cc
riscv/debug_module.h
riscv/decode.h
riscv/encoding.h
riscv/gdbserver.cc
riscv/gdbserver.h

index e3eb16b160c8c15f37cbbe5023f16a7868368f7d..8ad95137c1a4134fed985740a5b615ce3d240d1c 100644 (file)
@@ -41,6 +41,10 @@ bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes)
     clear_interrupt(bytes[0] | (bytes[1] << 8) |
         (bytes[2] << 16) | (bytes[3] << 24));
     return true;
+  } else if (len == 4 && addr == DEBUG_SETHALTNOT) {
+    set_halt_notification(bytes[0] | (bytes[1] << 8) |
+        (bytes[2] << 16) | (bytes[3] << 24));
+    return true;
   }
 
   fprintf(stderr, "ERROR: invalid store to debug module: %ld bytes at 0x%lx\n",
index d7c1a87baa797e710f13072b27b033fe74665d4a..7a78ad3d278ea3d744864e5c5dd1c3e4b5460cf3 100644 (file)
@@ -27,9 +27,23 @@ class debug_module_t : public abstract_device_t
       return interrupt.find(hartid) != interrupt.end();
     }
 
+    void set_halt_notification(uint32_t hartid) {
+      fprintf(stderr, "set debug halt_notification 0x%x\n", hartid);
+      halt_notification.insert(hartid);
+    }
+    void clear_halt_notification(uint32_t hartid) {
+      fprintf(stderr, "clear debug halt_notification 0x%x\n", hartid);
+      halt_notification.erase(hartid);
+    }
+    bool get_halt_notification(uint32_t hartid) const {
+      return halt_notification.find(hartid) != halt_notification.end();
+    }
+
   private:
     // Track which interrupts from module to debugger are set.
     std::set<uint32_t> interrupt;
+    // Track which halt notifications from debugger to module are set.
+    std::set<uint32_t> halt_notification;
     char debug_ram[DEBUG_RAM_SIZE];
 };
 
index 067d426da8c91cbe573b4d679049948d386e1cfc..1625398c8443d8d6ae8b86b4bcf60b2b423b79d8 100644 (file)
@@ -229,12 +229,6 @@ private:
  * automatically generated. */
 /* TODO */
 #include "/media/sf_tnewsome/Synced/SiFive/debug-spec/core_registers.tex.h"
-#define DCSR_CAUSE_NONE         0
-#define DCSR_CAUSE_SWBP         1
-#define DCSR_CAUSE_HWBP         2
-#define DCSR_CAUSE_DEBUGINT     3
-#define DCSR_CAUSE_STEPPED      4
-#define DCSR_CAUSE_HALT         5
 
 #define DEBUG_START             0x100
 #define DEBUG_ROM_START         0x800
index 11aa5187a4dd4efd59bcd3738fabb88fab32d119..fcc0a8a75efcd6d08aaa4d480b89b902547d8706 100644 (file)
 #define SSTATUS64_SD        0x8000000000000000
 
 #define DCSR_PRV            (3<<14)
+#define DCSR_CAUSE          7
+
+#define DCSR_CAUSE_NONE     0
+#define DCSR_CAUSE_SWBP     1
+#define DCSR_CAUSE_HWBP     2
+#define DCSR_CAUSE_DEBUGINT 3
+#define DCSR_CAUSE_STEP     4
+#define DCSR_CAUSE_HALT     5
 
 #define MIP_SSIP            (1 << IRQ_S_SOFT)
 #define MIP_HSIP            (1 << IRQ_H_SOFT)
index d3f2d4d1527eef92fe85d38e1c62de12b512eb51..0cccf3df0467d7d369df477dc2bbc9c5eff6282e 100644 (file)
@@ -247,7 +247,8 @@ void circular_buffer_t<T>::append(const T *src, unsigned int count)
 class halt_op_t : public operation_t
 {
   public:
-    halt_op_t(gdbserver_t& gdbserver) : operation_t(gdbserver) {};
+    halt_op_t(gdbserver_t& gdbserver, bool send_status=false) :
+      operation_t(gdbserver), send_status(send_status) {};
 
     bool perform_step(unsigned int step) {
       switch (step) {
@@ -287,10 +288,33 @@ class halt_op_t : public operation_t
 
           gs.sptbr_valid = false;
           gs.pte_cache.clear();
+
+          if (send_status) {
+            switch (get_field(gs.dcsr, DCSR_CAUSE)) {
+              case DCSR_CAUSE_NONE:
+                fprintf(stderr, "Internal error. Processor halted without reason.\n");
+                abort();
+
+              case DCSR_CAUSE_HWBP:
+              case DCSR_CAUSE_DEBUGINT:
+              case DCSR_CAUSE_STEP:
+              case DCSR_CAUSE_HALT:
+                // There's no gdb code for this.
+                gs.send_packet("T05");
+                break;
+              case DCSR_CAUSE_SWBP:
+                gs.send_packet("T05swbreak:;");
+                break;
+            }
+          }
+
           return true;
       }
       return false;
     }
+
+  private:
+    bool send_status;
 };
 
 class continue_op_t : public operation_t
@@ -461,8 +485,11 @@ class register_read_op_t : public operation_t
 class memory_read_op_t : public operation_t
 {
   public:
-    memory_read_op_t(gdbserver_t& gdbserver, reg_t vaddr, unsigned int length) :
-      operation_t(gdbserver), vaddr(vaddr), length(length) {};
+    // Read length bytes from vaddr, storing the result into data.
+    // If data is NULL, send the result straight to gdb.
+    memory_read_op_t(gdbserver_t& gdbserver, reg_t vaddr, unsigned int length,
+        unsigned char *data=NULL) :
+      operation_t(gdbserver), vaddr(vaddr), length(length), data(data) {};
 
     bool perform_step(unsigned int step)
     {
@@ -472,6 +499,8 @@ class memory_read_op_t : public operation_t
         access_size = (paddr % length);
         if (access_size == 0)
           access_size = length;
+        if (access_size > 8)
+          access_size = 8;
 
         gs.write_debug_ram(0, ld(S0, 0, (uint16_t) DEBUG_RAM_START + 16));
         switch (access_size) {
@@ -487,9 +516,6 @@ class memory_read_op_t : public operation_t
           case 8:
             gs.write_debug_ram(1, ld(S1, S0, 0));
             break;
-          default:
-            gs.send_packet("E12");
-            return true;
         }
         gs.write_debug_ram(2, sd(S1, 0, (uint16_t) DEBUG_RAM_START + 24));
         gs.write_debug_ram(3, jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*3))));
@@ -497,22 +523,30 @@ class memory_read_op_t : public operation_t
         gs.write_debug_ram(5, paddr >> 32);
         gs.set_interrupt(0);
 
-        gs.start_packet();
+        if (!data) {
+          gs.start_packet();
+        }
         return false;
       }
 
       char buffer[3];
       reg_t value = ((uint64_t) gs.read_debug_ram(7) << 32) | gs.read_debug_ram(6);
       for (unsigned int i = 0; i < access_size; i++) {
-        sprintf(buffer, "%02x", (unsigned int) (value & 0xff));
-        gs.send(buffer);
+        if (data) {
+          *(data++) = value & 0xff;
+        } else {
+          sprintf(buffer, "%02x", (unsigned int) (value & 0xff));
+          gs.send(buffer);
+        }
         value >>= 8;
       }
       length -= access_size;
       paddr += access_size;
 
       if (length == 0) {
-        gs.end_packet();
+        if (!data) {
+          gs.end_packet();
+        }
         return true;
       } else {
         gs.write_debug_ram(4, paddr);
@@ -523,8 +557,10 @@ class memory_read_op_t : public operation_t
     }
 
   private:
-    reg_t vaddr, paddr;
+    reg_t vaddr;
     unsigned int length;
+    unsigned char* data;
+    reg_t paddr;
     unsigned int access_size;
 };
 
@@ -1265,28 +1301,6 @@ 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);
-  }
-  fprintf(stderr, ">>> Read %x from %lx\n", instruction, address);
-}
-
-void software_breakpoint_t::remove(mmu_t* mmu)
-{
-  fprintf(stderr, ">>> write %x to %lx\n", instruction, address);
-  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
@@ -1312,22 +1326,35 @@ void gdbserver_t::handle_breakpoint(const std::vector<uint8_t> &packet)
     return send_packet("E53");
   }
 
-  processor_t *p = sim->get_core(0);
-  die("handle_breakpoint");
-  /*
-  mmu_t* mmu = p->mmu;
+  add_operation(new collect_translation_info_op_t(*this, bp.address, bp.size));
   if (insert) {
-    bp.insert(mmu);
+    // TODO: this only works on little-endian hosts.
+    unsigned char* swbp = new unsigned char[4];
+    if (bp.size == 2) {
+      swbp[0] = C_EBREAK & 0xff;
+      swbp[1] = (C_EBREAK >> 8) & 0xff;
+    } else {
+      swbp[0] = EBREAK & 0xff;
+      swbp[1] = (EBREAK >> 8) & 0xff;
+      swbp[2] = (EBREAK >> 16) & 0xff;
+      swbp[3] = (EBREAK >> 24) & 0xff;
+    }
+
+    add_operation(new memory_read_op_t(*this, bp.address, bp.size, bp.instruction));
+    add_operation(new memory_write_op_t(*this, bp.address, bp.size, swbp));
     breakpoints[bp.address] = bp;
 
   } else {
     bp = breakpoints[bp.address];
-    bp.remove(mmu);
+    unsigned char* instruction = new unsigned char[4];
+    memcpy(instruction, bp.instruction, 4);
+    add_operation(new memory_write_op_t(*this, bp.address, bp.size, instruction));
     breakpoints.erase(bp.address);
   }
-  mmu->flush_icache();
-  sim->debug_mmu->flush_icache();
-  */
+
+  // TODO mmu->flush_icache();
+  // TODO sim->debug_mmu->flush_icache();
+
   return send_packet("OK");
 }
 
@@ -1431,29 +1458,11 @@ void gdbserver_t::handle()
       }
     }
 
-    /* TODO
-    if (running && p->halted) {
-      // The core was running, but now it's halted. Better tell gdb.
-      switch (p->halt_reason) {
-        case HR_NONE:
-          fprintf(stderr, "Internal error. Processor halted without reason.\n");
-          abort();
-        case HR_STEPPED:
-        case HR_INTERRUPT:
-        case HR_CMDLINE:
-        case HR_ATTACHED:
-          // There's no gdb code for this.
-          send_packet("T05");
-          break;
-        case HR_SWBP:
-          send_packet("T05swbreak:;");
-          break;
-      }
-      send_packet("T00");
-      // TODO: Actually include register values here
-      running = false;
+    bool halt_notification = sim->debug_module.get_halt_notification(0);
+    if (halt_notification) {
+      sim->debug_module.clear_halt_notification(0);
+      add_operation(new halt_op_t(*this, true));
     }
-      */
 
     this->read();
     this->write();
index 9b3945046d5aa4c0a97c32dbc4efc630daa09762..f91498ab9e3fa6f9d4cc131527ef0e7e5eacd5c3 100644 (file)
@@ -51,10 +51,7 @@ class software_breakpoint_t
 public:
   reg_t address;
   unsigned int size;
-  uint32_t instruction;
-
-  void insert(mmu_t* mmu);
-  void remove(mmu_t* mmu);
+  unsigned char instruction[4];
 };
 
 class gdbserver_t;