int oldopts = fcntl(client_fd, F_GETFL, 0);
fcntl(client_fd, F_SETFL, oldopts | O_NONBLOCK);
expect_ack = false;
+
+ // gdb wants the core to be halted when it attaches.
+ processor_t *p = sim->get_core(0);
+ p->set_halted(true);
}
}
send_buf.reset();
} else {
recv_buf.data_added(bytes);
+ printf("Read %d bytes.\n", bytes);
}
}
void print_packet(const std::vector<uint8_t> &packet)
{
for (uint8_t c : packet) {
- fprintf(stderr, "%c", c);
+ if (c >= ' ' and c <= '~')
+ fprintf(stderr, "%c", c);
+ else
+ fprintf(stderr, "\\x%x", c);
}
fprintf(stderr, "\n");
}
break;
}
+ if (packet.empty() && b == 3) {
+ fprintf(stderr, "Received interrupt\n");
+ recv_buf.consume(1);
+ handle_interrupt();
+ break;
+ }
+
if (b == '$') {
// Start of new packet.
if (!packet.empty()) {
}
// There's a partial packet in the buffer. Wait until we get more data to
// process it.
- if (packet.size())
+ if (packet.size()) {
+ fprintf(stderr, "Partial packet: ");
+ print_packet(packet);
break;
+ }
}
}
return handle_read_memory(packet);
case 'p':
return handle_read_register(packet);
+ case 'c':
+ return handle_continue(packet);
}
// Not supported.
send_packet("");
}
+void gdbserver_t::handle_interrupt()
+{
+ processor_t *p = sim->get_core(0);
+ p->set_halted(true);
+ send_packet("S02"); // Pretend program received SIGINT.
+}
+
+void gdbserver_t::handle_continue(const std::vector<uint8_t> &packet)
+{
+ // c [addr]
+ processor_t *p = sim->get_core(0);
+ if (packet[2] != '#') {
+ std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
+ p->state.pc = consume_hex_number(iter, packet.end());
+ if (*iter != '#')
+ return send_packet("E16"); // EINVAL
+ }
+
+ p->set_halted(false);
+}
+
void gdbserver_t::handle()
{
if (client_fd > 0) {
// Process all pending messages from a client.
void handle();
- void handle_halt_reason(const std::vector<uint8_t> &packet);
void handle_packet(const std::vector<uint8_t> &packet);
+ void handle_interrupt();
+
+ void handle_halt_reason(const std::vector<uint8_t> &packet);
void handle_read_general_registers(const std::vector<uint8_t> &packet);
void handle_read_memory(const std::vector<uint8_t> &packet);
void handle_read_register(const std::vector<uint8_t> &packet);
+ void handle_continue(const std::vector<uint8_t> &packet);
private:
sim_t *sim;
processor_t::processor_t(const char* isa, sim_t* sim, uint32_t id)
: sim(sim), ext(NULL), disassembler(new disassembler_t),
- id(id), run(false), debug(false)
+ id(id), run(false), debug(false), halted(false)
{
parse_isa_string(isa);
ext->set_debug(value);
}
+void processor_t::set_halted(bool value)
+{
+ halted = value;
+}
+
void processor_t::set_histogram(bool value)
{
histogram_enabled = value;
~processor_t();
void set_debug(bool value);
+ void set_halted(bool value);
void set_histogram(bool value);
void reset(bool value);
void step(size_t n); // run for n cycles
reg_t isa;
std::string isa_string;
bool run; // !reset
+ // When true, display disassembly of each instruction that's executed.
bool debug;
+ // TODO: Should this just be rolled into `run`?
+ bool halted; // When true, no instructions are executed.
bool histogram_enabled;
std::vector<insn_desc_t> instructions;