diff --git a/Source/Interface/Core/Core.cpp b/Source/Interface/Core/Core.cpp index a22a62db6..0dccd11ed 100644 --- a/Source/Interface/Core/Core.cpp +++ b/Source/Interface/Core/Core.cpp @@ -65,6 +65,29 @@ std::string_view const& GetFlagName(unsigned Flag) { return FlagNames[Flag]; } +constexpr std::array 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: diff --git a/Source/Interface/Core/GdbServer.cpp b/Source/Interface/Core/GdbServer.cpp index 928233ba5..80a1ee05f 100644 --- a/Source/Interface/Core/GdbServer.cpp +++ b/Source/Interface/Core/GdbServer.cpp @@ -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 << "\n"; + xml << "\n";\ + xml << "\n"; + xml << "i386:x86-64\n"; + xml << "GNU/Linux\n"; + xml << "\n"; + + xml << "\n"; + // flags register + for(int i=0; i <= 32; i++) { + auto name = FEXCore::Core::GetFlagName(i); + xml << "\n"; + } + xml << ""; + + auto reg_numbered = [&](std::string_view name, int num, std::string_view type, int size) { + xml << "" << 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 << "\n"; + xml << "\n"; + xml << ""; + + // 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 << "\n"; + xml << "\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 stream) { case '$': { std::string packet = ReadPacket(*stream); responce = ProcessPacket(packet); - LogMan::Msg::E("%s", responce.c_str()); + std::cout << responce; SendPacket(*stream, responce); break; } diff --git a/Source/Interface/Core/GdbServer.h b/Source/Interface/Core/GdbServer.h index b0380e803..09915c349 100644 --- a/Source/Interface/Core/GdbServer.h +++ b/Source/Interface/Core/GdbServer.h @@ -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; diff --git a/include/FEXCore/Core/CoreState.h b/include/FEXCore/Core/CoreState.h index a9601b766..2d4c93f3e 100644 --- a/include/FEXCore/Core/CoreState.h +++ b/include/FEXCore/Core/CoreState.h @@ -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); }