diff -r 7a9eeecf2b52 -r 8c3ac5ac73d4 src/arch/arm/remote_gdb.hh --- a/src/arch/arm/remote_gdb.hh Thu Nov 05 09:40:12 2015 +0000 +++ b/src/arch/arm/remote_gdb.hh Mon Nov 16 07:14:30 2015 -0500 @@ -48,6 +48,7 @@ #include +#include "arch/arm/utility.hh" #include "base/remote_gdb.hh" class System; @@ -56,30 +57,6 @@ namespace ArmISA { -// AArch32 registers with vfpv3/neon -enum { - GDB32_R0 = 0, - GDB32_CPSR = 16, - GDB32_F0 = 17, - GDB32_FPSCR = 81, - GDB32_NUMREGS = 82 -}; - -// AArch64 registers -enum { - GDB64_X0 = 0, - GDB64_SPX = 31, - GDB64_PC = 32, - GDB64_CPSR = 33, - GDB64_V0 = 34, - GDB64_V0_32 = 2 * GDB64_V0, - GDB64_NUMREGS = 98 -}; - -const int GDB_REG_BYTES M5_VAR_USED = - std::max(GDB64_NUMREGS * sizeof(uint64_t), - GDB32_NUMREGS * sizeof(uint32_t)); - class RemoteGDB : public BaseRemoteGDB { protected: @@ -89,8 +66,45 @@ void getregs(); void setregs(); + class AArch32GdbRegCache : public BaseGdbRegCache + { + private: + struct { + uint32_t gpr[16]; + uint32_t fpr[8*3]; + uint32_t fpscr; + uint32_t cpsr; + } r; + public: + void *data() { return (void*)&r; } + size_t bytes() { return sizeof(r); } + void getregs(ThreadContext*); + void setregs(ThreadContext*); + ~AArch32GdbRegCache() {} + }; + + class AArch64GdbRegCache : public BaseGdbRegCache + { + private: + struct { + uint64_t x[31]; + uint64_t spx; + uint64_t pc; + uint64_t cpsr; + uint32_t v[32*4]; + } r; + public: + void *data() { return (void*)&r; } + size_t bytes() { return sizeof(r); } + void getregs(ThreadContext*); + void setregs(ThreadContext*); + ~AArch64GdbRegCache() {} + }; + public: RemoteGDB(System *_system, ThreadContext *tc); + ~RemoteGDB() { if (regCache) delete regCache; } + BaseGdbRegCache *gdbregs(); }; } // namespace ArmISA diff -r 7a9eeecf2b52 -r 8c3ac5ac73d4 src/arch/arm/remote_gdb.cc --- a/src/arch/arm/remote_gdb.cc Thu Nov 05 09:40:12 2015 +0000 +++ b/src/arch/arm/remote_gdb.cc Mon Nov 16 07:14:30 2015 -0500 @@ -162,7 +162,7 @@ using namespace ArmISA; RemoteGDB::RemoteGDB(System *_system, ThreadContext *tc) - : BaseRemoteGDB(_system, tc, GDB_REG_BYTES) + : BaseRemoteGDB(_system, tc) { } @@ -192,6 +192,96 @@ } } +void +RemoteGDB::AArch64GdbRegCache::getregs(ThreadContext *context) +{ + for (int i = 0; i < 31; ++i) + r.x[i] = context->readIntReg(INTREG_X0 + i); + r.spx = context->readIntReg(INTREG_SPX); + r.pc = context->pcState().pc(); + r.cpsr = context->readMiscRegNoEffect(MISCREG_CPSR); + + for (int i = 0; i < 32*4; i += 4) { + r.v[i + 0] = context->readFloatRegBits(i + 2); + r.v[i + 1] = context->readFloatRegBits(i + 3); + r.v[i + 2] = context->readFloatRegBits(i + 0); + r.v[i + 3] = context->readFloatRegBits(i + 1); + } +} + +void +RemoteGDB::AArch64GdbRegCache::setregs(ThreadContext *context) +{ + for (int i = 0; i < 31; ++i) + context->setIntReg(INTREG_X0 + i, r.x[i]); + context->pcState(r.pc); + context->setMiscRegNoEffect(MISCREG_CPSR, r.cpsr); + // Update the stack pointer. This should be done after + // updating CPSR/PSTATE since that might affect how SPX gets + // mapped. + context->setIntReg(INTREG_SPX, r.spx); + + for (int i = 0; i < 32*4; i += 4) { + context->setFloatRegBits(i + 2, r.v[i + 0]); + context->setFloatRegBits(i + 3, r.v[i + 1]); + context->setFloatRegBits(i + 0, r.v[i + 2]); + context->setFloatRegBits(i + 1, r.v[i + 3]); + } +} + +void +RemoteGDB::AArch32GdbRegCache::getregs(ThreadContext *context) +{ + r.gpr[0] = context->readIntReg(INTREG_R0); + r.gpr[1] = context->readIntReg(INTREG_R1); + r.gpr[2] = context->readIntReg(INTREG_R2); + r.gpr[3] = context->readIntReg(INTREG_R3); + r.gpr[4] = context->readIntReg(INTREG_R4); + r.gpr[5] = context->readIntReg(INTREG_R5); + r.gpr[6] = context->readIntReg(INTREG_R6); + r.gpr[7] = context->readIntReg(INTREG_R7); + r.gpr[8] = context->readIntReg(INTREG_R8); + r.gpr[9] = context->readIntReg(INTREG_R9); + r.gpr[10] = context->readIntReg(INTREG_R10); + r.gpr[11] = context->readIntReg(INTREG_R11); + r.gpr[12] = context->readIntReg(INTREG_R12); + r.gpr[13] = context->readIntReg(INTREG_SP); + r.gpr[14] = context->readIntReg(INTREG_LR); + r.gpr[15] = context->pcState().pc(); + + // One day somebody will implement transfer of FPRs correctly. + for (int i=0; i<8*3; i++) r.fpr[i] = 0; + + r.fpscr = context->readMiscRegNoEffect(MISCREG_FPSCR); + r.cpsr = context->readMiscRegNoEffect(MISCREG_CPSR); +} + +void +RemoteGDB::AArch32GdbRegCache::setregs(ThreadContext *context) +{ + context->setIntReg(INTREG_R0, r.gpr[0]); + context->setIntReg(INTREG_R1, r.gpr[1]); + context->setIntReg(INTREG_R2, r.gpr[2]); + context->setIntReg(INTREG_R3, r.gpr[3]); + context->setIntReg(INTREG_R4, r.gpr[4]); + context->setIntReg(INTREG_R5, r.gpr[5]); + context->setIntReg(INTREG_R6, r.gpr[6]); + context->setIntReg(INTREG_R7, r.gpr[7]); + context->setIntReg(INTREG_R8, r.gpr[8]); + context->setIntReg(INTREG_R9, r.gpr[9]); + context->setIntReg(INTREG_R10, r.gpr[10]); + context->setIntReg(INTREG_R11, r.gpr[11]); + context->setIntReg(INTREG_R12, r.gpr[12]); + context->setIntReg(INTREG_SP, r.gpr[13]); + context->setIntReg(INTREG_LR, r.gpr[14]); + context->pcState(r.gpr[15]); + + // One day somebody will implement transfer of FPRs correctly. + + context->setMiscReg(MISCREG_FPSCR, r.fpscr); + context->setMiscRegNoEffect(MISCREG_CPSR, r.cpsr); +} + /* * Translate the kernel debugger register format into the GDB register * format. @@ -200,57 +290,7 @@ RemoteGDB::getregs() { DPRINTF(GDBAcc, "getregs in remotegdb \n"); - - memset(gdbregs.regs, 0, gdbregs.bytes()); - - if (inAArch64(context)) { // AArch64 - // x0-x30 - for (int i = 0; i < 31; ++i) - gdbregs.regs64[GDB64_X0 + i] = context->readIntReg(INTREG_X0 + i); - gdbregs.regs64[GDB64_SPX] = context->readIntReg(INTREG_SPX); - // pc - gdbregs.regs64[GDB64_PC] = context->pcState().pc(); - // cpsr - gdbregs.regs64[GDB64_CPSR] = - context->readMiscRegNoEffect(MISCREG_CPSR); - // v0-v31 - for (int i = 0; i < 128; i += 4) { - int gdboff = GDB64_V0_32 + i; - gdbregs.regs32[gdboff + 0] = context->readFloatRegBits(i + 2); - gdbregs.regs32[gdboff + 1] = context->readFloatRegBits(i + 3); - gdbregs.regs32[gdboff + 2] = context->readFloatRegBits(i + 0); - gdbregs.regs32[gdboff + 3] = context->readFloatRegBits(i + 1); - } - } else { // AArch32 - // R0-R15 supervisor mode - gdbregs.regs32[GDB32_R0 + 0] = context->readIntReg(INTREG_R0); - gdbregs.regs32[GDB32_R0 + 1] = context->readIntReg(INTREG_R1); - gdbregs.regs32[GDB32_R0 + 2] = context->readIntReg(INTREG_R2); - gdbregs.regs32[GDB32_R0 + 3] = context->readIntReg(INTREG_R3); - gdbregs.regs32[GDB32_R0 + 4] = context->readIntReg(INTREG_R4); - gdbregs.regs32[GDB32_R0 + 5] = context->readIntReg(INTREG_R5); - gdbregs.regs32[GDB32_R0 + 6] = context->readIntReg(INTREG_R6); - gdbregs.regs32[GDB32_R0 + 7] = context->readIntReg(INTREG_R7); - gdbregs.regs32[GDB32_R0 + 8] = context->readIntReg(INTREG_R8); - gdbregs.regs32[GDB32_R0 + 9] = context->readIntReg(INTREG_R9); - gdbregs.regs32[GDB32_R0 + 10] = context->readIntReg(INTREG_R10); - gdbregs.regs32[GDB32_R0 + 11] = context->readIntReg(INTREG_R11); - gdbregs.regs32[GDB32_R0 + 12] = context->readIntReg(INTREG_R12); - gdbregs.regs32[GDB32_R0 + 13] = context->readIntReg(INTREG_SP); - gdbregs.regs32[GDB32_R0 + 14] = context->readIntReg(INTREG_LR); - gdbregs.regs32[GDB32_R0 + 15] = context->pcState().pc(); - - // CPSR - gdbregs.regs32[GDB32_CPSR] = context->readMiscRegNoEffect(MISCREG_CPSR); - - // vfpv3/neon floating point registers (32 double or 64 float) - for (int i = 0; i < NumFloatV7ArchRegs; ++i) - gdbregs.regs32[GDB32_F0 + i] = context->readFloatRegBits(i); - - // FPSCR - gdbregs.regs32[GDB32_FPSCR] = - context->readMiscRegNoEffect(MISCREG_FPSCR); - } + gdbregs()->getregs(context); } /* @@ -260,59 +300,19 @@ void RemoteGDB::setregs() { + DPRINTF(GDBAcc, "setregs in remotegdb \n"); + gdbregs()->setregs(context); +} - DPRINTF(GDBAcc, "setregs in remotegdb \n"); - if (inAArch64(context)) { // AArch64 - // x0-x30 - for (int i = 0; i < 31; ++i) - context->setIntReg(INTREG_X0 + i, gdbregs.regs64[GDB64_X0 + i]); - // pc - context->pcState(gdbregs.regs64[GDB64_PC]); - // cpsr - context->setMiscRegNoEffect(MISCREG_CPSR, gdbregs.regs64[GDB64_CPSR]); - // Update the stack pointer. This should be done after - // updating CPSR/PSTATE since that might affect how SPX gets - // mapped. - context->setIntReg(INTREG_SPX, gdbregs.regs64[GDB64_SPX]); - // v0-v31 - for (int i = 0; i < 128; i += 4) { - int gdboff = GDB64_V0_32 + i; - context->setFloatRegBits(i + 2, gdbregs.regs32[gdboff + 0]); - context->setFloatRegBits(i + 3, gdbregs.regs32[gdboff + 1]); - context->setFloatRegBits(i + 0, gdbregs.regs32[gdboff + 2]); - context->setFloatRegBits(i + 1, gdbregs.regs32[gdboff + 3]); - } - } else { // AArch32 - // R0-R15 supervisor mode - // arm registers are 32 bits wide, gdb registers are 64 bits wide - // two arm registers are packed into one gdb register (little endian) - context->setIntReg(INTREG_R0, gdbregs.regs32[GDB32_R0 + 0]); - context->setIntReg(INTREG_R1, gdbregs.regs32[GDB32_R0 + 1]); - context->setIntReg(INTREG_R2, gdbregs.regs32[GDB32_R0 + 2]); - context->setIntReg(INTREG_R3, gdbregs.regs32[GDB32_R0 + 3]); - context->setIntReg(INTREG_R4, gdbregs.regs32[GDB32_R0 + 4]); - context->setIntReg(INTREG_R5, gdbregs.regs32[GDB32_R0 + 5]); - context->setIntReg(INTREG_R6, gdbregs.regs32[GDB32_R0 + 6]); - context->setIntReg(INTREG_R7, gdbregs.regs32[GDB32_R0 + 7]); - context->setIntReg(INTREG_R8, gdbregs.regs32[GDB32_R0 + 8]); - context->setIntReg(INTREG_R9, gdbregs.regs32[GDB32_R0 + 9]); - context->setIntReg(INTREG_R10, gdbregs.regs32[GDB32_R0 + 10]); - context->setIntReg(INTREG_R11, gdbregs.regs32[GDB32_R0 + 11]); - context->setIntReg(INTREG_R12, gdbregs.regs32[GDB32_R0 + 12]); - context->setIntReg(INTREG_SP, gdbregs.regs32[GDB32_R0 + 13]); - context->setIntReg(INTREG_LR, gdbregs.regs32[GDB32_R0 + 14]); - context->pcState(gdbregs.regs32[GDB32_R0 + 7]); - - //CPSR - context->setMiscRegNoEffect(MISCREG_CPSR, gdbregs.regs32[GDB32_CPSR]); - - //vfpv3/neon floating point registers (32 double or 64 float) - for (int i = 0; i < NumFloatV7ArchRegs; ++i) - context->setFloatRegBits(i, gdbregs.regs32[GDB32_F0 + i]); - - //FPSCR - context->setMiscReg(MISCREG_FPSCR, gdbregs.regs32[GDB32_FPSCR]); +RemoteGDB::BaseGdbRegCache* +RemoteGDB::gdbregs() { + if (!regCache) { + if (inAArch64(context)) + regCache = new AArch64GdbRegCache(); + else + regCache = new AArch32GdbRegCache(); } + return regCache; } // Write bytes to kernel address space for debugger. diff -r 7a9eeecf2b52 -r 8c3ac5ac73d4 src/base/remote_gdb.hh --- a/src/base/remote_gdb.hh Thu Nov 05 09:40:12 2015 +0000 +++ b/src/base/remote_gdb.hh Mon Nov 16 07:14:30 2015 -0500 @@ -27,6 +27,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Nathan Binkert + * Boris Shingarov */ #ifndef __REMOTE_GDB_HH__ @@ -150,31 +151,45 @@ ThreadContext *context; protected: - class GdbRegCache + /** + * 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: - GdbRegCache(size_t newSize) : - regs64(new uint64_t[divCeil(newSize, sizeof(uint64_t))]), - size(newSize) - {} - ~GdbRegCache() - { - delete [] regs64; - } - union { - uint64_t *regs64; - uint32_t *regs32; - uint16_t *regs16; - uint8_t *regs8; - void *regs; - }; - // Size of cache in bytes. - size_t size; - size_t bytes() { return size; } + /** + * 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 void *data() = 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 bytes() = 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*) = 0; + + virtual ~BaseGdbRegCache() {}; }; - GdbRegCache gdbregs; + BaseGdbRegCache *regCache = NULL; protected: uint8_t getbyte(); @@ -192,8 +207,9 @@ template void write(Addr addr, T data); public: - BaseRemoteGDB(System *system, ThreadContext *context, size_t cacheSize); + BaseRemoteGDB(System *system, ThreadContext *context); virtual ~BaseRemoteGDB(); + virtual BaseGdbRegCache* gdbregs() = 0; void replaceThreadContext(ThreadContext *tc) { context = tc; } diff -r 7a9eeecf2b52 -r 8c3ac5ac73d4 src/base/remote_gdb.cc --- a/src/base/remote_gdb.cc Thu Nov 05 09:40:12 2015 +0000 +++ b/src/base/remote_gdb.cc Mon Nov 16 07:14:30 2015 -0500 @@ -27,6 +27,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Nathan Binkert + * Boris Shingarov */ /* @@ -270,12 +271,11 @@ gdb->trap(SIGTRAP); } -BaseRemoteGDB::BaseRemoteGDB(System *_system, ThreadContext *c, - size_t cacheSize) : inputEvent(NULL), trapEvent(this), listener(NULL), +BaseRemoteGDB::BaseRemoteGDB(System *_system, ThreadContext *c) : + inputEvent(NULL), trapEvent(this), listener(NULL), number(-1), fd(-1), active(false), attached(false), system(_system), - context(c), gdbregs(cacheSize), singleStepEvent(this) + context(c), singleStepEvent(this) { - memset(gdbregs.regs, 0, gdbregs.bytes()); } BaseRemoteGDB::~BaseRemoteGDB() @@ -700,7 +700,7 @@ if (!attached) return false; - bufferSize = gdbregs.bytes() * 2 + 256; + bufferSize = gdbregs()->bytes() * 2 + 256; buffer = (char*)malloc(bufferSize); DPRINTF(GDBMisc, "trap: PC=%s\n", context->pcState()); @@ -746,15 +746,15 @@ continue; case GDBRegR: - if (2 * gdbregs.bytes() > bufferSize) + if (2 * gdbregs()->bytes() > bufferSize) panic("buffer too small"); - mem2hex(buffer, gdbregs.regs, gdbregs.bytes()); + mem2hex(buffer, gdbregs()->data(), gdbregs()->bytes()); send(buffer); continue; case GDBRegW: - p = hex2mem(gdbregs.regs, p, gdbregs.bytes()); + p = hex2mem(gdbregs()->data(), p, gdbregs()->bytes()); if (p == NULL || *p != '\0') send("E01"); else { @@ -763,25 +763,6 @@ } continue; -#if 0 - case GDBSetReg: - val = hex2i(&p); - if (*p++ != '=') { - send("E01"); - continue; - } - if (val < 0 && val >= KGDB_NUMREGS) { - send("E01"); - continue; - } - - gdbregs.regs[val] = hex2i(&p); - setregs(); - send("OK"); - - continue; -#endif - case GDBMemR: val = hex2i(&p); if (*p++ != ',') {