GDBServer: Expand watchpoint ranges

Interpret Z2/Z3/Z4 kind values as byte lengths and represent each
watched byte with an owned CPU breakpoint. Validate MIPS
execute-breakpoint kinds, reject zero, overflowing, or excessively
large watch ranges, and avoid invasive changes to the CPU
memory-access dispatcher.
pull/3782/head
Stenzek 2 months ago
parent 71c88506ec
commit e3bea19784
No known key found for this signature in database

@ -19,6 +19,7 @@
#include "util/sockets.h"
#include <limits>
#include <optional>
#include <utility>
@ -31,6 +32,7 @@ static constexpr u8 GDB_SIGNAL_TRAP = 5;
static constexpr u32 MAX_PACKET_SIZE = 16384;
static constexpr u32 MAX_FRAMED_PACKET_SIZE = MAX_PACKET_SIZE + 4;
static constexpr u32 MAX_MEMORY_READ_SIZE = MAX_PACKET_SIZE / 2;
static constexpr u32 MAX_WATCHPOINT_LENGTH = 256;
namespace {
@ -509,6 +511,23 @@ bool GDBServer::Cmd$z(ClientSocket* client, std::string_view data)
}
const GDBBreakpointType type = static_cast<GDBBreakpointType>(bptype.value());
if (type == GDBBreakpointType::Software || type == GDBBreakpointType::Hardware)
{
if (bpkind.value() != sizeof(CPU::Instruction))
{
ERROR_LOG("Unsupported breakpoint kind {}", bpkind.value());
client->SendReplyWithAck("E01");
return true;
}
}
else if (bpkind.value() == 0 || bpkind.value() > MAX_WATCHPOINT_LENGTH ||
bpaddr.value() > (std::numeric_limits<VirtualMemoryAddress>::max() - (bpkind.value() - 1)))
{
ERROR_LOG("Invalid watchpoint length {} at 0x{:08X}", bpkind.value(), bpaddr.value());
client->SendReplyWithAck("E01");
return true;
}
if constexpr (add_breakpoint)
client->AddBreakpoint(type, bpaddr.value(), bpkind.value());
else
@ -681,16 +700,21 @@ void GDBServer::ClientSocket::AddBreakpoint(GDBBreakpointType type, VirtualMemor
break;
case GDBBreakpointType::Write:
acquire_breakpoint(CPU::BreakpointType::Write, address);
for (u32 offset = 0; offset < kind; offset++)
acquire_breakpoint(CPU::BreakpointType::Write, address + offset);
break;
case GDBBreakpointType::Read:
acquire_breakpoint(CPU::BreakpointType::Read, address);
for (u32 offset = 0; offset < kind; offset++)
acquire_breakpoint(CPU::BreakpointType::Read, address + offset);
break;
case GDBBreakpointType::Access:
acquire_breakpoint(CPU::BreakpointType::Read, address);
acquire_breakpoint(CPU::BreakpointType::Write, address);
for (u32 offset = 0; offset < kind; offset++)
{
acquire_breakpoint(CPU::BreakpointType::Read, address + offset);
acquire_breakpoint(CPU::BreakpointType::Write, address + offset);
}
break;
}
@ -725,16 +749,21 @@ void GDBServer::ClientSocket::RemoveBreakpoint(GDBBreakpointType type, VirtualMe
break;
case GDBBreakpointType::Write:
release_breakpoint(CPU::BreakpointType::Write, address);
for (u32 offset = 0; offset < kind; offset++)
release_breakpoint(CPU::BreakpointType::Write, address + offset);
break;
case GDBBreakpointType::Read:
release_breakpoint(CPU::BreakpointType::Read, address);
for (u32 offset = 0; offset < kind; offset++)
release_breakpoint(CPU::BreakpointType::Read, address + offset);
break;
case GDBBreakpointType::Access:
release_breakpoint(CPU::BreakpointType::Read, address);
release_breakpoint(CPU::BreakpointType::Write, address);
for (u32 offset = 0; offset < kind; offset++)
{
release_breakpoint(CPU::BreakpointType::Read, address + offset);
release_breakpoint(CPU::BreakpointType::Write, address + offset);
}
break;
}

Loading…
Cancel
Save