summaryrefslogtreecommitdiff
path: root/src/base/remote_gdb.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/base/remote_gdb.cc')
-rw-r--r--src/base/remote_gdb.cc724
1 files changed, 337 insertions, 387 deletions
diff --git a/src/base/remote_gdb.cc b/src/base/remote_gdb.cc
index 6ed5957d7..09796f1be 100644
--- a/src/base/remote_gdb.cc
+++ b/src/base/remote_gdb.cc
@@ -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);
}
-}
-#endif
-///////////////////////////////////////////////////////////
-//
-//
-//
+ const std::string name() const { return gdb->name() + ".hwbkpt"; }
-GDBListener::InputEvent::InputEvent(GDBListener *l, int fd, int e)
- : PollEvent(fd, e), listener(l)
-{}
+ void
+ process(ThreadContext *tc) override
+ {
+ DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc());
-void
-GDBListener::InputEvent::process(int revent)
+ if (tc == gdb->tc)
+ gdb->trap(SIGTRAP);
+ }
+};
+
+namespace {
+
+// Exception to throw when the connection to the client is broken.
+struct BadClient
{
- listener->accept();
-}
+ const char *warning;
+ BadClient(const char *_warning=NULL) : warning(_warning)
+ {}
+};
-GDBListener::GDBListener(BaseRemoteGDB *g, int p)
- : inputEvent(NULL), gdb(g), port(p)
+// Exception to throw when an error needs to be reported to the client.
+struct CmdError
{
- assert(!gdb->listener);
- gdb->listener = this;
-}
+ string error;
+ CmdError(std::string _error) : error(_error)
+ {}
+};
+
+// Exception to throw when something isn't supported.
+class Unsupported {};
-GDBListener::~GDBListener()
+// Convert a hex digit into an integer.
+// This returns -1 if the argument passed is no valid hex digit.
+int
+digit2i(char c)
{
- delete inputEvent;
+ 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);
}
-string
-GDBListener::name()
+// Convert the low 4 bits of an integer into an hex digit.
+char
+i2digit(int n)
{
- return gdb->name() + ".listener";
+ return ("0123456789abcdef"[n & 0x0f]);
}
+// Convert a byte array into an hex string.
void
-GDBListener::listen()
+mem2hex(char *vdst, const char *vsrc, int len)
{
- if (ListenSocket::allDisabled()) {
- warn_once("Sockets disabled, not accepting gdb connections");
- return;
- }
+ char *dst = vdst;
+ const char *src = vsrc;
- while (!listener.listen(port, true)) {
- DPRINTF(GDBMisc, "Can't bind port %d\n", port);
- port++;
+ while (len--) {
+ *dst++ = i2digit(*src >> 4);
+ *dst++ = i2digit(*src++);
}
-
- inputEvent = new InputEvent(this, listener.getfd(), POLLIN);
- pollQueue.schedule(inputEvent);
-
-#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
+ *dst = '\0';
}
-void
-GDBListener::accept()
+// 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)
{
- if (!listener.islistening())
- panic("GDBListener::accept(): cannot accept if we're not listening!");
-
- int sfd = listener.accept(true);
+ char *dst = vdst;
+ int msb, lsb;
- if (sfd != -1) {
- if (gdb->isattached())
- close(sfd);
- else
- gdb->attach(sfd);
+ 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;
}
-int
-GDBListener::getPort() const
+// 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)
{
- panic_if(!listener.islistening(),
- "Remote GDB port is unknown until GDBListener::listen() has "
- "been called.\n");
+ const char *src = *srcp;
+ Addr r = 0;
+ int nibble;
- return port;
+ while ((nibble = digit2i(*src)) >= 0) {
+ r *= 16;
+ r += nibble;
+ src++;
+ }
+ *srcp = src;
+ return r;
}
-BaseRemoteGDB::InputEvent::InputEvent(BaseRemoteGDB *g, int fd, int e)
- : PollEvent(fd, e), gdb(g)
-{}
+enum GdbBreakpointType {
+ GdbSoftBp = '0',
+ GdbHardBp = '1',
+ GdbWriteWp = '2',
+ GdbReadWp = '3',
+ GdbAccWp = '4',
+};
-void
-BaseRemoteGDB::InputEvent::process(int revent)
+const char *
+break_type(char c)
{
- 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();
+ 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";
}
}
-void
-BaseRemoteGDB::TrapEvent::process()
+std::map<Addr, HardBreakpoint *> hardBreakMap;
+
+EventQueue *
+getComInstEventQueue(ThreadContext *tc)
{
- gdb->trap(_type);
+ return tc->getCpuPtr()->comInstEventQueue[tc->threadId()];
}
-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(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)
{
+ debuggers.push_back(this);
}
BaseRemoteGDB::~BaseRemoteGDB()
{
- if (inputEvent)
- delete inputEvent;
+ delete connectEvent;
+ delete dataEvent;
}
string
BaseRemoteGDB::name()
{
- return system->name() + ".remote_gdb";
+ return sys->name() + ".remote_gdb";
}
-bool
-BaseRemoteGDB::isattached()
-{ return attached; }
+void
+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++;
+ }
+
+ connectEvent = new ConnectEvent(this, listener.getfd(), POLLIN);
+ pollQueue.schedule(connectEvent);
+
+ ccprintf(cerr, "%d: %s: listening for remote gdb on port %d\n",
+ curTick(), name(), _port);
+}
+
+void
+BaseRemoteGDB::connect()
+{
+ panic_if(!listener.islistening(),
+ "Cannot accept GDB connections if we're not listening!");
+
+ int sfd = listener.accept(true);
+
+ if (sfd != -1) {
+ if (isAttached())
+ close(sfd);
+ else
+ attach(sfd);
+ }
+}
+
+int
+BaseRemoteGDB::port() const
+{
+ panic_if(!listener.islistening(),
+ "Remote GDB port is unknown until listen() has been called.\n");
+ return _port;
+}
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,10 +668,10 @@ 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);
}
@@ -529,66 +679,24 @@ BaseRemoteGDB::write(Addr vaddr, size_t size, const char *data)
}
void
-BaseRemoteGDB::clearSingleStep()
-{
- descheduleInstCommitEvent(&singleStepEvent);
-}
-
-void
-BaseRemoteGDB::setSingleStep()
+BaseRemoteGDB::singleStep()
{
if (!singleStepEvent.scheduled())
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);
+ trap(SIGTRAP);
}
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)
+BaseRemoteGDB::clearSingleStep()
{
- DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc);
+ descheduleInstCommitEvent(&singleStepEvent);
}
void
-BaseRemoteGDB::HardBreakpoint::process(ThreadContext *tc)
+BaseRemoteGDB::setSingleStep()
{
- DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc());
-
- if (tc == gdb->context)
- gdb->trap(SIGTRAP);
+ if (!singleStepEvent.scheduled())
+ scheduleInstCommitEvent(&singleStepEvent, 1);
}
void
@@ -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");
@@ -644,42 +752,37 @@ BaseRemoteGDB::removeHardBreak(Addr addr, size_t len)
}
void
-BaseRemoteGDB::setTempBreakpoint(Addr bkpt)
+BaseRemoteGDB::clearTempBreakpoint(Addr &bkpt)
{
DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", bkpt);
- insertHardBreak(bkpt, sizeof(TheISA::MachInst));
+ removeHardBreak(bkpt, sizeof(TheISA::MachInst));
+ bkpt = 0;
}
void
-BaseRemoteGDB::clearTempBreakpoint(Addr &bkpt)
+BaseRemoteGDB::setTempBreakpoint(Addr bkpt)
{
DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", bkpt);
- removeHardBreak(bkpt, sizeof(TheISA::MachInst));
- bkpt = 0;
+ insertHardBreak(bkpt, sizeof(TheISA::MachInst));
}
-enum GdbBreakpointType {
- GdbSoftBp = '0',
- GdbHardBp = '1',
- GdbWriteWp = '2',
- GdbReadWp = '3',
- GdbAccWp = '4',
-};
+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);
+}
-const char *
-BaseRemoteGDB::break_type(char c)
+void
+BaseRemoteGDB::descheduleInstCommitEvent(Event *ev)
{
- 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";
- }
+ if (ev->scheduled())
+ getComInstEventQueue(tc)->deschedule(ev);
}
-std::map<char, GdbCommand> BaseRemoteGDB::command_map = {
+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;
-}