base: Refactor the GDB code.

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>
This commit is contained in:
Gabe Black
2017-05-11 14:11:28 -07:00
parent 9aadcc7972
commit 41ab3e6e7e
16 changed files with 543 additions and 505 deletions

View 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*

View 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
{

View 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;
}

View 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();

View 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;
}

View 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);

View 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;
}

View 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);

View 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;
}

View File

@@ -82,6 +82,7 @@ class RemoteGDB : public BaseRemoteGDB
}
};
RiscvGdbRegCache regCache;
public:
RemoteGDB(System *_system, ThreadContext *tc);

View 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;
}
}

View 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();

View 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;
}

View 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();

File diff suppressed because it is too large Load Diff

View File

@@ -36,7 +36,9 @@
#include <sys/signal.h>
#include <exception>
#include <map>
#include <string>
#include "arch/types.hh"
#include "base/intmath.hh"
@@ -49,62 +51,84 @@ 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;
};
typedef bool (BaseRemoteGDB::*Func)(Context &ctx);
const char * const name;
const Func func;
GdbCommand(const char *_name, Func _func) : name(_name), func(_func)
{}
};
const char GDBStart = '$';
const char GDBEnd = '#';
const char GDBGoodP = '+';
const char GDBBadP = '-';
const int GDBPacketBufLen = 1024;
class BaseRemoteGDB
{
private:
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);