From ecec88750729b2c94d5ca9dedbf7a755c46c41a7 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Tue, 16 Jan 2018 01:25:39 -0800 Subject: sim, arch, base: Refactor the base remote GDB class. 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 Reviewed-by: Gabe Black Maintainer: Gabe Black --- src/base/remote_gdb.hh | 396 +++++++++++++++++++++---------------------------- 1 file changed, 170 insertions(+), 226 deletions(-) (limited to 'src/base/remote_gdb.hh') diff --git a/src/base/remote_gdb.hh b/src/base/remote_gdb.hh index 121faaf2e..27b4ab488 100644 --- a/src/base/remote_gdb.hh +++ b/src/base/remote_gdb.hh @@ -49,265 +49,239 @@ 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 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 + 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 T read(Addr addr); - template 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 T read(Addr addr); + template void write(Addr addr, T data); + + // Single step. + void singleStep(); + EventWrapper 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 break_map_t; - typedef break_map_t::iterator break_iter_t; - break_map_t hardBreakMap; + static std::map 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 @@ -322,38 +296,8 @@ BaseRemoteGDB::read(Addr addr) template 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__ */ -- cgit v1.2.3