Flush icache when using swbps and report to gdb.
authorTim Newsome <tim@sifive.com>
Sun, 13 Mar 2016 01:50:32 +0000 (17:50 -0800)
committerTim Newsome <tim@sifive.com>
Mon, 23 May 2016 19:12:10 +0000 (12:12 -0700)
Makefile.in
riscv/execute.cc
riscv/gdbserver.cc
riscv/gdbserver.h
riscv/processor.cc
riscv/processor.h
riscv/sim.cc

index d6b04963c2fd293c15660d4faa36ad747431ed8e..1e353ab9668cd379d3e2f3ccc4843644500431a7 100644 (file)
@@ -121,7 +121,7 @@ INSTALL_EXE   := $(INSTALL) -m 555
 STOW          := @stow@
 
 # Tests
-bintests = 
+bintests = tests/gdbserver-smoke.py
 
 #-------------------------------------------------------------------------
 # Include subproject makefile fragments
@@ -333,8 +333,9 @@ deps : $(deps)
 #-------------------------------------------------------------------------
 
 bintest_outs = $(bintests:=.out)
-%.out: %
-       $^ < /dev/null > $@ 2>&1
+junk += $(bintest_outs)
+%.out: % all
+       ./$^ < /dev/null 2>&1 | tee $@
 
 check-cpp : $(test_outs)
        echo; grep -h -e'Unit Tests' -e'FAILED' -e'Segmentation' $^ < /dev/null; echo
index 4bfaf4a9d693bc1919271565e2581d48c0fe76d2..c36cb4ff4aab7542417fa3624de3f2aeaea6eaa3 100644 (file)
@@ -56,7 +56,7 @@ void processor_t::step(size_t n)
   // TODO: We should really not call this function at all when halted, to avoid
   // burning CPU.
   if (single_step) {
-    halted = false;
+    set_halted(false, HR_NONE);
     n = 1;
   }
 
@@ -136,6 +136,6 @@ miss:
 
   if (single_step) {
     single_step = false;
-    halted = true;
+    set_halted(true, HR_STEPPED);
   }
 }
index 83bc01387dc04aa25a3d26f88de9233f83cfaed6..70dac13c6af4b82a15f3b3028df4bc6ac74ac1de 100644 (file)
@@ -142,7 +142,7 @@ void gdbserver_t::accept()
 
     // gdb wants the core to be halted when it attaches.
     processor_t *p = sim->get_core(0);
-    p->set_halted(true);
+    p->set_halted(true, HR_ATTACHED);
   }
 }
 
@@ -165,7 +165,7 @@ void gdbserver_t::read()
     // The remote disconnected.
     client_fd = 0;
     processor_t *p = sim->get_core(0);
-    p->set_halted(false);
+    p->set_halted(false, HR_NONE);
     recv_buf.reset();
     send_buf.reset();
   } else {
@@ -260,7 +260,8 @@ void gdbserver_t::process_requests()
       if (b == '$') {
         // Start of new packet.
         if (!packet.empty()) {
-          fprintf(stderr, "Received malformed %ld-byte packet from debug client: ", packet.size());
+          fprintf(stderr, "Received malformed %ld-byte packet from debug client: ",
+              packet.size());
           print_packet(packet);
           recv_buf.consume(i);
           break;
@@ -337,6 +338,16 @@ uint64_t consume_hex_number(std::vector<uint8_t>::const_iterator &iter,
   return value;
 }
 
+void consume_string(std::string &str, std::vector<uint8_t>::const_iterator &iter,
+    std::vector<uint8_t>::const_iterator end, uint8_t separator)
+{
+  while (iter != end && *iter != separator) {
+    str.append(1, (char) *iter);
+    iter++;
+  }
+}
+
+
 void gdbserver_t::handle_register_read(const std::vector<uint8_t> &packet)
 {
   // p n
@@ -436,7 +447,7 @@ void gdbserver_t::handle_continue(const std::vector<uint8_t> &packet)
       return send_packet("E30");
   }
 
-  p->set_halted(false);
+  p->set_halted(false, HR_NONE);
   running = true;
 }
 
@@ -480,10 +491,12 @@ void software_breakpoint_t::insert(mmu_t* mmu)
     instruction = mmu->load_uint32(address);
     mmu->store_uint32(address, EBREAK);
   }
+  printf(">>> Read %x from %lx\n", instruction, address);
 }
 
 void software_breakpoint_t::remove(mmu_t* mmu)
 {
+  printf(">>> write %x to %lx\n", instruction, address);
   if (size == 2) {
     mmu->store_uint16(address, instruction);
   } else {
@@ -516,7 +529,6 @@ void gdbserver_t::handle_breakpoint(const std::vector<uint8_t> &packet)
     return send_packet("E53");
   }
 
-  processor_t *p = sim->get_core(0);
   mmu_t* mmu = sim->debug_mmu;
   if (insert) {
     bp.insert(mmu);
@@ -527,9 +539,40 @@ void gdbserver_t::handle_breakpoint(const std::vector<uint8_t> &packet)
     bp.remove(mmu);
     breakpoints.erase(bp.address);
   }
+  mmu->flush_icache();
+  processor_t *p = sim->get_core(0);
+  p->mmu->flush_icache();
   return send_packet("OK");
 }
 
+void gdbserver_t::handle_query(const std::vector<uint8_t> &packet)
+{
+  std::string name;
+  std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
+
+  consume_string(name, iter, packet.end(), ':');
+  if (iter != packet.end())
+    iter++;
+  if (name == "Supported") {
+    send("$");
+    running_checksum = 0;
+    while (iter != packet.end()) {
+      std::string feature;
+      consume_string(feature, iter, packet.end(), ';');
+      if (iter != packet.end())
+        iter++;
+      printf("is %s supported?\n", feature.c_str());
+      if (feature == "swbreak+") {
+        send("swbreak+;");
+      }
+    }
+    return send_running_checksum();
+  }
+
+  printf("Unsupported query %s\n", name.c_str());
+  return send_packet("");
+}
+
 void gdbserver_t::handle_packet(const std::vector<uint8_t> &packet)
 {
   if (compute_checksum(packet) != extract_checksum(packet)) {
@@ -568,6 +611,9 @@ void gdbserver_t::handle_packet(const std::vector<uint8_t> &packet)
     case 'z':
     case 'Z':
       return handle_breakpoint(packet);
+    case 'q':
+    case 'Q':
+      return handle_query(packet);
   }
 
   // Not supported.
@@ -579,7 +625,7 @@ void gdbserver_t::handle_packet(const std::vector<uint8_t> &packet)
 void gdbserver_t::handle_interrupt()
 {
   processor_t *p = sim->get_core(0);
-  p->set_halted(true);
+  p->set_halted(true, HR_INTERRUPT);
   send_packet("S02");   // Pretend program received SIGINT.
   running = false;
 }
@@ -589,6 +635,21 @@ void gdbserver_t::handle()
   processor_t *p = sim->get_core(0);
   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;
index 67ae6d069de0a3cb10d5b5ec4e7cde16b95fde32..8f52a92e9566a4ba9d151077ccc433753ebea82b 100644 (file)
@@ -75,6 +75,7 @@ public:
   void handle_kill(const std::vector<uint8_t> &packet);
   void handle_memory_binary_write(const std::vector<uint8_t> &packet);
   void handle_memory_read(const std::vector<uint8_t> &packet);
+  void handle_query(const std::vector<uint8_t> &packet);
   void handle_register_read(const std::vector<uint8_t> &packet);
   void handle_step(const std::vector<uint8_t> &packet);
 
index 1c539866466e2db12c98f416af1395d4db58ade7..4537c183b850dfb2bdc47773d33f34d925d2e307 100644 (file)
@@ -126,9 +126,10 @@ void processor_t::set_debug(bool value)
     ext->set_debug(value);
 }
 
-void processor_t::set_halted(bool value)
+void processor_t::set_halted(bool value, halt_reason_t reason)
 {
   halted = value;
+  halt_reason = reason;
 }
 
 void processor_t::set_single_step(bool value)
@@ -210,7 +211,7 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
 
   if (t.cause() == CAUSE_BREAKPOINT) {
     // TODO: Only do this if there is a debugger attached.
-    halted = true;
+    set_halted(true, HR_SWBP);
     return;
   }
 
index e654c0fea2b8aec2830ba060c73e87a02eb47950..869873fffe7e9100e336f6229940de36aa6626b5 100644 (file)
@@ -73,6 +73,15 @@ struct state_t
 #endif
 };
 
+typedef enum {
+      HR_NONE,
+      HR_STEPPED,       // A single step was completed
+      HR_SWBP,          // sbreak was executed
+      HR_INTERRUPT,     // Execution interrupted by debugger
+      HR_CMDLINE,       // Command line requested that the processor start halted
+      HR_ATTACHED       // Halted because a debugger attached
+} halt_reason_t;
+
 // this class represents one processor in a RISC-V machine.
 class processor_t : public abstract_device_t
 {
@@ -81,7 +90,7 @@ public:
   ~processor_t();
 
   void set_debug(bool value);
-  void set_halted(bool value);
+  void set_halted(bool value, halt_reason_t reason);
   void set_single_step(bool value);
   void set_histogram(bool value);
   void reset(bool value);
@@ -124,6 +133,7 @@ private:
   bool debug;
   // TODO: Should this just be rolled into `run`?
   bool halted;  // When true, no instructions are executed.
+  halt_reason_t halt_reason;        // Why is halted true?
   // When true, execute exactly one instruction (even if halted is true), then
   // set halted to true and single_step to false.
   bool single_step;
index 09c8b4402455acd9b89ef3279b60d54d66aee274..19d3d8471906d9b57a3fbde8dc1d583095fcd231 100644 (file)
@@ -45,7 +45,7 @@ sim_t::sim_t(const char* isa, size_t nprocs, size_t mem_mb, bool halted,
 
   for (size_t i = 0; i < procs.size(); i++) {
     procs[i] = new processor_t(isa, this, i);
-    procs[i]->set_halted(halted);
+    procs[i]->set_halted(halted, HR_CMDLINE);
   }
 
   rtc.reset(new rtc_t(procs));