Fixed single stepping, added support for vCont packets and ranged stepping (faster), initial work to support other breakpoint types

This commit is contained in:
Matt Phillips 2022-12-17 18:16:40 +00:00 committed by flyinghead
parent 0107435a73
commit 13f3c8281f
4 changed files with 112 additions and 25 deletions

View File

@ -85,11 +85,20 @@ public:
void step()
{
bool restoreBreakpoint = removeMatchpoint(0, Sh4cntx.pc, 2);
bool restoreBreakpoint = removeMatchpoint(Breakpoint::Type::BP_TYPE_SOFTWARE_BREAK, Sh4cntx.pc, 2);
u32 savedPc = Sh4cntx.pc;
emu.step();
if (restoreBreakpoint)
insertMatchpoint(0, savedPc, 2);
insertMatchpoint(Breakpoint::Type::BP_TYPE_SOFTWARE_BREAK, savedPc, 2);
}
void stepRange(u32 from, u32 to)
{
bool restoreBreakpoint = removeMatchpoint(Breakpoint::Type::BP_TYPE_SOFTWARE_BREAK, Sh4cntx.pc, 2);
u32 savedPc = Sh4cntx.pc;
emu.stepRange(from, to);
if (restoreBreakpoint)
insertMatchpoint(Breakpoint::Type::BP_TYPE_SOFTWARE_BREAK, savedPc, 2);
}
int readAllRegs(u32 **regs)
@ -200,10 +209,10 @@ public:
return false;
}
// TODO other matchpoint types
if (breakpoints.find(addr) != breakpoints.end())
if (breakpoints[type].find(addr) != breakpoints[type].end())
return true;
breakpoints[addr] = Breakpoint(type, addr);
breakpoints[addr].savedOp = ReadMem16_nommu(addr);
breakpoints[type][addr] = Breakpoint(type, addr);
breakpoints[type][addr].savedOp = ReadMem16_nommu(addr);
WriteMem16_nommu(addr, 0xC308); // trapa #0x20
return true;
}
@ -213,11 +222,11 @@ public:
WARN_LOG(COMMON, "removeMatchpoint: length != 2: %d", len);
return false;
}
auto it = breakpoints.find(addr);
if (it == breakpoints.end())
auto it = breakpoints[type].find(addr);
if (it == breakpoints[type].end())
return false;
WriteMem16_nommu(addr, it->second.savedOp);
breakpoints.erase(it);
breakpoints[type].erase(it);
return true;
}
@ -319,12 +328,22 @@ public:
u32 exception = 0;
struct Breakpoint {
enum Type
{
BP_TYPE_SOFTWARE_BREAK,
BP_TYPE_HARDWARE_BREAK,
BP_TYPE_WRITE_WATCHPOINT,
BP_TYPE_READ_WATCHPOINT,
BP_TYPE_ACCESS_WATCHPOINT,
BP_TYPE_COUNT
};
Breakpoint() = default;
Breakpoint(u16 type, u32 addr) : addr(addr), type(type) { }
u32 addr = 0;
u16 type = 0;
u16 savedOp = 0;
};
std::map<u32, Breakpoint> breakpoints;
std::map<u32, Breakpoint> breakpoints[Breakpoint::Type::BP_TYPE_COUNT];
std::vector<std::pair<u32, u32>> stack;
};

View File

@ -535,9 +535,13 @@ private:
sendPacket("");
}
else if (pkt.rfind("qSupported", 0) == 0)
{
// Tell the remote stub about features supported by GDB,
// and query the stub for features it supports
sendPacket("PacketSize=10000");
char qsupported[128];
sprintf_s(qsupported, 128, "PacketSize=%i;vContSupported+", MAX_PACKET_LEN);
sendPacket(qsupported);
}
else if (pkt.rfind("qSymbol:", 0) == 0)
// Notify the target that GDB is prepared to serve symbol lookup requests
sendPacket("OK");
@ -590,11 +594,41 @@ private:
if (pkt.rfind("vAttach;", 0) == 0)
sendPacket("S05");
else if (pkt.rfind("vCont?", 0) == 0)
// not supported
sendPacket("vCont;s;c");
// supported vCont actions - (c)ontinue, (C)ontinue with signal, (s)tep, (S)tep with signal, (r)ange-step
sendPacket("vCont;c;C;s;S;t;r");
else if (pkt.rfind("vCont", 0) == 0)
// not supported
WARN_LOG(COMMON, "vCont not supported %s", pkt.c_str());
{
std::string vContCmd = pkt.substr(strlen("vCont;"));
switch (vContCmd[0])
{
case 'c':
case 'C':
sendContinue(vContCmd);
break;
case 's':
step(EXCEPT_NONE);
break;
case 'S':
step();
case 'r':
{
u32 from, to;
if (sscanf(vContCmd.c_str(), "r%x,%x", &from, &to) == 2)
{
stepRange(from, to);
}
else
{
WARN_LOG(COMMON, "Unsupported vCont:r format %s", pkt.c_str());
sendContinue("c");
}
break;
}
default:
WARN_LOG(COMMON, "vCont action not supported %s", pkt[6], pkt.c_str());
}
}
else if (pkt.rfind("vFile:", 0) == 0)
// not supported
sendPacket("");
@ -637,6 +671,13 @@ private:
sendPacket("S05");
}
void stepRange(u32 from, u32 to)
{
sendPacket("OK");
agent.stepRange(from, to);
sendPacket("S05");
}
void insertMatchpoint(const std::string& pkt)
{
u32 type;
@ -647,22 +688,22 @@ private:
sendPacket("E01");
}
switch (type) {
case 0: // soft bp
case DebugAgent::Breakpoint::Type::BP_TYPE_SOFTWARE_BREAK: // soft bp
if (agent.insertMatchpoint(0, addr, len))
sendPacket("OK");
else
sendPacket("E01");
break;
case 1: // hardware bp
case DebugAgent::Breakpoint::Type::BP_TYPE_HARDWARE_BREAK: // hardware bp
sendPacket("");
break;
case 2: // write watchpoint
case DebugAgent::Breakpoint::Type::BP_TYPE_WRITE_WATCHPOINT: // write watchpoint
sendPacket("");
break;
case 3: // read watchpoint
case DebugAgent::Breakpoint::Type::BP_TYPE_READ_WATCHPOINT: // read watchpoint
sendPacket("");
break;
case 4: // access watchpoint
case DebugAgent::Breakpoint::Type::BP_TYPE_ACCESS_WATCHPOINT: // access watchpoint
sendPacket("");
break;
default:

View File

@ -587,8 +587,16 @@ void Emulator::runInternal()
{
if (singleStep)
{
singleStep = false;
sh4_cpu.Step();
singleStep = false;
}
else if(stepRangeTo != 0)
{
while (Sh4cntx.pc >= stepRangeFrom && Sh4cntx.pc <= stepRangeTo)
sh4_cpu.Step();
stepRangeFrom = 0;
stepRangeTo = 0;
}
else
{
@ -652,7 +660,8 @@ void Emulator::stop() {
rend_cancel_emu_wait();
try {
auto future = threadResult;
future.get();
if(future.valid())
future.get();
} catch (const FlycastException& e) {
WARN_LOG(COMMON, "%s", e.what());
}
@ -719,6 +728,14 @@ void Emulator::step()
stop();
}
void Emulator::stepRange(u32 from, u32 to)
{
stepRangeFrom = from;
stepRangeTo = to;
start();
stop();
}
void dc_loadstate(Deserializer& deser)
{
custom_texture.Terminate();
@ -826,7 +843,7 @@ void Emulator::start()
InitAudio();
try {
while (state == Running)
while (state == Running || singleStep || stepRangeTo != 0)
{
startTime = sh4_sched_now64();
renderTimeout = false;
@ -855,9 +872,13 @@ void Emulator::start()
bool Emulator::checkStatus()
{
try {
if (threadResult.wait_for(std::chrono::seconds(0)) == std::future_status::timeout)
return true;
threadResult.get();
if (threadResult.valid())
{
auto result = threadResult.wait_for(std::chrono::seconds(0));
if (result == std::future_status::timeout)
return true;
threadResult.get();
}
return false;
} catch (...) {
EventManager::event(Event::Pause);

View File

@ -130,6 +130,10 @@ public:
* Execute a single instruction.
*/
void step();
/**
* Execute instructions while PC is with range.
*/
void stepRange(u32 from, u32 to);
/**
* Return whether the emulator is currently running.
*/
@ -171,6 +175,8 @@ private:
bool singleStep = false;
u64 startTime = 0;
bool renderTimeout = false;
u32 stepRangeFrom = 0;
u32 stepRangeTo = 0;
};
extern Emulator emu;