GdbServer: Breakpoint intergation

This commit is contained in:
Scott Mansell authored and Stefanos Kornilios Mitsis Poiitidis committed 2020-03-06 07:56:01 +02:00
1 parent 9a89741ff2
commit 2babc1292c
8 files changed
+111 -45

No files matched your search

+5
View File
@@ -21,6 +21,9 @@ namespace FEXCore::Config {
case FEXCore::Config::CONFIG_SINGLESTEP:
CTX->RunningMode = Config != 0 ? FEXCore::Context::CoreRunningMode::MODE_SINGLESTEP : FEXCore::Context::CoreRunningMode::MODE_RUN;
break;
case FEXCore::Config::CONFIG_GDBSERVER:
Config != 0 ? CTX->StartGdbServer() : CTX->StopGdbServer();
break;
default: LogMan::Msg::A("Unknown configuration option");
}
}
@@ -41,6 +44,8 @@ namespace FEXCore::Config {
break;
case FEXCore::Config::CONFIG_SINGLESTEP:
return CTX->RunningMode == FEXCore::Context::CoreRunningMode::MODE_SINGLESTEP ? 1 : 0;
case FEXCore::Config::CONFIG_GDBSERVER:
return CTX->GetGdbServerStatus();
break;
default: LogMan::Msg::A("Unknown configuration option");
}
+10
View File
@@ -11,11 +11,13 @@
#include <FEXCore/Utils/Event.h>
#include <stdint.h>
#include <memory>
#include <mutex>
namespace FEXCore {
class SyscallHandler;
class BlockSamplingData;
class GdbServer;
namespace CPU {
class JITCore;
@@ -42,6 +44,7 @@ namespace FEXCore::Context {
int64_t MaxInstPerBlock {-1LL};
uint64_t VirtualMemSize {1ULL << 36};
FEXCore::Config::ConfigCore Core {FEXCore::Config::CONFIG_INTERPRETER};
bool GdbServer {false};
// LLVM JIT options
bool LLVM_MemoryValidation {false};
@@ -68,6 +71,8 @@ namespace FEXCore::Context {
CustomCPUFactoryType FallbackCPUFactory;
std::function<void(uint64_t ThreadId, FEXCore::Context::ExitReason)> CustomExitHandler;
#ifdef BLOCKSTATS
std::unique_ptr<FEXCore::BlockSamplingData> BlockData;
#endif
@@ -82,6 +87,10 @@ namespace FEXCore::Context {
void Run();
void Step();
bool GetGdbServerStatus() { return (bool)DebugServer; }
void StartGdbServer();
void StopGdbServer();
// Debugger interface
void CompileRIP(FEXCore::Core::InternalThreadState *Thread, uint64_t RIP);
uint64_t GetThreadCount() const;
@@ -128,6 +137,7 @@ namespace FEXCore::Context {
uint64_t StartingRIP;
IR::RegisterAllocationPass *RAPass {};
std::mutex ExitMutex;
std::unique_ptr<GdbServer> DebugServer;
bool StartPaused = false;
#if ENABLE_JITSYMBOLS
+11 -6
View File
@@ -284,17 +284,22 @@ namespace FEXCore::Context {
uint64_t SlotSize = Loader->InitializeThreadSlot(TLSSlotWriter);
Thread->State.State.rip = StartingRIP = Loader->DefaultRIP();
if (false) {
auto gdb = new GdbServer(this, Loader);
gdb->StartAndBlock();
StartPaused = true;
}
InitializeThread(Thread);
return true;
}
void Context::StartGdbServer() {
if (!DebugServer) {
DebugServer = std::make_unique<GdbServer>(this);
StartPaused = true;
}
}
void Context::StopGdbServer() {
DebugServer.reset();
}
void Context::WaitForIdle() {
do {
bool AllPaused = true;
+54 -19
View File
@@ -22,8 +22,22 @@
namespace FEXCore
{
GdbServer::GdbServer(FEXCore::Context::Context *ctx, FEXCore::CodeLoader *Loader) : CTX(ctx) {
std::tie(std::ignore, std::ignore, data_offset) = Loader->GetLayout();
static const std::string NO_REPLY = "}{\x7f}{"; // An "unlikely" packet
void GdbServer::Break() {
std::lock_guard lk(sendMutex);
if (CommsStream)
SendPacket(*CommsStream, "S05");
}
GdbServer::GdbServer(FEXCore::Context::Context *ctx) : CTX(ctx) {
ctx->CustomExitHandler = [&](uint64_t ThreadId, FEXCore::Context::ExitReason ExitReason) {
if (ExitReason == FEXCore::Context::ExitReason::EXIT_DEBUG) {
this->Break();
}
};
StartThread();
}
static int calculateChecksum(std::string &packet) {
@@ -100,7 +114,7 @@ std::string GdbServer::ReadPacket(std::iostream &stream) {
int expected_checksum = std::strtoul(hexString, nullptr, 16);
if (calculateChecksum(packet) == expected_checksum) {
LogMan::Msg::E("Received Packet: \"%s\"", packet.c_str());
LogMan::Msg::I("Received Packet: \"%s\"", packet.c_str());
stream << "+" << std::flush;
return packet;
} else {
@@ -141,8 +155,12 @@ static std::string escapePacket(std::string packet) {
}
void GdbServer::SendPacket(std::ostream &stream, std::string packet) {
// In-band signaling, not a great design
if (packet == NO_REPLY)
return;
auto escaped = escapePacket(packet);
LogMan::Msg::E("GdbServer Reply: %s", escaped.c_str());
//LogMan::Msg::E("GdbServer Reply: %s", escaped.c_str());
stream << '$' << escaped << '#';
stream << std::setfill('0') << std::setw(2) << std::hex << (int)calculateChecksum(escaped);
stream << std::flush;
@@ -150,7 +168,7 @@ void GdbServer::SendPacket(std::ostream &stream, std::string packet) {
std::string GdbServer::readRegs() {
auto state = CTX->GetCPUState();
state.rip = 0x47c990;
// state.rip = 0x47c990;
return encodeHex((unsigned char *)&state, sizeof(state)).substr(0, 572*2);
}
@@ -432,14 +450,14 @@ std::string GdbServer::handleV(std::string& packet) {
switch (action) {
case 'c':
CTX->Run();
return ""; // fixme
return NO_REPLY;
case 's':
CTX->Step();
return ""; // fixme
return NO_REPLY;
case 't':
CTX->ShouldStop = true;
return "";
return NO_REPLY;
default:
return "E00";
}
@@ -466,19 +484,26 @@ std::string GdbServer::ProcessPacket(std::string &packet) {
}
}
void GdbServer::GdbServerLoop(std::unique_ptr<std::iostream> stream) {
void GdbServer::GdbServerLoop() {
CommsStream = OpenSocket();
std::string responce;
// Outer server loop. Handles packet start, ACK/NAK and break
int c;
while ((c = stream->get()) >= 0 ) {
while ((c = CommsStream->get()) >= 0 ) {
switch (c) {
case '$': {
std::string packet = ReadPacket(*stream);
std::string packet = ReadPacket(*CommsStream);
responce = ProcessPacket(packet);
std::cout << responce;
SendPacket(*stream, responce);
{
std::lock_guard lk(sendMutex);
SendPacket(*CommsStream, responce);
}
if (responce == "") {
LogMan::Msg::D("Unknown packet %s", packet.c_str());
}
break;
}
case '+':
@@ -486,19 +511,29 @@ void GdbServer::GdbServerLoop(std::unique_ptr<std::iostream> stream) {
break;
case '-':
// NAK, Resend requested
SendPacket(*stream, responce);
{
std::lock_guard lk(sendMutex);
SendPacket(*CommsStream, responce);
}
break;
case '\x03': // ASCII EOT
LogMan::Msg::E("GdbServer: Break");
LogMan::Msg::D("GdbServer: Break");
CTX->Pause();
break;
default:
LogMan::Msg::E("GdbServer: Unexpected byte %c (%02x)", c, c);
LogMan::Msg::D("GdbServer: Unexpected byte %c (%02x)", c, c);
}
}
{
std::lock_guard lk(sendMutex);
CommsStream.release();
}
}
void GdbServer::StartThread(std::unique_ptr<std::iostream> stream) {
gdbServerThread = std::thread(&GdbServer::GdbServerLoop, this, std::move(stream));
void GdbServer::StartThread() {
gdbServerThread = std::thread(&GdbServer::GdbServerLoop, this);
}
std::unique_ptr<std::iostream> GdbServer::OpenSocket() {
@@ -535,7 +570,7 @@ std::unique_ptr<std::iostream> GdbServer::OpenSocket() {
// Block until a connection arrives
LogMan::Msg::E("GdbServer, waiting for connection");
LogMan::Msg::E("GdbServer, waiting for connection on localhost:8086");
listen(sockfd, 1);
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &addr_size);
+8 -11
View File
@@ -1,6 +1,6 @@
#include <mutex>
#include <thread>
#include <condition_variable>
#include "Interface/Context/Context.h"
@@ -10,16 +10,14 @@ namespace FEXCore {
class GdbServer {
public:
GdbServer(FEXCore::Context::Context *ctx, FEXCore::CodeLoader *Loader);
void StartAndBlock() { StartThread(OpenSocket()); Wait(); }
GdbServer(FEXCore::Context::Context *ctx);
private:
std::unique_ptr<std::iostream> OpenSocket();
void StartThread(std::unique_ptr<std::iostream> stream);
void GdbServerLoop(std::unique_ptr<std::iostream> stream);
void Wait() {
void Break();
}
std::unique_ptr<std::iostream> OpenSocket();
void StartThread();
void GdbServerLoop();
std::string ReadPacket(std::iostream &stream);
void SendPacket(std::ostream &stream, std::string packet);
@@ -34,9 +32,8 @@ private:
FEXCore::Context::Context *CTX;
std::thread gdbServerThread;
uint64_t data_offset;
std::condition_variable waiting;
std::unique_ptr<std::iostream> CommsStream;
std::mutex sendMutex;
};
}
+8 -1
View File
@@ -378,8 +378,14 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView<true> const
ud2();
break;
case 4: // HLT
case 6: // INT3
{
mov(al, 1);
xchg(byte [STATE + offsetof(FEXCore::Core::ThreadState, RunningEvents.ShouldStop)], al);
auto offset = Op->Reason == 4 ?
offsetof(FEXCore::Core::ThreadState, RunningEvents.ShouldStop) // HLT
: offsetof(FEXCore::Core::ThreadState, RunningEvents.ShouldPause); // INT3
xchg(byte [STATE + offset], al);
// This code matches what is in EXITFUNCTION
if (SpillSlots) {
@@ -398,6 +404,7 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView<true> const
#endif
ret();
break;
}
default: LogMan::Msg::A("Unknown Break reason: %d", Op->Reason);
}
break;
+14 -8
View File
@@ -3060,12 +3060,9 @@ void OpDispatchBuilder::ALUOp(OpcodeArgs) {
void OpDispatchBuilder::INTOp(OpcodeArgs) {
uint8_t Reason{};
uint8_t Literal{};
BlockSetRIP = true;
bool setRIP = false;
switch (Op->OP) {
case 0xCC:
Reason = 0;
break;
case 0xCD:
Reason = 1;
Literal = Op->Src1.TypeLiteral.Literal;
@@ -3078,15 +3075,24 @@ void OpDispatchBuilder::INTOp(OpcodeArgs) {
break;
case 0xF4: {
Reason = 4;
// We want to set RIP to the next instruction after HLT
auto NewRIP = _Constant(Op->PC + Op->InstSize);
_StoreContext(8, offsetof(FEXCore::Core::CPUState, rip), NewRIP);
setRIP = true;
break;
}
case 0x0B:
Reason = 5;
case 0xCC:
Reason = 6;
setRIP = true;
break;
break;
}
if (setRIP) {
BlockSetRIP = setRIP;
// We want to set RIP to the next instruction after HLT/INT3
auto NewRIP = _Constant(Op->PC + Op->InstSize);
_StoreContext(8, offsetof(FEXCore::Core::CPUState, rip), NewRIP);
}
if (Op->OP == 0xCE) { // Conditional to only break if Overflow == 1
+1
View File
@@ -10,6 +10,7 @@ namespace FEXCore::Config {
CONFIG_DEFAULTCORE,
CONFIG_VIRTUALMEMSIZE,
CONFIG_SINGLESTEP,
CONFIG_GDBSERVER,
};
enum ConfigCore {