[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:
parent
0acc46e52e
commit
ea9cf0c8f9
|
@ -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>());
|
||||
}
|
||||
|
|
|
@ -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(); }},
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue