sim, arch, base: Refactor the base remote GDB class.

Fold the GDBListener class into the main BaseRemoteGDB class, move
around a bunch of functions, convert a lot of internal functions to
be private, move some functions into the .cc, make some functions
non-virtual which didn't really need to be overridden.

Change-Id: Id0832b730b0fdfb2eababa5067e72c66de1c147d
Reviewed-on: https://gem5-review.googlesource.com/7422
Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
Reviewed-by: Gabe Black <gabeblack@google.com>
Maintainer: Gabe Black <gabeblack@google.com>
This commit is contained in:
Gabe Black
2018-01-16 01:25:39 -08:00
parent 372adea687
commit ecec887507
18 changed files with 612 additions and 728 deletions

View File

@@ -144,9 +144,11 @@
using namespace std;
using namespace AlphaISA;
RemoteGDB::RemoteGDB(System *_system, ThreadContext *tc)
: BaseRemoteGDB(_system, tc)
RemoteGDB::RemoteGDB(System *_system, ThreadContext *tc, int _port)
: BaseRemoteGDB(_system, tc, _port)
{
warn_once("Breakpoints do not work in Alpha PAL mode.\n"
" See PCEventQueue::doService() in cpu/pc_event.cc.\n");
}
/*
@@ -165,7 +167,7 @@ RemoteGDB::acc(Addr va, size_t len)
do {
if (IsK0Seg(va)) {
if (va < (K0SegBase + system->memSize())) {
if (va < (K0SegBase + system()->memSize())) {
DPRINTF(GDBAcc, "acc: Mapping is valid K0SEG <= "
"%#x < K0SEG + size\n", va);
return true;
@@ -187,9 +189,9 @@ RemoteGDB::acc(Addr va, size_t len)
if (PcPAL(va) || va < 0x10000)
return true;
Addr ptbr = context->readMiscRegNoEffect(IPR_PALtemp20);
Addr ptbr = context()->readMiscRegNoEffect(IPR_PALtemp20);
PageTableEntry pte =
kernel_pte_lookup(context->getPhysProxy(), ptbr, va);
kernel_pte_lookup(context()->getPhysProxy(), ptbr, va);
if (!pte.valid()) {
DPRINTF(GDBAcc, "acc: %#x pte is invalid\n", va);
return false;
@@ -247,31 +249,10 @@ RemoteGDB::AlphaGdbRegCache::setRegs(ThreadContext *context) const
context->pcState(r.pc);
}
// Write bytes to kernel address space for debugger.
bool
RemoteGDB::write(Addr vaddr, size_t size, const char *data)
BaseGdbRegCache*
RemoteGDB::gdbRegs()
{
if (BaseRemoteGDB::write(vaddr, size, data)) {
#ifdef IMB
alpha_pal_imb();
#endif
return true;
} else {
return false;
}
}
void
RemoteGDB::insertHardBreak(Addr addr, size_t len)
{
warn_once("Breakpoints do not work in Alpha PAL mode.\n"
" See PCEventQueue::doService() in cpu/pc_event.cc.\n");
BaseRemoteGDB::insertHardBreak(addr, len);
}
RemoteGDB::BaseGdbRegCache*
RemoteGDB::gdbRegs() {
return new AlphaGdbRegCache(this);
return new AlphaGdbRegCache(this);
}

View File

@@ -51,9 +51,6 @@ class RemoteGDB : public BaseRemoteGDB
protected:
// Machine memory
bool acc(Addr addr, size_t len) override;
bool write(Addr addr, size_t size, const char *data) override;
void insertHardBreak(Addr addr, size_t len) override;
class AlphaGdbRegCache : public BaseGdbRegCache
{
@@ -70,11 +67,15 @@ class RemoteGDB : public BaseRemoteGDB
size_t size() const { return sizeof(r); }
void getRegs(ThreadContext*);
void setRegs(ThreadContext*) const;
const std::string name() const { return gdb->name() + ".AlphaGdbRegCache"; }
const std::string
name() const
{
return gdb->name() + ".AlphaGdbRegCache";
}
};
public:
RemoteGDB(System *system, ThreadContext *context);
RemoteGDB(System *system, ThreadContext *context, int _port);
BaseGdbRegCache *gdbRegs() override;
};

View File

@@ -164,8 +164,8 @@
using namespace std;
using namespace ArmISA;
RemoteGDB::RemoteGDB(System *_system, ThreadContext *tc)
: BaseRemoteGDB(_system, tc), regCache32(this), regCache64(this)
RemoteGDB::RemoteGDB(System *_system, ThreadContext *tc, int _port)
: BaseRemoteGDB(_system, tc, _port), regCache32(this), regCache64(this)
{
}
@@ -177,7 +177,7 @@ RemoteGDB::acc(Addr va, size_t len)
{
if (FullSystem) {
for (ChunkGenerator gen(va, len, PageBytes); !gen.done(); gen.next()) {
if (!virtvalid(context, gen.addr())) {
if (!virtvalid(context(), gen.addr())) {
DPRINTF(GDBAcc, "acc: %#x mapping is invalid\n", va);
return false;
}
@@ -189,7 +189,7 @@ RemoteGDB::acc(Addr va, size_t len)
TlbEntry entry;
//Check to make sure the first byte is mapped into the processes address
//space.
if (context->getProcessPtr()->pTable->lookup(va, entry))
if (context()->getProcessPtr()->pTable->lookup(va, entry))
return true;
return false;
}
@@ -301,10 +301,10 @@ RemoteGDB::AArch32GdbRegCache::setRegs(ThreadContext *context) const
context->setMiscRegNoEffect(MISCREG_CPSR, r.cpsr);
}
RemoteGDB::BaseGdbRegCache*
BaseGdbRegCache*
RemoteGDB::gdbRegs()
{
if (inAArch64(context))
if (inAArch64(context()))
return &regCache64;
else
return &regCache32;

View File

@@ -115,7 +115,7 @@ class RemoteGDB : public BaseRemoteGDB
AArch64GdbRegCache regCache64;
public:
RemoteGDB(System *_system, ThreadContext *tc);
RemoteGDB(System *_system, ThreadContext *tc, int _port);
BaseGdbRegCache *gdbRegs();
};
} // namespace ArmISA

View File

@@ -151,8 +151,8 @@
using namespace std;
using namespace MipsISA;
RemoteGDB::RemoteGDB(System *_system, ThreadContext *tc)
: BaseRemoteGDB(_system, tc), regCache(this)
RemoteGDB::RemoteGDB(System *_system, ThreadContext *tc, int _port)
: BaseRemoteGDB(_system, tc, _port), regCache(this)
{
}
@@ -168,7 +168,7 @@ RemoteGDB::acc(Addr va, size_t len)
if (FullSystem)
panic("acc not implemented for MIPS FS!");
else
return context->getProcessPtr()->pTable->lookup(va, entry);
return context()->getProcessPtr()->pTable->lookup(va, entry);
}
void
@@ -205,7 +205,8 @@ RemoteGDB::MipsGdbRegCache::setRegs(ThreadContext *context) const
context->setFloatRegBits(FLOATREG_FIR, r.fir);
}
RemoteGDB::BaseGdbRegCache*
RemoteGDB::gdbRegs() {
BaseGdbRegCache*
RemoteGDB::gdbRegs()
{
return &regCache;
}

View File

@@ -80,7 +80,7 @@ class RemoteGDB : public BaseRemoteGDB
MipsGdbRegCache regCache;
public:
RemoteGDB(System *_system, ThreadContext *tc);
RemoteGDB(System *_system, ThreadContext *tc, int _port);
BaseGdbRegCache *gdbRegs();
};

View File

@@ -151,8 +151,8 @@
using namespace std;
using namespace PowerISA;
RemoteGDB::RemoteGDB(System *_system, ThreadContext *tc)
: BaseRemoteGDB(_system, tc), regCache(this)
RemoteGDB::RemoteGDB(System *_system, ThreadContext *tc, int _port)
: BaseRemoteGDB(_system, tc, _port), regCache(this)
{
}
@@ -171,7 +171,7 @@ RemoteGDB::acc(Addr va, size_t len)
if (FullSystem)
panic("acc not implemented for POWER FS!");
else
return context->getProcessPtr()->pTable->lookup(va, entry);
return context()->getProcessPtr()->pTable->lookup(va, entry);
}
void
@@ -216,8 +216,9 @@ RemoteGDB::PowerGdbRegCache::setRegs(ThreadContext *context) const
context->setIntReg(INTREG_XER, betoh(r.xer));
}
RemoteGDB::BaseGdbRegCache*
RemoteGDB::gdbRegs() {
BaseGdbRegCache*
RemoteGDB::gdbRegs()
{
return &regCache;
}

View File

@@ -79,7 +79,7 @@ class RemoteGDB : public BaseRemoteGDB
PowerGdbRegCache regCache;
public:
RemoteGDB(System *_system, ThreadContext *tc);
RemoteGDB(System *_system, ThreadContext *tc, int _port);
BaseGdbRegCache *gdbRegs();
};

View File

@@ -148,8 +148,8 @@
using namespace std;
using namespace RiscvISA;
RemoteGDB::RemoteGDB(System *_system, ThreadContext *tc)
: BaseRemoteGDB(_system, tc), regCache(this)
RemoteGDB::RemoteGDB(System *_system, ThreadContext *tc, int _port)
: BaseRemoteGDB(_system, tc, _port), regCache(this)
{
}
@@ -160,7 +160,7 @@ RemoteGDB::acc(Addr va, size_t len)
if (FullSystem)
panic("acc not implemented for RISCV FS!");
else
return context->getProcessPtr()->pTable->lookup(va, entry);
return context()->getProcessPtr()->pTable->lookup(va, entry);
}
void
@@ -199,7 +199,8 @@ RemoteGDB::RiscvGdbRegCache::setRegs(ThreadContext *context) const
context->setMiscReg(i, r.csr[i - ExplicitCSRs]);
}
RemoteGDB::BaseGdbRegCache*
RemoteGDB::gdbRegs() {
BaseGdbRegCache*
RemoteGDB::gdbRegs()
{
return &regCache;
}

View File

@@ -85,7 +85,7 @@ class RemoteGDB : public BaseRemoteGDB
RiscvGdbRegCache regCache;
public:
RemoteGDB(System *_system, ThreadContext *tc);
RemoteGDB(System *_system, ThreadContext *tc, int _port);
BaseGdbRegCache *gdbRegs();
};

View File

@@ -147,8 +147,8 @@
using namespace std;
using namespace SparcISA;
RemoteGDB::RemoteGDB(System *_system, ThreadContext *c)
: BaseRemoteGDB(_system, c), regCache32(this), regCache64(this)
RemoteGDB::RemoteGDB(System *_system, ThreadContext *c, int _port)
: BaseRemoteGDB(_system, c, _port), regCache32(this), regCache64(this)
{}
///////////////////////////////////////////////////////////
@@ -170,7 +170,7 @@ RemoteGDB::acc(Addr va, size_t len)
TlbEntry entry;
// Check to make sure the first byte is mapped into the processes
// address space.
if (context->getProcessPtr()->pTable->lookup(va, entry))
if (context()->getProcessPtr()->pTable->lookup(va, entry))
return true;
return false;
}
@@ -244,10 +244,10 @@ RemoteGDB::SPARC64GdbRegCache::setRegs(ThreadContext *context) const
}
RemoteGDB::BaseGdbRegCache*
BaseGdbRegCache*
RemoteGDB::gdbRegs()
{
PSTATE pstate = context->readMiscReg(MISCREG_PSTATE);
PSTATE pstate = context()->readMiscReg(MISCREG_PSTATE);
if (pstate.am) {
return &regCache32;
} else {

View File

@@ -69,7 +69,11 @@ class RemoteGDB : public BaseRemoteGDB
size_t size() const { return sizeof(r); }
void getRegs(ThreadContext*);
void setRegs(ThreadContext*) const;
const std::string name() const { return gdb->name() + ".SPARCGdbRegCache"; }
const std::string
name() const
{
return gdb->name() + ".SPARCGdbRegCache";
}
};
class SPARC64GdbRegCache : public BaseGdbRegCache
@@ -91,14 +95,18 @@ class RemoteGDB : public BaseRemoteGDB
size_t size() const { return sizeof(r); }
void getRegs(ThreadContext*);
void setRegs(ThreadContext*) const;
const std::string name() const { return gdb->name() + ".SPARC64GdbRegCache"; }
const std::string
name() const
{
return gdb->name() + ".SPARC64GdbRegCache";
}
};
SPARCGdbRegCache regCache32;
SPARC64GdbRegCache regCache64;
public:
RemoteGDB(System *_system, ThreadContext *tc);
RemoteGDB(System *_system, ThreadContext *tc, int _port);
BaseGdbRegCache *gdbRegs();
};
} // namespace SparcISA

View File

@@ -64,8 +64,8 @@
using namespace std;
using namespace X86ISA;
RemoteGDB::RemoteGDB(System *_system, ThreadContext *c) :
BaseRemoteGDB(_system, c), regCache32(this), regCache64(this)
RemoteGDB::RemoteGDB(System *_system, ThreadContext *c, int _port) :
BaseRemoteGDB(_system, c, _port), regCache32(this), regCache64(this)
{}
bool
@@ -73,9 +73,9 @@ RemoteGDB::acc(Addr va, size_t len)
{
if (FullSystem) {
Walker *walker = dynamic_cast<TLB *>(
context->getDTBPtr())->getWalker();
context()->getDTBPtr())->getWalker();
unsigned logBytes;
Fault fault = walker->startFunctional(context, va, logBytes,
Fault fault = walker->startFunctional(context(), va, logBytes,
BaseTLB::Read);
if (fault != NoFault)
return false;
@@ -84,19 +84,19 @@ RemoteGDB::acc(Addr va, size_t len)
if ((va & ~mask(logBytes)) == (endVa & ~mask(logBytes)))
return true;
fault = walker->startFunctional(context, endVa, logBytes,
fault = walker->startFunctional(context(), endVa, logBytes,
BaseTLB::Read);
return fault == NoFault;
} else {
TlbEntry entry;
return context->getProcessPtr()->pTable->lookup(va, entry);
return context()->getProcessPtr()->pTable->lookup(va, entry);
}
}
RemoteGDB::BaseGdbRegCache*
BaseGdbRegCache*
RemoteGDB::gdbRegs()
{
HandyM5Reg m5reg = context->readMiscRegNoEffect(MISCREG_M5_REG);
HandyM5Reg m5reg = context()->readMiscRegNoEffect(MISCREG_M5_REG);
if (m5reg.submode == SixtyFourBitMode)
return &regCache64;
else

View File

@@ -143,7 +143,7 @@ class RemoteGDB : public BaseRemoteGDB
AMD64GdbRegCache regCache64;
public:
RemoteGDB(System *system, ThreadContext *context);
RemoteGDB(System *system, ThreadContext *context, int _port);
BaseGdbRegCache *gdbRegs();
};
} // namespace X86ISA

View File

@@ -154,179 +154,236 @@ static const char GDBBadP = '-';
static const int GDBPacketBufLen = 1024;
#ifndef NDEBUG
vector<BaseRemoteGDB *> debuggers;
void
debugger()
class HardBreakpoint : public PCEvent
{
static int current_debugger = -1;
if (current_debugger >= 0 && current_debugger < (int)debuggers.size()) {
BaseRemoteGDB *gdb = debuggers[current_debugger];
if (!gdb->isattached())
gdb->listener->accept();
if (gdb->isattached())
gdb->trap(SIGILL);
private:
BaseRemoteGDB *gdb;
public:
int refcount;
public:
HardBreakpoint(BaseRemoteGDB *_gdb, PCEventQueue *q, Addr pc)
: PCEvent(q, "HardBreakpoint Event", pc),
gdb(_gdb), refcount(0)
{
DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc);
}
const std::string name() const { return gdb->name() + ".hwbkpt"; }
void
process(ThreadContext *tc) override
{
DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc());
if (tc == gdb->tc)
gdb->trap(SIGTRAP);
}
};
namespace {
// Exception to throw when the connection to the client is broken.
struct BadClient
{
const char *warning;
BadClient(const char *_warning=NULL) : warning(_warning)
{}
};
// Exception to throw when an error needs to be reported to the client.
struct CmdError
{
string error;
CmdError(std::string _error) : error(_error)
{}
};
// Exception to throw when something isn't supported.
class Unsupported {};
// Convert a hex digit into an integer.
// This returns -1 if the argument passed is no valid hex digit.
int
digit2i(char c)
{
if (c >= '0' && c <= '9')
return (c - '0');
else if (c >= 'a' && c <= 'f')
return (c - 'a' + 10);
else if (c >= 'A' && c <= 'F')
return (c - 'A' + 10);
else
return (-1);
}
// Convert the low 4 bits of an integer into an hex digit.
char
i2digit(int n)
{
return ("0123456789abcdef"[n & 0x0f]);
}
// Convert a byte array into an hex string.
void
mem2hex(char *vdst, const char *vsrc, int len)
{
char *dst = vdst;
const char *src = vsrc;
while (len--) {
*dst++ = i2digit(*src >> 4);
*dst++ = i2digit(*src++);
}
*dst = '\0';
}
// Convert an hex string into a byte array.
// This returns a pointer to the character following the last valid
// hex digit. If the string ends in the middle of a byte, NULL is
// returned.
const char *
hex2mem(char *vdst, const char *src, int maxlen)
{
char *dst = vdst;
int msb, lsb;
while (*src && maxlen--) {
msb = digit2i(*src++);
if (msb < 0)
return (src - 1);
lsb = digit2i(*src++);
if (lsb < 0)
return (NULL);
*dst++ = (msb << 4) | lsb;
}
return src;
}
// Convert an hex string into an integer.
// This returns a pointer to the character following the last valid
// hex digit.
Addr
hex2i(const char **srcp)
{
const char *src = *srcp;
Addr r = 0;
int nibble;
while ((nibble = digit2i(*src)) >= 0) {
r *= 16;
r += nibble;
src++;
}
*srcp = src;
return r;
}
enum GdbBreakpointType {
GdbSoftBp = '0',
GdbHardBp = '1',
GdbWriteWp = '2',
GdbReadWp = '3',
GdbAccWp = '4',
};
const char *
break_type(char c)
{
switch(c) {
case GdbSoftBp: return "software breakpoint";
case GdbHardBp: return "hardware breakpoint";
case GdbWriteWp: return "write watchpoint";
case GdbReadWp: return "read watchpoint";
case GdbAccWp: return "access watchpoint";
default: return "unknown breakpoint/watchpoint";
}
}
#endif
///////////////////////////////////////////////////////////
//
//
//
std::map<Addr, HardBreakpoint *> hardBreakMap;
GDBListener::InputEvent::InputEvent(GDBListener *l, int fd, int e)
: PollEvent(fd, e), listener(l)
{}
void
GDBListener::InputEvent::process(int revent)
EventQueue *
getComInstEventQueue(ThreadContext *tc)
{
listener->accept();
return tc->getCpuPtr()->comInstEventQueue[tc->threadId()];
}
GDBListener::GDBListener(BaseRemoteGDB *g, int p)
: inputEvent(NULL), gdb(g), port(p)
{
assert(!gdb->listener);
gdb->listener = this;
}
GDBListener::~GDBListener()
BaseRemoteGDB::BaseRemoteGDB(System *_system, ThreadContext *c, int _port) :
connectEvent(nullptr), dataEvent(nullptr), _port(_port), fd(-1),
active(false), attached(false), sys(_system), tc(c),
trapEvent(this), singleStepEvent(*this)
{
delete inputEvent;
debuggers.push_back(this);
}
BaseRemoteGDB::~BaseRemoteGDB()
{
delete connectEvent;
delete dataEvent;
}
string
GDBListener::name()
BaseRemoteGDB::name()
{
return gdb->name() + ".listener";
return sys->name() + ".remote_gdb";
}
void
GDBListener::listen()
BaseRemoteGDB::listen()
{
if (ListenSocket::allDisabled()) {
warn_once("Sockets disabled, not accepting gdb connections");
return;
}
while (!listener.listen(port, true)) {
DPRINTF(GDBMisc, "Can't bind port %d\n", port);
port++;
while (!listener.listen(_port, true)) {
DPRINTF(GDBMisc, "Can't bind port %d\n", _port);
_port++;
}
inputEvent = new InputEvent(this, listener.getfd(), POLLIN);
pollQueue.schedule(inputEvent);
connectEvent = new ConnectEvent(this, listener.getfd(), POLLIN);
pollQueue.schedule(connectEvent);
#ifndef NDEBUG
gdb->number = debuggers.size();
debuggers.push_back(gdb);
#endif
#ifndef NDEBUG
ccprintf(cerr, "%d: %s: listening for remote gdb #%d on port %d\n",
curTick(), name(), gdb->number, port);
#else
ccprintf(cerr, "%d: %s: listening for remote gdb on port %d\n",
curTick(), name(), port);
#endif
curTick(), name(), _port);
}
void
GDBListener::accept()
BaseRemoteGDB::connect()
{
if (!listener.islistening())
panic("GDBListener::accept(): cannot accept if we're not listening!");
panic_if(!listener.islistening(),
"Cannot accept GDB connections if we're not listening!");
int sfd = listener.accept(true);
if (sfd != -1) {
if (gdb->isattached())
if (isAttached())
close(sfd);
else
gdb->attach(sfd);
attach(sfd);
}
}
int
GDBListener::getPort() const
BaseRemoteGDB::port() const
{
panic_if(!listener.islistening(),
"Remote GDB port is unknown until GDBListener::listen() has "
"been called.\n");
return port;
"Remote GDB port is unknown until listen() has been called.\n");
return _port;
}
BaseRemoteGDB::InputEvent::InputEvent(BaseRemoteGDB *g, int fd, int e)
: PollEvent(fd, e), gdb(g)
{}
void
BaseRemoteGDB::InputEvent::process(int revent)
{
if (gdb->trapEvent.scheduled()) {
warn("GDB trap event has already been scheduled! "
"Ignoring this input event.");
return;
}
if (revent & POLLIN) {
gdb->trapEvent.type(SIGILL);
gdb->scheduleInstCommitEvent(&gdb->trapEvent, 0);
} else if (revent & POLLNVAL) {
gdb->descheduleInstCommitEvent(&gdb->trapEvent);
gdb->detach();
}
}
void
BaseRemoteGDB::TrapEvent::process()
{
gdb->trap(_type);
}
void
BaseRemoteGDB::processSingleStepEvent()
{
if (!singleStepEvent.scheduled())
scheduleInstCommitEvent(&singleStepEvent, 1);
trap(SIGTRAP);
}
BaseRemoteGDB::BaseRemoteGDB(System *_system, ThreadContext *c) :
inputEvent(NULL), trapEvent(this), listener(NULL), number(-1),
fd(-1), active(false), attached(false), system(_system),
context(c),
singleStepEvent([this]{ processSingleStepEvent(); }, name())
{
}
BaseRemoteGDB::~BaseRemoteGDB()
{
if (inputEvent)
delete inputEvent;
}
string
BaseRemoteGDB::name()
{
return system->name() + ".remote_gdb";
}
bool
BaseRemoteGDB::isattached()
{ return attached; }
void
BaseRemoteGDB::attach(int f)
{
fd = f;
inputEvent = new InputEvent(this, fd, POLLIN);
pollQueue.schedule(inputEvent);
dataEvent = new DataEvent(this, fd, POLLIN);
pollQueue.schedule(dataEvent);
attached = true;
DPRINTFN("remote gdb attached\n");
@@ -341,13 +398,106 @@ BaseRemoteGDB::detach()
close(fd);
fd = -1;
pollQueue.remove(inputEvent);
pollQueue.remove(dataEvent);
DPRINTFN("remote gdb detached\n");
}
/////////////////////////
//
//
// This function does all command processing for interfacing to a
// remote gdb. Note that the error codes are ignored by gdb at
// present, but might eventually become meaningful. (XXX) It might
// makes sense to use POSIX errno values, because that is what the
// gdb/remote.c functions want to return.
bool
BaseRemoteGDB::trap(int type)
{
if (!attached)
return false;
DPRINTF(GDBMisc, "trap: PC=%s\n", tc->pcState());
clearSingleStep();
/*
* The first entry to this function is normally through
* a breakpoint trap in kgdb_connect(), in which case we
* must advance past the breakpoint because gdb will not.
*
* On the first entry here, we expect that gdb is not yet
* listening to us, so just enter the interaction loop.
* After the debugger is "active" (connected) it will be
* waiting for a "signaled" message from us.
*/
if (!active) {
active = true;
} else {
// Tell remote host that an exception has occurred.
send(csprintf("S%02x", type).c_str());
}
// Stick frame regs into our reg cache.
regCachePtr = gdbRegs();
regCachePtr->getRegs(tc);
char data[GDBPacketBufLen + 1];
GdbCommand::Context cmdCtx;
cmdCtx.type = type;
cmdCtx.data = &data[1];
for (;;) {
try {
size_t datalen = recv(data, sizeof(data));
if (datalen < 1)
throw BadClient();
data[datalen] = 0; // Sentinel
cmdCtx.cmd_byte = data[0];
cmdCtx.len = datalen - 1;
auto cmdIt = command_map.find(cmdCtx.cmd_byte);
if (cmdIt == command_map.end()) {
DPRINTF(GDBMisc, "Unknown command: %c(%#x)\n",
cmdCtx.cmd_byte, cmdCtx.cmd_byte);
throw Unsupported();
}
cmdCtx.cmd = &(cmdIt->second);
if (!(this->*(cmdCtx.cmd->func))(cmdCtx))
break;
} catch (BadClient &e) {
if (e.warning)
warn(e.warning);
detach();
break;
} catch (Unsupported &e) {
send("");
} catch (CmdError &e) {
send(e.error.c_str());
} catch (...) {
panic("Unrecognzied GDB exception.");
}
}
return true;
}
void
BaseRemoteGDB::incomingData(int revent)
{
if (trapEvent.scheduled()) {
warn("GDB trap event has already been scheduled!");
return;
}
if (revent & POLLIN) {
trapEvent.type(SIGILL);
scheduleInstCommitEvent(&trapEvent, 0);
} else if (revent & POLLNVAL) {
descheduleInstCommitEvent(&trapEvent);
detach();
}
}
uint8_t
BaseRemoteGDB::getbyte()
@@ -368,35 +518,6 @@ BaseRemoteGDB::putbyte(uint8_t b)
throw BadClient("Couldn't write data to the debugger.");
}
// Send a packet to gdb
void
BaseRemoteGDB::send(const char *bp)
{
const char *p;
uint8_t csum, c;
DPRINTF(GDBSend, "send: %s\n", bp);
do {
p = bp;
// Start sending a packet
putbyte(GDBStart);
// Send the contents, and also keep a check sum.
for (csum = 0; (c = *p); p++) {
putbyte(c);
csum += c;
}
// Send the ending character.
putbyte(GDBEnd);
// Send the checksum.
putbyte(i2digit(csum >> 4));
putbyte(i2digit(csum));
// Try transmitting over and over again until the other end doesn't
// send an error back.
c = getbyte();
} while ((c & 0x7f) == GDBBadP);
}
// Receive a packet from gdb
int
BaseRemoteGDB::recv(char *bp, int maxlen)
@@ -460,6 +581,35 @@ BaseRemoteGDB::recv(char *bp, int maxlen)
return len;
}
// Send a packet to gdb
void
BaseRemoteGDB::send(const char *bp)
{
const char *p;
uint8_t csum, c;
DPRINTF(GDBSend, "send: %s\n", bp);
do {
p = bp;
// Start sending a packet
putbyte(GDBStart);
// Send the contents, and also keep a check sum.
for (csum = 0; (c = *p); p++) {
putbyte(c);
csum += c;
}
// Send the ending character.
putbyte(GDBEnd);
// Send the checksum.
putbyte(i2digit(csum >> 4));
putbyte(i2digit(csum));
// Try transmitting over and over again until the other end doesn't
// send an error back.
c = getbyte();
} while ((c & 0x7f) == GDBBadP);
}
// Read bytes from kernel address space for debugger.
bool
BaseRemoteGDB::read(Addr vaddr, size_t size, char *data)
@@ -475,10 +625,10 @@ BaseRemoteGDB::read(Addr vaddr, size_t size, char *data)
DPRINTF(GDBRead, "read: addr=%#x, size=%d", vaddr, size);
if (FullSystem) {
FSTranslatingPortProxy &proxy = context->getVirtProxy();
FSTranslatingPortProxy &proxy = tc->getVirtProxy();
proxy.readBlob(vaddr, (uint8_t*)data, size);
} else {
SETranslatingPortProxy &proxy = context->getMemProxy();
SETranslatingPortProxy &proxy = tc->getMemProxy();
proxy.readBlob(vaddr, (uint8_t*)data, size);
}
@@ -518,16 +668,24 @@ BaseRemoteGDB::write(Addr vaddr, size_t size, const char *data)
DPRINTFNR("\n");
}
if (FullSystem) {
FSTranslatingPortProxy &proxy = context->getVirtProxy();
FSTranslatingPortProxy &proxy = tc->getVirtProxy();
proxy.writeBlob(vaddr, (uint8_t*)data, size);
} else {
SETranslatingPortProxy &proxy = context->getMemProxy();
SETranslatingPortProxy &proxy = tc->getMemProxy();
proxy.writeBlob(vaddr, (uint8_t*)data, size);
}
return true;
}
void
BaseRemoteGDB::singleStep()
{
if (!singleStepEvent.scheduled())
scheduleInstCommitEvent(&singleStepEvent, 1);
trap(SIGTRAP);
}
void
BaseRemoteGDB::clearSingleStep()
{
@@ -541,56 +699,6 @@ BaseRemoteGDB::setSingleStep()
scheduleInstCommitEvent(&singleStepEvent, 1);
}
PCEventQueue *BaseRemoteGDB::getPcEventQueue()
{
return &system->pcEventQueue;
}
EventQueue *
BaseRemoteGDB::getComInstEventQueue()
{
BaseCPU *cpu = context->getCpuPtr();
return cpu->comInstEventQueue[context->threadId()];
}
void
BaseRemoteGDB::scheduleInstCommitEvent(Event *ev, int delta)
{
EventQueue *eq = getComInstEventQueue();
// Here "ticks" aren't simulator ticks which measure time, they're
// instructions committed by the CPU.
eq->schedule(ev, eq->getCurTick() + delta);
}
void
BaseRemoteGDB::descheduleInstCommitEvent(Event *ev)
{
if (ev->scheduled())
getComInstEventQueue()->deschedule(ev);
}
bool
BaseRemoteGDB::checkBpLen(size_t len)
{
return len == sizeof(MachInst);
}
BaseRemoteGDB::HardBreakpoint::HardBreakpoint(BaseRemoteGDB *_gdb, Addr pc)
: PCEvent(_gdb->getPcEventQueue(), "HardBreakpoint Event", pc),
gdb(_gdb), refcount(0)
{
DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc);
}
void
BaseRemoteGDB::HardBreakpoint::process(ThreadContext *tc)
{
DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc());
if (tc == gdb->context)
gdb->trap(SIGTRAP);
}
void
BaseRemoteGDB::insertSoftBreak(Addr addr, size_t len)
{
@@ -619,7 +727,7 @@ BaseRemoteGDB::insertHardBreak(Addr addr, size_t len)
HardBreakpoint *&bkpt = hardBreakMap[addr];
if (bkpt == 0)
bkpt = new HardBreakpoint(this, addr);
bkpt = new HardBreakpoint(this, &sys->pcEventQueue, addr);
bkpt->refcount++;
}
@@ -632,7 +740,7 @@ BaseRemoteGDB::removeHardBreak(Addr addr, size_t len)
DPRINTF(GDBMisc, "Removing hardware breakpoint at %#x\n", addr);
break_iter_t i = hardBreakMap.find(addr);
auto i = hardBreakMap.find(addr);
if (i == hardBreakMap.end())
throw CmdError("E0C");
@@ -643,13 +751,6 @@ BaseRemoteGDB::removeHardBreak(Addr addr, size_t len)
}
}
void
BaseRemoteGDB::setTempBreakpoint(Addr bkpt)
{
DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", bkpt);
insertHardBreak(bkpt, sizeof(TheISA::MachInst));
}
void
BaseRemoteGDB::clearTempBreakpoint(Addr &bkpt)
{
@@ -658,28 +759,30 @@ BaseRemoteGDB::clearTempBreakpoint(Addr &bkpt)
bkpt = 0;
}
enum GdbBreakpointType {
GdbSoftBp = '0',
GdbHardBp = '1',
GdbWriteWp = '2',
GdbReadWp = '3',
GdbAccWp = '4',
};
const char *
BaseRemoteGDB::break_type(char c)
void
BaseRemoteGDB::setTempBreakpoint(Addr bkpt)
{
switch(c) {
case GdbSoftBp: return "software breakpoint";
case GdbHardBp: return "hardware breakpoint";
case GdbWriteWp: return "write watchpoint";
case GdbReadWp: return "read watchpoint";
case GdbAccWp: return "access watchpoint";
default: return "unknown breakpoint/watchpoint";
}
DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", bkpt);
insertHardBreak(bkpt, sizeof(TheISA::MachInst));
}
std::map<char, GdbCommand> BaseRemoteGDB::command_map = {
void
BaseRemoteGDB::scheduleInstCommitEvent(Event *ev, int delta)
{
EventQueue *eq = getComInstEventQueue(tc);
// Here "ticks" aren't simulator ticks which measure time, they're
// instructions committed by the CPU.
eq->schedule(ev, eq->getCurTick() + delta);
}
void
BaseRemoteGDB::descheduleInstCommitEvent(Event *ev)
{
if (ev->scheduled())
getComInstEventQueue(tc)->deschedule(ev);
}
std::map<char, BaseRemoteGDB::GdbCommand> BaseRemoteGDB::command_map = {
// last signal
{ '?', { "KGDB_SIGNAL", &BaseRemoteGDB::cmd_signal } },
// set baud (deprecated)
@@ -736,6 +839,11 @@ std::map<char, GdbCommand> BaseRemoteGDB::command_map = {
{ 'Z', { "KGDB_SET_HW_BKPT", &BaseRemoteGDB::cmd_set_hw_bkpt } },
};
bool
BaseRemoteGDB::checkBpLen(size_t len)
{
return len == sizeof(MachInst);
}
bool
BaseRemoteGDB::cmd_unsupported(GdbCommand::Context &ctx)
@@ -759,7 +867,7 @@ BaseRemoteGDB::cmd_cont(GdbCommand::Context &ctx)
const char *p = ctx.data;
if (ctx.len) {
Addr newPc = hex2i(&p);
context->pcState(newPc);
tc->pcState(newPc);
}
clearSingleStep();
return false;
@@ -772,7 +880,7 @@ BaseRemoteGDB::cmd_async_cont(GdbCommand::Context &ctx)
hex2i(&p);
if (*p++ == ';') {
Addr newPc = hex2i(&p);
context->pcState(newPc);
tc->pcState(newPc);
}
clearSingleStep();
return false;
@@ -803,7 +911,7 @@ BaseRemoteGDB::cmd_reg_w(GdbCommand::Context &ctx)
if (p == NULL || *p != '\0')
throw CmdError("E01");
regCachePtr->setRegs(context);
regCachePtr->setRegs(tc);
send("OK");
return true;
@@ -883,7 +991,7 @@ BaseRemoteGDB::cmd_async_step(GdbCommand::Context &ctx)
hex2i(&p); // Ignore the subcommand byte.
if (*p++ == ';') {
Addr newPc = hex2i(&p);
context->pcState(newPc);
tc->pcState(newPc);
}
setSingleStep();
return false;
@@ -895,7 +1003,7 @@ BaseRemoteGDB::cmd_step(GdbCommand::Context &ctx)
if (ctx.len) {
const char *p = ctx.data;
Addr newPc = hex2i(&p);
context->pcState(newPc);
tc->pcState(newPc);
}
setSingleStep();
return false;
@@ -966,161 +1074,3 @@ BaseRemoteGDB::cmd_set_hw_bkpt(GdbCommand::Context &ctx)
return true;
}
// This function does all command processing for interfacing to a
// remote gdb. Note that the error codes are ignored by gdb at
// present, but might eventually become meaningful. (XXX) It might
// makes sense to use POSIX errno values, because that is what the
// gdb/remote.c functions want to return.
bool
BaseRemoteGDB::trap(int type)
{
if (!attached)
return false;
DPRINTF(GDBMisc, "trap: PC=%s\n", context->pcState());
clearSingleStep();
/*
* The first entry to this function is normally through
* a breakpoint trap in kgdb_connect(), in which case we
* must advance past the breakpoint because gdb will not.
*
* On the first entry here, we expect that gdb is not yet
* listening to us, so just enter the interaction loop.
* After the debugger is "active" (connected) it will be
* waiting for a "signaled" message from us.
*/
if (!active) {
active = true;
} else {
// Tell remote host that an exception has occurred.
send(csprintf("S%02x", type).c_str());
}
// Stick frame regs into our reg cache.
regCachePtr = gdbRegs();
regCachePtr->getRegs(context);
char data[GDBPacketBufLen + 1];
GdbCommand::Context cmdCtx;
cmdCtx.type = type;
cmdCtx.data = &data[1];
for (;;) {
try {
size_t datalen = recv(data, sizeof(data));
if (datalen < 1)
throw BadClient();
data[datalen] = 0; // Sentinel
cmdCtx.cmd_byte = data[0];
cmdCtx.len = datalen - 1;
auto cmdIt = command_map.find(cmdCtx.cmd_byte);
if (cmdIt == command_map.end()) {
DPRINTF(GDBMisc, "Unknown command: %c(%#x)\n",
cmdCtx.cmd_byte, cmdCtx.cmd_byte);
throw Unsupported();
}
cmdCtx.cmd = &(cmdIt->second);
if (!(this->*(cmdCtx.cmd->func))(cmdCtx))
break;
} catch (BadClient &e) {
if (e.warning)
warn(e.warning);
detach();
break;
} catch (Unsupported &e) {
send("");
} catch (CmdError &e) {
send(e.error.c_str());
} catch (...) {
panic("Unrecognzied GDB exception.");
}
}
return true;
}
// Convert a hex digit into an integer.
// This returns -1 if the argument passed is no valid hex digit.
int
BaseRemoteGDB::digit2i(char c)
{
if (c >= '0' && c <= '9')
return (c - '0');
else if (c >= 'a' && c <= 'f')
return (c - 'a' + 10);
else if (c >= 'A' && c <= 'F')
return (c - 'A' + 10);
else
return (-1);
}
// Convert the low 4 bits of an integer into an hex digit.
char
BaseRemoteGDB::i2digit(int n)
{
return ("0123456789abcdef"[n & 0x0f]);
}
// Convert a byte array into an hex string.
void
BaseRemoteGDB::mem2hex(char *vdst, const char *vsrc, int len)
{
char *dst = vdst;
const char *src = vsrc;
while (len--) {
*dst++ = i2digit(*src >> 4);
*dst++ = i2digit(*src++);
}
*dst = '\0';
}
// Convert an hex string into a byte array.
// This returns a pointer to the character following the last valid
// hex digit. If the string ends in the middle of a byte, NULL is
// returned.
const char *
BaseRemoteGDB::hex2mem(char *vdst, const char *src, int maxlen)
{
char *dst = vdst;
int msb, lsb;
while (*src && maxlen--) {
msb = digit2i(*src++);
if (msb < 0)
return (src - 1);
lsb = digit2i(*src++);
if (lsb < 0)
return (NULL);
*dst++ = (msb << 4) | lsb;
}
return src;
}
// Convert an hex string into an integer.
// This returns a pointer to the character following the last valid
// hex digit.
Addr
BaseRemoteGDB::hex2i(const char **srcp)
{
const char *src = *srcp;
Addr r = 0;
int nibble;
while ((nibble = digit2i(*src)) >= 0) {
r *= 16;
r += nibble;
src++;
}
*srcp = src;
return r;
}

View File

@@ -49,68 +49,210 @@
class System;
class ThreadContext;
class GDBListener;
class BaseRemoteGDB;
class HardBreakpoint;
struct GdbCommand
/**
* Concrete subclasses of this abstract class represent how the
* register values are transmitted on the wire. Usually each
* architecture should define one subclass, but there can be more
* if there is more than one possible wire format. For example,
* ARM defines both AArch32GdbRegCache and AArch64GdbRegCache.
*/
class BaseGdbRegCache
{
public:
struct Context
{
const GdbCommand *cmd;
char cmd_byte;
int type;
char *data;
int len;
};
typedef bool (BaseRemoteGDB::*Func)(Context &ctx);
/**
* Return the pointer to the raw bytes buffer containing the
* register values. Each byte of this buffer is literally
* encoded as two hex digits in the g or G RSP packet.
*/
virtual char *data() const = 0;
const char * const name;
const Func func;
/**
* Return the size of the raw buffer, in bytes
* (i.e., half of the number of digits in the g/G packet).
*/
virtual size_t size() const = 0;
GdbCommand(const char *_name, Func _func) : name(_name), func(_func)
/**
* Fill the raw buffer from the registers in the ThreadContext.
*/
virtual void getRegs(ThreadContext*) = 0;
/**
* Set the ThreadContext's registers from the values
* in the raw buffer.
*/
virtual void setRegs(ThreadContext*) const = 0;
/**
* Return the name to use in places like DPRINTF.
* Having each concrete superclass redefine this member
* is useful in situations where the class of the regCache
* can change on the fly.
*/
virtual const std::string name() const = 0;
BaseGdbRegCache(BaseRemoteGDB *g) : gdb(g)
{}
virtual ~BaseGdbRegCache()
{}
protected:
BaseRemoteGDB *gdb;
};
class BaseRemoteGDB
{
friend class HardBreakpoint;
public:
/*
* Interface to other parts of the simulator.
*/
BaseRemoteGDB(System *system, ThreadContext *context, int _port);
virtual ~BaseRemoteGDB();
std::string name();
void listen();
void connect();
int port() const;
void attach(int fd);
void detach();
bool isAttached() { return attached; }
void replaceThreadContext(ThreadContext *_tc) { tc = _tc; }
bool trap(int type);
bool breakpoint() { return trap(SIGTRAP); }
private:
friend void debugger();
friend class GDBListener;
/*
* Connection to the external GDB.
*/
void incomingData(int revent);
void connectWrapper(int revent) { connect(); }
protected:
/// Exception to throw when the connection to the client is broken.
struct BadClient
template <void (BaseRemoteGDB::*F)(int revent)>
class SocketEvent : public PollEvent
{
const char *warning;
BadClient(const char *_warning=NULL) : warning(_warning)
protected:
BaseRemoteGDB *gdb;
public:
SocketEvent(BaseRemoteGDB *gdb, int fd, int e) :
PollEvent(fd, e), gdb(gdb)
{}
void process(int revent) { (gdb->*F)(revent); }
};
/// Exception to throw when an error needs to be reported to the client.
struct CmdError
typedef SocketEvent<&BaseRemoteGDB::connectWrapper> ConnectEvent;
typedef SocketEvent<&BaseRemoteGDB::incomingData> DataEvent;
friend ConnectEvent;
friend DataEvent;
ConnectEvent *connectEvent;
DataEvent *dataEvent;
ListenSocket listener;
int _port;
// The socket commands come in through.
int fd;
// Transfer data to/from GDB.
uint8_t getbyte();
void putbyte(uint8_t b);
int recv(char *data, int len);
void send(const char *data);
/*
* Simulator side debugger state.
*/
bool active;
bool attached;
System *sys;
ThreadContext *tc;
BaseGdbRegCache *regCachePtr;
class TrapEvent : public Event
{
std::string error;
CmdError(std::string _error) : error(_error)
protected:
int _type;
BaseRemoteGDB *gdb;
public:
TrapEvent(BaseRemoteGDB *g) : gdb(g)
{}
void type(int t) { _type = t; }
void process() { gdb->trap(_type); }
} trapEvent;
/*
* The interface to the simulated system.
*/
// Machine memory.
bool read(Addr addr, size_t size, char *data);
bool write(Addr addr, size_t size, const char *data);
template <class T> T read(Addr addr);
template <class T> void write(Addr addr, T data);
// Single step.
void singleStep();
EventWrapper<BaseRemoteGDB, &BaseRemoteGDB::singleStep> singleStepEvent;
void clearSingleStep();
void setSingleStep();
/// Schedule an event which will be triggered "delta" instructions later.
void scheduleInstCommitEvent(Event *ev, int delta);
/// Deschedule an instruction count based event.
void descheduleInstCommitEvent(Event *ev);
// Breakpoints.
void insertSoftBreak(Addr addr, size_t len);
void removeSoftBreak(Addr addr, size_t len);
void insertHardBreak(Addr addr, size_t len);
void removeHardBreak(Addr addr, size_t len);
void clearTempBreakpoint(Addr &bkpt);
void setTempBreakpoint(Addr bkpt);
/*
* GDB commands.
*/
struct GdbCommand
{
public:
struct Context
{
const GdbCommand *cmd;
char cmd_byte;
int type;
char *data;
int len;
};
typedef bool (BaseRemoteGDB::*Func)(Context &ctx);
const char * const name;
const Func func;
GdbCommand(const char *_name, Func _func) : name(_name), func(_func) {}
};
/// Exception to throw when something isn't supported.
class Unsupported {};
// Helper functions
protected:
int digit2i(char);
char i2digit(int);
Addr hex2i(const char **);
// Address formats, break types, and gdb commands may change
// between architectures, so they're defined as virtual
// functions.
virtual void mem2hex(char *, const char *, int);
virtual const char * hex2mem(char *, const char *, int);
virtual const char * break_type(char c);
protected:
static std::map<char, GdbCommand> command_map;
bool cmd_unsupported(GdbCommand::Context &ctx);
@@ -131,183 +273,15 @@ class BaseRemoteGDB
bool cmd_set_hw_bkpt(GdbCommand::Context &ctx);
protected:
class InputEvent : public PollEvent
{
protected:
BaseRemoteGDB *gdb;
ThreadContext *context() { return tc; }
System *system() { return sys; }
public:
InputEvent(BaseRemoteGDB *g, int fd, int e);
void process(int revent);
};
class TrapEvent : public Event
{
protected:
int _type;
BaseRemoteGDB *gdb;
public:
TrapEvent(BaseRemoteGDB *g) : gdb(g)
{}
void type(int t) { _type = t; }
void process();
};
friend class InputEvent;
InputEvent *inputEvent;
TrapEvent trapEvent;
GDBListener *listener;
int number;
protected:
// The socket commands come in through
int fd;
protected:
bool active;
bool attached;
System *system;
ThreadContext *context;
protected:
/**
* Concrete subclasses of this abstract class represent how the
* register values are transmitted on the wire. Usually each
* architecture should define one subclass, but there can be more
* if there is more than one possible wire format. For example,
* ARM defines both AArch32GdbRegCache and AArch64GdbRegCache.
*/
class BaseGdbRegCache
{
public:
/**
* Return the pointer to the raw bytes buffer containing the
* register values. Each byte of this buffer is literally
* encoded as two hex digits in the g or G RSP packet.
*/
virtual char *data() const = 0;
/**
* Return the size of the raw buffer, in bytes
* (i.e., half of the number of digits in the g/G packet).
*/
virtual size_t size() const = 0;
/**
* Fill the raw buffer from the registers in the ThreadContext.
*/
virtual void getRegs(ThreadContext*) = 0;
/**
* Set the ThreadContext's registers from the values
* in the raw buffer.
*/
virtual void setRegs(ThreadContext*) const = 0;
/**
* Return the name to use in places like DPRINTF.
* Having each concrete superclass redefine this member
* is useful in situations where the class of the regCache
* can change on the fly.
*/
virtual const std::string name() const = 0;
BaseGdbRegCache(BaseRemoteGDB *g) : gdb(g)
{}
virtual ~BaseGdbRegCache()
{}
protected:
BaseRemoteGDB *gdb;
};
BaseGdbRegCache *regCachePtr;
protected:
uint8_t getbyte();
void putbyte(uint8_t b);
int recv(char *data, int len);
void send(const char *data);
protected:
// Machine memory
virtual bool read(Addr addr, size_t size, char *data);
virtual bool write(Addr addr, size_t size, const char *data);
template <class T> T read(Addr addr);
template <class T> void write(Addr addr, T data);
public:
BaseRemoteGDB(System *system, ThreadContext *context);
virtual ~BaseRemoteGDB();
virtual BaseGdbRegCache *gdbRegs() = 0;
void replaceThreadContext(ThreadContext *tc) { context = tc; }
void attach(int fd);
void detach();
bool isattached();
virtual bool acc(Addr addr, size_t len) = 0;
bool trap(int type);
virtual bool breakpoint()
{
return trap(SIGTRAP);
}
void processSingleStepEvent();
EventFunctionWrapper singleStepEvent;
void clearSingleStep();
void setSingleStep();
PCEventQueue *getPcEventQueue();
EventQueue *getComInstEventQueue();
/// Schedule an event which will be triggered "delta" instructions later.
void scheduleInstCommitEvent(Event *ev, int delta);
/// Deschedule an instruction count based event.
void descheduleInstCommitEvent(Event *ev);
protected:
// To be implemented by subclasses.
virtual bool checkBpLen(size_t len);
class HardBreakpoint : public PCEvent
{
private:
BaseRemoteGDB *gdb;
virtual BaseGdbRegCache *gdbRegs() = 0;
public:
int refcount;
public:
HardBreakpoint(BaseRemoteGDB *_gdb, Addr addr);
const std::string name() const { return gdb->name() + ".hwbkpt"; }
virtual void process(ThreadContext *tc);
};
friend class HardBreakpoint;
typedef std::map<Addr, HardBreakpoint *> break_map_t;
typedef break_map_t::iterator break_iter_t;
break_map_t hardBreakMap;
void insertSoftBreak(Addr addr, size_t len);
void removeSoftBreak(Addr addr, size_t len);
virtual void insertHardBreak(Addr addr, size_t len);
void removeHardBreak(Addr addr, size_t len);
protected:
void clearTempBreakpoint(Addr &bkpt);
void setTempBreakpoint(Addr bkpt);
public:
std::string name();
virtual bool acc(Addr addr, size_t len) = 0;
};
template <class T>
@@ -322,38 +296,8 @@ BaseRemoteGDB::read(Addr addr)
template <class T>
inline void
BaseRemoteGDB::write(Addr addr, T data)
{ write(addr, sizeof(T), (const char *)&data); }
class GDBListener
{
protected:
class InputEvent : public PollEvent
{
protected:
GDBListener *listener;
public:
InputEvent(GDBListener *l, int fd, int e);
void process(int revent);
};
friend class InputEvent;
InputEvent *inputEvent;
protected:
ListenSocket listener;
BaseRemoteGDB *gdb;
int port;
public:
GDBListener(BaseRemoteGDB *g, int p);
~GDBListener();
void accept();
void listen();
std::string name();
int getPort() const;
};
write(addr, sizeof(T), (const char *)&data);
}
#endif /* __REMOTE_GDB_H__ */

View File

@@ -261,16 +261,15 @@ System::registerThreadContext(ThreadContext *tc, ContextID assigned)
#if THE_ISA != NULL_ISA
int port = getRemoteGDBPort();
if (port) {
RemoteGDB *rgdb = new RemoteGDB(this, tc);
GDBListener *gdbl = new GDBListener(rgdb, port + id);
gdbl->listen();
RemoteGDB *rgdb = new RemoteGDB(this, tc, port + id);
rgdb->listen();
BaseCPU *cpu = tc->getCpuPtr();
if (cpu->waitForRemoteGDB()) {
inform("%s: Waiting for a remote GDB connection on port %d.\n",
cpu->name(), gdbl->getPort());
cpu->name(), rgdb->port());
gdbl->accept();
rgdb->connect();
}
if (remoteGDB.size() <= id) {
remoteGDB.resize(id + 1);

View File

@@ -75,7 +75,6 @@
#endif
class BaseRemoteGDB;
class GDBListener;
class KvmVM;
class ObjectFile;
class ThreadContext;
@@ -491,7 +490,6 @@ class System : public MemObject
public:
std::vector<BaseRemoteGDB *> remoteGDB;
std::vector<GDBListener *> gdbListen;
bool breakpoint();
public: