Skip to content

Commit

Permalink
[GDBStub] Use main thread as default thread ID
Browse files Browse the repository at this point in the history
  • Loading branch information
emoose committed Oct 6, 2024
1 parent 416b2d0 commit 851d7af
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 38 deletions.
93 changes: 55 additions & 38 deletions src/xenia/debug/gdb/gdbstub.cc
Original file line number Diff line number Diff line change
Expand Up @@ -193,24 +193,6 @@ uint8_t from_hexchar(char c) {
return 0;
}

std::string GDBStub::DebuggerDetached() {
// Delete all breakpoints
auto& state = cache_.breakpoints;

for (auto& breakpoint : state.all_breakpoints) {
processor_->RemoveBreakpoint(breakpoint.get());
}

state.code_breakpoints_by_guest_address.clear();
state.all_breakpoints.clear();

if (processor_->execution_state() == cpu::ExecutionState::kPaused) {
ExecutionContinue();
}

return kGdbReplyOK;
}

std::string GDBStub::ReadRegister(xe::cpu::ThreadDebugInfo* thread,
uint32_t rid) {
// Send registers as 32-bit, otherwise some debuggers will switch to 64-bit
Expand Down Expand Up @@ -546,23 +528,33 @@ void GDBStub::UpdateCache() {
object_table->GetObjectsByType<XModule>(XObject::Type::Module);

cache_.thread_debug_infos = processor_->QueryThreadDebugInfos();
cache_.cur_thread_id = cache_.thread_debug_infos[0]->thread_id;
if (cache_.cur_thread_id == -1) {
cache_.cur_thread_id = emulator_->main_thread_id();
}
}

std::string GDBStub::ReadRegister(const std::string& data) {
auto* thread = cache_.cur_thread_info();
if (!thread) {
return kGdbReplyError;
}
uint32_t rid = hex_to_u32(data);
std::string result = ReadRegister(cache_.cur_thread_info(), rid);
std::string result = ReadRegister(thread, rid);
if (result.empty()) {
return kGdbReplyError; // TODO: is this error correct?
}
return result;
}

std::string GDBStub::ReadRegisters() {
auto* thread = cache_.cur_thread_info();
if (!thread) {
return kGdbReplyError;
}
std::string result;
result.reserve(68 * 16 + 3 * 8);
for (int i = 0; i < 71; ++i) {
result += ReadRegister(cache_.cur_thread_info(), i);
result += ReadRegister(thread, i);
}
return result;
}
Expand Down Expand Up @@ -758,9 +750,18 @@ void GDBStub::OnFocus() {}
void GDBStub::OnDetached() {
UpdateCache();

// Remove all breakpoints.
while (!cache_.breakpoints.all_breakpoints.empty()) {
DeleteCodeBreakpoint(cache_.breakpoints.all_breakpoints.front().get());
// Delete all breakpoints
auto& state = cache_.breakpoints;

for (auto& breakpoint : state.all_breakpoints) {
processor_->RemoveBreakpoint(breakpoint.get());
}

state.code_breakpoints_by_guest_address.clear();
state.all_breakpoints.clear();

if (processor_->execution_state() == cpu::ExecutionState::kPaused) {
ExecutionContinue();
}
}

Expand Down Expand Up @@ -821,10 +822,18 @@ std::string GDBStub::HandleGDBCommand(const GDBCommand& command) {
}},

// Detach
{"D", [&](const GDBCommand& cmd) { return DebuggerDetached(); }},
{"D",
[&](const GDBCommand& cmd) {
OnDetached();
return kGdbReplyOK;
}},

// Kill request (just treat as detach for now)
{"k", [&](const GDBCommand& cmd) { return DebuggerDetached(); }},
{"k",
[&](const GDBCommand& cmd) {
OnDetached();
return kGdbReplyOK;
}},

// Enable extended mode
{"!", [&](const GDBCommand& cmd) { return kGdbReplyOK; }},
Expand Down Expand Up @@ -857,24 +866,32 @@ std::string GDBStub::HandleGDBCommand(const GDBCommand& command) {
// Get current debugger thread ID
{"qC",
[&](const GDBCommand& cmd) {
return "QC" + std::to_string(cache_.cur_thread_info()->thread_id);
auto* thread = cache_.cur_thread_info();
if (!thread) {
return std::string(kGdbReplyError);
}
return "QC" + std::to_string(thread->thread_id);
}},
// Set current debugger thread ID
{"H",
[&](const GDBCommand& cmd) {
// Reset to known good ID
cache_.cur_thread_id =
cache_.thread_debug_infos.size()
? cache_.thread_debug_infos[0]->thread_id
: -1;

// Check if the desired thread ID exists
int threadId = std::stol(cmd.data.substr(1), 0, 16);
for (auto& thread : cache_.thread_debug_infos) {
if (thread->thread_id == threadId) {
cache_.cur_thread_id = threadId;
break;

if (!threadId) {
// Treat Thread 0 as main thread, seems to work for IDA
cache_.cur_thread_id = emulator_->main_thread_id();
} else {
uint32_t thread_id = -1;

// Check if the desired thread ID exists
for (auto& thread : cache_.thread_debug_infos) {
if (thread->thread_id == threadId) {
thread_id = threadId;
break;
}
}

cache_.cur_thread_id = thread_id;
}

return kGdbReplyOK;
Expand Down
4 changes: 4 additions & 0 deletions src/xenia/emulator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@ Emulator::~Emulator() {
ExceptionHandler::Uninstall(Emulator::ExceptionCallbackThunk, this);
}

uint32_t Emulator::main_thread_id() {
return main_thread_ ? main_thread_->thread_id() : 0;
}

X_STATUS Emulator::Setup(
ui::Window* display_window, ui::ImGuiDrawer* imgui_drawer,
bool require_cpu_backend,
Expand Down
2 changes: 2 additions & 0 deletions src/xenia/emulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ class Emulator {
// Are we currently running a title?
bool is_title_open() const { return title_id_.has_value(); }

uint32_t main_thread_id();

// Window used for displaying graphical output. Can be null.
ui::Window* display_window() const { return display_window_; }

Expand Down

0 comments on commit 851d7af

Please sign in to comment.