[dynarmic] separate abi functors (win/nix) and impl aliases for gdb commands & document them

This commit is contained in:
lizzie 2025-07-25 02:49:06 +01:00
parent 7617f743f9
commit 117546c7c8
Signed by untrusted user: Lizzie
GPG key ID: D9E134A23AD395CE
4 changed files with 59 additions and 71 deletions

View file

@ -1,11 +1,11 @@
# Development # Development
* **Windows**: [Windows Building Guide](./docs/build/Windows.md) * **Windows**: [Windows Building Guide](./build/Windows.md)
* **Linux**: [Linux Building Guide](./docs/build/Linux.md) * **Linux**: [Linux Building Guide](./build/Linux.md)
* **Android**: [Android Building Guide](./docs/build/Android.md) * **Android**: [Android Building Guide](./build/Android.md)
* **Solaris**: [Solaris Building Guide](./docs/build/Solaris.md) * **Solaris**: [Solaris Building Guide](./build/Solaris.md)
* **FreeBSD**: [FreeBSD Building Guide](./docs/build/FreeBSD.md) * **FreeBSD**: [FreeBSD Building Guide](./build/FreeBSD.md)
* **macOS**: [macOS Building Guide](./docs/build/macOS.md) * **macOS**: [macOS Building Guide](./build/macOS.md)
# Building speedup # Building speedup
@ -31,7 +31,7 @@ Then type `target remote localhost:1234` and type `c` (for continue) - and then
### gdb cheatsheet ### gdb cheatsheet
- `mo <cmd>`: Monitor commands, `get info`, `get fastmem` and `get mappings` are available. - `mo <cmd>`: Monitor commands, `get info`, `get fastmem` and `get mappings` are available. Type `mo help` for more info.
- `detach`: Detach from remote (i.e restarting the emulator). - `detach`: Detach from remote (i.e restarting the emulator).
- `c`: Continue - `c`: Continue
- `p <expr>`: Print variable, `p/x <expr>` for hexadecimal. - `p <expr>`: Print variable, `p/x <expr>` for hexadecimal.

View file

@ -119,6 +119,20 @@ void ABI_PopCallerSaveRegistersAndAdjustStack(BlockOfCode& code, const std::size
ABI_PopRegistersAndAdjustStack(code, frame_size, ABI_ALL_CALLER_SAVE); ABI_PopRegistersAndAdjustStack(code, frame_size, ABI_ALL_CALLER_SAVE);
} }
// Windows ABI registers are not in the same allocation algorithm as unix's
#ifdef _MSC_VER
void ABI_PushCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, const HostLoc exception) {
std::vector<HostLoc> regs;
std::remove_copy(ABI_ALL_CALLER_SAVE.begin(), ABI_ALL_CALLER_SAVE.end(), std::back_inserter(regs), exception);
ABI_PushRegistersAndAdjustStack(code, 0, regs);
}
void ABI_PopCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, const HostLoc exception) {
std::vector<HostLoc> regs;
std::remove_copy(ABI_ALL_CALLER_SAVE.begin(), ABI_ALL_CALLER_SAVE.end(), std::back_inserter(regs), exception);
ABI_PopRegistersAndAdjustStack(code, 0, regs);
}
#else
static consteval size_t ABI_AllCallerSaveSize() noexcept { static consteval size_t ABI_AllCallerSaveSize() noexcept {
return ABI_ALL_CALLER_SAVE.max_size(); return ABI_ALL_CALLER_SAVE.max_size();
} }
@ -166,24 +180,14 @@ alignas(64) static constinit std::array<HostLoc, ABI_AllCallerSaveSize() - 1> AB
}; };
void ABI_PushCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, const HostLoc exception) { void ABI_PushCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, const HostLoc exception) {
#ifdef _MSC_VER
std::vector<HostLoc> regs;
std::remove_copy(ABI_ALL_CALLER_SAVE.begin(), ABI_ALL_CALLER_SAVE.end(), std::back_inserter(regs), exception);
ABI_PushRegistersAndAdjustStack(code, 0, regs);
#else
ASSUME(size_t(exception) < 32); ASSUME(size_t(exception) < 32);
ABI_PushRegistersAndAdjustStack(code, 0, ABI_CALLER_SAVED_EXCEPT_TABLE[size_t(exception)]); ABI_PushRegistersAndAdjustStack(code, 0, ABI_CALLER_SAVED_EXCEPT_TABLE[size_t(exception)]);
#endif
} }
void ABI_PopCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, const HostLoc exception) { void ABI_PopCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, const HostLoc exception) {
#ifdef _MSC_VER
std::vector<HostLoc> regs;
std::remove_copy(ABI_ALL_CALLER_SAVE.begin(), ABI_ALL_CALLER_SAVE.end(), std::back_inserter(regs), exception);
ABI_PopRegistersAndAdjustStack(code, 0, regs);
#else
ASSUME(size_t(exception) < 32); ASSUME(size_t(exception) < 32);
ABI_PopRegistersAndAdjustStack(code, 0, ABI_CALLER_SAVED_EXCEPT_TABLE[size_t(exception)]); ABI_PopRegistersAndAdjustStack(code, 0, ABI_CALLER_SAVED_EXCEPT_TABLE[size_t(exception)]);
#endif
} }
#endif
} // namespace Dynarmic::Backend::X64 } // namespace Dynarmic::Backend::X64

View file

@ -136,6 +136,7 @@ public:
case Dynarmic::A64::Exception::SendEvent: case Dynarmic::A64::Exception::SendEvent:
case Dynarmic::A64::Exception::SendEventLocal: case Dynarmic::A64::Exception::SendEventLocal:
case Dynarmic::A64::Exception::Yield: case Dynarmic::A64::Exception::Yield:
LOG_TRACE(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", static_cast<std::size_t>(exception), pc, m_memory.Read32(pc));
return; return;
case Dynarmic::A64::Exception::NoExecuteFault: case Dynarmic::A64::Exception::NoExecuteFault:
LOG_CRITICAL(Core_ARM, "Cannot execute instruction at unmapped address {:#016x}", pc); LOG_CRITICAL(Core_ARM, "Cannot execute instruction at unmapped address {:#016x}", pc);
@ -144,12 +145,10 @@ public:
default: default:
if (m_debugger_enabled) { if (m_debugger_enabled) {
ReturnException(pc, InstructionBreakpoint); ReturnException(pc, InstructionBreakpoint);
return; } else {
m_parent.LogBacktrace(m_process);
LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", static_cast<std::size_t>(exception), pc, m_memory.Read32(pc));
} }
m_parent.LogBacktrace(m_process);
LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",
static_cast<std::size_t>(exception), pc, m_memory.Read32(pc));
} }
} }

View file

@ -554,32 +554,31 @@ void GDBStub::HandleVCont(std::string_view command, std::vector<DebuggerAction>&
} }
} }
constexpr std::array<std::pair<const char*, Kernel::Svc::MemoryState>, 22> MemoryStateNames{{
{"----- Free ------", Kernel::Svc::MemoryState::Free},
{"Io ", Kernel::Svc::MemoryState::Io},
{"Static ", Kernel::Svc::MemoryState::Static},
{"Code ", Kernel::Svc::MemoryState::Code},
{"CodeData ", Kernel::Svc::MemoryState::CodeData},
{"Normal ", Kernel::Svc::MemoryState::Normal},
{"Shared ", Kernel::Svc::MemoryState::Shared},
{"AliasCode ", Kernel::Svc::MemoryState::AliasCode},
{"AliasCodeData ", Kernel::Svc::MemoryState::AliasCodeData},
{"Ipc ", Kernel::Svc::MemoryState::Ipc},
{"Stack ", Kernel::Svc::MemoryState::Stack},
{"ThreadLocal ", Kernel::Svc::MemoryState::ThreadLocal},
{"Transferred ", Kernel::Svc::MemoryState::Transferred},
{"SharedTransferred", Kernel::Svc::MemoryState::SharedTransferred},
{"SharedCode ", Kernel::Svc::MemoryState::SharedCode},
{"Inaccessible ", Kernel::Svc::MemoryState::Inaccessible},
{"NonSecureIpc ", Kernel::Svc::MemoryState::NonSecureIpc},
{"NonDeviceIpc ", Kernel::Svc::MemoryState::NonDeviceIpc},
{"Kernel ", Kernel::Svc::MemoryState::Kernel},
{"GeneratedCode ", Kernel::Svc::MemoryState::GeneratedCode},
{"CodeOut ", Kernel::Svc::MemoryState::CodeOut},
{"Coverage ", Kernel::Svc::MemoryState::Coverage},
}};
static constexpr const char* GetMemoryStateName(Kernel::Svc::MemoryState state) { static constexpr const char* GetMemoryStateName(Kernel::Svc::MemoryState state) {
constexpr std::array<std::pair<const char*, Kernel::Svc::MemoryState>, 22> MemoryStateNames{{
{"----- Free ------", Kernel::Svc::MemoryState::Free},
{"Io ", Kernel::Svc::MemoryState::Io},
{"Static ", Kernel::Svc::MemoryState::Static},
{"Code ", Kernel::Svc::MemoryState::Code},
{"CodeData ", Kernel::Svc::MemoryState::CodeData},
{"Normal ", Kernel::Svc::MemoryState::Normal},
{"Shared ", Kernel::Svc::MemoryState::Shared},
{"AliasCode ", Kernel::Svc::MemoryState::AliasCode},
{"AliasCodeData ", Kernel::Svc::MemoryState::AliasCodeData},
{"Ipc ", Kernel::Svc::MemoryState::Ipc},
{"Stack ", Kernel::Svc::MemoryState::Stack},
{"ThreadLocal ", Kernel::Svc::MemoryState::ThreadLocal},
{"Transferred ", Kernel::Svc::MemoryState::Transferred},
{"SharedTransferred", Kernel::Svc::MemoryState::SharedTransferred},
{"SharedCode ", Kernel::Svc::MemoryState::SharedCode},
{"Inaccessible ", Kernel::Svc::MemoryState::Inaccessible},
{"NonSecureIpc ", Kernel::Svc::MemoryState::NonSecureIpc},
{"NonDeviceIpc ", Kernel::Svc::MemoryState::NonDeviceIpc},
{"Kernel ", Kernel::Svc::MemoryState::Kernel},
{"GeneratedCode ", Kernel::Svc::MemoryState::GeneratedCode},
{"CodeOut ", Kernel::Svc::MemoryState::CodeOut},
{"Coverage ", Kernel::Svc::MemoryState::Coverage},
}};
for (size_t i = 0; i < MemoryStateNames.size(); i++) { for (size_t i = 0; i < MemoryStateNames.size(); i++) {
if (std::get<1>(MemoryStateNames[i]) == state) { if (std::get<1>(MemoryStateNames[i]) == state) {
return std::get<0>(MemoryStateNames[i]); return std::get<0>(MemoryStateNames[i]);
@ -611,13 +610,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
auto* process = GetProcess(); auto* process = GetProcess();
auto& page_table = process->GetPageTable(); auto& page_table = process->GetPageTable();
if (command_str == "fastmem" || command_str == "get fastmem") {
const char* commands = "Commands:\n"
" get fastmem\n"
" get info\n"
" get mappings\n";
if (command_str == "get fastmem") {
if (Settings::IsFastmemEnabled()) { if (Settings::IsFastmemEnabled()) {
const auto& impl = page_table.GetImpl(); const auto& impl = page_table.GetImpl();
const auto region = reinterpret_cast<uintptr_t>(impl.fastmem_arena); const auto region = reinterpret_cast<uintptr_t>(impl.fastmem_arena);
@ -630,7 +623,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
} else { } else {
reply = "Fastmem is not enabled.\n"; reply = "Fastmem is not enabled.\n";
} }
} else if (command_str == "get info") { } else if (command_str == "info" || command_str == "get info") {
auto modules = Core::FindModules(process); auto modules = Core::FindModules(process);
reply = fmt::format("Process: {:#x} ({})\n" reply = fmt::format("Process: {:#x} ({})\n"
@ -648,8 +641,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
GetInteger(page_table.GetHeapRegionStart()), GetInteger(page_table.GetHeapRegionStart()),
GetInteger(page_table.GetHeapRegionStart()) + page_table.GetHeapRegionSize() - 1, GetInteger(page_table.GetHeapRegionStart()) + page_table.GetHeapRegionSize() - 1,
GetInteger(page_table.GetAliasCodeRegionStart()), GetInteger(page_table.GetAliasCodeRegionStart()),
GetInteger(page_table.GetAliasCodeRegionStart()) + page_table.GetAliasCodeRegionSize() - GetInteger(page_table.GetAliasCodeRegionStart()) + page_table.GetAliasCodeRegionSize() - 1,
1,
GetInteger(page_table.GetStackRegionStart()), GetInteger(page_table.GetStackRegionStart()),
GetInteger(page_table.GetStackRegionStart()) + page_table.GetStackRegionSize() - 1); GetInteger(page_table.GetStackRegionStart()) + page_table.GetStackRegionSize() - 1);
@ -657,7 +649,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
reply += fmt::format(" {:#012x} - {:#012x} {}\n", vaddr, reply += fmt::format(" {:#012x} - {:#012x} {}\n", vaddr,
GetInteger(Core::GetModuleEnd(process, vaddr)), name); GetInteger(Core::GetModuleEnd(process, vaddr)), name);
} }
} else if (command_str == "get mappings") { } else if (command_str == "mappings" || command_str == "get mappings") {
reply = "Mappings:\n"; reply = "Mappings:\n";
VAddr cur_addr = 0; VAddr cur_addr = 0;
@ -675,15 +667,11 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
std::numeric_limits<u64>::max()) { std::numeric_limits<u64>::max()) {
const char* state = GetMemoryStateName(svc_mem_info.state); const char* state = GetMemoryStateName(svc_mem_info.state);
const char* perm = GetMemoryPermissionString(svc_mem_info); const char* perm = GetMemoryPermissionString(svc_mem_info);
const char l = True(svc_mem_info.attribute & MemoryAttribute::Locked) ? 'L' : '-'; const char l = True(svc_mem_info.attribute & MemoryAttribute::Locked) ? 'L' : '-';
const char i = const char i = True(svc_mem_info.attribute & MemoryAttribute::IpcLocked) ? 'I' : '-';
True(svc_mem_info.attribute & MemoryAttribute::IpcLocked) ? 'I' : '-'; const char d = True(svc_mem_info.attribute & MemoryAttribute::DeviceShared) ? 'D' : '-';
const char d =
True(svc_mem_info.attribute & MemoryAttribute::DeviceShared) ? 'D' : '-';
const char u = True(svc_mem_info.attribute & MemoryAttribute::Uncached) ? 'U' : '-'; const char u = True(svc_mem_info.attribute & MemoryAttribute::Uncached) ? 'U' : '-';
const char p = const char p =True(svc_mem_info.attribute & MemoryAttribute::PermissionLocked) ? 'P' : '-';
True(svc_mem_info.attribute & MemoryAttribute::PermissionLocked) ? 'P' : '-';
reply += fmt::format( reply += fmt::format(
" {:#012x} - {:#012x} {} {} {}{}{}{}{} [{}, {}]\n", svc_mem_info.base_address, " {:#012x} - {:#012x} {} {} {}{}{}{}{} [{}, {}]\n", svc_mem_info.base_address,
@ -698,11 +686,8 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
cur_addr = next_address; cur_addr = next_address;
} }
} else if (command_str == "help") {
reply = commands;
} else { } else {
reply = "Unknown command.\n"; reply += "Commands: fastmem, info, mappings\n";
reply += commands;
} }
std::span<const u8> reply_span{reinterpret_cast<u8*>(&reply.front()), reply.size()}; std::span<const u8> reply_span{reinterpret_cast<u8*>(&reply.front()), reply.size()};