From 1f0612d593ae5459643dbbe1a146a315abee9f09 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 10 Mar 2016 12:29:29 -0800 Subject: [PATCH] Software breakpoints seem to work. --- riscv/execute.cc | 5 +-- riscv/gdbserver.cc | 89 +++++++++++++++++++++++++++++++++++++++++----- riscv/gdbserver.h | 15 ++++++++ riscv/processor.cc | 6 ++++ 4 files changed, 102 insertions(+), 13 deletions(-) diff --git a/riscv/execute.cc b/riscv/execute.cc index b632600..4bfaf4a 100644 --- a/riscv/execute.cc +++ b/riscv/execute.cc @@ -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; diff --git a/riscv/gdbserver.cc b/riscv/gdbserver.cc index e8517ae..83bc013 100644 --- a/riscv/gdbserver.cc +++ b/riscv/gdbserver.cc @@ -17,6 +17,9 @@ #include "gdbserver.h" #include "mmu.h" +#define C_EBREAK 0x9002 +#define EBREAK 0x00100073 + template unsigned int circular_buffer_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 &packet) std::vector::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 &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 &packet) std::vector::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 &packet) std::vector::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 &packet) std::vector::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 &packet) std::vector::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 &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 &packet) +{ + // insert: Z type,addr,kind + // remove: z type,addr,kind + + software_breakpoint_t bp; + bool insert = (packet[1] == 'Z'); + std::vector::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 &packet) { if (compute_checksum(packet) != extract_checksum(packet)) { @@ -497,6 +565,9 @@ void gdbserver_t::handle_packet(const std::vector &packet) return handle_continue(packet); case 's': return handle_step(packet); + case 'z': + case 'Z': + return handle_breakpoint(packet); } // Not supported. diff --git a/riscv/gdbserver.h b/riscv/gdbserver.h index 178003d..67ae6d0 100644 --- a/riscv/gdbserver.h +++ b/riscv/gdbserver.h @@ -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 &packet); void handle_interrupt(); + void handle_breakpoint(const std::vector &packet); void handle_continue(const std::vector &packet); void handle_extended(const std::vector &packet); void handle_general_registers_read(const std::vector &packet); @@ -78,6 +91,8 @@ private: // but it isn't, we need to tell gdb about it. bool running; + std::map breakpoints; + // Read pending data from the client. void read(); void write(); diff --git a/riscv/processor.cc b/riscv/processor.cc index 05fdb1c..1c53986 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -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; -- 2.30.2