Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GdbServer: Support 32-bit context definitions #4205

Merged
merged 4 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions Source/Tools/LinuxEmulation/GdbServer/Info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,17 @@ 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 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
69 changes: 61 additions & 8 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ GdbServer::~GdbServer() {

GdbServer::GdbServer(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* SignalDelegation, FEX::HLE::SyscallHandler* const SyscallHandler)
: CTX(ctx)
, SyscallHandler {SyscallHandler} {
, SyscallHandler {SyscallHandler}
, SignalDelegation {SignalDelegation} {
// Pass all signals by default
std::fill(PassSignals.begin(), PassSignals.end(), true);

Expand All @@ -107,10 +108,21 @@ GdbServer::GdbServer(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator*
return false;
}

auto ThreadObject = FEX::HLE::ThreadManager::GetStateObjectFromFEXCoreThread(Thread);
ThreadObject->GdbInfo = {};
ThreadObject->GdbInfo->Signal = Signal;

ThreadObject->GdbInfo->SignalPC = ArchHelpers::Context::GetPc(ucontext);
this->SignalDelegation->SpillSRA(Thread, ucontext, Thread->CurrentFrame->InSyscallInfo);

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;
},
Expand Down Expand Up @@ -145,6 +157,10 @@ static fextl::string hexstring(fextl::istringstream& ss, int delm) {
return ret;
}

static fextl::string appendHex(const char* data, size_t length) {
return fextl::fmt::format("{:#02x}", fmt::join(data, data + length, ""));
}

static fextl::string encodeHex(const unsigned char* data, size_t length) {
fextl::ostringstream ss;

Expand Down Expand Up @@ -271,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 {};
Expand All @@ -281,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<uint64_t*>(ThreadObject->GdbInfo->GPRs),
ThreadObject->GdbInfo->PState);
} else {
GDB.rip = ThreadObject->Thread->CurrentFrame->State.rip;
neobrain marked this conversation as resolved.
Show resolved Hide resolved
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]));
Expand All @@ -302,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;
Expand Down Expand Up @@ -406,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};
Expand Down Expand Up @@ -639,8 +661,39 @@ 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<const char*>(&GDB.gregs[i]), GPRSize);
}
str += appendHex(reinterpret_cast<const char*>(&GDB.rip), GPRSize);
str += appendHex(reinterpret_cast<const char*>(&GDB.eflags), sizeof(uint32_t));

str += appendHex(reinterpret_cast<const char*>(&GDB.cs), sizeof(uint32_t));
str += appendHex(reinterpret_cast<const char*>(&GDB.ss), sizeof(uint32_t));
str += appendHex(reinterpret_cast<const char*>(&GDB.ds), sizeof(uint32_t));
str += appendHex(reinterpret_cast<const char*>(&GDB.es), sizeof(uint32_t));
str += appendHex(reinterpret_cast<const char*>(&GDB.fs), sizeof(uint32_t));
str += appendHex(reinterpret_cast<const char*>(&GDB.gs), sizeof(uint32_t));
for (auto& mm : GDB.mm) {
str += appendHex(reinterpret_cast<const char*>(&mm), sizeof(X80Float));
}

str += appendHex(reinterpret_cast<const char*>(&GDB.fctrl), sizeof(uint32_t));
str += appendHex(reinterpret_cast<const char*>(&GDB.fstat), sizeof(uint32_t));
str += appendHex(reinterpret_cast<const char*>(&GDB.dummies), sizeof(GDB.dummies));

for (size_t i = 0; i < NumXMM; ++i) {
str += appendHex(reinterpret_cast<const char*>(&GDB.xmm[i]), XMMSize);
}

str += appendHex(reinterpret_cast<const char*>(&GDB.mxcsr), sizeof(uint32_t));

return {str, HandledPacketType::TYPE_ACK};
}

GdbServer::HandledPacketType GdbServer::CommandThreadOp(const fextl::string& packet) {
Expand Down
1 change: 1 addition & 0 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ class GdbServer {

FEXCore::Context::Context* CTX;
FEX::HLE::SyscallHandler* const SyscallHandler;
FEX::HLE::SignalDelegator* SignalDelegation;
fextl::unique_ptr<FEXCore::Threads::Thread> gdbServerThread;
fextl::unique_ptr<std::iostream> CommsStream;
std::mutex sendMutex;
Expand Down
5 changes: 3 additions & 2 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@ class SignalDelegator final : public FEXCore::SignalDelegator, public FEXCore::A
}

void SaveTelemetry();

void SpillSRA(FEXCore::Core::InternalThreadState* Thread, void* ucontext, uint32_t IgnoreMask);

private:
// Called from the thunk handler to handle the signal
void HandleGuestSignal(FEX::HLE::ThreadStateObject* ThreadObject, int Signal, void* Info, void* UContext);
Expand Down Expand Up @@ -242,8 +245,6 @@ class SignalDelegator final : public FEXCore::SignalDelegator, public FEXCore::A
///< FP state now follows after this.
};

void SpillSRA(FEXCore::Core::InternalThreadState* Thread, void* ucontext, uint32_t IgnoreMask);

void RestoreFrame_x64(FEXCore::Core::InternalThreadState* Thread, ArchHelpers::Context::ContextBackup* Context,
FEXCore::Core::CpuStateFrame* Frame, void* ucontext);
void RestoreFrame_ia32(FEXCore::Core::InternalThreadState* Thread, ArchHelpers::Context::ContextBackup* Context,
Expand Down
9 changes: 9 additions & 0 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,15 @@ struct ThreadStateObject : public FEXCore::Allocator::FEXAllocOperators {
std::atomic_bool ThreadSleeping {false};
FEXCore::InterruptableConditionVariable ThreadPaused;

// GDB signal information
struct GdbInfoStruct {
int Signal {};
uint64_t SignalPC {};
uint64_t GPRs[32];
uint64_t PState {};
};
std::optional<GdbInfoStruct> GdbInfo;

int StatusCode {};
};

Expand Down
Loading