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:
@@ -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*
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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 ®Cache32;
|
||||
else
|
||||
return new AArch32GdbRegCache(this);
|
||||
return ®Cache64;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 ®Cache;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 ®Cache;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 ®Cache;
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ class RemoteGDB : public BaseRemoteGDB
|
||||
}
|
||||
};
|
||||
|
||||
RiscvGdbRegCache regCache;
|
||||
|
||||
public:
|
||||
RemoteGDB(System *_system, ThreadContext *tc);
|
||||
|
||||
@@ -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 ®Cache32;
|
||||
} else {
|
||||
return ®Cache64;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 ®Cache64;
|
||||
else
|
||||
return new X86GdbRegCache(this);
|
||||
return ®Cache32;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user