[GDBStub] Use main thread as default thread ID

This commit is contained in:
emoose 2024-10-06 09:05:42 +01:00
parent 26cfa69497
commit c9778a4032
3 changed files with 61 additions and 38 deletions

View File

@ -193,24 +193,6 @@ uint8_t from_hexchar(char c) {
return 0; 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, std::string GDBStub::ReadRegister(xe::cpu::ThreadDebugInfo* thread,
uint32_t rid) { uint32_t rid) {
// Send registers as 32-bit, otherwise some debuggers will switch to 64-bit // Send registers as 32-bit, otherwise some debuggers will switch to 64-bit
@ -546,12 +528,18 @@ void GDBStub::UpdateCache() {
object_table->GetObjectsByType<XModule>(XObject::Type::Module); object_table->GetObjectsByType<XModule>(XObject::Type::Module);
cache_.thread_debug_infos = processor_->QueryThreadDebugInfos(); 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) { 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); 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()) { if (result.empty()) {
return kGdbReplyError; // TODO: is this error correct? return kGdbReplyError; // TODO: is this error correct?
} }
@ -559,10 +547,14 @@ std::string GDBStub::ReadRegister(const std::string& data) {
} }
std::string GDBStub::ReadRegisters() { std::string GDBStub::ReadRegisters() {
auto* thread = cache_.cur_thread_info();
if (!thread) {
return kGdbReplyError;
}
std::string result; std::string result;
result.reserve(68 * 16 + 3 * 8); result.reserve(68 * 16 + 3 * 8);
for (int i = 0; i < 71; ++i) { for (int i = 0; i < 71; ++i) {
result += ReadRegister(cache_.cur_thread_info(), i); result += ReadRegister(thread, i);
} }
return result; return result;
} }
@ -758,9 +750,18 @@ void GDBStub::OnFocus() {}
void GDBStub::OnDetached() { void GDBStub::OnDetached() {
UpdateCache(); UpdateCache();
// Remove all breakpoints. // Delete all breakpoints
while (!cache_.breakpoints.all_breakpoints.empty()) { auto& state = cache_.breakpoints;
DeleteCodeBreakpoint(cache_.breakpoints.all_breakpoints.front().get());
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();
} }
} }
@ -821,10 +822,18 @@ std::string GDBStub::HandleGDBCommand(const GDBCommand& command) {
}}, }},
// Detach // Detach
{"D", [&](const GDBCommand& cmd) { return DebuggerDetached(); }}, {"D",
[&](const GDBCommand& cmd) {
OnDetached();
return kGdbReplyOK;
}},
// Kill request (just treat as detach for now) // Kill request (just treat as detach for now)
{"k", [&](const GDBCommand& cmd) { return DebuggerDetached(); }}, {"k",
[&](const GDBCommand& cmd) {
OnDetached();
return kGdbReplyOK;
}},
// Enable extended mode // Enable extended mode
{"!", [&](const GDBCommand& cmd) { return kGdbReplyOK; }}, {"!", [&](const GDBCommand& cmd) { return kGdbReplyOK; }},
@ -857,24 +866,32 @@ std::string GDBStub::HandleGDBCommand(const GDBCommand& command) {
// Get current debugger thread ID // Get current debugger thread ID
{"qC", {"qC",
[&](const GDBCommand& cmd) { [&](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 // Set current debugger thread ID
{"H", {"H",
[&](const GDBCommand& cmd) { [&](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); int threadId = std::stol(cmd.data.substr(1), 0, 16);
for (auto& thread : cache_.thread_debug_infos) {
if (thread->thread_id == threadId) { if (!threadId) {
cache_.cur_thread_id = threadId; // Treat Thread 0 as main thread, seems to work for IDA
break; 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; return kGdbReplyOK;

View File

@ -174,6 +174,10 @@ Emulator::~Emulator() {
ExceptionHandler::Uninstall(Emulator::ExceptionCallbackThunk, this); ExceptionHandler::Uninstall(Emulator::ExceptionCallbackThunk, this);
} }
uint32_t Emulator::main_thread_id() {
return main_thread_ ? main_thread_->thread_id() : 0;
}
X_STATUS Emulator::Setup( X_STATUS Emulator::Setup(
ui::Window* display_window, ui::ImGuiDrawer* imgui_drawer, ui::Window* display_window, ui::ImGuiDrawer* imgui_drawer,
bool require_cpu_backend, bool require_cpu_backend,

View File

@ -124,6 +124,8 @@ class Emulator {
// Are we currently running a title? // Are we currently running a title?
bool is_title_open() const { return title_id_.has_value(); } bool is_title_open() const { return title_id_.has_value(); }
uint32_t main_thread_id();
// Window used for displaying graphical output. Can be null. // Window used for displaying graphical output. Can be null.
ui::Window* display_window() const { return display_window_; } ui::Window* display_window() const { return display_window_; }