Skip to content

Commit

Permalink
GdbServer: Support 32-bit context definitions
Browse files Browse the repository at this point in the history
Requires restructuring a couple of things, but nothing too crazy here.
  • Loading branch information
Sonicadvance1 committed Dec 10, 2024
1 parent ec51ac7 commit 1c35755
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 75 deletions.
64 changes: 38 additions & 26 deletions Source/Tools/LinuxEmulation/GdbServer/Info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,18 @@ fextl::string BuildOSXML() {
return xml.str();
}

fextl::string BuildTargetXML() {
fextl::string BuildTargetXML(bool Is64Bit) {
fextl::ostringstream xml;

xml << "<?xml version='1.0'?>\n";
xml << "<!DOCTYPE target SYSTEM 'gdb-target.dtd'>\n";
xml << "<target>\n";
xml << "<architecture>i386:x86-64</architecture>\n";
if (Is64Bit) {
xml << "<architecture>i386:x86-64</architecture>\n";
}
else {
xml << "<architecture>i386</architecture>\n";
}
xml << "<osabi>GNU/Linux</osabi>\n";
xml << "<feature name='org.gnu.gdb.i386.core'>\n";

Expand All @@ -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);

Expand Down Expand Up @@ -165,34 +175,36 @@ 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);
}

reg("mxcsr", "int", 32);

xml << "</feature>\n";

xml << "<feature name='org.gnu.gdb.i386.avx'>";
xml <<
R"(<vector id="v4f" type="ieee_single" count="4"/>
<vector id="v2d" type="ieee_double" count="2"/>
<vector id="v16i8" type="int8" count="16"/>
<vector id="v8i16" type="int16" count="8"/>
<vector id="v4i32" type="int32" count="4"/>
<vector id="v2i64" type="int64" count="2"/>
<union id="vec128">
<field name="v4_float" type="v4f"/>
<field name="v2_double" type="v2d"/>
<field name="v16_int8" type="v16i8"/>
<field name="v8_int16" type="v8i16"/>
<field name="v4_int32" type="v4i32"/>
<field name="v2_int64" type="v2i64"/>
<field name="uint128" type="uint128"/>
</union>
)";
for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) {
reg(fmt::format("ymm{}h", i), "vec128", 128);
if (Is64Bit) {
xml << "<feature name='org.gnu.gdb.i386.avx'>";
xml <<
R"(<vector id="v4f" type="ieee_single" count="4"/>
<vector id="v2d" type="ieee_double" count="2"/>
<vector id="v16i8" type="int8" count="16"/>
<vector id="v8i16" type="int16" count="8"/>
<vector id="v4i32" type="int32" count="4"/>
<vector id="v2i64" type="int64" count="2"/>
<union id="vec128">
<field name="v4_float" type="v4f"/>
<field name="v2_double" type="v2d"/>
<field name="v16_int8" type="v16i8"/>
<field name="v8_int16" type="v8i16"/>
<field name="v4_int32" type="v4i32"/>
<field name="v2_int64" type="v2i64"/>
<field name="uint128" type="uint128"/>
</union>
)";
for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS / (Is64Bit ? 1 : 2); i++) {
reg(fmt::format("ymm{}h", i), "vec128", 128);
}
}
xml << "</feature>\n";

Expand Down
2 changes: 1 addition & 1 deletion Source/Tools/LinuxEmulation/GdbServer/Info.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
114 changes: 71 additions & 43 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<typename T>
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<uint64_t*>(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]));
Expand All @@ -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
Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -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<GDBContextDefinition>(CurrentThread);
return {encodeHex((unsigned char*)&GDB, sizeof(GDB)), HandledPacketType::TYPE_ACK};
}
else {
auto GDB = GenerateContextDefinition<GDBContextDefinition_32>(CurrentThread);
return {encodeHex((unsigned char*)&GDB, sizeof(GDB)), HandledPacketType::TYPE_ACK};
}
}

GdbServer::HandledPacketType GdbServer::CommandThreadOp(const fextl::string& packet) {
Expand Down Expand Up @@ -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<const uint8_t*>(&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]<typename T>(auto CurrentThread, size_t addr) -> GdbServer::HandledPacketType {
auto GDB = GenerateContextDefinition<T>(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<const uint8_t*>(&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()<GDBContextDefinition>(CurrentThread, addr);
}
else {
return GenerateAndFetchContextDefinition.template operator()<GDBContextDefinition_32>(CurrentThread, addr);
}
}

GdbServer::HandledPacketType GdbServer::CommandQuery(const fextl::string& packet) {
Expand Down
15 changes: 10 additions & 5 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<size_t GPRCount, typename GPRType, size_t XMMCount, size_t XMMArray>
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<FEXCore::Core::CPUState::NUM_GPRS, uint64_t, FEXCore::Core::CPUState::NUM_XMMS, 4>;
using GDBContextDefinition_32 = GDBContextDefinitionBase<FEXCore::Core::CPUState::NUM_GPRS / 2, uint32_t, FEXCore::Core::CPUState::NUM_XMMS / 2, 2>;

template<class T>
T GenerateContextDefinition(const FEX::HLE::ThreadStateObject* ThreadObject);

FEXCore::Context::Context* CTX;
FEX::HLE::SyscallHandler* const SyscallHandler;
Expand Down

0 comments on commit 1c35755

Please sign in to comment.