From dd233bc49946aa059b6ea9494b870d20076ce1b8 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 4 May 2016 18:51:26 -0700 Subject: [PATCH] Single step appears to work. --- riscv/execute.cc | 21 ++++++++++++++-- riscv/gdbserver.cc | 60 ++++++++++++++++++++++++++++++++-------------- riscv/gdbserver.h | 2 +- riscv/insns/dret.h | 3 +++ riscv/processor.cc | 1 + riscv/processor.h | 8 +++++++ tests/gdbserver.py | 3 ++- 7 files changed, 76 insertions(+), 22 deletions(-) diff --git a/riscv/execute.cc b/riscv/execute.cc index f67843e..8f7b85f 100644 --- a/riscv/execute.cc +++ b/riscv/execute.cc @@ -66,6 +66,10 @@ void processor_t::step(size_t n) n = std::min(n, (size_t) 11); } + if (debug) { + fprintf(stderr, "step(%ld)\n", n); + } + while (n > 0) { size_t instret = 0; reg_t pc = state.pc; @@ -89,12 +93,25 @@ void processor_t::step(size_t n) { take_interrupt(); - if (unlikely(debug)) + // When we might single step, use the slow loop instead of the fast one. + if (unlikely(debug || state.single_step != state.STEP_NONE || state.dcsr.cause)) { while (instret < n) { + // TODO: implement this for the main loop also. To keep + // performance good, probably go into this version when entering + // debug mode or something. + if (unlikely(state.single_step == state.STEP_STEPPING)) { + state.single_step = state.STEP_STEPPED; + } else if (unlikely(state.single_step == state.STEP_STEPPED)) { + state.single_step = state.STEP_NONE; + enter_debug_mode(DCSR_CAUSE_STEP); + // enter_debug_mode changed state.pc, so we can't just continue. + break; + } + insn_fetch_t fetch = mmu->load_insn(pc); - if (!state.serialized) + if (debug && !state.serialized) disasm(fetch.insn); pc = execute_insn(this, pc, fetch); advance_pc(); diff --git a/riscv/gdbserver.cc b/riscv/gdbserver.cc index 0cccf3d..b181e27 100644 --- a/riscv/gdbserver.cc +++ b/riscv/gdbserver.cc @@ -66,13 +66,13 @@ static uint32_t jal(unsigned int rd, uint32_t imm) { MATCH_JAL; } -static uint32_t csrsi(unsigned int csr, uint8_t imm) { +static uint32_t csrsi(unsigned int csr, uint16_t imm) { return (csr << 20) | (bits(imm, 4, 0) << 15) | MATCH_CSRRSI; } -static uint32_t csrci(unsigned int csr, uint8_t imm) { +static uint32_t csrci(unsigned int csr, uint16_t imm) { return (csr << 20) | (bits(imm, 4, 0) << 15) | MATCH_CSRRCI; @@ -320,7 +320,8 @@ class halt_op_t : public operation_t class continue_op_t : public operation_t { public: - continue_op_t(gdbserver_t& gdbserver) : operation_t(gdbserver) {}; + continue_op_t(gdbserver_t& gdbserver, bool single_step) : + operation_t(gdbserver), single_step(single_step) {}; bool perform_step(unsigned int step) { switch (step) { @@ -352,17 +353,29 @@ class continue_op_t : public operation_t return false; case 3: - gs.write_debug_ram(0, ld(S0, 0, (uint16_t) DEBUG_RAM_START+16)); + gs.write_debug_ram(0, ld(S0, 0, (uint16_t) DEBUG_RAM_START+24)); gs.write_debug_ram(1, csrw(S0, CSR_MCAUSE)); - gs.write_debug_ram(2, csrci(DCSR_ADDRESS, DCSR_HALT_MASK)); - gs.write_debug_ram(3, jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*3)))); - gs.write_debug_ram(4, gs.saved_mcause); - gs.write_debug_ram(5, gs.saved_mcause >> 32); + gs.write_debug_ram(2, lw(S0, 0, (uint16_t) DEBUG_RAM_START+20)); + gs.write_debug_ram(3, csrw(S0, CSR_DCSR)); + gs.write_debug_ram(4, jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*4)))); + + reg_t dcsr = gs.dcsr & ~DCSR_HALT_MASK; + if (single_step) + dcsr |= DCSR_STEP_MASK; + else + dcsr &= ~DCSR_STEP_MASK; + gs.write_debug_ram(5, dcsr); + + gs.write_debug_ram(6, gs.saved_mcause); + gs.write_debug_ram(7, gs.saved_mcause >> 32); gs.set_interrupt(0); return true; } return false; } + + private: + bool single_step; }; class general_registers_read_op_t : public operation_t @@ -534,12 +547,15 @@ class memory_read_op_t : public operation_t for (unsigned int i = 0; i < access_size; i++) { if (data) { *(data++) = value & 0xff; + fprintf(stderr, "%02x", (unsigned int) (value & 0xff)); } else { sprintf(buffer, "%02x", (unsigned int) (value & 0xff)); gs.send(buffer); } value >>= 8; } + if (data) + fprintf(stderr, "\n"); length -= access_size; paddr += access_size; @@ -568,7 +584,7 @@ class memory_write_op_t : public operation_t { public: memory_write_op_t(gdbserver_t& gdbserver, reg_t vaddr, unsigned int length, - unsigned char *data) : + const unsigned char *data) : operation_t(gdbserver), vaddr(vaddr), offset(0), length(length), data(data) {}; ~memory_write_op_t() { @@ -584,6 +600,11 @@ class memory_write_op_t : public operation_t if (access_size == 0) access_size = length; + fprintf(stderr, "write to 0x%lx -> 0x%lx: ", vaddr, paddr); + for (unsigned int i = 0; i < length; i++) + fprintf(stderr, "%02x", data[i]); + fprintf(stderr, "\n"); + gs.write_debug_ram(0, ld(S0, 0, (uint16_t) DEBUG_RAM_START + 16)); switch (access_size) { case 1: @@ -661,7 +682,7 @@ class memory_write_op_t : public operation_t unsigned int offset; unsigned int length; unsigned int access_size; - unsigned char *data; + const unsigned char *data; }; class collect_translation_info_op_t : public operation_t @@ -1267,7 +1288,7 @@ void gdbserver_t::handle_continue(const std::vector &packet) return send_packet("E30"); } - add_operation(new continue_op_t(*this)); + add_operation(new continue_op_t(*this, false)); } void gdbserver_t::handle_step(const std::vector &packet) @@ -1281,8 +1302,7 @@ void gdbserver_t::handle_step(const std::vector &packet) return send_packet("E40"); } - // TODO: p->set_single_step(true); - // TODO running = true; + add_operation(new continue_op_t(*this, true)); } void gdbserver_t::handle_kill(const std::vector &packet) @@ -1340,16 +1360,20 @@ void gdbserver_t::handle_breakpoint(const std::vector &packet) swbp[3] = (EBREAK >> 24) & 0xff; } - add_operation(new memory_read_op_t(*this, bp.address, bp.size, bp.instruction)); + breakpoints[bp.address] = new software_breakpoint_t(bp); + add_operation(new memory_read_op_t(*this, bp.address, bp.size, + breakpoints[bp.address]->instruction)); add_operation(new memory_write_op_t(*this, bp.address, bp.size, swbp)); - breakpoints[bp.address] = bp; } else { - bp = breakpoints[bp.address]; + software_breakpoint_t *found_bp; + found_bp = breakpoints[bp.address]; 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)); + memcpy(instruction, found_bp->instruction, 4); + add_operation(new memory_write_op_t(*this, found_bp->address, + found_bp->size, instruction)); breakpoints.erase(bp.address); + delete found_bp; } // TODO mmu->flush_icache(); diff --git a/riscv/gdbserver.h b/riscv/gdbserver.h index f91498a..2ab2ffe 100644 --- a/riscv/gdbserver.h +++ b/riscv/gdbserver.h @@ -166,7 +166,7 @@ private: // but it isn't, we need to tell gdb about it. bool running; - std::map breakpoints; + std::map breakpoints; // Read pending data from the client. void read(); diff --git a/riscv/insns/dret.h b/riscv/insns/dret.h index 6cfd1e2..35c19cb 100644 --- a/riscv/insns/dret.h +++ b/riscv/insns/dret.h @@ -4,3 +4,6 @@ p->set_privilege(STATE.dcsr.prv); /* We're not in Debug Mode anymore. */ STATE.dcsr.cause = 0; + +if (STATE.dcsr.step) + STATE.single_step = STATE.STEP_STEPPING; diff --git a/riscv/processor.cc b/riscv/processor.cc index d43defc..4c4e3dd 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -279,6 +279,7 @@ static bool validate_vm(int max_xlen, reg_t vm) void processor_t::set_csr(int which, reg_t val) { + fprintf(stderr, "set_csr(0x%x, 0x%lx)\n", which, val); val = zext_xlen(val); reg_t delegable_ints = MIP_SSIP | MIP_STIP | MIP_SEIP | (1 << IRQ_COP); reg_t all_ints = delegable_ints | MIP_MSIP | MIP_MTIP; diff --git a/riscv/processor.h b/riscv/processor.h index 9c2f7a6..721da2c 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -81,6 +81,14 @@ struct state_t uint32_t frm; bool serialized; // whether timer CSRs are in a well-defined state + // When true, execute a single instruction and then enter debug mode. This + // can only be set by executing dret. + enum { + STEP_NONE, + STEP_STEPPING, + STEP_STEPPED + } single_step; + reg_t load_reservation; #ifdef RISCV_ENABLE_COMMITLOG diff --git a/tests/gdbserver.py b/tests/gdbserver.py index 90ebbe9..c3c2eca 100755 --- a/tests/gdbserver.py +++ b/tests/gdbserver.py @@ -36,9 +36,10 @@ class DebugTest(unittest.TestCase): def test_breakpoint(self): self.gdb.command("b print_row") # The breakpoint should be hit exactly 10 times. - for _ in range(10): + for i in range(10): output = self.gdb.command("c") self.assertIn("Continuing", output) + self.assertIn("length=%d" % i, output) self.assertIn("Breakpoint 1", output) output = self.gdb.command("c") self.assertIn("Continuing", output) -- 2.30.2