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