[GDBStub] Allow register writes, disable ctx promotion for --debug

Register changes won't always register if context promotion pass is enabled,
fortunately this was noted by benvanik at
3d30b2eec3/src/xenia/debug/ui/debug_window.cc (L1004)

Disabling context promotion pass if --debug is set seems to allow register
updates fine, without too much performance loss on my end.

Still need to implement PC and CR reg writes, and the WriteRegistersAll cmd

Not completely sure if all register writes actually take effect yet, seems
GPR are fine at least but unsure about others
This commit is contained in:
emoose 2024-10-07 22:26:41 +01:00
parent 0acc46e52e
commit ea9cf0c8f9
3 changed files with 74 additions and 5 deletions

View File

@ -33,6 +33,8 @@ DEFINE_bool(disable_context_promotion, false,
"some sports games, but will reduce performance.",
"CPU");
DECLARE_bool(debug);
namespace xe {
namespace cpu {
namespace ppc {
@ -59,7 +61,10 @@ PPCTranslator::PPCTranslator(PPCFrontend* frontend) : frontend_(frontend) {
// Passes are executed in the order they are added. Multiple of the same
// pass type may be used.
if (!cvars::disable_context_promotion) {
// Disable context promotion for debug, otherwise register changes won't apply
// correctly
if (!cvars::disable_context_promotion && !cvars::debug) {
if (validate) {
compiler_->AddPass(std::make_unique<passes::ValidationPass>());
}

View File

@ -523,6 +523,54 @@ std::string GDBStub::RegisterRead(xe::cpu::ThreadDebugInfo* thread,
// gpr
return string_util::to_hex_string((uint32_t)thread->guest_context.r[rid]);
}
std::string GDBStub::RegisterWrite(xe::cpu::ThreadDebugInfo* thread,
uint32_t rid, const std::string_view value) {
auto* guest_context = thread->thread->thread_state()->context();
switch (rid) {
// pc
case 64:
return kGdbReplyOK; // TODO: figure a way to change this
case 65:
guest_context->msr = string_util::from_string<uint32_t>(value, true);
thread->guest_context.msr = guest_context->msr;
return kGdbReplyOK;
case 66:
// CR
return kGdbReplyOK; // TODO: figure a way to change this
case 67:
guest_context->lr = string_util::from_string<uint32_t>(value, true);
thread->guest_context.lr = guest_context->lr;
return kGdbReplyOK;
case 68:
guest_context->ctr = string_util::from_string<uint32_t>(value, true);
thread->guest_context.ctr = guest_context->ctr;
return kGdbReplyOK;
// xer
case 69:
return kGdbReplyOK;
case 70:
guest_context->fpscr.value =
string_util::from_string<uint32_t>(value, true);
thread->guest_context.fpscr.value = guest_context->fpscr.value;
return kGdbReplyOK;
}
if (rid > 70) {
return kGdbReplyError;
}
// fpr
if (rid > 31) {
guest_context->f[rid - 32] = string_util::from_string<double>(value, true);
thread->guest_context.f[rid - 32] = guest_context->f[rid - 32];
return kGdbReplyOK;
}
// gpr
guest_context->r[rid] = string_util::from_string<uint32_t>(value, true);
thread->guest_context.r[rid] = guest_context->r[rid];
return kGdbReplyOK;
}
std::string GDBStub::RegisterRead(const std::string& data) {
auto* thread = cache_.cur_thread_info();
@ -537,6 +585,22 @@ std::string GDBStub::RegisterRead(const std::string& data) {
return result;
}
std::string GDBStub::RegisterWrite(const std::string& data) {
auto* thread = cache_.cur_thread_info();
if (!thread) {
return kGdbReplyError;
}
auto value_sep = data.find('=');
if (value_sep == std::string::npos) {
return kGdbReplyError;
}
uint32_t rid =
string_util::from_string<uint32_t>(data.substr(0, value_sep), true);
return RegisterWrite(thread, rid, data.data() + value_sep + 1);
}
std::string GDBStub::RegisterReadAll() {
auto* thread = cache_.cur_thread_info();
if (!thread) {
@ -901,10 +965,7 @@ std::string GDBStub::HandleGDBCommand(const GDBCommand& command) {
// Read register
{"p", [&](const GDBCommand& cmd) { return RegisterRead(cmd.data); }},
// Write register
{"P",
[&](const GDBCommand& cmd) {
return kGdbReplyOK; // TODO: we'll just tell it write was fine
}},
{"P", [&](const GDBCommand& cmd) { return RegisterWrite(cmd.data); }},
// Read all registers
{"g", [&](const GDBCommand& cmd) { return RegisterReadAll(); }},

View File

@ -63,7 +63,10 @@ class GDBStub : public cpu::DebugListener {
std::string DebuggerDetached();
std::string RegisterRead(xe::cpu::ThreadDebugInfo* thread, uint32_t rid);
std::string RegisterWrite(xe::cpu::ThreadDebugInfo* thread, uint32_t rid,
const std::string_view value);
std::string RegisterRead(const std::string& data);
std::string RegisterWrite(const std::string& data);
std::string RegisterReadAll();
std::string ExecutionPause();
std::string ExecutionContinue();