diff --git a/Source/Tools/LinuxEmulation/GdbServer/Info.cpp b/Source/Tools/LinuxEmulation/GdbServer/Info.cpp index 3352ee8154..dfd87ff255 100644 --- a/Source/Tools/LinuxEmulation/GdbServer/Info.cpp +++ b/Source/Tools/LinuxEmulation/GdbServer/Info.cpp @@ -77,13 +77,17 @@ 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"; 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 cd9dab0588..1e217efb24 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.cpp @@ -109,19 +109,20 @@ GdbServer::GdbServer(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* } auto ThreadObject = FEX::HLE::ThreadManager::GetStateObjectFromFEXCoreThread(Thread); - ThreadObject->GdbInfo.Signal = Signal; + ThreadObject->GdbInfo = {}; + ThreadObject->GdbInfo->Signal = Signal; - ThreadObject->GdbInfo.SignalPC = ArchHelpers::Context::GetPc(ucontext); - uint32_t IgnoreMask = Thread->CurrentFrame->InSyscallInfo & 0xFFFF; - this->SignalDelegation->SpillSRA(Thread, ucontext, IgnoreMask); + ThreadObject->GdbInfo->SignalPC = ArchHelpers::Context::GetPc(ucontext); + this->SignalDelegation->SpillSRA(Thread, ucontext, Thread->CurrentFrame->InSyscallInfo); - memcpy(ThreadObject->GdbInfo.GPRs, ArchHelpers::Context::GetArmGPRs(ucontext), sizeof(uint64_t) * 32); - ThreadObject->GdbInfo.PState = ArchHelpers::Context::GetArmPState(ucontext); + memcpy(ThreadObject->GdbInfo->GPRs, ArchHelpers::Context::GetArmGPRs(ucontext), sizeof(ThreadObject->GdbInfo->GPRs)); + ThreadObject->GdbInfo->PState = ArchHelpers::Context::GetArmPState(ucontext); // Let GDB know that we have a signal this->Break(Thread, Signal); WaitForThreadWakeup(); + ThreadObject->GdbInfo.reset(); return true; }, @@ -156,6 +157,10 @@ static fextl::string hexstring(fextl::istringstream& ss, int delm) { return ret; } +static std::string appendHex(const unsigned char* data, size_t length) { + return fmt::format("{:#02x}", fmt::join(data, data + length, "")); +} + static fextl::string encodeHex(const unsigned char* data, size_t length) { fextl::ostringstream ss; @@ -282,7 +287,6 @@ const FEX::HLE::ThreadStateObject* GdbServer::FindThreadByTID(uint32_t TID) { return Threads->at(0); } - GdbServer::GDBContextDefinition GdbServer::GenerateContextDefinition(const FEX::HLE::ThreadStateObject* ThreadObject) { GDBContextDefinition GDB {}; FEXCore::Core::CPUState state {}; @@ -292,9 +296,16 @@ GdbServer::GDBContextDefinition GdbServer::GenerateContextDefinition(const FEX:: // Encode the GDB context definition memcpy(&GDB.gregs[0], &state.gregs[0], sizeof(GDB.gregs)); - memcpy(&GDB.rip, &state.rip, sizeof(GDB.rip)); + if (ThreadObject->GdbInfo.has_value()) { + 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); + } else { + GDB.rip = ThreadObject->Thread->CurrentFrame->State.rip; + GDB.eflags = CTX->ReconstructCompactedEFLAGS(ThreadObject->Thread, false, nullptr, 0); + } for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_MMS; ++i) { memcpy(&GDB.mm[i], &state.mm[i], sizeof(GDB.mm[i])); @@ -313,8 +324,8 @@ GdbServer::GDBContextDefinition GdbServer::GenerateContextDefinition(const FEX:: 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)); + memcpy(&GDB.xmm[i][0], &XMM_Low[i], sizeof(__uint128_t)); + memcpy(&GDB.xmm[i][2], &YMM_High[i], sizeof(__uint128_t)); } return GDB; @@ -417,7 +428,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 +661,41 @@ GdbServer::HandledPacketType GdbServer::CommandReadRegisters(const fextl::string // Pause up front SyscallHandler->TM.Pause(); const FEX::HLE::ThreadStateObject* CurrentThread = FindThreadByTID(CurrentDebuggingThread); + const size_t NumGPR = Is64BitMode() ? FEXCore::Core::CPUState::NUM_GPRS : FEXCore::Core::CPUState::NUM_GPRS / 2; + const size_t GPRSize = Is64BitMode() ? sizeof(uint64_t) : sizeof(uint32_t); + const size_t NumXMM = Is64BitMode() ? FEXCore::Core::CPUState::NUM_XMMS : FEXCore::Core::CPUState::NUM_XMMS / 2; + const size_t XMMSize = Is64BitMode() ? sizeof(__uint128_t) * 2 : sizeof(__uint128_t); + fextl::string str; auto GDB = GenerateContextDefinition(CurrentThread); - return {encodeHex((unsigned char*)&GDB, sizeof(GDBContextDefinition)), HandledPacketType::TYPE_ACK}; + for (size_t i = 0; i < NumGPR; ++i) { + str += appendHex(reinterpret_cast(&GDB.gregs[i]), GPRSize); + } + str += appendHex(reinterpret_cast(&GDB.rip), GPRSize); + str += appendHex(reinterpret_cast(&GDB.eflags), sizeof(uint32_t)); + + str += appendHex(reinterpret_cast(&GDB.cs), sizeof(uint32_t)); + str += appendHex(reinterpret_cast(&GDB.ss), sizeof(uint32_t)); + str += appendHex(reinterpret_cast(&GDB.ds), sizeof(uint32_t)); + str += appendHex(reinterpret_cast(&GDB.es), sizeof(uint32_t)); + str += appendHex(reinterpret_cast(&GDB.fs), sizeof(uint32_t)); + str += appendHex(reinterpret_cast(&GDB.gs), sizeof(uint32_t)); + for (auto& mm : GDB.mm) { + str += appendHex(reinterpret_cast(&mm), sizeof(X80Float)); + } + + str += appendHex(reinterpret_cast(&GDB.fctrl), sizeof(uint32_t)); + str += appendHex(reinterpret_cast(&GDB.fstat), sizeof(uint32_t)); + for (auto& dummy : GDB.dummies) { + str += appendHex(reinterpret_cast(&dummy), sizeof(uint32_t)); + } + + for (size_t i = 0; i < NumXMM; ++i) { + str += appendHex(reinterpret_cast(&GDB.xmm[i]), XMMSize); + } + + str += appendHex(reinterpret_cast(&GDB.mxcsr), sizeof(uint32_t)); + + return {str, HandledPacketType::TYPE_ACK}; } GdbServer::HandledPacketType GdbServer::CommandThreadOp(const fextl::string& packet) { diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.h index 9060702110..2401a88357 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.h @@ -90,7 +90,8 @@ struct ThreadStateObject : public FEXCore::Allocator::FEXAllocOperators { uint64_t SignalPC {}; uint64_t GPRs[32]; uint64_t PState {}; - } GdbInfo; + }; + std::optional GdbInfo; int StatusCode {}; };