remote_gdb.hh revision 12031
12SN/A/*
211274Sshingarov@labware.com * Copyright 2015 LabWare
310595Sgabeblack@google.com * Copyright 2014 Google, Inc.
41762SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
52SN/A * All rights reserved.
62SN/A *
72SN/A * Redistribution and use in source and binary forms, with or without
82SN/A * modification, are permitted provided that the following conditions are
92SN/A * met: redistributions of source code must retain the above copyright
102SN/A * notice, this list of conditions and the following disclaimer;
112SN/A * redistributions in binary form must reproduce the above copyright
122SN/A * notice, this list of conditions and the following disclaimer in the
132SN/A * documentation and/or other materials provided with the distribution;
142SN/A * neither the name of the copyright holders nor the names of its
152SN/A * contributors may be used to endorse or promote products derived from
162SN/A * this software without specific prior written permission.
172SN/A *
182SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
192SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
202SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
212SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
222SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
232SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
242SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
252SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
262SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
272SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
282SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
292665Ssaidi@eecs.umich.edu *
302665Ssaidi@eecs.umich.edu * Authors: Nathan Binkert
3111274Sshingarov@labware.com *          Boris Shingarov
322SN/A */
332SN/A
342SN/A#ifndef __REMOTE_GDB_HH__
352SN/A#define __REMOTE_GDB_HH__
362SN/A
373960Sgblack@eecs.umich.edu#include <sys/signal.h>
3877SN/A
3912031Sgabeblack@google.com#include <exception>
408229Snate@binkert.org#include <map>
4112031Sgabeblack@google.com#include <string>
428229Snate@binkert.org
432986Sgblack@eecs.umich.edu#include "arch/types.hh"
4410595Sgabeblack@google.com#include "base/intmath.hh"
4556SN/A#include "base/pollevent.hh"
4656SN/A#include "base/socket.hh"
478229Snate@binkert.org#include "cpu/pc_event.hh"
482SN/A
492SN/Aclass System;
502680Sktlim@umich.educlass ThreadContext;
512SN/A
521910SN/Aclass GDBListener;
533536Sgblack@eecs.umich.edu
5412031Sgabeblack@google.comclass BaseRemoteGDB;
5512031Sgabeblack@google.com
5612031Sgabeblack@google.comstruct GdbCommand
572SN/A{
5812031Sgabeblack@google.com  public:
5912031Sgabeblack@google.com    struct Context
6012031Sgabeblack@google.com    {
6112031Sgabeblack@google.com        const GdbCommand *cmd;
6212031Sgabeblack@google.com        char cmd_byte;
6312031Sgabeblack@google.com        int type;
6412031Sgabeblack@google.com        char *data;
6512031Sgabeblack@google.com        int len;
6612031Sgabeblack@google.com    };
6712031Sgabeblack@google.com
6812031Sgabeblack@google.com    typedef bool (BaseRemoteGDB::*Func)(Context &ctx);
6912031Sgabeblack@google.com
7012031Sgabeblack@google.com    const char * const name;
7112031Sgabeblack@google.com    const Func func;
7212031Sgabeblack@google.com
7312031Sgabeblack@google.com    GdbCommand(const char *_name, Func _func) : name(_name), func(_func)
7412031Sgabeblack@google.com    {}
753536Sgblack@eecs.umich.edu};
763536Sgblack@eecs.umich.edu
773536Sgblack@eecs.umich.educlass BaseRemoteGDB
783536Sgblack@eecs.umich.edu{
791910SN/A  private:
801910SN/A    friend void debugger();
811910SN/A    friend class GDBListener;
821910SN/A
8312031Sgabeblack@google.com  protected:
8412031Sgabeblack@google.com    /// Exception to throw when the connection to the client is broken.
8512031Sgabeblack@google.com    struct BadClient
8612031Sgabeblack@google.com    {
8712031Sgabeblack@google.com        const char *warning;
8812031Sgabeblack@google.com        BadClient(const char *_warning=NULL) : warning(_warning)
8912031Sgabeblack@google.com        {}
9012031Sgabeblack@google.com    };
9112031Sgabeblack@google.com    /// Exception to throw when an error needs to be reported to the client.
9212031Sgabeblack@google.com    struct CmdError
9312031Sgabeblack@google.com    {
9412031Sgabeblack@google.com        std::string error;
9512031Sgabeblack@google.com        CmdError(std::string _error) : error(_error)
9612031Sgabeblack@google.com        {}
9712031Sgabeblack@google.com    };
9812031Sgabeblack@google.com    /// Exception to throw when something isn't supported.
9912031Sgabeblack@google.com    class Unsupported {};
10012031Sgabeblack@google.com
10112031Sgabeblack@google.com    // Helper functions
1023536Sgblack@eecs.umich.edu  protected:
1033536Sgblack@eecs.umich.edu    int digit2i(char);
1043536Sgblack@eecs.umich.edu    char i2digit(int);
1053536Sgblack@eecs.umich.edu    Addr hex2i(const char **);
10612031Sgabeblack@google.com    // Address formats, break types, and gdb commands may change
10712031Sgabeblack@google.com    // between architectures, so they're defined as virtual
10812031Sgabeblack@google.com    // functions.
10911274Sshingarov@labware.com    virtual void mem2hex(char *, const char *, int);
11011274Sshingarov@labware.com    virtual const char * hex2mem(char *, const char *, int);
1113536Sgblack@eecs.umich.edu    virtual const char * break_type(char c);
11212031Sgabeblack@google.com
11312031Sgabeblack@google.com  protected:
11412031Sgabeblack@google.com    static std::map<char, GdbCommand> command_map;
11512031Sgabeblack@google.com
11612031Sgabeblack@google.com    bool cmd_unsupported(GdbCommand::Context &ctx);
11712031Sgabeblack@google.com
11812031Sgabeblack@google.com    bool cmd_signal(GdbCommand::Context &ctx);
11912031Sgabeblack@google.com    bool cmd_cont(GdbCommand::Context &ctx);
12012031Sgabeblack@google.com    bool cmd_async_cont(GdbCommand::Context &ctx);
12112031Sgabeblack@google.com    bool cmd_detach(GdbCommand::Context &ctx);
12212031Sgabeblack@google.com    bool cmd_reg_r(GdbCommand::Context &ctx);
12312031Sgabeblack@google.com    bool cmd_reg_w(GdbCommand::Context &ctx);
12412031Sgabeblack@google.com    bool cmd_set_thread(GdbCommand::Context &ctx);
12512031Sgabeblack@google.com    bool cmd_mem_r(GdbCommand::Context &ctx);
12612031Sgabeblack@google.com    bool cmd_mem_w(GdbCommand::Context &ctx);
12712031Sgabeblack@google.com    bool cmd_query_var(GdbCommand::Context &ctx);
12812031Sgabeblack@google.com    bool cmd_step(GdbCommand::Context &ctx);
12912031Sgabeblack@google.com    bool cmd_async_step(GdbCommand::Context &ctx);
13012031Sgabeblack@google.com    bool cmd_clr_hw_bkpt(GdbCommand::Context &ctx);
13112031Sgabeblack@google.com    bool cmd_set_hw_bkpt(GdbCommand::Context &ctx);
1323536Sgblack@eecs.umich.edu
1332SN/A  protected:
13410598Sgabeblack@google.com    class InputEvent : public PollEvent
1352SN/A    {
1362SN/A      protected:
1373536Sgblack@eecs.umich.edu        BaseRemoteGDB *gdb;
1382SN/A
1392SN/A      public:
14010598Sgabeblack@google.com        InputEvent(BaseRemoteGDB *g, int fd, int e);
1412SN/A        void process(int revent);
1422SN/A    };
1432SN/A
14410598Sgabeblack@google.com    class TrapEvent : public Event
14510597Sgabeblack@google.com    {
14610597Sgabeblack@google.com      protected:
14710597Sgabeblack@google.com        int _type;
14810597Sgabeblack@google.com        BaseRemoteGDB *gdb;
14910597Sgabeblack@google.com
15010597Sgabeblack@google.com      public:
15110597Sgabeblack@google.com        TrapEvent(BaseRemoteGDB *g) : gdb(g)
15210597Sgabeblack@google.com        {}
15310597Sgabeblack@google.com
15410597Sgabeblack@google.com        void type(int t) { _type = t; }
15510597Sgabeblack@google.com        void process();
15610597Sgabeblack@google.com    };
15710597Sgabeblack@google.com
15810598Sgabeblack@google.com    friend class InputEvent;
15910598Sgabeblack@google.com    InputEvent *inputEvent;
16010597Sgabeblack@google.com    TrapEvent trapEvent;
1611910SN/A    GDBListener *listener;
1621910SN/A    int number;
1632SN/A
1642SN/A  protected:
16512031Sgabeblack@google.com    // The socket commands come in through
1662SN/A    int fd;
1672SN/A
1682SN/A  protected:
1692SN/A    bool active;
1702SN/A    bool attached;
1712SN/A
1722SN/A    System *system;
1732680Sktlim@umich.edu    ThreadContext *context;
1742SN/A
1752SN/A  protected:
17611274Sshingarov@labware.com    /**
17711274Sshingarov@labware.com     * Concrete subclasses of this abstract class represent how the
17811274Sshingarov@labware.com     * register values are transmitted on the wire.  Usually each
17911274Sshingarov@labware.com     * architecture should define one subclass, but there can be more
18011274Sshingarov@labware.com     * if there is more than one possible wire format.  For example,
18111274Sshingarov@labware.com     * ARM defines both AArch32GdbRegCache and AArch64GdbRegCache.
18211274Sshingarov@labware.com     */
18311274Sshingarov@labware.com    class BaseGdbRegCache
1843536Sgblack@eecs.umich.edu    {
1853536Sgblack@eecs.umich.edu      public:
18611274Sshingarov@labware.com
18711274Sshingarov@labware.com        /**
18811274Sshingarov@labware.com         * Return the pointer to the raw bytes buffer containing the
18911274Sshingarov@labware.com         * register values.  Each byte of this buffer is literally
19011274Sshingarov@labware.com         * encoded as two hex digits in the g or G RSP packet.
19111274Sshingarov@labware.com         */
19211274Sshingarov@labware.com        virtual char *data() const = 0;
19311274Sshingarov@labware.com
19411274Sshingarov@labware.com        /**
19511274Sshingarov@labware.com         * Return the size of the raw buffer, in bytes
19611274Sshingarov@labware.com         * (i.e., half of the number of digits in the g/G packet).
19711274Sshingarov@labware.com         */
19811274Sshingarov@labware.com        virtual size_t size() const = 0;
19911274Sshingarov@labware.com
20011274Sshingarov@labware.com        /**
20111274Sshingarov@labware.com         * Fill the raw buffer from the registers in the ThreadContext.
20211274Sshingarov@labware.com         */
20311274Sshingarov@labware.com        virtual void getRegs(ThreadContext*) = 0;
20411274Sshingarov@labware.com
20511274Sshingarov@labware.com        /**
20611274Sshingarov@labware.com         * Set the ThreadContext's registers from the values
20711274Sshingarov@labware.com         * in the raw buffer.
20811274Sshingarov@labware.com         */
20911274Sshingarov@labware.com        virtual void setRegs(ThreadContext*) const = 0;
21011274Sshingarov@labware.com
21111274Sshingarov@labware.com        /**
21211274Sshingarov@labware.com         * Return the name to use in places like DPRINTF.
21311274Sshingarov@labware.com         * Having each concrete superclass redefine this member
21411274Sshingarov@labware.com         * is useful in situations where the class of the regCache
21511274Sshingarov@labware.com         * can change on the fly.
21611274Sshingarov@labware.com         */
21711274Sshingarov@labware.com        virtual const std::string name() const = 0;
21811274Sshingarov@labware.com
21911274Sshingarov@labware.com        BaseGdbRegCache(BaseRemoteGDB *g) : gdb(g)
2203536Sgblack@eecs.umich.edu        {}
22112031Sgabeblack@google.com        virtual ~BaseGdbRegCache()
22212031Sgabeblack@google.com        {}
2233536Sgblack@eecs.umich.edu
22411274Sshingarov@labware.com      protected:
22511274Sshingarov@labware.com        BaseRemoteGDB *gdb;
2263536Sgblack@eecs.umich.edu    };
2273536Sgblack@eecs.umich.edu
22812031Sgabeblack@google.com    BaseGdbRegCache *regCachePtr;
22912031Sgabeblack@google.com
2303536Sgblack@eecs.umich.edu  protected:
23112031Sgabeblack@google.com    uint8_t getbyte();
23212031Sgabeblack@google.com    void putbyte(uint8_t b);
2332SN/A
2342SN/A    int recv(char *data, int len);
23512031Sgabeblack@google.com    void send(const char *data);
2362SN/A
2372SN/A  protected:
2382SN/A    // Machine memory
2393536Sgblack@eecs.umich.edu    virtual bool read(Addr addr, size_t size, char *data);
2403536Sgblack@eecs.umich.edu    virtual bool write(Addr addr, size_t size, const char *data);
2412SN/A
2422SN/A    template <class T> T read(Addr addr);
2432SN/A    template <class T> void write(Addr addr, T data);
2442SN/A
2452SN/A  public:
24611274Sshingarov@labware.com    BaseRemoteGDB(System *system, ThreadContext *context);
2473536Sgblack@eecs.umich.edu    virtual ~BaseRemoteGDB();
24811274Sshingarov@labware.com    virtual BaseGdbRegCache *gdbRegs() = 0;
2492SN/A
2502680Sktlim@umich.edu    void replaceThreadContext(ThreadContext *tc) { context = tc; }
251180SN/A
2522SN/A    void attach(int fd);
2532SN/A    void detach();
2542SN/A    bool isattached();
2552SN/A
2563536Sgblack@eecs.umich.edu    virtual bool acc(Addr addr, size_t len) = 0;
2572SN/A    bool trap(int type);
2583960Sgblack@eecs.umich.edu    virtual bool breakpoint()
2593960Sgblack@eecs.umich.edu    {
2603960Sgblack@eecs.umich.edu        return trap(SIGTRAP);
2613960Sgblack@eecs.umich.edu    }
2622SN/A
2632SN/A  protected:
26410601Sgabeblack@google.com    class SingleStepEvent : public Event
26510601Sgabeblack@google.com    {
26610601Sgabeblack@google.com      protected:
26710601Sgabeblack@google.com        BaseRemoteGDB *gdb;
26810601Sgabeblack@google.com
26910601Sgabeblack@google.com      public:
27010601Sgabeblack@google.com        SingleStepEvent(BaseRemoteGDB *g) : gdb(g)
27110601Sgabeblack@google.com        {}
27210601Sgabeblack@google.com
27310601Sgabeblack@google.com        void process();
27410601Sgabeblack@google.com    };
27510601Sgabeblack@google.com
27610601Sgabeblack@google.com    SingleStepEvent singleStepEvent;
27710601Sgabeblack@google.com
27810601Sgabeblack@google.com    void clearSingleStep();
27910601Sgabeblack@google.com    void setSingleStep();
2802SN/A
2812SN/A    PCEventQueue *getPcEventQueue();
28210599Sgabeblack@google.com    EventQueue *getComInstEventQueue();
28310599Sgabeblack@google.com
28410599Sgabeblack@google.com    /// Schedule an event which will be triggered "delta" instructions later.
28510599Sgabeblack@google.com    void scheduleInstCommitEvent(Event *ev, int delta);
28610599Sgabeblack@google.com    /// Deschedule an instruction count based event.
28710599Sgabeblack@google.com    void descheduleInstCommitEvent(Event *ev);
2882SN/A
2892SN/A  protected:
29010589Sgabeblack@google.com    virtual bool checkBpLen(size_t len);
29110589Sgabeblack@google.com
2922SN/A    class HardBreakpoint : public PCEvent
2932SN/A    {
2942SN/A      private:
2953536Sgblack@eecs.umich.edu        BaseRemoteGDB *gdb;
2962SN/A
2972SN/A      public:
298507SN/A        int refcount;
299507SN/A
300507SN/A      public:
3013536Sgblack@eecs.umich.edu        HardBreakpoint(BaseRemoteGDB *_gdb, Addr addr);
3028737Skoansin.tan@gmail.com        const std::string name() const { return gdb->name() + ".hwbkpt"; }
3032SN/A
3042680Sktlim@umich.edu        virtual void process(ThreadContext *tc);
3052SN/A    };
3062SN/A    friend class HardBreakpoint;
3072SN/A
3082SN/A    typedef std::map<Addr, HardBreakpoint *> break_map_t;
3092SN/A    typedef break_map_t::iterator break_iter_t;
3102SN/A    break_map_t hardBreakMap;
3112SN/A
31212031Sgabeblack@google.com    void insertSoftBreak(Addr addr, size_t len);
31312031Sgabeblack@google.com    void removeSoftBreak(Addr addr, size_t len);
31412031Sgabeblack@google.com    virtual void insertHardBreak(Addr addr, size_t len);
31512031Sgabeblack@google.com    void removeHardBreak(Addr addr, size_t len);
3162SN/A
3173550Sgblack@eecs.umich.edu  protected:
3183550Sgblack@eecs.umich.edu    void clearTempBreakpoint(Addr &bkpt);
3193550Sgblack@eecs.umich.edu    void setTempBreakpoint(Addr bkpt);
3203550Sgblack@eecs.umich.edu
321507SN/A  public:
322507SN/A    std::string name();
3232SN/A};
3242SN/A
3252SN/Atemplate <class T>
3262SN/Ainline T
3273536Sgblack@eecs.umich.eduBaseRemoteGDB::read(Addr addr)
3282SN/A{
3292SN/A    T temp;
3302SN/A    read(addr, sizeof(T), (char *)&temp);
3312SN/A    return temp;
3322SN/A}
3332SN/A
3342SN/Atemplate <class T>
3352SN/Ainline void
3363536Sgblack@eecs.umich.eduBaseRemoteGDB::write(Addr addr, T data)
3372SN/A{ write(addr, sizeof(T), (const char *)&data); }
3382SN/A
3392SN/Aclass GDBListener
3402SN/A{
3412SN/A  protected:
34210598Sgabeblack@google.com    class InputEvent : public PollEvent
3432SN/A    {
3442SN/A      protected:
3452SN/A        GDBListener *listener;
3462SN/A
3472SN/A      public:
34810598Sgabeblack@google.com        InputEvent(GDBListener *l, int fd, int e);
3492SN/A        void process(int revent);
3502SN/A    };
3512SN/A
35210598Sgabeblack@google.com    friend class InputEvent;
35310598Sgabeblack@google.com    InputEvent *inputEvent;
3542SN/A
3552SN/A  protected:
3562SN/A    ListenSocket listener;
3573536Sgblack@eecs.umich.edu    BaseRemoteGDB *gdb;
3582SN/A    int port;
3592SN/A
3602SN/A  public:
3613536Sgblack@eecs.umich.edu    GDBListener(BaseRemoteGDB *g, int p);
3622SN/A    ~GDBListener();
3632SN/A
3642SN/A    void accept();
3652SN/A    void listen();
366507SN/A    std::string name();
3672SN/A};
3682SN/A
3692SN/A#endif /* __REMOTE_GDB_H__ */
370