mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-07 17:00:19 +02:00
171 lines
5.6 KiB
C++
171 lines
5.6 KiB
C++
// SPDX-License-Identifier: MIT
|
|
/*
|
|
$info$
|
|
tags: glue|gdbserver
|
|
$end_info$
|
|
*/
|
|
#pragma once
|
|
|
|
#include <FEXCore/Config/Config.h>
|
|
#include <FEXCore/Core/SignalDelegator.h>
|
|
#include <FEXCore/Utils/Event.h>
|
|
#include <FEXCore/Utils/Threads.h>
|
|
#include <FEXCore/fextl/memory.h>
|
|
#include <FEXCore/fextl/string.h>
|
|
|
|
#include <Common/AsyncNet.h>
|
|
|
|
#include <atomic>
|
|
#include <mutex>
|
|
#include <stdint.h>
|
|
|
|
#include "LinuxSyscalls/SignalDelegator.h"
|
|
|
|
namespace FEX {
|
|
|
|
class GdbServer {
|
|
public:
|
|
GdbServer(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* SignalDelegation, FEX::HLE::SyscallHandler* const SyscallHandler);
|
|
~GdbServer();
|
|
|
|
// Public for threading
|
|
void GdbServerLoop();
|
|
|
|
void AlertLibrariesChanged() {
|
|
LibraryMapChanged = true;
|
|
}
|
|
|
|
private:
|
|
void Break(FEXCore::Core::InternalThreadState* Thread, int signal);
|
|
|
|
void OpenListenSocket();
|
|
void CloseListenSocket();
|
|
void StartThread();
|
|
fextl::string ReadPacket(const std::span<std::byte>& stream);
|
|
void SendPacket(fasio::tcp_socket&, const fextl::string& packet);
|
|
|
|
void SendACK(fasio::tcp_socket&, bool NACK);
|
|
|
|
Event ThreadBreakEvent {};
|
|
void WaitForThreadWakeup();
|
|
|
|
struct HandledPacketType {
|
|
fextl::string Response {};
|
|
enum ResponseType {
|
|
TYPE_NONE,
|
|
TYPE_UNKNOWN,
|
|
TYPE_ACK,
|
|
TYPE_NACK,
|
|
TYPE_ONLYACK,
|
|
TYPE_ONLYNACK,
|
|
};
|
|
ResponseType TypeResponse {};
|
|
};
|
|
|
|
void SendPacketPair(const HandledPacketType& packetPair);
|
|
HandledPacketType ProcessPacket(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);
|
|
|
|
HandledPacketType HandlevFile(const fextl::string& packet);
|
|
HandledPacketType HandlevCont(const fextl::string& packet);
|
|
|
|
// Command handlers
|
|
HandledPacketType CommandEnableExtendedMode(const fextl::string& packet);
|
|
HandledPacketType CommandQueryHalted(const fextl::string& packet);
|
|
HandledPacketType CommandContinue(const fextl::string& packet);
|
|
HandledPacketType CommandDetach(const fextl::string& packet);
|
|
HandledPacketType CommandReadRegisters(const fextl::string& packet);
|
|
HandledPacketType CommandThreadOp(const fextl::string& packet);
|
|
HandledPacketType CommandKill(const fextl::string& packet);
|
|
HandledPacketType CommandMemory(const fextl::string& packet);
|
|
HandledPacketType CommandReadReg(const fextl::string& packet);
|
|
HandledPacketType CommandQuery(const fextl::string& packet);
|
|
HandledPacketType CommandSingleStep(const fextl::string& packet);
|
|
HandledPacketType CommandQueryThreadAlive(const fextl::string& packet);
|
|
HandledPacketType CommandMultiLetterV(const fextl::string& packet);
|
|
HandledPacketType CommandBreakpoint(const fextl::string& packet);
|
|
HandledPacketType CommandUnknown(const fextl::string& packet);
|
|
|
|
/**
|
|
* @brief Returns the ThreadStateObject for the matching TID, or parent thread if TID isn't found
|
|
*
|
|
* @param TID Which TID to search for
|
|
*/
|
|
const FEX::HLE::ThreadStateObject* FindThreadByTID(uint32_t TID);
|
|
|
|
struct X80Float {
|
|
uint8_t Data[10];
|
|
};
|
|
|
|
struct FEX_PACKED GDBContextDefinition {
|
|
uint64_t gregs[FEXCore::Core::CPUState::NUM_GPRS];
|
|
uint64_t rip;
|
|
uint32_t eflags;
|
|
uint32_t cs, ss, ds, es, fs, gs;
|
|
X80Float mm[FEXCore::Core::CPUState::NUM_MMS];
|
|
uint32_t fctrl;
|
|
uint32_t fstat;
|
|
uint32_t dummies[6];
|
|
uint64_t xmm[FEXCore::Core::CPUState::NUM_XMMS][4];
|
|
uint32_t mxcsr;
|
|
};
|
|
|
|
GDBContextDefinition GenerateContextDefinition(const FEX::HLE::ThreadStateObject* ThreadObject);
|
|
|
|
FEXCore::Context::Context* CTX;
|
|
FEX::HLE::SyscallHandler* const SyscallHandler;
|
|
FEX::HLE::SignalDelegator* SignalDelegation;
|
|
fextl::unique_ptr<FEXCore::Threads::Thread> gdbServerThread;
|
|
fasio::poll_reactor Reactor;
|
|
std::optional<fasio::tcp_acceptor> Acceptor;
|
|
std::optional<fasio::tcp_socket> CommsSocket;
|
|
fextl::vector<std::byte> CommsBuffer;
|
|
|
|
std::pair<fextl::vector<std::byte>::iterator, bool> MatchPacket(fextl::vector<std::byte>::iterator begin, fextl::vector<std::byte>::iterator end);
|
|
void HandlePacket(fasio::error ec, size_t BytesInMessage);
|
|
|
|
std::mutex sendMutex;
|
|
bool SettingNoAckMode {false};
|
|
bool NoAckMode {false};
|
|
bool NonStopMode {false};
|
|
fextl::string ThreadString {};
|
|
fextl::string OSDataString {};
|
|
void buildLibraryMap();
|
|
std::atomic<bool> LibraryMapChanged = true;
|
|
fextl::string LibraryMapString {};
|
|
|
|
// Used to keep track of which signals to pass to the guest
|
|
std::array<bool, FEX::HLE::SignalDelegator::MAX_SIGNALS + 1> PassSignals {};
|
|
uint32_t CurrentDebuggingThread {};
|
|
fextl::string GdbUnixSocketPath {};
|
|
FEX_CONFIG_OPT(Filename, APP_FILENAME);
|
|
FEX_CONFIG_OPT(Is64BitMode, IS64BIT_MODE);
|
|
};
|
|
|
|
} // namespace FEX
|