diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.cpp index 07032705f..e2e4dbfb5 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.cpp @@ -408,11 +408,100 @@ void GdbServer::buildLibraryMap() { LibraryMapChanged = false; } +// Binary data transfer handlers + +GdbServer::HandledPacketType GdbServer::XferCommandExecFile(const fextl::string& annex, int offset, int length) { + int annex_pid; + if (annex.empty()) { + annex_pid = getpid(); + } else { + auto ss_pid = fextl::istringstream(annex); + ss_pid >> std::hex >> annex_pid; + } + + if (annex_pid == getpid()) { + return {EncodeXferString(Filename(), offset, length), HandledPacketType::TYPE_ACK}; + } + + return {"E00", HandledPacketType::TYPE_ACK}; +} + +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 {"E00", HandledPacketType::TYPE_ACK}; +} + +GdbServer::HandledPacketType GdbServer::XferCommandThreads(const fextl::string& annex, int offset, int length) { + if (offset == 0) { + auto Threads = SyscallHandler->TM.GetThreads(); + + ThreadString.clear(); + fextl::ostringstream ss; + ss << "\n"; + for (auto& Thread : *Threads) { + // Thread id is in hex without 0x prefix + const auto ThreadName = GDB::Info::GetThreadName(::getpid(), Thread->ThreadInfo.TID); + ss << "ThreadInfo.TID << "\""; + if (!ThreadName.empty()) { + ss << " name=\"" << ThreadName << "\""; + } + ss << "/>\n"; + } + + ss << "\n"; + ss << std::flush; + ThreadString = ss.str(); + } + + return {EncodeXferString(ThreadString, offset, length), HandledPacketType::TYPE_ACK}; +} + +GdbServer::HandledPacketType GdbServer::XferCommandOSData(const fextl::string& annex, int offset, int length) { + if (offset == 0) { + OSDataString = GDB::Info::BuildOSXML(); + } + return {EncodeXferString(OSDataString, offset, length), HandledPacketType::TYPE_ACK}; +} + +GdbServer::HandledPacketType GdbServer::XferCommandLibraries(const fextl::string& annex, int offset, int length) { + if (offset == 0) { + // Attempt to rebuild when reading from zero + buildLibraryMap(); + } + return {EncodeXferString(LibraryMapString, offset, length), HandledPacketType::TYPE_ACK}; +} + +GdbServer::HandledPacketType GdbServer::XferCommandAuxv(const fextl::string& annex, int offset, int length) { + auto CodeLoader = SyscallHandler->GetCodeLoader(); + uint64_t auxv_ptr, auxv_size; + CodeLoader->GetAuxv(auxv_ptr, auxv_size); + fextl::string data; + if (Is64BitMode()) { + data.resize(auxv_size); + memcpy(data.data(), reinterpret_cast(auxv_ptr), data.size()); + } else { + // We need to transcode from 32-bit auxv_t to 64-bit + data.resize(auxv_size / sizeof(Elf32_auxv_t) * sizeof(Elf64_auxv_t)); + size_t NumAuxv = auxv_size / sizeof(Elf32_auxv_t); + for (size_t i = 0; i < NumAuxv; ++i) { + Elf32_auxv_t* auxv = reinterpret_cast(auxv_ptr + i * sizeof(Elf32_auxv_t)); + Elf64_auxv_t tmp; + tmp.a_type = auxv->a_type; + tmp.a_un.a_val = auxv->a_un.a_val; + memcpy(data.data() + i * sizeof(Elf64_auxv_t), &tmp, sizeof(Elf64_auxv_t)); + } + } + + return {EncodeXferString(data, offset, length), HandledPacketType::TYPE_ACK}; +} + GdbServer::HandledPacketType GdbServer::handleXfer(const fextl::string& packet) { fextl::string object; fextl::string rw; fextl::string annex; - int annex_pid; int offset; int length; @@ -426,12 +515,7 @@ GdbServer::HandledPacketType GdbServer::handleXfer(const fextl::string& packet) std::getline(ss, object, ':'); std::getline(ss, rw, ':'); std::getline(ss, annex, ':'); - if (annex == "") { - annex_pid = getpid(); - } else { - auto ss_pid = fextl::istringstream(annex); - ss_pid >> std::hex >> annex_pid; - } + ss >> std::hex >> offset; ss.get(expectComma); ss >> std::hex >> length; @@ -442,98 +526,42 @@ GdbServer::HandledPacketType GdbServer::handleXfer(const fextl::string& packet) } } - // Lambda to correctly encode any reply - auto encode = [&](fextl::string data) -> fextl::string { - if (offset == data.size()) { - return "l"; - } - if (offset >= data.size()) { - return "E34"; // ERANGE - } - if ((data.size() - offset) > length) { - return "m" + data.substr(offset, length); - } - return "l" + data.substr(offset); - }; + // Specific object documentation: https://sourceware.org/gdb/current/onlinedocs/gdb.html/General-Query-Packets.html#qXfer-read + if (object == "auxv") { + return XferCommandAuxv(annex, offset, length); + } + + // btrace + // btrace-conf if (object == "exec-file") { - if (annex_pid == getpid()) { - return {encode(Filename()), HandledPacketType::TYPE_ACK}; - } - - return {"E00", HandledPacketType::TYPE_ACK}; + return XferCommandExecFile(annex, offset, length); } if (object == "features") { - if (annex == "target.xml") { - return {encode(GDB::Info::BuildTargetXML()), HandledPacketType::TYPE_ACK}; - } - - return {"E00", HandledPacketType::TYPE_ACK}; - } - - if (object == "threads") { - if (offset == 0) { - auto Threads = SyscallHandler->TM.GetThreads(); - - ThreadString.clear(); - fextl::ostringstream ss; - ss << "\n"; - for (auto& Thread : *Threads) { - // Thread id is in hex without 0x prefix - const auto ThreadName = GDB::Info::GetThreadName(::getpid(), Thread->ThreadInfo.TID); - ss << "ThreadInfo.TID << "\""; - if (!ThreadName.empty()) { - ss << " name=\"" << ThreadName << "\""; - } - ss << "/>\n"; - } - - ss << "\n"; - ss << std::flush; - ThreadString = ss.str(); - } - - return {encode(ThreadString), HandledPacketType::TYPE_ACK}; - } - - if (object == "osdata") { - if (offset == 0) { - OSDataString = GDB::Info::BuildOSXML(); - } - return {encode(OSDataString), HandledPacketType::TYPE_ACK}; + return XferCommandFeatures(annex, offset, length); } if (object == "libraries") { - if (offset == 0) { - // Attempt to rebuild when reading from zero - buildLibraryMap(); - } - return {encode(LibraryMapString), HandledPacketType::TYPE_ACK}; + return XferCommandLibraries(annex, offset, length); } - if (object == "auxv") { - auto CodeLoader = SyscallHandler->GetCodeLoader(); - uint64_t auxv_ptr, auxv_size; - CodeLoader->GetAuxv(auxv_ptr, auxv_size); - fextl::string data; - if (Is64BitMode()) { - data.resize(auxv_size); - memcpy(data.data(), reinterpret_cast(auxv_ptr), data.size()); - } else { - // We need to transcode from 32-bit auxv_t to 64-bit - data.resize(auxv_size / sizeof(Elf32_auxv_t) * sizeof(Elf64_auxv_t)); - size_t NumAuxv = auxv_size / sizeof(Elf32_auxv_t); - for (size_t i = 0; i < NumAuxv; ++i) { - Elf32_auxv_t* auxv = reinterpret_cast(auxv_ptr + i * sizeof(Elf32_auxv_t)); - Elf64_auxv_t tmp; - tmp.a_type = auxv->a_type; - tmp.a_un.a_val = auxv->a_un.a_val; - memcpy(data.data() + i * sizeof(Elf64_auxv_t), &tmp, sizeof(Elf64_auxv_t)); - } - } + // libraries-svr4 + // memory-map + // sdata + // siginfo:read + // siginfo:write - return {encode(std::move(data)), HandledPacketType::TYPE_ACK}; + if (object == "threads") { + return XferCommandThreads(annex, offset, length); + } + + // traceframe-info + // uib + // fdpic + + if (object == "osdata") { + return XferCommandOSData(annex, offset, length); } return {"", HandledPacketType::TYPE_UNKNOWN}; diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.h index 7749e34cf..237f1f9a1 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.h @@ -70,11 +70,33 @@ private: void SendPacketPair(const HandledPacketType& packetPair); HandledPacketType ProcessPacket(const fextl::string& packet); - HandledPacketType handleXfer(const fextl::string& packet); HandledPacketType handleProgramOffsets(); HandledPacketType ThreadAction(char action, uint32_t tid); + // Binary data transfer handlers + // XFer function to correctly encode any reply + static fextl::string EncodeXferString(const fextl::string& data, int offset, int length) { + if (offset == data.size()) { + return "l"; + } + if (offset >= data.size()) { + return "E34"; // ERANGE + } + if ((data.size() - offset) > length) { + return "m" + data.substr(offset, length); + } + return "l" + data.substr(offset); + }; + + HandledPacketType XferCommandExecFile(const fextl::string& annex, int offset, int length); + HandledPacketType XferCommandFeatures(const fextl::string& annex, int offset, int length); + HandledPacketType XferCommandThreads(const fextl::string& annex, int offset, int length); + HandledPacketType XferCommandOSData(const fextl::string& annex, int offset, int length); + HandledPacketType XferCommandLibraries(const fextl::string& annex, int offset, int length); + HandledPacketType XferCommandAuxv(const fextl::string& annex, int offset, int length); + HandledPacketType handleXfer(const fextl::string& packet); + // Command handlers HandledPacketType CommandEnableExtendedMode(const fextl::string& packet); HandledPacketType CommandQueryHalted(const fextl::string& packet);