base: Refactor the GDB code.
authorGabe Black <gabeblack@google.com>
Thu, 11 May 2017 21:11:28 +0000 (14:11 -0700)
committerGabe Black <gabeblack@google.com>
Thu, 18 May 2017 16:48:09 +0000 (16:48 +0000)
The new version modularizes the implementation of the various commands,
gets rid of dynamic allocation of the register cache, fixes some small
style problems, and uses exceptions to simplify error handling internal to
the GDB stub.

Change-Id: Iff3548373ce4adfb99106a810f5713b769df89b2
Reviewed-on: https://gem5-review.googlesource.com/3280
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-by: Boris Shingarov <shingarov@gmail.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>

16 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

index 8c01005da4a2000cb2b26d0d9fd8eec4e6a154f3..a9ec4cf8938e03010e12664290675b5a11e197e7 100644 (file)
@@ -262,12 +262,12 @@ RemoteGDB::write(Addr vaddr, size_t size, const char *data)
 }
 
 
-bool
+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");
-    return BaseRemoteGDB::insertHardBreak(addr, len);
+    BaseRemoteGDB::insertHardBreak(addr, len);
 }
 
 RemoteGDB::BaseGdbRegCache*
index 4b71fd23a0d9ab23c29469a15b4241f2c1a05b21..38ff91933322a0cd845d01d2ff0811e056c23529 100644 (file)
@@ -53,7 +53,7 @@ class RemoteGDB : public BaseRemoteGDB
     bool acc(Addr addr, size_t len);
     bool write(Addr addr, size_t size, const char *data);
 
-    bool insertHardBreak(Addr addr, size_t len);
+    void insertHardBreak(Addr addr, size_t len) override;
 
     class AlphaGdbRegCache : public BaseGdbRegCache
     {
index b0f6d8e5ede54db000f8d7057afe77e8d955fac9..eefe62b425963baf459929c56fffed9ef1893195 100644 (file)
@@ -165,7 +165,7 @@ using namespace std;
 using namespace ArmISA;
 
 RemoteGDB::RemoteGDB(System *_system, ThreadContext *tc)
-    : BaseRemoteGDB(_system, tc)
+    : BaseRemoteGDB(_system, tc), regCache32(this), regCache64(this)
 {
 }
 
@@ -297,7 +297,7 @@ RemoteGDB::BaseGdbRegCache*
 RemoteGDB::gdbRegs()
 {
     if (inAArch64(context))
-        return new AArch64GdbRegCache(this);
+        return &regCache32;
     else
-        return new AArch32GdbRegCache(this);
+        return &regCache64;
 }
index 13ceac17fed229c6aeccd43c33166d06cba64cbc..acd6f32d25a2c6c218e8ca4f8a17d76dae062d85 100644 (file)
@@ -79,7 +79,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() + ".AArch32GdbRegCache"; }
+        const std::string
+        name() const
+        {
+            return gdb->name() + ".AArch32GdbRegCache";
+        }
     };
 
     class AArch64GdbRegCache : public BaseGdbRegCache
@@ -98,9 +102,16 @@ 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() + ".AArch64GdbRegCache"; }
+        const std::string
+        name() const
+        {
+            return gdb->name() + ".AArch64GdbRegCache";
+        }
     };
 
+    AArch32GdbRegCache regCache32;
+    AArch64GdbRegCache regCache64;
+
   public:
     RemoteGDB(System *_system, ThreadContext *tc);
     BaseGdbRegCache *gdbRegs();
index 4fa7cac70af39b20266e39ff37161db56796bce6..2cc2d779b531b7a66cf46f77e8bc661dfcd4d538 100644 (file)
@@ -152,7 +152,7 @@ using namespace std;
 using namespace MipsISA;
 
 RemoteGDB::RemoteGDB(System *_system, ThreadContext *tc)
-    : BaseRemoteGDB(_system, tc)
+    : BaseRemoteGDB(_system, tc), regCache(this)
 {
 }
 
@@ -207,5 +207,5 @@ RemoteGDB::MipsGdbRegCache::setRegs(ThreadContext *context) const
 
 RemoteGDB::BaseGdbRegCache*
 RemoteGDB::gdbRegs() {
-    return new MipsGdbRegCache(this);
+    return &regCache;
 }
index fd006e0b663b9d853a548ee4c7613f4d1d28155a..fba55d84c284587dc5164f77e8efbfcce85224c5 100644 (file)
@@ -70,9 +70,14 @@ 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() + ".MipsGdbRegCache"; }
+        const std::string
+        name() const
+        {
+            return gdb->name() + ".MipsGdbRegCache";
+        }
     };
 
+    MipsGdbRegCache regCache;
 
   public:
     RemoteGDB(System *_system, ThreadContext *tc);
index 1ed7afbc085cb227914bfdd4b4e5f38209af0c74..c85aa38f2c05aee60d2a6ac9f1659ac8fabe4eee 100644 (file)
@@ -152,7 +152,7 @@ using namespace std;
 using namespace PowerISA;
 
 RemoteGDB::RemoteGDB(System *_system, ThreadContext *tc)
-    : BaseRemoteGDB(_system, tc)
+    : BaseRemoteGDB(_system, tc), regCache(this)
 {
 }
 
@@ -218,6 +218,6 @@ RemoteGDB::PowerGdbRegCache::setRegs(ThreadContext *context) const
 
 RemoteGDB::BaseGdbRegCache*
 RemoteGDB::gdbRegs() {
-    return new PowerGdbRegCache(this);
+    return &regCache;
 }
 
index e1c3962667547662c642cef719cba8ad55ceb6ed..9fefb345bdd5db5be1a521aa2c0e618843688171 100644 (file)
@@ -69,9 +69,14 @@ 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() + ".PowerGdbRegCache"; }
+        const std::string
+        name() const
+        {
+            return gdb->name() + ".PowerGdbRegCache";
+        }
     };
 
+    PowerGdbRegCache regCache;
 
   public:
     RemoteGDB(System *_system, ThreadContext *tc);
index 2b508762deaa429600fdde0719639daae7c7ecca..3488c81922e8f59a196478a946919810f08c3e70 100644 (file)
@@ -149,7 +149,7 @@ using namespace std;
 using namespace RiscvISA;
 
 RemoteGDB::RemoteGDB(System *_system, ThreadContext *tc)
-    : BaseRemoteGDB(_system, tc)
+    : BaseRemoteGDB(_system, tc), regCache(this)
 {
 }
 
@@ -201,5 +201,5 @@ RemoteGDB::RiscvGdbRegCache::setRegs(ThreadContext *context) const
 
 RemoteGDB::BaseGdbRegCache*
 RemoteGDB::gdbRegs() {
-    return new RiscvGdbRegCache(this);
+    return &regCache;
 }
index 735faae023f6bc20a8dd23248b07432315f405e9..4b9d6e7f2af1058efef7d0b174510068b549b9ba 100644 (file)
@@ -82,6 +82,7 @@ class RemoteGDB : public BaseRemoteGDB
         }
     };
 
+    RiscvGdbRegCache regCache;
 
   public:
     RemoteGDB(System *_system, ThreadContext *tc);
index b7ecd3b7aafa071470f7fd42a8a1b28fd9211e6b..3f4df0d3a9bf3950d2b786a45da030ae2f579268 100644 (file)
@@ -148,7 +148,7 @@ using namespace std;
 using namespace SparcISA;
 
 RemoteGDB::RemoteGDB(System *_system, ThreadContext *c)
-    : BaseRemoteGDB(_system, c)
+    : BaseRemoteGDB(_system, c), regCache32(this), regCache64(this)
 {}
 
 ///////////////////////////////////////////////////////////
@@ -248,10 +248,9 @@ RemoteGDB::BaseGdbRegCache*
 RemoteGDB::gdbRegs()
 {
     PSTATE pstate = context->readMiscReg(MISCREG_PSTATE);
-    if (pstate.am)
-    {DPRINTF(GDBRead, "Creating 32-bit GDB\n");
-        return new SPARCGdbRegCache(this);}
-    else
-    {DPRINTF(GDBRead, "Creating 64-bit GDB\n");
-        return new SPARC64GdbRegCache(this);}
+    if (pstate.am) {
+        return &regCache32;
+    } else {
+        return &regCache64;
+    }
 }
index 543683ee8e0d70e722f2146126f26f3b2d0aa3b2..653f0b113cc773d2e5ae39a3e0109335b6a527e1 100644 (file)
@@ -94,6 +94,9 @@ class RemoteGDB : public BaseRemoteGDB
         const std::string name() const { return gdb->name() + ".SPARC64GdbRegCache"; }
     };
 
+    SPARCGdbRegCache regCache32;
+    SPARC64GdbRegCache regCache64;
+
   public:
     RemoteGDB(System *_system, ThreadContext *tc);
     BaseGdbRegCache *gdbRegs();
index 4a9140e6456b653dfa738e4a17221cd4dbd226a9..79613971aaf0ad34b65ef481c4e9a90f83c145e6 100644 (file)
@@ -65,7 +65,7 @@ using namespace std;
 using namespace X86ISA;
 
 RemoteGDB::RemoteGDB(System *_system, ThreadContext *c) :
-    BaseRemoteGDB(_system, c)
+    BaseRemoteGDB(_system, c), regCache32(this), regCache64(this)
 {}
 
 bool
@@ -97,9 +97,9 @@ RemoteGDB::gdbRegs()
 {
     HandyM5Reg m5reg = context->readMiscRegNoEffect(MISCREG_M5_REG);
     if (m5reg.submode == SixtyFourBitMode)
-        return new AMD64GdbRegCache(this);
+        return &regCache64;
     else
-        return new X86GdbRegCache(this);
+        return &regCache32;
 }
 
 
index 5696e3dc7e05b23d7c59d213c903003e73b01c5d..4a917925e9e517d49284f537a87a579d17411aca 100644 (file)
@@ -85,7 +85,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() + ".X86GdbRegCache"; }
+        const std::string
+        name() const
+        {
+            return gdb->name() + ".X86GdbRegCache";
+        }
     };
 
     class AMD64GdbRegCache : public BaseGdbRegCache
@@ -128,9 +132,16 @@ 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() + ".AMD64GdbRegCache"; }
+        const std::string
+        name() const
+        {
+            return gdb->name() + ".AMD64GdbRegCache";
+        }
     };
 
+    X86GdbRegCache regCache32;
+    AMD64GdbRegCache regCache64;
+
   public:
     RemoteGDB(System *system, ThreadContext *context);
     BaseGdbRegCache *gdbRegs();
index 57fccd978f89a297f644af225f61f0be9b6c7b3e..f7b0253a52ddfa99299384d5340a7d8b163014cd 100644 (file)
 using namespace std;
 using namespace TheISA;
 
+static const char GDBStart = '$';
+static const char GDBEnd = '#';
+static const char GDBGoodP = '+';
+static const char GDBBadP = '-';
+
+static const int GDBPacketBufLen = 1024;
+
 #ifndef NDEBUG
 vector<BaseRemoteGDB *> debuggers;
 
@@ -188,8 +195,7 @@ GDBListener::GDBListener(BaseRemoteGDB *g, int p)
 
 GDBListener::~GDBListener()
 {
-    if (inputEvent)
-        delete inputEvent;
+    delete inputEvent;
 }
 
 string
@@ -319,6 +325,8 @@ void
 BaseRemoteGDB::detach()
 {
     attached = false;
+    active = false;
+    clearSingleStep();
     close(fd);
     fd = -1;
 
@@ -326,75 +334,31 @@ BaseRemoteGDB::detach()
     DPRINTFN("remote gdb detached\n");
 }
 
-const char *
-BaseRemoteGDB::gdb_command(char cmd)
-{
-    switch (cmd) {
-      case GDBSignal: return "KGDB_SIGNAL";
-      case GDBSetBaud: return "KGDB_SET_BAUD";
-      case GDBSetBreak: return "KGDB_SET_BREAK";
-      case GDBCont: return "KGDB_CONT";
-      case GDBAsyncCont: return "KGDB_ASYNC_CONT";
-      case GDBDebug: return "KGDB_DEBUG";
-      case GDBDetach: return "KGDB_DETACH";
-      case GDBRegR: return "KGDB_REG_R";
-      case GDBRegW: return "KGDB_REG_W";
-      case GDBSetThread: return "KGDB_SET_THREAD";
-      case GDBCycleStep: return "KGDB_CYCLE_STEP";
-      case GDBSigCycleStep: return "KGDB_SIG_CYCLE_STEP";
-      case GDBKill: return "KGDB_KILL";
-      case GDBMemW: return "KGDB_MEM_W";
-      case GDBMemR: return "KGDB_MEM_R";
-      case GDBSetReg: return "KGDB_SET_REG";
-      case GDBReadReg: return "KGDB_READ_REG";
-      case GDBQueryVar: return "KGDB_QUERY_VAR";
-      case GDBSetVar: return "KGDB_SET_VAR";
-      case GDBReset: return "KGDB_RESET";
-      case GDBStep: return "KGDB_STEP";
-      case GDBAsyncStep: return "KGDB_ASYNC_STEP";
-      case GDBThreadAlive: return "KGDB_THREAD_ALIVE";
-      case GDBTargetExit: return "KGDB_TARGET_EXIT";
-      case GDBBinaryDload: return "KGDB_BINARY_DLOAD";
-      case GDBClrHwBkpt: return "KGDB_CLR_HW_BKPT";
-      case GDBSetHwBkpt: return "KGDB_SET_HW_BKPT";
-      case GDBStart: return "KGDB_START";
-      case GDBEnd: return "KGDB_END";
-      case GDBGoodP: return "KGDB_GOODP";
-      case GDBBadP: return "KGDB_BADP";
-      default: return "KGDB_UNKNOWN";
-    }
-}
-
 /////////////////////////
 //
 //
 
-bool
-BaseRemoteGDB::getbyte(uint8_t &b)
+uint8_t
+BaseRemoteGDB::getbyte()
 {
-    if (::read(fd, &b, sizeof(b)) == sizeof(b)) {
-        return true;
-    } else {
-        warn("Couldn't read data from debugger, detaching.");
-        detach();
-        return false;
-    }
+    uint8_t b;
+    if (::read(fd, &b, sizeof(b)) == sizeof(b))
+        return b;
+
+    throw BadClient("Couldn't read data from debugger.");
 }
 
-bool
+void
 BaseRemoteGDB::putbyte(uint8_t b)
 {
-    if (::write(fd, &b, sizeof(b)) == sizeof(b)) {
-        return true;
-    } else {
-        warn("Couldn't write data to the debugger, detaching.");
-        detach();
-        return false;
-    }
+    if (::write(fd, &b, sizeof(b)) == sizeof(b))
+        return;
+
+    throw BadClient("Couldn't write data to the debugger.");
 }
 
 // Send a packet to gdb
-ssize_t
+void
 BaseRemoteGDB::send(const char *bp)
 {
     const char *p;
@@ -404,28 +368,22 @@ BaseRemoteGDB::send(const char *bp)
 
     do {
         p = bp;
-        //Start sending a packet
-        if (!putbyte(GDBStart))
-            return -1;
-        //Send the contents, and also keep a check sum.
+        // Start sending a packet
+        putbyte(GDBStart);
+        // Send the contents, and also keep a check sum.
         for (csum = 0; (c = *p); p++) {
-            if (!putbyte(c))
-                return -1;
+            putbyte(c);
             csum += c;
         }
-        if (//Send the ending character.
-            !putbyte(GDBEnd) ||
-            //Sent the checksum.
-            !putbyte(i2digit(csum >> 4)) ||
-            !putbyte(i2digit(csum))) {
-            return -1;
-        }
-        //Try transmitting over and over again until the other end doesn't
-        //send an error back.
-        if (!getbyte(c))
-            return -1;
+        // 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);
-    return 0;
 }
 
 // Receive a packet from gdb
@@ -440,17 +398,13 @@ BaseRemoteGDB::recv(char *bp, int maxlen)
     do {
         p = bp;
         csum = len = 0;
-        //Find the beginning of a packet
-        do {
-            if (!getbyte(c))
-                return -1;
-        } while (c != GDBStart);
-
-        //Read until you find the end of the data in the packet, and keep
-        //track of the check sum.
+        // Find the beginning of a packet
+        while ((c = getbyte()) != GDBStart);
+
+        // Read until you find the end of the data in the packet, and keep
+        // track of the check sum.
         while (len < maxlen) {
-            if (!getbyte(c))
-                return -1;
+            c = getbyte();
             if (c == GDBEnd)
                 break;
             c &= 0x7f;
@@ -459,46 +413,40 @@ BaseRemoteGDB::recv(char *bp, int maxlen)
             len++;
         }
 
-        //Mask the check sum, and terminate the command string.
+        // Mask the check sum, and terminate the command string.
         csum &= 0xff;
         *p = '\0';
 
-        //If the command was too long, report an error.
+        // If the command was too long, report an error.
         if (len >= maxlen) {
-            if (!putbyte(GDBBadP))
-                return -1;
+            putbyte(GDBBadP);
             continue;
         }
 
-        //Bring in the checksum. If the check sum matches, csum will be 0.
-        uint8_t csum1, csum2;
-        if (!getbyte(csum1) || !getbyte(csum2))
-            return -1;
-        csum -= digit2i(csum1) * 16;
-        csum -= digit2i(csum2);
+        // Bring in the checksum. If the check sum matches, csum will be 0.
+        csum -= digit2i(getbyte()) * 16;
+        csum -= digit2i(getbyte());
 
-        //If the check sum was correct
+        // If the check sum was correct
         if (csum == 0) {
-            //Report that the packet was received correctly
-            if (!putbyte(GDBGoodP))
-                return -1;
+            // Report that the packet was received correctly
+            putbyte(GDBGoodP);
             // Sequence present?
             if (bp[2] == ':') {
-                if (!putbyte(bp[0]) || !putbyte(bp[1]))
-                    return -1;
+                putbyte(bp[0]);
+                putbyte(bp[1]);
                 len -= 3;
                 memcpy(bp, bp+3, len);
             }
             break;
         }
-        //Otherwise, report that there was a mistake.
-        if (!putbyte(GDBBadP))
-            return -1;
+        // Otherwise, report that there was a mistake.
+        putbyte(GDBBadP);
     } while (1);
 
-    DPRINTF(GDBRecv, "recv:  %s: %s\n", gdb_command(*bp), bp);
+    DPRINTF(GDBRecv, "recv:  %s\n", bp);
 
-    return (len);
+    return len;
 }
 
 // Read bytes from kernel address space for debugger.
@@ -632,60 +580,56 @@ BaseRemoteGDB::HardBreakpoint::process(ThreadContext *tc)
         gdb->trap(SIGTRAP);
 }
 
-bool
+void
 BaseRemoteGDB::insertSoftBreak(Addr addr, size_t len)
 {
     if (!checkBpLen(len))
-        panic("invalid length\n");
+        throw BadClient("Invalid breakpoint length\n");
 
     return insertHardBreak(addr, len);
 }
 
-bool
+void
 BaseRemoteGDB::removeSoftBreak(Addr addr, size_t len)
 {
     if (!checkBpLen(len))
-        panic("invalid length\n");
+        throw BadClient("Invalid breakpoint length.\n");
 
     return removeHardBreak(addr, len);
 }
 
-bool
+void
 BaseRemoteGDB::insertHardBreak(Addr addr, size_t len)
 {
     if (!checkBpLen(len))
-        panic("invalid length\n");
+        throw BadClient("Invalid breakpoint length\n");
 
-    DPRINTF(GDBMisc, "inserting hardware breakpoint at %#x\n", addr);
+    DPRINTF(GDBMisc, "Inserting hardware breakpoint at %#x\n", addr);
 
     HardBreakpoint *&bkpt = hardBreakMap[addr];
     if (bkpt == 0)
         bkpt = new HardBreakpoint(this, addr);
 
     bkpt->refcount++;
-
-    return true;
 }
 
-bool
+void
 BaseRemoteGDB::removeHardBreak(Addr addr, size_t len)
 {
     if (!checkBpLen(len))
-        panic("invalid length\n");
+        throw BadClient("Invalid breakpoint length\n");
 
-    DPRINTF(GDBMisc, "removing hardware breakpoint at %#x\n", addr);
+    DPRINTF(GDBMisc, "Removing hardware breakpoint at %#x\n", addr);
 
     break_iter_t i = hardBreakMap.find(addr);
     if (i == hardBreakMap.end())
-        return false;
+        throw CmdError("E0C");
 
     HardBreakpoint *hbp = (*i).second;
     if (--hbp->refcount == 0) {
         delete hbp;
         hardBreakMap.erase(i);
     }
-
-    return true;
 }
 
 void
@@ -703,19 +647,316 @@ 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)
 {
     switch(c) {
-      case '0': return "software breakpoint";
-      case '1': return "hardware breakpoint";
-      case '2': return "write watchpoint";
-      case '3': return "read watchpoint";
-      case '4': return "access watchpoint";
+      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";
     }
 }
 
+std::map<char, GdbCommand> BaseRemoteGDB::command_map = {
+    // last signal
+    { '?', { "KGDB_SIGNAL", &BaseRemoteGDB::cmd_signal } },
+    // set baud (deprecated)
+    { 'b', { "KGDB_SET_BAUD", &BaseRemoteGDB::cmd_unsupported } },
+    // set breakpoint (deprecated)
+    { 'B', { "KGDB_SET_BREAK", &BaseRemoteGDB::cmd_unsupported } },
+    // resume
+    { 'c', { "KGDB_CONT", &BaseRemoteGDB::cmd_cont } },
+    // continue with signal
+    { 'C', { "KGDB_ASYNC_CONT", &BaseRemoteGDB::cmd_async_cont } },
+    // toggle debug flags (deprecated)
+    { 'd', { "KGDB_DEBUG", &BaseRemoteGDB::cmd_unsupported } },
+    // detach remote gdb
+    { 'D', { "KGDB_DETACH", &BaseRemoteGDB::cmd_detach } },
+    // read general registers
+    { 'g', { "KGDB_REG_R", &BaseRemoteGDB::cmd_reg_r } },
+    // write general registers
+    { 'G', { "KGDB_REG_W", &BaseRemoteGDB::cmd_reg_w } },
+    // set thread
+    { 'H', { "KGDB_SET_THREAD", &BaseRemoteGDB::cmd_set_thread } },
+    // step a single cycle
+    { 'i', { "KGDB_CYCLE_STEP", &BaseRemoteGDB::cmd_unsupported } },
+    // signal then cycle step
+    { 'I', { "KGDB_SIG_CYCLE_STEP", &BaseRemoteGDB::cmd_unsupported } },
+    // kill program
+    { 'k', { "KGDB_KILL", &BaseRemoteGDB::cmd_detach } },
+    // read memory
+    { 'm', { "KGDB_MEM_R", &BaseRemoteGDB::cmd_mem_r } },
+    // write memory
+    { 'M', { "KGDB_MEM_W", &BaseRemoteGDB::cmd_mem_w } },
+    // read register
+    { 'p', { "KGDB_READ_REG", &BaseRemoteGDB::cmd_unsupported } },
+    // write register
+    { 'P', { "KGDB_SET_REG", &BaseRemoteGDB::cmd_unsupported } },
+    // query variable
+    { 'q', { "KGDB_QUERY_VAR", &BaseRemoteGDB::cmd_query_var } },
+    // set variable
+    { 'Q', { "KGDB_SET_VAR", &BaseRemoteGDB::cmd_unsupported } },
+    // reset system (deprecated)
+    { 'r', { "KGDB_RESET", &BaseRemoteGDB::cmd_unsupported } },
+    // step
+    { 's', { "KGDB_STEP", &BaseRemoteGDB::cmd_step } },
+    // signal and step
+    { 'S', { "KGDB_ASYNC_STEP", &BaseRemoteGDB::cmd_async_step } },
+    // find out if the thread is alive
+    { 'T', { "KGDB_THREAD_ALIVE", &BaseRemoteGDB::cmd_unsupported } },
+    // target exited
+    { 'W', { "KGDB_TARGET_EXIT", &BaseRemoteGDB::cmd_unsupported } },
+    // write memory
+    { 'X', { "KGDB_BINARY_DLOAD", &BaseRemoteGDB::cmd_unsupported } },
+    // remove breakpoint or watchpoint
+    { 'z', { "KGDB_CLR_HW_BKPT", &BaseRemoteGDB::cmd_clr_hw_bkpt } },
+    // insert breakpoint or watchpoint
+    { 'Z', { "KGDB_SET_HW_BKPT", &BaseRemoteGDB::cmd_set_hw_bkpt } },
+};
+
+
+bool
+BaseRemoteGDB::cmd_unsupported(GdbCommand::Context &ctx)
+{
+    DPRINTF(GDBMisc, "Unsupported command: %s\n", ctx.cmd->name);
+    DDUMP(GDBMisc, ctx.data, ctx.len);
+    throw Unsupported();
+}
+
+
+bool
+BaseRemoteGDB::cmd_signal(GdbCommand::Context &ctx)
+{
+    send(csprintf("S%02x", ctx.type).c_str());
+    return true;
+}
+
+bool
+BaseRemoteGDB::cmd_cont(GdbCommand::Context &ctx)
+{
+    const char *p = ctx.data;
+    if (ctx.len) {
+        Addr newPc = hex2i(&p);
+        context->pcState(newPc);
+    }
+    clearSingleStep();
+    return false;
+}
+
+bool
+BaseRemoteGDB::cmd_async_cont(GdbCommand::Context &ctx)
+{
+    const char *p = ctx.data;
+    hex2i(&p);
+    if (*p++ == ';') {
+        Addr newPc = hex2i(&p);
+        context->pcState(newPc);
+    }
+    clearSingleStep();
+    return false;
+}
+
+bool
+BaseRemoteGDB::cmd_detach(GdbCommand::Context &ctx)
+{
+    detach();
+    return false;
+}
+
+bool
+BaseRemoteGDB::cmd_reg_r(GdbCommand::Context &ctx)
+{
+    char buf[2 * regCachePtr->size() + 1];
+    buf[2 * regCachePtr->size()] = '\0';
+    mem2hex(buf, regCachePtr->data(), regCachePtr->size());
+    send(buf);
+    return true;
+}
+
+bool
+BaseRemoteGDB::cmd_reg_w(GdbCommand::Context &ctx)
+{
+    const char *p = ctx.data;
+    p = hex2mem(regCachePtr->data(), p, regCachePtr->size());
+    if (p == NULL || *p != '\0')
+        throw CmdError("E01");
+
+    regCachePtr->setRegs(context);
+    send("OK");
+
+    return true;
+}
+
+bool
+BaseRemoteGDB::cmd_set_thread(GdbCommand::Context &ctx)
+{
+    const char *p = ctx.data + 1; // Ignore the subcommand byte.
+    if (hex2i(&p) != 0)
+        throw CmdError("E01");
+    send("OK");
+    return true;
+}
+
+bool
+BaseRemoteGDB::cmd_mem_r(GdbCommand::Context &ctx)
+{
+    const char *p = ctx.data;
+    Addr addr = hex2i(&p);
+    if (*p++ != ',')
+        throw CmdError("E02");
+    size_t len = hex2i(&p);
+    if (*p != '\0')
+        throw CmdError("E03");
+    if (!acc(addr, len))
+        throw CmdError("E05");
+
+    char buf[len];
+    if (!read(addr, len, buf))
+        throw CmdError("E05");
+
+    char temp[2 * len + 1];
+    temp[2 * len] = '\0';
+    mem2hex(temp, buf, len);
+    send(temp);
+    return true;
+}
+
+bool
+BaseRemoteGDB::cmd_mem_w(GdbCommand::Context &ctx)
+{
+    const char *p = ctx.data;
+    Addr addr = hex2i(&p);
+    if (*p++ != ',')
+        throw CmdError("E06");
+    size_t len = hex2i(&p);
+    if (*p++ != ':')
+        throw CmdError("E07");
+    if (len * 2 > ctx.len - (p - ctx.data))
+        throw CmdError("E08");
+    char buf[len];
+    p = (char *)hex2mem(buf, p, len);
+    if (p == NULL)
+        throw CmdError("E09");
+    if (!acc(addr, len))
+        throw CmdError("E0A");
+    if (!write(addr, len, buf))
+        throw CmdError("E0B");
+    send("OK");
+    return true;
+}
+
+bool
+BaseRemoteGDB::cmd_query_var(GdbCommand::Context &ctx)
+{
+    if (string(ctx.data, ctx.len - 1) != "C")
+        throw Unsupported();
+    send("QC0");
+    return true;
+}
+
+bool
+BaseRemoteGDB::cmd_async_step(GdbCommand::Context &ctx)
+{
+    const char *p = ctx.data;
+    hex2i(&p); // Ignore the subcommand byte.
+    if (*p++ == ';') {
+        Addr newPc = hex2i(&p);
+        context->pcState(newPc);
+    }
+    setSingleStep();
+    return false;
+}
+
+bool
+BaseRemoteGDB::cmd_step(GdbCommand::Context &ctx)
+{
+    if (ctx.len) {
+        const char *p = ctx.data;
+        Addr newPc = hex2i(&p);
+        context->pcState(newPc);
+    }
+    setSingleStep();
+    return false;
+}
+
+bool
+BaseRemoteGDB::cmd_clr_hw_bkpt(GdbCommand::Context &ctx)
+{
+    const char *p = ctx.data;
+    char subcmd = *p++;
+    if (*p++ != ',')
+        throw CmdError("E0D");
+    Addr addr = hex2i(&p);
+    if (*p++ != ',')
+        throw CmdError("E0D");
+    size_t len = hex2i(&p);
+
+    DPRINTF(GDBMisc, "clear %s, addr=%#x, len=%d\n",
+            break_type(subcmd), addr, len);
+
+    switch (subcmd) {
+      case GdbSoftBp:
+        removeSoftBreak(addr, len);
+        break;
+      case GdbHardBp:
+        removeHardBreak(addr, len);
+        break;
+      case GdbWriteWp:
+      case GdbReadWp:
+      case GdbAccWp:
+      default: // unknown
+        throw Unsupported();
+    }
+    send("OK");
+
+    return true;
+}
+
+bool
+BaseRemoteGDB::cmd_set_hw_bkpt(GdbCommand::Context &ctx)
+{
+    const char *p = ctx.data;
+    char subcmd = *p++;
+    if (*p++ != ',')
+        throw CmdError("E0D");
+    Addr addr = hex2i(&p);
+    if (*p++ != ',')
+        throw CmdError("E0D");
+    size_t len = hex2i(&p);
+
+    DPRINTF(GDBMisc, "set %s, addr=%#x, len=%d\n",
+            break_type(subcmd), addr, len);
+
+    switch (subcmd) {
+      case GdbSoftBp:
+        insertSoftBreak(addr, len);
+        break;
+      case GdbHardBp:
+        insertHardBreak(addr, len);
+        break;
+      case GdbWriteWp:
+      case GdbReadWp:
+      case GdbAccWp:
+      default: // unknown
+        throw Unsupported();
+    }
+    send("OK");
+
+    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
@@ -724,24 +965,10 @@ BaseRemoteGDB::break_type(char c)
 bool
 BaseRemoteGDB::trap(int type)
 {
-    uint64_t val;
-    size_t datalen, len;
-    char data[GDBPacketBufLen + 1];
-    size_t bufferSize;
-    const char *p;
-    char command, subcmd;
-    string var;
-    bool ret;
 
     if (!attached)
         return false;
 
-    unique_ptr<BaseRemoteGDB::BaseGdbRegCache> regCache(gdbRegs());
-
-    bufferSize = regCache->size() * 2 + 256;
-    unique_ptr<char[]> buffer_mem(new char[bufferSize]);
-    char *buffer = buffer_mem.get();
-
     DPRINTF(GDBMisc, "trap: PC=%s\n", context->pcState());
 
     clearSingleStep();
@@ -760,298 +987,50 @@ BaseRemoteGDB::trap(int type)
         active = true;
     } else {
         // Tell remote host that an exception has occurred.
-        snprintf(buffer, bufferSize, "S%02x", type);
-        if (send(buffer) < 0)
-            return true;
+        send(csprintf("S%02x", type).c_str());
     }
 
     // Stick frame regs into our reg cache.
-    regCache->getRegs(context);
-
-    for (;;) {
-        int recved = recv(data, sizeof(data));
-        if (recved < 0)
-            return true;
-        datalen = recved;
-        data[sizeof(data) - 1] = 0; // Sentinel
-        command = data[0];
-        subcmd = 0;
-        p = data + 1;
-        switch (command) {
-
-          case GDBSignal:
-            // if this command came from a running gdb, answer it --
-            // the other guy has no way of knowing if we're in or out
-            // of this loop when he issues a "remote-signal".
-            snprintf(buffer, bufferSize,
-                    "S%02x", type);
-            if (send(buffer) < 0)
-                return true;
-            continue;
-
-          case GDBRegR:
-            if (2 * regCache->size() > bufferSize)
-                panic("buffer too small");
-
-            mem2hex(buffer, regCache->data(), regCache->size());
-            if (send(buffer) < 0)
-                return true;
-            continue;
-
-          case GDBRegW:
-            p = hex2mem(regCache->data(), p, regCache->size());
-            if (p == NULL || *p != '\0') {
-                if (send("E01") < 0)
-                    return true;
-            } else {
-                regCache->setRegs(context);
-                if (send("OK") < 0)
-                    return true;
-            }
-            continue;
-
-          case GDBMemR:
-            val = hex2i(&p);
-            if (*p++ != ',') {
-                if (send("E02") < 0)
-                    return true;
-                continue;
-            }
-            len = hex2i(&p);
-            if (*p != '\0') {
-                if (send("E03") < 0)
-                    return true;
-                continue;
-            }
-            if (len > bufferSize) {
-                if (send("E04") < 0)
-                    return true;
-                continue;
-            }
-            if (!acc(val, len)) {
-                if (send("E05") < 0)
-                    return true;
-                continue;
-            }
-
-            if (read(val, (size_t)len, buffer)) {
-               // variable length array would be nice, but C++ doesn't
-               // officially support those...
-               char *temp = new char[2*len+1];
-               mem2hex(temp, buffer, len);
-               if (send(temp) < 0) {
-                   delete [] temp;
-                   return true;
-               }
-               delete [] temp;
-            } else {
-               if (send("E05") < 0)
-                   return true;
-            }
-            continue;
+    regCachePtr = gdbRegs();
+    regCachePtr->getRegs(context);
 
-          case GDBMemW:
-            val = hex2i(&p);
-            if (*p++ != ',') {
-                if (send("E06") < 0)
-                    return true;
-                continue;
-            }
-            len = hex2i(&p);
-            if (*p++ != ':') {
-                if (send("E07") < 0)
-                    return true;
-                continue;
-            }
-            if (len > datalen - (p - data)) {
-                if (send("E08") < 0)
-                    return true;
-                continue;
-            }
-            p = hex2mem(buffer, p, bufferSize);
-            if (p == NULL) {
-                if (send("E09") < 0)
-                    return true;
-                continue;
-            }
-            if (!acc(val, len)) {
-                if (send("E0A") < 0)
-                    return true;
-                continue;
-            }
-            if (write(val, (size_t)len, buffer)) {
-                if (send("OK") < 0)
-                    return true;
-            } else {
-                if (send("E0B") < 0)
-                    return true;
-            }
-            continue;
-
-          case GDBSetThread:
-            subcmd = *p++;
-            val = hex2i(&p);
-            if (val == 0) {
-                if (send("OK") < 0)
-                    return true;
-            } else {
-                if (send("E01") < 0)
-                    return true;
-            }
-            continue;
-
-          case GDBDetach:
-          case GDBKill:
-            active = false;
-            clearSingleStep();
-            detach();
-            return true;
-
-          case GDBAsyncCont:
-            subcmd = hex2i(&p);
-            if (*p++ == ';') {
-                val = hex2i(&p);
-                context->pcState(val);
-            }
-            clearSingleStep();
-            return true;
-
-          case GDBCont:
-            if (p - data < (ptrdiff_t)datalen) {
-                val = hex2i(&p);
-                context->pcState(val);
-            }
-            clearSingleStep();
-            return true;
-
-          case GDBAsyncStep:
-            subcmd = hex2i(&p);
-            if (*p++ == ';') {
-                val = hex2i(&p);
-                context->pcState(val);
-            }
-            setSingleStep();
-            return true;
-
-          case GDBStep:
-            if (p - data < (ptrdiff_t)datalen) {
-                val = hex2i(&p);
-                context->pcState(val);
-            }
-            setSingleStep();
-            return true;
-
-          case GDBClrHwBkpt:
-            subcmd = *p++;
-            if (*p++ != ',' && send("E0D") < 0)
-                return true;
-            val = hex2i(&p);
-            if (*p++ != ',' && send("E0D") < 0)
-                return true;
-            len = hex2i(&p);
-
-            DPRINTF(GDBMisc, "clear %s, addr=%#x, len=%d\n",
-                    break_type(subcmd), val, len);
-
-            ret = false;
-
-            switch (subcmd) {
-              case '0': // software breakpoint
-                ret = removeSoftBreak(val, len);
-                break;
-
-              case '1': // hardware breakpoint
-                ret = removeHardBreak(val, len);
-                break;
+    char data[GDBPacketBufLen + 1];
+    GdbCommand::Context cmdCtx;
+    cmdCtx.type = type;
+    cmdCtx.data = &data[1];
 
-              case '2': // write watchpoint
-              case '3': // read watchpoint
-              case '4': // access watchpoint
-              default: // unknown
-                if (send("") < 0)
-                    return true;
-                break;
+    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 (send(ret ? "OK" : "E0C") < 0)
-                return true;
-            continue;
-
-          case GDBSetHwBkpt:
-            subcmd = *p++;
-            if (*p++ != ',' && send("E0D") < 0)
-                return true;
-            val = hex2i(&p);
-            if (*p++ != ',' && send("E0D") < 0)
-                return true;
-            len = hex2i(&p);
-
-            DPRINTF(GDBMisc, "set %s, addr=%#x, len=%d\n",
-                    break_type(subcmd), val, len);
-
-            ret = false;
-
-            switch (subcmd) {
-              case '0': // software breakpoint
-                ret = insertSoftBreak(val, len);
+            if (!(this->*(cmdCtx.cmd->func))(cmdCtx))
                 break;
 
-              case '1': // hardware breakpoint
-                ret = insertHardBreak(val, len);
-                break;
-
-              case '2': // write watchpoint
-              case '3': // read watchpoint
-              case '4': // access watchpoint
-              default: // unknown
-                if (send("") < 0)
-                    return true;
-                break;
-            }
-
-            if (send(ret ? "OK" : "E0C") < 0)
-                return true;
-            continue;
-
-          case GDBQueryVar:
-            var = string(p, datalen - 1);
-            if (var == "C") {
-                if (send("QC0") < 0)
-                    return true;
-            } else {
-                if (send("") < 0)
-                    return true;
-            }
-            continue;
-
-          case GDBSetBaud:
-          case GDBSetBreak:
-          case GDBDebug:
-          case GDBCycleStep:
-          case GDBSigCycleStep:
-          case GDBReadReg:
-          case GDBSetVar:
-          case GDBReset:
-          case GDBThreadAlive:
-          case GDBTargetExit:
-          case GDBBinaryDload:
-            // Unsupported command
-            DPRINTF(GDBMisc, "Unsupported command: %s\n",
-                    gdb_command(command));
-            DDUMP(GDBMisc, (uint8_t *)data, datalen);
-            if (send("") < 0)
-                return true;
-            continue;
-
-          default:
-            // Unknown command.
-            DPRINTF(GDBMisc, "Unknown command: %c(%#x)\n",
-                    command, command);
-            if (send("") < 0)
-                return true;
-            continue;
-
-
+        } 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.");
         }
     }
 
@@ -1068,7 +1047,6 @@ BaseRemoteGDB::digit2i(char c)
     else if (c >= 'a' && c <= 'f')
         return (c - 'a' + 10);
     else if (c >= 'A' && c <= 'F')
-
         return (c - 'A' + 10);
     else
         return (-1);
@@ -1114,7 +1092,7 @@ BaseRemoteGDB::hex2mem(char *vdst, const char *src, int maxlen)
             return (NULL);
         *dst++ = (msb << 4) | lsb;
     }
-    return (src);
+    return src;
 }
 
 // Convert an hex string into an integer.
@@ -1133,6 +1111,6 @@ BaseRemoteGDB::hex2i(const char **srcp)
         src++;
     }
     *srcp = src;
-    return (r);
+    return r;
 }
 
index b3a2b5c601c0fe2892f5c23824404ce8adb92d78..b860f5d334467f5686aa69d5346507d19906dab1 100644 (file)
@@ -36,7 +36,9 @@
 
 #include <sys/signal.h>
 
+#include <exception>
 #include <map>
+#include <string>
 
 #include "arch/types.hh"
 #include "base/intmath.hh"
@@ -49,43 +51,28 @@ class ThreadContext;
 
 class GDBListener;
 
-enum GDBCommands
+class BaseRemoteGDB;
+
+struct GdbCommand
 {
-    GDBSignal              = '?', // last signal
-    GDBSetBaud             = 'b', // set baud (depracated)
-    GDBSetBreak            = 'B', // set breakpoint (depracated)
-    GDBCont                = 'c', // resume
-    GDBAsyncCont           = 'C', // continue with signal
-    GDBDebug               = 'd', // toggle debug flags (deprecated)
-    GDBDetach              = 'D', // detach remote gdb
-    GDBRegR                = 'g', // read general registers
-    GDBRegW                = 'G', // write general registers
-    GDBSetThread           = 'H', // set thread
-    GDBCycleStep           = 'i', // step a single cycle
-    GDBSigCycleStep        = 'I', // signal then cycle step
-    GDBKill                = 'k', // kill program
-    GDBMemR                = 'm', // read memory
-    GDBMemW                = 'M', // write memory
-    GDBReadReg             = 'p', // read register
-    GDBSetReg              = 'P', // write register
-    GDBQueryVar            = 'q', // query variable
-    GDBSetVar              = 'Q', // set variable
-    GDBReset               = 'r', // reset system.  (Deprecated)
-    GDBStep                = 's', // step
-    GDBAsyncStep           = 'S', // signal and step
-    GDBThreadAlive         = 'T', // find out if the thread is alive
-    GDBTargetExit          = 'W', // target exited
-    GDBBinaryDload         = 'X', // write memory
-    GDBClrHwBkpt           = 'z', // remove breakpoint or watchpoint
-    GDBSetHwBkpt           = 'Z'  // insert breakpoint or watchpoint
-};
+  public:
+    struct Context
+    {
+        const GdbCommand *cmd;
+        char cmd_byte;
+        int type;
+        char *data;
+        int len;
+    };
 
-const char GDBStart = '$';
-const char GDBEnd = '#';
-const char GDBGoodP = '+';
-const char GDBBadP = '-';
+    typedef bool (BaseRemoteGDB::*Func)(Context &ctx);
 
-const int GDBPacketBufLen = 1024;
+    const char * const name;
+    const Func func;
+
+    GdbCommand(const char *_name, Func _func) : name(_name), func(_func)
+    {}
+};
 
 class BaseRemoteGDB
 {
@@ -93,18 +80,55 @@ class BaseRemoteGDB
     friend void debugger();
     friend class GDBListener;
 
-    //Helper functions
+  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 {};
+
+    // 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.
+    // 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);
-    virtual const char * gdb_command(char cmd);
+
+  protected:
+    static std::map<char, GdbCommand> command_map;
+
+    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:
     class InputEvent : public PollEvent
@@ -138,13 +162,10 @@ class BaseRemoteGDB
     int number;
 
   protected:
-    //The socket commands come in through
+    // The socket commands come in through
     int fd;
 
   protected:
-#ifdef notyet
-    label_t recover;
-#endif
     bool active;
     bool attached;
 
@@ -197,17 +218,21 @@ class BaseRemoteGDB
 
         BaseGdbRegCache(BaseRemoteGDB *g) : gdb(g)
         {}
+        virtual ~BaseGdbRegCache()
+        {}
 
       protected:
         BaseRemoteGDB *gdb;
     };
 
+    BaseGdbRegCache *regCachePtr;
+
   protected:
-    bool getbyte(uint8_t &b);
-    bool putbyte(uint8_t b);
+    uint8_t getbyte();
+    void putbyte(uint8_t b);
 
     int recv(char *data, int len);
-    ssize_t send(const char *data);
+    void send(const char *data);
 
   protected:
     // Machine memory
@@ -284,10 +309,10 @@ class BaseRemoteGDB
     typedef break_map_t::iterator break_iter_t;
     break_map_t hardBreakMap;
 
-    bool insertSoftBreak(Addr addr, size_t len);
-    bool removeSoftBreak(Addr addr, size_t len);
-    virtual bool insertHardBreak(Addr addr, size_t len);
-    bool removeHardBreak(Addr addr, size_t len);
+    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);