Skip to content

Commit

Permalink
[GDBStub] Fix debugger showing invalid symbols after pausing/continuing
Browse files Browse the repository at this point in the history
  • Loading branch information
emoose committed Oct 8, 2024
1 parent fff2768 commit c6242ee
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 34 deletions.
80 changes: 51 additions & 29 deletions src/xenia/debug/gdb/gdbstub.cc
Original file line number Diff line number Diff line change
Expand Up @@ -181,29 +181,33 @@ std::unique_ptr<GDBStub> GDBStub::Create(Emulator* emulator, int listen_port) {
}

bool GDBStub::Initialize() {
socket_ = xe::SocketServer::Create(
listen_port_, [this](std::unique_ptr<Socket> client) { Listen(client); });
socket_ = xe::SocketServer::Create(listen_port_,
[this](std::unique_ptr<Socket> socket) {
GDBClient client;
client.socket = std::move(socket);
Listen(client);
});

UpdateCache();
return true;
}

void GDBStub::Listen(std::unique_ptr<Socket>& client) {
void GDBStub::Listen(GDBClient& client) {
// Client is connected - pause execution
ExecutionPause();
UpdateCache();

client->set_nonblocking(true);
client.socket->set_nonblocking(true);

std::string receive_buffer;

while (!stop_thread_) {
if (!client->is_connected()) {
if (!client.socket->is_connected()) {
break;
}

if (!ProcessIncomingData(client, receive_buffer)) {
if (!client->is_connected()) {
if (!ProcessIncomingData(client)) {
if (!client.socket->is_connected()) {
break;
}
// No data available, can do other work or sleep
Expand Down Expand Up @@ -240,8 +244,7 @@ void GDBStub::Listen(std::unique_ptr<Socket>& client) {
}
}

void GDBStub::SendPacket(std::unique_ptr<Socket>& client,
const std::string& data) {
void GDBStub::SendPacket(GDBClient& client, const std::string& data) {
std::stringstream ss;
ss << char(ControlCode::PacketStart) << data << char(ControlCode::PacketEnd);

Expand All @@ -253,7 +256,7 @@ void GDBStub::SendPacket(std::unique_ptr<Socket>& client,
ss << std::hex << std::setw(2) << std::setfill('0') << (checksum & 0xff);
std::string packet = ss.str();

client->Send(packet.c_str(), packet.size());
client.socket->Send(packet.c_str(), packet.size());
}

#ifdef DEBUG
Expand Down Expand Up @@ -293,16 +296,15 @@ std::string GetPacketFriendlyName(const std::string& packetCommand) {
}
#endif

bool GDBStub::ProcessIncomingData(std::unique_ptr<Socket>& client,
std::string& receive_buffer) {
bool GDBStub::ProcessIncomingData(GDBClient& client) {
char buffer[1024];
size_t received = client->Receive(buffer, sizeof(buffer));
size_t received = client.socket->Receive(buffer, sizeof(buffer));
if (received == uint64_t(-1) || // disconnected
received == 0) {
return false;
}

receive_buffer.append(buffer, received);
client.receive_buffer.append(buffer, received);

// Hacky interrupt '\03' packet handling, some reason checksum isn't
// attached to this?
Expand All @@ -312,16 +314,16 @@ bool GDBStub::ProcessIncomingData(std::unique_ptr<Socket>& client,
// to try again
size_t packet_end;
while (isInterrupt ||
(packet_end = receive_buffer.find('#')) != std::string::npos) {
if (isInterrupt || packet_end + 2 < receive_buffer.length()) {
(packet_end = client.receive_buffer.find('#')) != std::string::npos) {
if (isInterrupt || packet_end + 2 < client.receive_buffer.length()) {
std::string current_packet;
if (isInterrupt) {
current_packet = char(ControlCode::Interrupt);
receive_buffer = "";
client.receive_buffer = "";
isInterrupt = false;
} else {
current_packet = receive_buffer.substr(0, packet_end + 3);
receive_buffer = receive_buffer.substr(packet_end + 3);
current_packet = client.receive_buffer.substr(0, packet_end + 3);
client.receive_buffer = client.receive_buffer.substr(packet_end + 3);
}

GDBCommand command;
Expand All @@ -334,13 +336,18 @@ bool GDBStub::ProcessIncomingData(std::unique_ptr<Socket>& client,
command.data);
#endif

ControlCode result = ControlCode::Ack;
client->Send(&result, 1);
std::string response = HandleGDBCommand(command);
if (!client.no_ack_mode) {
ControlCode result = ControlCode::Ack;
client.socket->Send(&result, 1);
}

std::string response = HandleGDBCommand(client, command);
SendPacket(client, response);
} else {
ControlCode result = ControlCode::Nack;
client->Send(&result, 1);
if (!client.no_ack_mode) {
ControlCode result = ControlCode::Nack;
client.socket->Send(&result, 1);
}
}
} else {
break;
Expand Down Expand Up @@ -653,15 +660,15 @@ std::string GDBStub::ExecutionPause() {
return kGdbReplyError;
}
processor_->Pause();
return kGdbReplyOK;
return "";
}

std::string GDBStub::ExecutionContinue() {
#ifdef DEBUG
debugging::DebugPrint("GDBStub: ExecutionContinue\n");
#endif
processor_->Continue();
return kGdbReplyOK;
return "";
}

std::string GDBStub::ExecutionStep() {
Expand All @@ -674,7 +681,7 @@ std::string GDBStub::ExecutionStep() {
processor_->StepGuestInstruction(cache_.last_bp_thread_id);
}

return kGdbReplyOK;
return "";
}

std::string GDBStub::MemoryRead(const std::string& data) {
Expand Down Expand Up @@ -790,6 +797,14 @@ std::string GDBStub::BuildThreadList() {
return buffer;
}

std::string GDBStub::QueryPacket(GDBClient& client, const std::string& data) {
if (data == "StartNoAckMode") {
client.no_ack_mode = true;
return kGdbReplyOK;
}
return kGdbReplyError;
}

std::string GDBStub::GetThreadStateReply(uint32_t thread_id,
SignalCode signal) {
auto* thread = cache_.thread_info(thread_id);
Expand Down Expand Up @@ -969,7 +984,8 @@ void GDBStub::OnBreakpointHit(Breakpoint* breakpoint,
UpdateCache();
}

std::string GDBStub::HandleGDBCommand(const GDBCommand& command) {
std::string GDBStub::HandleGDBCommand(GDBClient& client,
const GDBCommand& command) {
static const std::unordered_map<std::string,
std::function<std::string(const GDBCommand&)>>
command_map = {
Expand Down Expand Up @@ -1021,6 +1037,12 @@ std::string GDBStub::HandleGDBCommand(const GDBCommand& command) {
{"G",
[&](const GDBCommand& cmd) { return RegisterWriteAll(cmd.data); }},

// Query / setting change
{"Q",
[&](const GDBCommand& cmd) {
return QueryPacket(client, cmd.data);
}},

// Attach to specific process ID - IDA used to send this, but doesn't
// after some changes?
{"vAttach", [&](const GDBCommand& cmd) { return "S05"; }},
Expand Down Expand Up @@ -1099,7 +1121,7 @@ std::string GDBStub::HandleGDBCommand(const GDBCommand& command) {
{"qSupported",
[&](const GDBCommand& cmd) {
return "PacketSize=1024;qXfer:features:read+;qXfer:threads:read+;"
"qXfer:memory-map:read+";
"qXfer:memory-map:read+;QStartNoAckMode+";
}},
// Thread list (IDA requests this but ignores in favor of qXfer?)
{"qfThreadInfo",
Expand Down
16 changes: 11 additions & 5 deletions src/xenia/debug/gdb/gdbstub.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,20 @@ class GDBStub : public cpu::DebugListener {
uint8_t checksum{};
};

struct GDBClient {
std::unique_ptr<Socket> socket;
bool no_ack_mode = false;
std::string receive_buffer;
};

explicit GDBStub(Emulator* emulator, int listen_port);
bool Initialize();

void Listen(std::unique_ptr<Socket>& client);
void SendPacket(std::unique_ptr<Socket>& client, const std::string& data);
bool ProcessIncomingData(std::unique_ptr<Socket>& client,
std::string& receive_buffer);
void Listen(GDBClient& client);
void SendPacket(GDBClient& client, const std::string& data);
bool ProcessIncomingData(GDBClient& client);
bool ParsePacket(const std::string& packet, GDBCommand& out_cmd);
std::string HandleGDBCommand(const GDBCommand& command);
std::string HandleGDBCommand(GDBClient& client, const GDBCommand& command);

void UpdateCache();

Expand All @@ -98,6 +103,7 @@ class GDBStub : public cpu::DebugListener {
std::string MemoryRead(const std::string& data);
std::string MemoryWrite(const std::string& data);
std::string BuildThreadList();
std::string QueryPacket(GDBClient& client, const std::string& data);

std::string GetThreadStateReply(uint32_t thread_id, SignalCode signal);

Expand Down

0 comments on commit c6242ee

Please sign in to comment.