// 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);
}
}
// 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 {
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;
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
return send_packet("E30");
}
- p->set_halted(false);
+ p->set_halted(false, HR_NONE);
running = true;
}
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 {
return send_packet("E53");
}
- processor_t *p = sim->get_core(0);
mmu_t* mmu = sim->debug_mmu;
if (insert) {
bp.insert(mmu);
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)) {
case 'z':
case 'Z':
return handle_breakpoint(packet);
+ case 'q':
+ case 'Q':
+ return handle_query(packet);
}
// Not supported.
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;
}
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;
#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
{
~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);
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;