mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-27 20:01:04 +01:00
GdbServer: Implement xml target for register order
We can now simply memcpy much of memory state.
This commit is contained in:
1 parent
e44b3ca495
commit
545b542f9b
4 files changed
+128
-20
No files matched your search
@@ -65,6 +65,29 @@ std::string_view const& GetFlagName(unsigned Flag) {
|
||||
return FlagNames[Flag];
|
||||
}
|
||||
|
||||
constexpr std::array<std::string_view const, 16> RegNames = {
|
||||
"rax",
|
||||
"rbx",
|
||||
"rcx",
|
||||
"rdx",
|
||||
"rsi",
|
||||
"rdi",
|
||||
"rbp",
|
||||
"rsp",
|
||||
"r8",
|
||||
"r9",
|
||||
"r10",
|
||||
"r11",
|
||||
"r12",
|
||||
"r13",
|
||||
"r14",
|
||||
"r15",
|
||||
};
|
||||
|
||||
std::string_view const& GetGRegName(unsigned Reg) {
|
||||
return RegNames[Reg];
|
||||
}
|
||||
|
||||
namespace DefaultFallbackCore {
|
||||
class DefaultFallbackCore final : public FEXCore::CPU::CPUBackend {
|
||||
public:
|
||||
|
||||
@@ -148,6 +148,101 @@ void GdbServer::SendPacket(std::ostream &stream, std::string packet) {
|
||||
stream << std::flush;
|
||||
}
|
||||
|
||||
std::string GdbServer::readRegs() {
|
||||
auto state = CTX->GetCPUState();
|
||||
state.rip = 0x47c990;
|
||||
|
||||
return encodeHex((unsigned char *)&state, sizeof(state)).substr(0, 572*2);
|
||||
}
|
||||
|
||||
std::string buildTargetXML() {
|
||||
using FEXCore::Core::CPUState;
|
||||
|
||||
std::ostringstream xml;
|
||||
|
||||
int dummy_offset = sizeof(CPUState);
|
||||
int dummy_num = sizeof(CPUState) / 8;
|
||||
auto dummy = [&](int size) { dummy_offset+= size; return dummy_num++; };
|
||||
|
||||
xml << "<?xml version='1.0'?>\n";
|
||||
xml << "<!DOCTYPE target SYSTEM 'gdb-target.dtd'>\n";\
|
||||
xml << "<target version='1.0'>\n";
|
||||
xml << "<architecture>i386:x86-64</architecture>\n";
|
||||
xml << "<osabi>GNU/Linux</osabi>\n";
|
||||
xml << "<feature name='org.gnu.gdb.i386.core'>\n";
|
||||
|
||||
xml << "<flags id='fex_eflags' size='32'>\n";
|
||||
// flags register
|
||||
for(int i=0; i <= 32; i++) {
|
||||
auto name = FEXCore::Core::GetFlagName(i);
|
||||
xml << "<field name='" << name << "' start='" << i << "' end='" << i << "' />\n";
|
||||
}
|
||||
xml << "</flags>";
|
||||
|
||||
auto reg_numbered = [&](std::string_view name, int num, std::string_view type, int size) {
|
||||
xml << "<reg name='" << name << "' bitsize='" << size << "' type='" << type;
|
||||
xml << "' regnum='" << num << "' />" << std::endl;
|
||||
};
|
||||
auto reg = [&](std::string_view name, int offset, std::string_view type, int size) {
|
||||
reg_numbered(name, offset / 8, type, size);
|
||||
};
|
||||
|
||||
// Register ordering.
|
||||
// We want to just memcpy our x86 state to gdb, so we tell it the ordering.
|
||||
|
||||
// GPRs
|
||||
for (int i=0; i < 16; i++) {
|
||||
reg(FEXCore::Core::GetGRegName(i), offsetof(CPUState, gregs[i]), "int64", 64);
|
||||
}
|
||||
|
||||
reg("rip", offsetof(CPUState, rip), "code_ptr", 64);
|
||||
reg("eflags", offsetof(CPUState, flags), "fex_eflags", 8*32);
|
||||
reg("gs", offsetof(CPUState, gs), "int64", 64);
|
||||
reg("fs", offsetof(CPUState, fs), "int64", 64);
|
||||
|
||||
// Fake registers which GDB requires, but we don't support;
|
||||
// We stick them past the end of our cpu state.
|
||||
|
||||
// non-userspace segment registers
|
||||
reg_numbered("cs", dummy(4), "int32", 32);
|
||||
reg_numbered("ss", dummy(4), "int32", 32);
|
||||
reg_numbered("ds", dummy(4), "int32", 32);
|
||||
reg_numbered("es", dummy(4), "int32", 32);
|
||||
|
||||
// x87 stack
|
||||
for (int i=0; i < 8; i++) {
|
||||
reg_numbered("st" + std::to_string(i), dummy(10), "i387_ext", 80);
|
||||
}
|
||||
|
||||
// x87 control
|
||||
reg_numbered("fctrl", dummy(4), "int32", 32);
|
||||
reg_numbered("fstat", dummy(4), "int32", 32);
|
||||
reg_numbered("ftag", dummy(4), "int32", 32);
|
||||
reg_numbered("fiseg", dummy(4), "int32", 32);
|
||||
reg_numbered("fioff", dummy(4), "int32", 32);
|
||||
reg_numbered("foseg", dummy(4), "int32", 32);
|
||||
reg_numbered("fooff", dummy(4), "int32", 32);
|
||||
reg_numbered("fop", dummy(4), "int32", 32);
|
||||
|
||||
|
||||
xml << "</feature>\n";
|
||||
xml << "<feature name='org.gnu.gdb.i386.sse'>\n";
|
||||
xml << "<vector id='sse' type='int32' count='4' />";
|
||||
|
||||
// SSE regs
|
||||
for (int i=0; i < 16; i++) {
|
||||
reg("xmm" + std::to_string(i), offsetof(CPUState, xmm[i]), "sse", 128);
|
||||
}
|
||||
|
||||
reg("mxcsr", dummy(4), "int", 32);
|
||||
|
||||
xml << "</feature>\n";
|
||||
xml << "</target>\n";
|
||||
xml << std::flush;
|
||||
|
||||
return xml.str();
|
||||
}
|
||||
|
||||
std::string GdbServer::handleXfer(std::string &packet) {
|
||||
|
||||
std::string object;
|
||||
@@ -191,6 +286,11 @@ std::string GdbServer::handleXfer(std::string &packet) {
|
||||
return encode(CTX->SyscallHandler.GetFilename());
|
||||
return "E00";
|
||||
}
|
||||
if (object == "features") {
|
||||
if (annex == "target.xml")
|
||||
return encode(buildTargetXML());
|
||||
return "E00";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -234,7 +334,7 @@ std::string GdbServer::handleQuery(std::string &packet) {
|
||||
auto match = [&](const char *str) -> bool { return packet.rfind(str, 0) == 0; };
|
||||
|
||||
if (match("qSupported")) {
|
||||
return "PacketSize=2000;qXfer:exec-file:read+";
|
||||
return "PacketSize=5000;xmlRegisters=i386;qXfer:exec-file:read+;qXfer:features:read+";
|
||||
}
|
||||
if (match("qAttached")) {
|
||||
return "1"; // We don't currently support launching executables from gdb.
|
||||
@@ -313,24 +413,6 @@ std::string GdbServer::handleV(std::string& packet) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string readRegs() {
|
||||
std::ostringstream ss;
|
||||
|
||||
// The gdb RDP protocol just squirts 27 registers, as 16 digit hex onto the wire.
|
||||
ss << std::setfill('0') << std::setw(16) << std::hex;
|
||||
|
||||
for (uint64_t i = 0; i < 70; i++) {
|
||||
// I don't know how the regs map... lets just ask
|
||||
uint64_t data = (i | 0x80dd000000cc0000 | i << 32 | i << 56);
|
||||
if (i == 16) { // RIP
|
||||
data = 0x47c990;
|
||||
}
|
||||
ss << std::setfill('0') << std::setw(16) << std::hex << __builtin_bswap64(data);
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
std::string GdbServer::ProcessPacket(std::string &packet) {
|
||||
switch (packet[0]) {
|
||||
case '?':
|
||||
@@ -360,7 +442,7 @@ void GdbServer::GdbServerLoop(std::unique_ptr<std::iostream> stream) {
|
||||
case '$': {
|
||||
std::string packet = ReadPacket(*stream);
|
||||
responce = ProcessPacket(packet);
|
||||
LogMan::Msg::E("%s", responce.c_str());
|
||||
std::cout << responce;
|
||||
SendPacket(*stream, responce);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ private:
|
||||
std::string handleMemory(std::string &packet);
|
||||
std::string handleV(std::string& packet);
|
||||
|
||||
std::string readRegs();
|
||||
|
||||
FEXCore::Context::Context *CTX;
|
||||
std::thread gdbServerThread;
|
||||
uint64_t data_offset;
|
||||
|
||||
@@ -35,4 +35,5 @@ namespace FEXCore::Core {
|
||||
constexpr uint64_t PAGE_SIZE = 4096;
|
||||
|
||||
std::string_view const& GetFlagName(unsigned Flag);
|
||||
std::string_view const& GetGRegName(unsigned Reg);
|
||||
}
|
||||
Reference in new issue
Block a user