sim, arch, base: Refactor the base remote GDB class.
authorGabe Black <gabeblack@google.com>
Tue, 16 Jan 2018 09:25:39 +0000 (01:25 -0800)
committerGabe Black <gabeblack@google.com>
Sat, 20 Jan 2018 07:28:42 +0000 (07:28 +0000)
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>

18 files changed:
src/arch/alpha/remote_gdb.cc
src/arch/alpha/remote_gdb.hh
src/arch/arm/remote_gdb.cc
src/arch/arm/remote_gdb.hh
src/arch/mips/remote_gdb.cc
src/arch/mips/remote_gdb.hh
src/arch/power/remote_gdb.cc
src/arch/power/remote_gdb.hh
src/arch/riscv/remote_gdb.cc
src/arch/riscv/remote_gdb.hh
src/arch/sparc/remote_gdb.cc
src/arch/sparc/remote_gdb.hh
src/arch/x86/remote_gdb.cc
src/arch/x86/remote_gdb.hh
src/base/remote_gdb.cc
src/base/remote_gdb.hh
src/sim/system.cc
src/sim/system.hh

index a9ec4cf8938e03010e12664290675b5a11e197e7..f3eafc0feb7d37109048b8858b7a08e2ff4be2f1 100644 (file)
 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)
-{
-    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)
+BaseGdbRegCache*
+RemoteGDB::gdbRegs()
 {
-    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);
 }
 
index c8ed709f6ed2cc1fef958a84d8ded0d25f386511..1e99b5fdc84fbd645055d5a073d05505dcd246a6 100644 (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;
 };
 
index 6dc68b190a8662edc7f56b498aa83b86486bd0de..f12734182043b438d4f07c94c5bfe7075f125747 100644 (file)
 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;
index 328fbadb377fd72b5f479fc2600262cde2afcb93..e5d50ee136ea473e7a4d6c0a82b340e92f29c157 100644 (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
index 2cc2d779b531b7a66cf46f77e8bc661dfcd4d538..e17f8fd1dd63a74c87643209d00763a1f7e7bd65 100644 (file)
 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;
 }
index fba55d84c284587dc5164f77e8efbfcce85224c5..169754a53c9350540765382edb64cccf25f27f30 100644 (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();
 };
 
index c85aa38f2c05aee60d2a6ac9f1659ac8fabe4eee..7bdd3ba6a7f806e0275c6803f3c2d64d96b83337 100644 (file)
 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;
 }
 
index 9fefb345bdd5db5be1a521aa2c0e618843688171..2894fc124232717c0b323e28e4361bdcbf9765f7 100644 (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();
 };
 
index 3488c81922e8f59a196478a946919810f08c3e70..4f423fc01ff721867e13ed3c06beef26d93b5d2b 100644 (file)
 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;
 }
index 4b9d6e7f2af1058efef7d0b174510068b549b9ba..739cb5a3e7897ca94c33d9ba61be4918c3db1b04 100644 (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();
 };
 
index 3f4df0d3a9bf3950d2b786a45da030ae2f579268..baec0e7be822220f7a0e4805e4ac49a417c7be1e 100644 (file)
 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 {
index 653f0b113cc773d2e5ae39a3e0109335b6a527e1..f0ddd54e1bb8ff003337e3dfa969a05cc63a9322 100644 (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
index a6fdabd7384cc822618a4a240b8b6ca7ae0dd257..175cabba3bba35e010dd7dd4c0e7b78e0bf581c1 100644 (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
index f1cbcbe8c3e4ba408a725a3960cfab39eed90ed4..0cae4fe306c325865e86d1e36f0e8475bad944a6 100644 (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
index 6ed5957d786ff4da02b00f6e04a3e5b490371f52..09796f1be4a4be3521ea3d23cd169bd44f3a0732 100644 (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);
     }
-}
-#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)
@@ -455,9 +576,38 @@ BaseRemoteGDB::recv(char *bp, int maxlen)
         putbyte(GDBBadP);
     } while (1);
 
-    DPRINTF(GDBRecv, "recv:  %s\n", bp);
+    DPRINTF(GDBRecv, "recv:  %s\n", bp);
+
+    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);
 
-    return len;
+    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.
@@ -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;
-}
index 121faaf2ec3f1b4dd0aecc0abe974b850ff8ea2b..27b4ab488f4f1b0c4e3906ed6aa8004087c4d7eb 100644 (file)
 class System;
 class ThreadContext;
 
-class GDBListener;
-
 class BaseRemoteGDB;
-
-struct GdbCommand
+class HardBreakpoint;
+
+/**
+ * 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;
+
+    /**
+     * 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;
 
-    const char * const name;
-    const Func func;
+    /**
+     * 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;
 
-    GdbCommand(const char *_name, Func _func) : name(_name), func(_func)
+    BaseGdbRegCache(BaseRemoteGDB *g) : gdb(g)
     {}
+    virtual ~BaseGdbRegCache()
+    {}
+
+  protected:
+    BaseRemoteGDB *gdb;
 };
 
 class BaseRemoteGDB
 {
-  private:
-    friend void debugger();
-    friend class GDBListener;
+    friend class HardBreakpoint;
+  public:
 
-  protected:
-    /// 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
-    {
-        std::string error;
-        CmdError(std::string _error) : error(_error)
-        {}
-    };
-    /// Exception to throw when something isn't supported.
-    class Unsupported {};
+    /*
+     * Interface to other parts of the simulator.
+     */
+    BaseRemoteGDB(System *system, ThreadContext *context, int _port);
+    virtual ~BaseRemoteGDB();
 
-    // 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);
+    std::string name();
 
-  protected:
-    static std::map<char, GdbCommand> command_map;
+    void listen();
+    void connect();
 
-    bool cmd_unsupported(GdbCommand::Context &ctx);
+    int port() const;
 
-    bool cmd_signal(GdbCommand::Context &ctx);
-    bool cmd_cont(GdbCommand::Context &ctx);
-    bool cmd_async_cont(GdbCommand::Context &ctx);
-    bool cmd_detach(GdbCommand::Context &ctx);
-    bool cmd_reg_r(GdbCommand::Context &ctx);
-    bool cmd_reg_w(GdbCommand::Context &ctx);
-    bool cmd_set_thread(GdbCommand::Context &ctx);
-    bool cmd_mem_r(GdbCommand::Context &ctx);
-    bool cmd_mem_w(GdbCommand::Context &ctx);
-    bool cmd_query_var(GdbCommand::Context &ctx);
-    bool cmd_step(GdbCommand::Context &ctx);
-    bool cmd_async_step(GdbCommand::Context &ctx);
-    bool cmd_clr_hw_bkpt(GdbCommand::Context &ctx);
-    bool cmd_set_hw_bkpt(GdbCommand::Context &ctx);
+    void attach(int fd);
+    void detach();
+    bool isAttached() { return attached; }
 
-  protected:
-    class InputEvent : public PollEvent
-    {
-      protected:
-        BaseRemoteGDB *gdb;
+    void replaceThreadContext(ThreadContext *_tc) { tc = _tc; }
 
-      public:
-        InputEvent(BaseRemoteGDB *g, int fd, int e);
-        void process(int revent);
-    };
+    bool trap(int type);
+    bool breakpoint() { return trap(SIGTRAP); }
 
-    class TrapEvent : public Event
+  private:
+    /*
+     * Connection to the external GDB.
+     */
+    void incomingData(int revent);
+    void connectWrapper(int revent) { connect(); }
+
+    template <void (BaseRemoteGDB::*F)(int revent)>
+    class SocketEvent : public PollEvent
     {
       protected:
-        int _type;
         BaseRemoteGDB *gdb;
 
       public:
-        TrapEvent(BaseRemoteGDB *g) : gdb(g)
+        SocketEvent(BaseRemoteGDB *gdb, int fd, int e) :
+            PollEvent(fd, e), gdb(gdb)
         {}
 
-        void type(int t) { _type = t; }
-        void process();
+        void process(int revent) { (gdb->*F)(revent); }
     };
 
-    friend class InputEvent;
-    InputEvent *inputEvent;
-    TrapEvent trapEvent;
-    GDBListener *listener;
-    int number;
+    typedef SocketEvent<&BaseRemoteGDB::connectWrapper> ConnectEvent;
+    typedef SocketEvent<&BaseRemoteGDB::incomingData> DataEvent;
 
-  protected:
-    // The socket commands come in through
-    int fd;
-
-  protected:
-    bool active;
-    bool attached;
+    friend ConnectEvent;
+    friend DataEvent;
 
-    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:
+    ConnectEvent *connectEvent;
+    DataEvent *dataEvent;
 
-        /**
-         * 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;
-    };
+    ListenSocket listener;
+    int _port;
 
-    BaseGdbRegCache *regCachePtr;
+    // The socket commands come in through.
+    int fd;
 
-  protected:
+    // Transfer data to/from GDB.
     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);
+    /*
+     * Simulator side debugger state.
+     */
+    bool active;
+    bool attached;
 
-    template <class T> T read(Addr addr);
-    template <class T> void write(Addr addr, T data);
+    System *sys;
+    ThreadContext *tc;
 
-  public:
-    BaseRemoteGDB(System *system, ThreadContext *context);
-    virtual ~BaseRemoteGDB();
-    virtual BaseGdbRegCache *gdbRegs() = 0;
+    BaseGdbRegCache *regCachePtr;
 
-    void replaceThreadContext(ThreadContext *tc) { context = tc; }
+    class TrapEvent : public Event
+    {
+      protected:
+        int _type;
+        BaseRemoteGDB *gdb;
 
-    void attach(int fd);
-    void detach();
-    bool isattached();
+      public:
+        TrapEvent(BaseRemoteGDB *g) : gdb(g)
+        {}
 
-    virtual bool acc(Addr addr, size_t len) = 0;
-    bool trap(int type);
-    virtual bool breakpoint()
-    {
-        return trap(SIGTRAP);
-    }
+        void type(int t) { _type = t; }
+        void process() { gdb->trap(_type); }
+    } trapEvent;
 
-    void processSingleStepEvent();
-    EventFunctionWrapper singleStepEvent;
+    /*
+     * 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();
 
-    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:
-    virtual bool checkBpLen(size_t len);
+    // 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);
 
-    class HardBreakpoint : public PCEvent
-    {
-      private:
-        BaseRemoteGDB *gdb;
+    void clearTempBreakpoint(Addr &bkpt);
+    void setTempBreakpoint(Addr bkpt);
 
+    /*
+     * GDB commands.
+     */
+    struct GdbCommand
+    {
       public:
-        int refcount;
+        struct Context
+        {
+            const GdbCommand *cmd;
+            char cmd_byte;
+            int type;
+            char *data;
+            int len;
+        };
 
-      public:
-        HardBreakpoint(BaseRemoteGDB *_gdb, Addr addr);
-        const std::string name() const { return gdb->name() + ".hwbkpt"; }
+        typedef bool (BaseRemoteGDB::*Func)(Context &ctx);
 
-        virtual void process(ThreadContext *tc);
+        const char * const name;
+        const Func func;
+
+        GdbCommand(const char *_name, Func _func) : name(_name), func(_func) {}
     };
-    friend class HardBreakpoint;
 
-    typedef std::map<Addr, HardBreakpoint *> break_map_t;
-    typedef break_map_t::iterator break_iter_t;
-    break_map_t hardBreakMap;
+    static std::map<char, GdbCommand> command_map;
 
-    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);
+    bool cmd_unsupported(GdbCommand::Context &ctx);
+
+    bool cmd_signal(GdbCommand::Context &ctx);
+    bool cmd_cont(GdbCommand::Context &ctx);
+    bool cmd_async_cont(GdbCommand::Context &ctx);
+    bool cmd_detach(GdbCommand::Context &ctx);
+    bool cmd_reg_r(GdbCommand::Context &ctx);
+    bool cmd_reg_w(GdbCommand::Context &ctx);
+    bool cmd_set_thread(GdbCommand::Context &ctx);
+    bool cmd_mem_r(GdbCommand::Context &ctx);
+    bool cmd_mem_w(GdbCommand::Context &ctx);
+    bool cmd_query_var(GdbCommand::Context &ctx);
+    bool cmd_step(GdbCommand::Context &ctx);
+    bool cmd_async_step(GdbCommand::Context &ctx);
+    bool cmd_clr_hw_bkpt(GdbCommand::Context &ctx);
+    bool cmd_set_hw_bkpt(GdbCommand::Context &ctx);
 
   protected:
-    void clearTempBreakpoint(Addr &bkpt);
-    void setTempBreakpoint(Addr bkpt);
+    ThreadContext *context() { return tc; }
+    System *system() { return sys; }
 
-  public:
-    std::string name();
+    // To be implemented by subclasses.
+    virtual bool checkBpLen(size_t len);
+
+    virtual BaseGdbRegCache *gdbRegs() = 0;
+
+    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__ */
index 2f047f227a6f9f180738489371968beef7d7a724..ed01e0e64c66f9a456a8cfd2daa9605c8893051f 100644 (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);
index acd3108a0117296cfd6ae7841e7c42b839077e1c..5b0c1787297a9ef0ac31c2220e0cff8b8cfbe76a 100644 (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: