GdbServer: Implement xml target for register order

We can now simply memcpy much of memory state.
This commit is contained in:
Scott Mansell authored and Stefanos Kornilios Mitsis Poiitidis committed 2020-03-06 07:56:01 +02:00
1 parent e44b3ca495
commit 545b542f9b
4 files changed
+128 -20

No files matched your search

+23
View File
@@ -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:
+102 -20
View File
@@ -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;
}
+2
View File
@@ -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;
+1
View File
@@ -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);
}