remote_gdb.hh revision 13470
12207SN/A/* 22207SN/A * Copyright 2015 LabWare 32207SN/A * Copyright 2014 Google, Inc. 42207SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 52207SN/A * All rights reserved. 62207SN/A * 72207SN/A * Redistribution and use in source and binary forms, with or without 82207SN/A * modification, are permitted provided that the following conditions are 92207SN/A * met: redistributions of source code must retain the above copyright 102207SN/A * notice, this list of conditions and the following disclaimer; 112207SN/A * redistributions in binary form must reproduce the above copyright 122207SN/A * notice, this list of conditions and the following disclaimer in the 132207SN/A * documentation and/or other materials provided with the distribution; 142207SN/A * neither the name of the copyright holders nor the names of its 152207SN/A * contributors may be used to endorse or promote products derived from 162207SN/A * this software without specific prior written permission. 172207SN/A * 182207SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 192207SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 202207SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 212207SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 222207SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 232207SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 242207SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 252207SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 262207SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 272665Ssaidi@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 282665Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 292665Ssaidi@eecs.umich.edu * 302207SN/A * Authors: Nathan Binkert 312207SN/A * Boris Shingarov 3211793Sbrandon.potter@amd.com */ 3311793Sbrandon.potter@amd.com 342972Sgblack@eecs.umich.edu#ifndef __REMOTE_GDB_HH__ 358229Snate@binkert.org#define __REMOTE_GDB_HH__ 362454SN/A 372454SN/A#include <sys/signal.h> 382680Sktlim@umich.edu 398232Snate@binkert.org#include <exception> 405759Shsul@eecs.umich.edu#include <map> 4111854Sbrandon.potter@amd.com#include <string> 427678Sgblack@eecs.umich.edu 435759Shsul@eecs.umich.edu#include "arch/types.hh" 4411800Sbrandon.potter@amd.com#include "base/intmath.hh" 452474SN/A#include "base/pollevent.hh" 462207SN/A#include "base/socket.hh" 472474SN/A#include "cpu/pc_event.hh" 482474SN/A 492474SN/Aclass System; 5011851Sbrandon.potter@amd.comclass ThreadContext; 5111851Sbrandon.potter@amd.com 522474SN/Aclass BaseRemoteGDB; 532474SN/Aclass HardBreakpoint; 5410318Sandreas.hansson@arm.com 552474SN/A/** 562474SN/A * Concrete subclasses of this abstract class represent how the 572474SN/A * register values are transmitted on the wire. Usually each 582474SN/A * architecture should define one subclass, but there can be more 592474SN/A * if there is more than one possible wire format. For example, 602474SN/A * ARM defines both AArch32GdbRegCache and AArch64GdbRegCache. 612474SN/A */ 6211386Ssteve.reinhardt@amd.comclass BaseGdbRegCache 632474SN/A{ 642474SN/A public: 652474SN/A 662474SN/A /** 672474SN/A * Return the pointer to the raw bytes buffer containing the 682474SN/A * register values. Each byte of this buffer is literally 692474SN/A * encoded as two hex digits in the g or G RSP packet. 7011851Sbrandon.potter@amd.com */ 715759Shsul@eecs.umich.edu virtual char *data() const = 0; 7211389Sbrandon.potter@amd.com 7311389Sbrandon.potter@amd.com /** 7411389Sbrandon.potter@amd.com * Return the size of the raw buffer, in bytes 755759Shsul@eecs.umich.edu * (i.e., half of the number of digits in the g/G packet). 765759Shsul@eecs.umich.edu */ 775771Shsul@eecs.umich.edu virtual size_t size() const = 0; 785759Shsul@eecs.umich.edu 795759Shsul@eecs.umich.edu /** 805759Shsul@eecs.umich.edu * Fill the raw buffer from the registers in the ThreadContext. 8111321Ssteve.reinhardt@amd.com */ 825759Shsul@eecs.umich.edu virtual void getRegs(ThreadContext*) = 0; 8311320Ssteve.reinhardt@amd.com 845759Shsul@eecs.umich.edu /** 855759Shsul@eecs.umich.edu * Set the ThreadContext's registers from the values 865759Shsul@eecs.umich.edu * in the raw buffer. 875759Shsul@eecs.umich.edu */ 885759Shsul@eecs.umich.edu virtual void setRegs(ThreadContext*) const = 0; 895759Shsul@eecs.umich.edu 905759Shsul@eecs.umich.edu /** 9110318Sandreas.hansson@arm.com * Return the name to use in places like DPRINTF. 925759Shsul@eecs.umich.edu * Having each concrete superclass redefine this member 935759Shsul@eecs.umich.edu * is useful in situations where the class of the regCache 945759Shsul@eecs.umich.edu * can change on the fly. 955759Shsul@eecs.umich.edu */ 9611389Sbrandon.potter@amd.com virtual const std::string name() const = 0; 9711389Sbrandon.potter@amd.com 9811389Sbrandon.potter@amd.com BaseGdbRegCache(BaseRemoteGDB *g) : gdb(g) 9911389Sbrandon.potter@amd.com {} 1005759Shsul@eecs.umich.edu virtual ~BaseGdbRegCache() 1015759Shsul@eecs.umich.edu {} 1025759Shsul@eecs.umich.edu 1035759Shsul@eecs.umich.edu protected: 1045759Shsul@eecs.umich.edu BaseRemoteGDB *gdb; 1055759Shsul@eecs.umich.edu}; 1065759Shsul@eecs.umich.edu 1075759Shsul@eecs.umich.educlass BaseRemoteGDB 1085759Shsul@eecs.umich.edu{ 1095759Shsul@eecs.umich.edu friend class HardBreakpoint; 1105759Shsul@eecs.umich.edu public: 1115759Shsul@eecs.umich.edu 1125759Shsul@eecs.umich.edu /* 1135759Shsul@eecs.umich.edu * Interface to other parts of the simulator. 1146227Snate@binkert.org */ 1155759Shsul@eecs.umich.edu BaseRemoteGDB(System *system, ThreadContext *context, int _port); 1165759Shsul@eecs.umich.edu virtual ~BaseRemoteGDB(); 1175759Shsul@eecs.umich.edu 1186227Snate@binkert.org std::string name(); 1195759Shsul@eecs.umich.edu 1205759Shsul@eecs.umich.edu void listen(); 1215759Shsul@eecs.umich.edu void connect(); 1225759Shsul@eecs.umich.edu 12311320Ssteve.reinhardt@amd.com int port() const; 12411320Ssteve.reinhardt@amd.com 1255759Shsul@eecs.umich.edu void attach(int fd); 12611320Ssteve.reinhardt@amd.com void detach(); 1275759Shsul@eecs.umich.edu bool isAttached() { return attached; } 1285759Shsul@eecs.umich.edu 1295759Shsul@eecs.umich.edu void replaceThreadContext(ThreadContext *_tc) { tc = _tc; } 1305759Shsul@eecs.umich.edu 1315759Shsul@eecs.umich.edu bool trap(int type); 1325759Shsul@eecs.umich.edu bool breakpoint() { return trap(SIGTRAP); } 1335759Shsul@eecs.umich.edu 1345759Shsul@eecs.umich.edu private: 1355759Shsul@eecs.umich.edu /* 1365759Shsul@eecs.umich.edu * Connection to the external GDB. 1375759Shsul@eecs.umich.edu */ 1388601Ssteve.reinhardt@amd.com void incomingData(int revent); 1395759Shsul@eecs.umich.edu void connectWrapper(int revent) { connect(); } 1405759Shsul@eecs.umich.edu 1415759Shsul@eecs.umich.edu template <void (BaseRemoteGDB::*F)(int revent)> 1425759Shsul@eecs.umich.edu class SocketEvent : public PollEvent 1435759Shsul@eecs.umich.edu { 1445759Shsul@eecs.umich.edu protected: 1455759Shsul@eecs.umich.edu BaseRemoteGDB *gdb; 1465759Shsul@eecs.umich.edu 1475759Shsul@eecs.umich.edu public: 1485759Shsul@eecs.umich.edu SocketEvent(BaseRemoteGDB *gdb, int fd, int e) : 1495759Shsul@eecs.umich.edu PollEvent(fd, e), gdb(gdb) 1505759Shsul@eecs.umich.edu {} 1515759Shsul@eecs.umich.edu 1525759Shsul@eecs.umich.edu void process(int revent) { (gdb->*F)(revent); } 1535759Shsul@eecs.umich.edu }; 1545759Shsul@eecs.umich.edu 1555759Shsul@eecs.umich.edu typedef SocketEvent<&BaseRemoteGDB::connectWrapper> ConnectEvent; 1568852Sandreas.hansson@arm.com typedef SocketEvent<&BaseRemoteGDB::incomingData> DataEvent; 1575759Shsul@eecs.umich.edu 1585759Shsul@eecs.umich.edu friend ConnectEvent; 1595759Shsul@eecs.umich.edu friend DataEvent; 1605759Shsul@eecs.umich.edu 1615759Shsul@eecs.umich.edu ConnectEvent *connectEvent; 1626227Snate@binkert.org DataEvent *dataEvent; 1638852Sandreas.hansson@arm.com 1645759Shsul@eecs.umich.edu ListenSocket listener; 1658852Sandreas.hansson@arm.com int _port; 1665759Shsul@eecs.umich.edu 1675759Shsul@eecs.umich.edu // The socket commands come in through. 1685759Shsul@eecs.umich.edu int fd; 1695759Shsul@eecs.umich.edu 1705759Shsul@eecs.umich.edu // Transfer data to/from GDB. 1715958Sgblack@eecs.umich.edu uint8_t getbyte(); 1725958Sgblack@eecs.umich.edu void putbyte(uint8_t b); 1735759Shsul@eecs.umich.edu 1745759Shsul@eecs.umich.edu void recv(std::vector<char> &bp); 17511389Sbrandon.potter@amd.com void send(const char *data); 1765759Shsul@eecs.umich.edu 1775759Shsul@eecs.umich.edu /* 1785759Shsul@eecs.umich.edu * Simulator side debugger state. 17911851Sbrandon.potter@amd.com */ 1802474SN/A bool active; 1816820SLisa.Hsu@amd.com bool attached; 18211801Sbrandon.potter@amd.com 1837532Ssteve.reinhardt@amd.com System *sys; 1846820SLisa.Hsu@amd.com ThreadContext *tc; 1855183Ssaidi@eecs.umich.edu 1867532Ssteve.reinhardt@amd.com BaseGdbRegCache *regCachePtr; 18711851Sbrandon.potter@amd.com 1887532Ssteve.reinhardt@amd.com class TrapEvent : public Event 18911851Sbrandon.potter@amd.com { 19011801Sbrandon.potter@amd.com protected: 1917532Ssteve.reinhardt@amd.com int _type; 1927532Ssteve.reinhardt@amd.com BaseRemoteGDB *gdb; 1937532Ssteve.reinhardt@amd.com 1947532Ssteve.reinhardt@amd.com public: 1957532Ssteve.reinhardt@amd.com TrapEvent(BaseRemoteGDB *g) : gdb(g) 1967532Ssteve.reinhardt@amd.com {} 19711851Sbrandon.potter@amd.com 1987532Ssteve.reinhardt@amd.com void type(int t) { _type = t; } 1997532Ssteve.reinhardt@amd.com void process() { gdb->trap(_type); } 2007532Ssteve.reinhardt@amd.com } trapEvent; 2017532Ssteve.reinhardt@amd.com 2027532Ssteve.reinhardt@amd.com /* 20311851Sbrandon.potter@amd.com * The interface to the simulated system. 2045759Shsul@eecs.umich.edu */ 20510318Sandreas.hansson@arm.com // Machine memory. 2062474SN/A bool read(Addr addr, size_t size, char *data); 2077532Ssteve.reinhardt@amd.com bool write(Addr addr, size_t size, const char *data); 2085713Shsul@eecs.umich.edu 2095713Shsul@eecs.umich.edu template <class T> T read(Addr addr); 2107701Sgblack@eecs.umich.edu template <class T> void write(Addr addr, T data); 2117701Sgblack@eecs.umich.edu 2124997Sgblack@eecs.umich.edu // Single step. 2135713Shsul@eecs.umich.edu void singleStep(); 2142474SN/A EventWrapper<BaseRemoteGDB, &BaseRemoteGDB::singleStep> singleStepEvent; 2152474SN/A 2165958Sgblack@eecs.umich.edu void clearSingleStep(); 21711851Sbrandon.potter@amd.com void setSingleStep(); 2185958Sgblack@eecs.umich.edu 2195958Sgblack@eecs.umich.edu /// Schedule an event which will be triggered "delta" instructions later. 2206701Sgblack@eecs.umich.edu void scheduleInstCommitEvent(Event *ev, int delta); 2215958Sgblack@eecs.umich.edu /// Deschedule an instruction count based event. 2225958Sgblack@eecs.umich.edu void descheduleInstCommitEvent(Event *ev); 2235958Sgblack@eecs.umich.edu 22411851Sbrandon.potter@amd.com // Breakpoints. 2255958Sgblack@eecs.umich.edu void insertSoftBreak(Addr addr, size_t len); 2265958Sgblack@eecs.umich.edu void removeSoftBreak(Addr addr, size_t len); 2275958Sgblack@eecs.umich.edu void insertHardBreak(Addr addr, size_t len); 2285958Sgblack@eecs.umich.edu void removeHardBreak(Addr addr, size_t len); 2295958Sgblack@eecs.umich.edu 2305958Sgblack@eecs.umich.edu void clearTempBreakpoint(Addr &bkpt); 23111851Sbrandon.potter@amd.com void setTempBreakpoint(Addr bkpt); 2325958Sgblack@eecs.umich.edu 2335958Sgblack@eecs.umich.edu /* 2345958Sgblack@eecs.umich.edu * GDB commands. 2355958Sgblack@eecs.umich.edu */ 23610223Ssteve.reinhardt@amd.com struct GdbCommand 2375958Sgblack@eecs.umich.edu { 2385958Sgblack@eecs.umich.edu public: 23910223Ssteve.reinhardt@amd.com struct Context 2405958Sgblack@eecs.umich.edu { 2415958Sgblack@eecs.umich.edu const GdbCommand *cmd; 2425958Sgblack@eecs.umich.edu char cmd_byte; 24310223Ssteve.reinhardt@amd.com int type; 2445958Sgblack@eecs.umich.edu char *data; 2455958Sgblack@eecs.umich.edu int len; 246 }; 247 248 typedef bool (BaseRemoteGDB::*Func)(Context &ctx); 249 250 const char * const name; 251 const Func func; 252 253 GdbCommand(const char *_name, Func _func) : name(_name), func(_func) {} 254 }; 255 256 static std::map<char, GdbCommand> command_map; 257 258 bool cmd_unsupported(GdbCommand::Context &ctx); 259 260 bool cmd_signal(GdbCommand::Context &ctx); 261 bool cmd_cont(GdbCommand::Context &ctx); 262 bool cmd_async_cont(GdbCommand::Context &ctx); 263 bool cmd_detach(GdbCommand::Context &ctx); 264 bool cmd_reg_r(GdbCommand::Context &ctx); 265 bool cmd_reg_w(GdbCommand::Context &ctx); 266 bool cmd_set_thread(GdbCommand::Context &ctx); 267 bool cmd_mem_r(GdbCommand::Context &ctx); 268 bool cmd_mem_w(GdbCommand::Context &ctx); 269 bool cmd_query_var(GdbCommand::Context &ctx); 270 bool cmd_step(GdbCommand::Context &ctx); 271 bool cmd_async_step(GdbCommand::Context &ctx); 272 bool cmd_clr_hw_bkpt(GdbCommand::Context &ctx); 273 bool cmd_set_hw_bkpt(GdbCommand::Context &ctx); 274 275 protected: 276 ThreadContext *context() { return tc; } 277 System *system() { return sys; } 278 279 // To be implemented by subclasses. 280 virtual bool checkBpLen(size_t len); 281 282 virtual BaseGdbRegCache *gdbRegs() = 0; 283 284 virtual bool acc(Addr addr, size_t len) = 0; 285}; 286 287template <class T> 288inline T 289BaseRemoteGDB::read(Addr addr) 290{ 291 T temp; 292 read(addr, sizeof(T), (char *)&temp); 293 return temp; 294} 295 296template <class T> 297inline void 298BaseRemoteGDB::write(Addr addr, T data) 299{ 300 write(addr, sizeof(T), (const char *)&data); 301} 302 303#endif /* __REMOTE_GDB_H__ */ 304