diff --git a/Source/Tools/LinuxEmulation/GdbServer/Info.cpp b/Source/Tools/LinuxEmulation/GdbServer/Info.cpp index 3352ee8154..db28f3c7e3 100644 --- a/Source/Tools/LinuxEmulation/GdbServer/Info.cpp +++ b/Source/Tools/LinuxEmulation/GdbServer/Info.cpp @@ -77,13 +77,18 @@ fextl::string BuildOSXML() { return xml.str(); } -fextl::string BuildTargetXML() { +fextl::string BuildTargetXML(bool Is64Bit) { fextl::ostringstream xml; xml << "\n"; xml << "\n"; xml << "\n"; - xml << "i386:x86-64\n"; + if (Is64Bit) { + xml << "i386:x86-64\n"; + } + else { + xml << "i386\n"; + } xml << "GNU/Linux\n"; xml << "\n"; @@ -108,11 +113,16 @@ fextl::string BuildTargetXML() { // We want to just memcpy our x86 state to gdb, so we tell it the ordering. // GPRs - for (uint32_t i = 0; i < FEXCore::Core::CPUState::NUM_GPRS; i++) { - reg(GDB::Info::GetGRegName(i), "int64", 64); + for (uint32_t i = 0; i < FEXCore::Core::CPUState::NUM_GPRS / (Is64Bit ? 1 : 2); i++) { + if (Is64Bit) { + reg(GDB::Info::GetGRegName(i), "int64", 64); + } + else { + reg(GDB::Info::GetGRegName(i), "int32", 32); + } } - reg("rip", "code_ptr", 64); + reg("rip", "code_ptr", Is64Bit ? 64 : 32); reg("eflags", "fex_eflags", 32); @@ -165,7 +175,7 @@ fextl::string BuildTargetXML() { )"; // SSE regs - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) { + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS / (Is64Bit ? 1 : 2); i++) { reg(fextl::fmt::format("xmm{}", i), "vec128", 128); } @@ -173,26 +183,28 @@ fextl::string BuildTargetXML() { xml << "\n"; - xml << ""; - xml << - R"( - - - - - - - - - - - - - - - )"; - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) { - reg(fmt::format("ymm{}h", i), "vec128", 128); + if (Is64Bit) { + xml << ""; + xml << + R"( + + + + + + + + + + + + + + + )"; + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS / (Is64Bit ? 1 : 2); i++) { + reg(fmt::format("ymm{}h", i), "vec128", 128); + } } xml << "\n"; diff --git a/Source/Tools/LinuxEmulation/GdbServer/Info.h b/Source/Tools/LinuxEmulation/GdbServer/Info.h index d3a7ff45c6..9450c7cbc3 100644 --- a/Source/Tools/LinuxEmulation/GdbServer/Info.h +++ b/Source/Tools/LinuxEmulation/GdbServer/Info.h @@ -47,5 +47,5 @@ fextl::string BuildOSXML(); /** * @brief Returns the GDB specific construct of target describing XML. */ -fextl::string BuildTargetXML(); +fextl::string BuildTargetXML(bool Is64Bit); } // namespace FEX::GDB::Info diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.cpp index 2f9680bd26..67f52a0629 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.cpp @@ -282,19 +282,23 @@ const FEX::HLE::ThreadStateObject* GdbServer::FindThreadByTID(uint32_t TID) { return Threads->at(0); } - -GdbServer::GDBContextDefinition GdbServer::GenerateContextDefinition(const FEX::HLE::ThreadStateObject* ThreadObject) { - GDBContextDefinition GDB {}; +template +T GdbServer::GenerateContextDefinition(const FEX::HLE::ThreadStateObject* ThreadObject) { + T GDB {}; FEXCore::Core::CPUState state {}; // Copy the thread state. memcpy(&state, ThreadObject->Thread->CurrentFrame, sizeof(state)); // Encode the GDB context definition - memcpy(&GDB.gregs[0], &state.gregs[0], sizeof(GDB.gregs)); - memcpy(&GDB.rip, &state.rip, sizeof(GDB.rip)); + for (size_t i = 0; i < std::size(state.gregs); ++i) { + memcpy(&GDB.gregs[i], &state.gregs[i], sizeof(state.gregs[0])); + } + GDB.rip = CTX->RestoreRIPFromHostPC(ThreadObject->Thread, ThreadObject->GdbInfo.SignalPC); - GDB.eflags = CTX->ReconstructCompactedEFLAGS(ThreadObject->Thread, false, nullptr, 0); + const bool WasInJIT = CTX->IsAddressInCodeBuffer(ThreadObject->Thread, ThreadObject->GdbInfo.SignalPC); + GDB.eflags = CTX->ReconstructCompactedEFLAGS(ThreadObject->Thread, WasInJIT, const_cast(ThreadObject->GdbInfo.GPRs), + ThreadObject->GdbInfo.PState); for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_MMS; ++i) { memcpy(&GDB.mm[i], &state.mm[i], sizeof(GDB.mm[i])); @@ -310,16 +314,25 @@ GdbServer::GDBContextDefinition GdbServer::GenerateContextDefinition(const FEX:: __uint128_t XMM_Low[FEXCore::Core::CPUState::NUM_XMMS]; __uint128_t YMM_High[FEXCore::Core::CPUState::NUM_XMMS]; - - CTX->ReconstructXMMRegisters(ThreadObject->Thread, XMM_Low, YMM_High); - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; ++i) { - memcpy(&GDB.xmm[0], &XMM_Low[i], sizeof(__uint128_t)); - memcpy(&GDB.xmm[2], &YMM_High[i], sizeof(__uint128_t)); + constexpr auto xmm_count = std::size(GDB.xmm); + constexpr auto xmm_size = std::size(GDB.xmm[0]); + + CTX->ReconstructXMMRegisters(ThreadObject->Thread, XMM_Low, xmm_size == 4 ? YMM_High : nullptr); + for (size_t i = 0; i < xmm_count; ++i) { + memcpy(&GDB.xmm[i][0], &XMM_Low[i], sizeof(__uint128_t)); + if (xmm_size == 4) { + memcpy(&GDB.xmm[i][2], &YMM_High[i], sizeof(__uint128_t)); + } } return GDB; } +template +GdbServer::GDBContextDefinition GdbServer::GenerateContextDefinition(const FEX::HLE::ThreadStateObject*); +template +GdbServer::GDBContextDefinition_32 GdbServer::GenerateContextDefinition(const FEX::HLE::ThreadStateObject*); + void GdbServer::buildLibraryMap() { if (!LibraryMapChanged) { // No need to update @@ -417,7 +430,7 @@ GdbServer::HandledPacketType GdbServer::XferCommandExecFile(const fextl::string& GdbServer::HandledPacketType GdbServer::XferCommandFeatures(const fextl::string& annex, int offset, int length) { if (annex == "target.xml") { - return {EncodeXferString(GDB::Info::BuildTargetXML(), offset, length), HandledPacketType::TYPE_ACK}; + return {EncodeXferString(GDB::Info::BuildTargetXML(Is64BitMode()), offset, length), HandledPacketType::TYPE_ACK}; } return {"E00", HandledPacketType::TYPE_ACK}; @@ -650,8 +663,14 @@ GdbServer::HandledPacketType GdbServer::CommandReadRegisters(const fextl::string // Pause up front SyscallHandler->TM.Pause(); const FEX::HLE::ThreadStateObject* CurrentThread = FindThreadByTID(CurrentDebuggingThread); - auto GDB = GenerateContextDefinition(CurrentThread); - return {encodeHex((unsigned char*)&GDB, sizeof(GDBContextDefinition)), HandledPacketType::TYPE_ACK}; + if (Is64BitMode()) { + auto GDB = GenerateContextDefinition(CurrentThread); + return {encodeHex((unsigned char*)&GDB, sizeof(GDB)), HandledPacketType::TYPE_ACK}; + } + else { + auto GDB = GenerateContextDefinition(CurrentThread); + return {encodeHex((unsigned char*)&GDB, sizeof(GDB)), HandledPacketType::TYPE_ACK}; + } } GdbServer::HandledPacketType GdbServer::CommandThreadOp(const fextl::string& packet) { @@ -737,35 +756,44 @@ GdbServer::HandledPacketType GdbServer::CommandReadReg(const fextl::string& pack ss >> std::hex >> addr; const FEX::HLE::ThreadStateObject* CurrentThread = FindThreadByTID(CurrentDebuggingThread); - auto GDB = GenerateContextDefinition(CurrentThread); - - if (addr >= offsetof(GDBContextDefinition, gregs[0]) && addr < offsetof(GDBContextDefinition, gregs[16])) { - return {encodeHex((unsigned char*)(&GDB.gregs[addr / sizeof(uint64_t)]), sizeof(uint64_t)), HandledPacketType::TYPE_ACK}; - } else if (addr == offsetof(GDBContextDefinition, rip)) { - return {encodeHex((unsigned char*)(&GDB.rip), sizeof(uint64_t)), HandledPacketType::TYPE_ACK}; - } else if (addr == offsetof(GDBContextDefinition, eflags)) { - return {encodeHex((unsigned char*)(&GDB.eflags), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; - } else if (addr >= offsetof(GDBContextDefinition, cs) && addr < offsetof(GDBContextDefinition, mm[0])) { - uint32_t Empty {}; - return {encodeHex((unsigned char*)(&Empty), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; - } else if (addr >= offsetof(GDBContextDefinition, mm[0]) && addr < offsetof(GDBContextDefinition, mm[8])) { - return {encodeHex((unsigned char*)(&GDB.mm[(addr - offsetof(GDBContextDefinition, mm[0])) / sizeof(X80Float)]), sizeof(X80Float)), - HandledPacketType::TYPE_ACK}; - } else if (addr == offsetof(GDBContextDefinition, fctrl)) { - return {encodeHex((unsigned char*)(&GDB.fctrl), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; - } else if (addr == offsetof(GDBContextDefinition, fstat)) { - return {encodeHex((unsigned char*)(&GDB.fstat), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; - } else if (addr >= offsetof(GDBContextDefinition, dummies[0]) && addr < offsetof(GDBContextDefinition, dummies[6])) { - return {encodeHex((unsigned char*)(&GDB.dummies[0]), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; - } else if (addr >= offsetof(GDBContextDefinition, xmm[0][0]) && addr < offsetof(GDBContextDefinition, xmm[16][0])) { - const auto XmmIndex = (addr - offsetof(GDBContextDefinition, xmm[0][0])) / FEXCore::Core::CPUState::XMM_AVX_REG_SIZE; - return {encodeHex(reinterpret_cast(&GDB.xmm[XmmIndex]), FEXCore::Core::CPUState::XMM_AVX_REG_SIZE), HandledPacketType::TYPE_ACK}; - } else if (addr == offsetof(GDBContextDefinition, mxcsr)) { - return {encodeHex((unsigned char*)(&GDB.mxcsr), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; - } - - LogMan::Msg::EFmt("Unknown GDB register 0x{:x}", addr); - return {"E00", HandledPacketType::TYPE_ACK}; + auto GenerateAndFetchContextDefinition = [this](auto CurrentThread, size_t addr) -> GdbServer::HandledPacketType { + auto GDB = GenerateContextDefinition(CurrentThread); + + if (addr >= offsetof(T, gregs[0]) && addr < offsetof(T, gregs[std::size(GDB.gregs)])) { + return {encodeHex((unsigned char*)(&GDB.gregs[addr / sizeof(GDB.gregs[0])]), sizeof(GDB.gregs[0])), HandledPacketType::TYPE_ACK}; + } else if (addr == offsetof(T, rip)) { + return {encodeHex((unsigned char*)(&GDB + offsetof(T, rip)), sizeof(GDB.rip)), HandledPacketType::TYPE_ACK}; + } else if (addr == offsetof(T, eflags)) { + return {encodeHex((unsigned char*)(&GDB + offsetof(T, eflags)), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; + } else if (addr >= offsetof(T, cs) && addr < offsetof(T, mm[0])) { + uint32_t Empty {}; + return {encodeHex((unsigned char*)(&Empty), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; + } else if (addr >= offsetof(T, mm[0]) && addr <= offsetof(T, mm[std::size(GDB.mm)])) { + return {encodeHex((unsigned char*)(&GDB.mm[(addr - offsetof(T, mm[0])) / sizeof(X80Float)]), sizeof(X80Float)), + HandledPacketType::TYPE_ACK}; + } else if (addr == offsetof(T, fctrl)) { + return {encodeHex((unsigned char*)(&GDB + offsetof(T, fctrl)), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; + } else if (addr == offsetof(T, fstat)) { + return {encodeHex((unsigned char*)(&GDB + offsetof(T, fstat)), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; + } else if (addr >= offsetof(T, dummies[0]) && addr < offsetof(T, dummies[std::size(GDB.dummies)])) { + return {encodeHex((unsigned char*)(&GDB.dummies[0]), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; + } else if (addr >= offsetof(T, xmm[0][0]) && addr < offsetof(T, xmm[std::size(GDB.xmm)][0])) { + const auto XmmIndex = (addr - offsetof(T, xmm[0][0])) / sizeof(GDB.xmm); + return {encodeHex(reinterpret_cast(&GDB.xmm[XmmIndex]), sizeof(GDB.xmm)), HandledPacketType::TYPE_ACK}; + } else if (addr == offsetof(T, mxcsr)) { + return {encodeHex((unsigned char*)(&GDB + offsetof(T, mxcsr)), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; + } + + LogMan::Msg::EFmt("Unknown GDB register 0x{:x}", addr); + return {"E00", HandledPacketType::TYPE_ACK}; + }; + + if (Is64BitMode()) { + return GenerateAndFetchContextDefinition.template operator()(CurrentThread, addr); + } + else { + return GenerateAndFetchContextDefinition.template operator()(CurrentThread, addr); + } } GdbServer::HandledPacketType GdbServer::CommandQuery(const fextl::string& packet) { diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.h index af749d8f89..2e98dfb76e 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.h @@ -128,20 +128,25 @@ class GdbServer { uint8_t Data[10]; }; - struct FEX_PACKED GDBContextDefinition { - uint64_t gregs[FEXCore::Core::CPUState::NUM_GPRS]; - uint64_t rip; + template + struct FEX_PACKED GDBContextDefinitionBase { + GPRType gregs[GPRCount]; + GPRType rip; uint32_t eflags; uint32_t cs, ss, ds, es, fs, gs; X80Float mm[FEXCore::Core::CPUState::NUM_MMS]; uint32_t fctrl; uint32_t fstat; uint32_t dummies[6]; - uint64_t xmm[FEXCore::Core::CPUState::NUM_XMMS][4]; + uint64_t xmm[XMMCount][XMMArray]; uint32_t mxcsr; }; - GDBContextDefinition GenerateContextDefinition(const FEX::HLE::ThreadStateObject* ThreadObject); + using GDBContextDefinition = GDBContextDefinitionBase; + using GDBContextDefinition_32 = GDBContextDefinitionBase; + + template + T GenerateContextDefinition(const FEX::HLE::ThreadStateObject* ThreadObject); FEXCore::Context::Context* CTX; FEX::HLE::SyscallHandler* const SyscallHandler;