remote_gdb.hh revision 10599
12SN/A/*
21762SN/A * Copyright 2014 Google, Inc.
32SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
42SN/A * All rights reserved.
52SN/A *
62SN/A * Redistribution and use in source and binary forms, with or without
72SN/A * modification, are permitted provided that the following conditions are
82SN/A * met: redistributions of source code must retain the above copyright
92SN/A * notice, this list of conditions and the following disclaimer;
102SN/A * redistributions in binary form must reproduce the above copyright
112SN/A * notice, this list of conditions and the following disclaimer in the
122SN/A * documentation and/or other materials provided with the distribution;
132SN/A * neither the name of the copyright holders nor the names of its
142SN/A * contributors may be used to endorse or promote products derived from
152SN/A * this software without specific prior written permission.
162SN/A *
172SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
182SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
192SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
202SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
212SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
222SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
232SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
242SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
252SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
262SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
272665Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
282665Ssaidi@eecs.umich.edu *
292665Ssaidi@eecs.umich.edu * Authors: Nathan Binkert
302SN/A */
312SN/A
321112SN/A#ifndef __REMOTE_GDB_HH__
331112SN/A#define __REMOTE_GDB_HH__
342SN/A
353386Sgblack@eecs.umich.edu#include <sys/signal.h>
362SN/A
372SN/A#include <map>
382SN/A
392SN/A#include "arch/types.hh"
402SN/A#include "base/intmath.hh"
412SN/A#include "base/pollevent.hh"
422SN/A#include "base/socket.hh"
432SN/A#include "cpu/pc_event.hh"
442SN/A
452SN/Aclass System;
462SN/Aclass ThreadContext;
474070Ssaidi@eecs.umich.edu
482SN/Aclass GDBListener;
492SN/A
502SN/Aenum GDBCommands
512SN/A{
522SN/A    GDBSignal              = '?', // last signal
532SN/A    GDBSetBaud             = 'b', // set baud (depracated)
542SN/A    GDBSetBreak            = 'B', // set breakpoint (depracated)
552SN/A    GDBCont                = 'c', // resume
562SN/A    GDBAsyncCont           = 'C', // continue with signal
572SN/A    GDBDebug               = 'd', // toggle debug flags (deprecated)
582SN/A    GDBDetach              = 'D', // detach remote gdb
592SN/A    GDBRegR                = 'g', // read general registers
602SN/A    GDBRegW                = 'G', // write general registers
612SN/A    GDBSetThread           = 'H', // set thread
623814Ssaidi@eecs.umich.edu    GDBCycleStep           = 'i', // step a single cycle
633814Ssaidi@eecs.umich.edu    GDBSigCycleStep        = 'I', // signal then cycle step
643814Ssaidi@eecs.umich.edu    GDBKill                = 'k', // kill program
653814Ssaidi@eecs.umich.edu    GDBMemR                = 'm', // read memory
663814Ssaidi@eecs.umich.edu    GDBMemW                = 'M', // write memory
673814Ssaidi@eecs.umich.edu    GDBReadReg             = 'p', // read register
683814Ssaidi@eecs.umich.edu    GDBSetReg              = 'P', // write register
693814Ssaidi@eecs.umich.edu    GDBQueryVar            = 'q', // query variable
703814Ssaidi@eecs.umich.edu    GDBSetVar              = 'Q', // set variable
713814Ssaidi@eecs.umich.edu    GDBReset               = 'r', // reset system.  (Deprecated)
723814Ssaidi@eecs.umich.edu    GDBStep                = 's', // step
734070Ssaidi@eecs.umich.edu    GDBAsyncStep           = 'S', // signal and step
744070Ssaidi@eecs.umich.edu    GDBThreadAlive         = 'T', // find out if the thread is alive
754070Ssaidi@eecs.umich.edu    GDBTargetExit          = 'W', // target exited
764070Ssaidi@eecs.umich.edu    GDBBinaryDload         = 'X', // write memory
774070Ssaidi@eecs.umich.edu    GDBClrHwBkpt           = 'z', // remove breakpoint or watchpoint
784070Ssaidi@eecs.umich.edu    GDBSetHwBkpt           = 'Z'  // insert breakpoint or watchpoint
793814Ssaidi@eecs.umich.edu};
802SN/A
812SN/Aconst char GDBStart = '$';
822SN/Aconst char GDBEnd = '#';
832SN/Aconst char GDBGoodP = '+';
842SN/Aconst char GDBBadP = '-';
852SN/A
862SN/Aconst int GDBPacketBufLen = 1024;
872SN/A
882SN/Aclass BaseRemoteGDB
892SN/A{
902SN/A  private:
913422Sgblack@eecs.umich.edu    friend void debugger();
923422Sgblack@eecs.umich.edu    friend class GDBListener;
933422Sgblack@eecs.umich.edu
943422Sgblack@eecs.umich.edu    //Helper functions
953422Sgblack@eecs.umich.edu  protected:
963422Sgblack@eecs.umich.edu    int digit2i(char);
973422Sgblack@eecs.umich.edu    char i2digit(int);
983422Sgblack@eecs.umich.edu    Addr hex2i(const char **);
993422Sgblack@eecs.umich.edu    //Address formats, break types, and gdb commands may change
1003422Sgblack@eecs.umich.edu    //between architectures, so they're defined as virtual
1013422Sgblack@eecs.umich.edu    //functions.
1023422Sgblack@eecs.umich.edu    virtual void mem2hex(void *, const void *, int);
1033422Sgblack@eecs.umich.edu    virtual const char * hex2mem(void *, const char *, int);
1043422Sgblack@eecs.umich.edu    virtual const char * break_type(char c);
1053422Sgblack@eecs.umich.edu    virtual const char * gdb_command(char cmd);
1063422Sgblack@eecs.umich.edu
1073422Sgblack@eecs.umich.edu  protected:
1083422Sgblack@eecs.umich.edu    class InputEvent : public PollEvent
1093422Sgblack@eecs.umich.edu    {
1103422Sgblack@eecs.umich.edu      protected:
1113422Sgblack@eecs.umich.edu        BaseRemoteGDB *gdb;
1123422Sgblack@eecs.umich.edu
1133422Sgblack@eecs.umich.edu      public:
1143422Sgblack@eecs.umich.edu        InputEvent(BaseRemoteGDB *g, int fd, int e);
1154103Ssaidi@eecs.umich.edu        void process(int revent);
1164103Ssaidi@eecs.umich.edu    };
1174103Ssaidi@eecs.umich.edu
1184103Ssaidi@eecs.umich.edu    class TrapEvent : public Event
1194103Ssaidi@eecs.umich.edu    {
1204103Ssaidi@eecs.umich.edu      protected:
1214103Ssaidi@eecs.umich.edu        int _type;
1224103Ssaidi@eecs.umich.edu        BaseRemoteGDB *gdb;
1234103Ssaidi@eecs.umich.edu
1244244Ssaidi@eecs.umich.edu      public:
1254244Ssaidi@eecs.umich.edu        TrapEvent(BaseRemoteGDB *g) : gdb(g)
1264244Ssaidi@eecs.umich.edu        {}
1274244Ssaidi@eecs.umich.edu
1284244Ssaidi@eecs.umich.edu        void type(int t) { _type = t; }
1294244Ssaidi@eecs.umich.edu        void process();
1304103Ssaidi@eecs.umich.edu    };
1314103Ssaidi@eecs.umich.edu
1324103Ssaidi@eecs.umich.edu    friend class InputEvent;
1334259Sgblack@eecs.umich.edu    InputEvent *inputEvent;
1344259Sgblack@eecs.umich.edu    TrapEvent trapEvent;
1354259Sgblack@eecs.umich.edu    GDBListener *listener;
1364259Sgblack@eecs.umich.edu    int number;
1374259Sgblack@eecs.umich.edu
1384259Sgblack@eecs.umich.edu  protected:
1394259Sgblack@eecs.umich.edu    //The socket commands come in through
1404259Sgblack@eecs.umich.edu    int fd;
1414259Sgblack@eecs.umich.edu
1424259Sgblack@eecs.umich.edu  protected:
1434258Sgblack@eecs.umich.edu#ifdef notyet
1444257Sgblack@eecs.umich.edu    label_t recover;
1454259Sgblack@eecs.umich.edu#endif
1464259Sgblack@eecs.umich.edu    bool active;
1474259Sgblack@eecs.umich.edu    bool attached;
1484258Sgblack@eecs.umich.edu
1494258Sgblack@eecs.umich.edu    System *system;
1504258Sgblack@eecs.umich.edu    ThreadContext *context;
1514258Sgblack@eecs.umich.edu
1524258Sgblack@eecs.umich.edu  protected:
1534103Ssaidi@eecs.umich.edu    class GdbRegCache
1544259Sgblack@eecs.umich.edu    {
1554259Sgblack@eecs.umich.edu      public:
1564259Sgblack@eecs.umich.edu        GdbRegCache(size_t newSize) :
1574259Sgblack@eecs.umich.edu            regs64(new uint64_t[divCeil(newSize, sizeof(uint64_t))]),
1584258Sgblack@eecs.umich.edu            size(newSize)
1594258Sgblack@eecs.umich.edu        {}
1604258Sgblack@eecs.umich.edu        ~GdbRegCache()
1614258Sgblack@eecs.umich.edu        {
1624258Sgblack@eecs.umich.edu            delete [] regs64;
1634258Sgblack@eecs.umich.edu        }
1644259Sgblack@eecs.umich.edu
1654258Sgblack@eecs.umich.edu        union {
1664258Sgblack@eecs.umich.edu            uint64_t *regs64;
1674258Sgblack@eecs.umich.edu            uint32_t *regs32;
1684258Sgblack@eecs.umich.edu            uint16_t *regs16;
1694258Sgblack@eecs.umich.edu            uint8_t *regs8;
1704258Sgblack@eecs.umich.edu            void *regs;
1714258Sgblack@eecs.umich.edu        };
1724259Sgblack@eecs.umich.edu        // Size of cache in bytes.
1734259Sgblack@eecs.umich.edu        size_t size;
1744261Sgblack@eecs.umich.edu        size_t bytes() { return size; }
1754258Sgblack@eecs.umich.edu    };
1764258Sgblack@eecs.umich.edu
1774257Sgblack@eecs.umich.edu    GdbRegCache gdbregs;
1784261Sgblack@eecs.umich.edu
1794261Sgblack@eecs.umich.edu  protected:
1804261Sgblack@eecs.umich.edu    uint8_t getbyte();
1814261Sgblack@eecs.umich.edu    void putbyte(uint8_t b);
1824258Sgblack@eecs.umich.edu
1834258Sgblack@eecs.umich.edu    int recv(char *data, int len);
1844258Sgblack@eecs.umich.edu    void send(const char *data);
1854258Sgblack@eecs.umich.edu
1864258Sgblack@eecs.umich.edu  protected:
1874258Sgblack@eecs.umich.edu    // Machine memory
1884257Sgblack@eecs.umich.edu    virtual bool read(Addr addr, size_t size, char *data);
1894259Sgblack@eecs.umich.edu    virtual bool write(Addr addr, size_t size, const char *data);
1904258Sgblack@eecs.umich.edu
1914258Sgblack@eecs.umich.edu    template <class T> T read(Addr addr);
1924257Sgblack@eecs.umich.edu    template <class T> void write(Addr addr, T data);
1934261Sgblack@eecs.umich.edu
1944261Sgblack@eecs.umich.edu  public:
1954261Sgblack@eecs.umich.edu    BaseRemoteGDB(System *system, ThreadContext *context, size_t cacheSize);
1964258Sgblack@eecs.umich.edu    virtual ~BaseRemoteGDB();
1974260Sgblack@eecs.umich.edu
1984258Sgblack@eecs.umich.edu    void replaceThreadContext(ThreadContext *tc) { context = tc; }
1994258Sgblack@eecs.umich.edu
2004258Sgblack@eecs.umich.edu    void attach(int fd);
2014258Sgblack@eecs.umich.edu    void detach();
2024258Sgblack@eecs.umich.edu    bool isattached();
2034257Sgblack@eecs.umich.edu
2044259Sgblack@eecs.umich.edu    virtual bool acc(Addr addr, size_t len) = 0;
2054259Sgblack@eecs.umich.edu    bool trap(int type);
2064258Sgblack@eecs.umich.edu    virtual bool breakpoint()
2074258Sgblack@eecs.umich.edu    {
2084258Sgblack@eecs.umich.edu        return trap(SIGTRAP);
2094258Sgblack@eecs.umich.edu    }
2104258Sgblack@eecs.umich.edu
2114258Sgblack@eecs.umich.edu  protected:
2124258Sgblack@eecs.umich.edu    virtual void getregs() = 0;
2134258Sgblack@eecs.umich.edu    virtual void setregs() = 0;
2144257Sgblack@eecs.umich.edu
2154258Sgblack@eecs.umich.edu    virtual void clearSingleStep() = 0;
2164260Sgblack@eecs.umich.edu    virtual void setSingleStep() = 0;
2174258Sgblack@eecs.umich.edu
2184258Sgblack@eecs.umich.edu    PCEventQueue *getPcEventQueue();
2194258Sgblack@eecs.umich.edu    EventQueue *getComInstEventQueue();
2204258Sgblack@eecs.umich.edu
2214258Sgblack@eecs.umich.edu    /// Schedule an event which will be triggered "delta" instructions later.
2224258Sgblack@eecs.umich.edu    void scheduleInstCommitEvent(Event *ev, int delta);
2234259Sgblack@eecs.umich.edu    /// Deschedule an instruction count based event.
2244259Sgblack@eecs.umich.edu    void descheduleInstCommitEvent(Event *ev);
2254259Sgblack@eecs.umich.edu
2264259Sgblack@eecs.umich.edu  protected:
2274259Sgblack@eecs.umich.edu    virtual bool checkBpLen(size_t len);
2284259Sgblack@eecs.umich.edu
2294258Sgblack@eecs.umich.edu    class HardBreakpoint : public PCEvent
2304258Sgblack@eecs.umich.edu    {
2314257Sgblack@eecs.umich.edu      private:
2324258Sgblack@eecs.umich.edu        BaseRemoteGDB *gdb;
2334258Sgblack@eecs.umich.edu
2344258Sgblack@eecs.umich.edu      public:
2354258Sgblack@eecs.umich.edu        int refcount;
2364258Sgblack@eecs.umich.edu
2374257Sgblack@eecs.umich.edu      public:
2384258Sgblack@eecs.umich.edu        HardBreakpoint(BaseRemoteGDB *_gdb, Addr addr);
2394260Sgblack@eecs.umich.edu        const std::string name() const { return gdb->name() + ".hwbkpt"; }
2404258Sgblack@eecs.umich.edu
2414258Sgblack@eecs.umich.edu        virtual void process(ThreadContext *tc);
2424258Sgblack@eecs.umich.edu    };
2434257Sgblack@eecs.umich.edu    friend class HardBreakpoint;
2444258Sgblack@eecs.umich.edu
2454260Sgblack@eecs.umich.edu    typedef std::map<Addr, HardBreakpoint *> break_map_t;
2464258Sgblack@eecs.umich.edu    typedef break_map_t::iterator break_iter_t;
2474258Sgblack@eecs.umich.edu    break_map_t hardBreakMap;
2484258Sgblack@eecs.umich.edu
2494257Sgblack@eecs.umich.edu    bool insertSoftBreak(Addr addr, size_t len);
2504258Sgblack@eecs.umich.edu    bool removeSoftBreak(Addr addr, size_t len);
2514260Sgblack@eecs.umich.edu    virtual bool insertHardBreak(Addr addr, size_t len);
2524258Sgblack@eecs.umich.edu    bool removeHardBreak(Addr addr, size_t len);
2534258Sgblack@eecs.umich.edu
2544258Sgblack@eecs.umich.edu  protected:
2554258Sgblack@eecs.umich.edu    void clearTempBreakpoint(Addr &bkpt);
2564258Sgblack@eecs.umich.edu    void setTempBreakpoint(Addr bkpt);
2574257Sgblack@eecs.umich.edu
2584259Sgblack@eecs.umich.edu  public:
2594259Sgblack@eecs.umich.edu    std::string name();
2604259Sgblack@eecs.umich.edu};
2614259Sgblack@eecs.umich.edu
2624259Sgblack@eecs.umich.edutemplate <class T>
2634259Sgblack@eecs.umich.eduinline T
2644259Sgblack@eecs.umich.eduBaseRemoteGDB::read(Addr addr)
2654259Sgblack@eecs.umich.edu{
2664259Sgblack@eecs.umich.edu    T temp;
2674259Sgblack@eecs.umich.edu    read(addr, sizeof(T), (char *)&temp);
2684259Sgblack@eecs.umich.edu    return temp;
2694259Sgblack@eecs.umich.edu}
2704259Sgblack@eecs.umich.edu
2714259Sgblack@eecs.umich.edutemplate <class T>
2724259Sgblack@eecs.umich.eduinline void
2734257Sgblack@eecs.umich.eduBaseRemoteGDB::write(Addr addr, T data)
2744258Sgblack@eecs.umich.edu{ write(addr, sizeof(T), (const char *)&data); }
2754258Sgblack@eecs.umich.edu
2764258Sgblack@eecs.umich.educlass GDBListener
2774258Sgblack@eecs.umich.edu{
2784258Sgblack@eecs.umich.edu  protected:
2794257Sgblack@eecs.umich.edu    class InputEvent : public PollEvent
2804257Sgblack@eecs.umich.edu    {
2814257Sgblack@eecs.umich.edu      protected:
2824257Sgblack@eecs.umich.edu        GDBListener *listener;
2834257Sgblack@eecs.umich.edu
2844259Sgblack@eecs.umich.edu      public:
2854259Sgblack@eecs.umich.edu        InputEvent(GDBListener *l, int fd, int e);
2864259Sgblack@eecs.umich.edu        void process(int revent);
2874259Sgblack@eecs.umich.edu    };
2884257Sgblack@eecs.umich.edu
2894257Sgblack@eecs.umich.edu    friend class InputEvent;
2904257Sgblack@eecs.umich.edu    InputEvent *inputEvent;
2914258Sgblack@eecs.umich.edu
2924258Sgblack@eecs.umich.edu  protected:
2934258Sgblack@eecs.umich.edu    ListenSocket listener;
2944257Sgblack@eecs.umich.edu    BaseRemoteGDB *gdb;
2954259Sgblack@eecs.umich.edu    int port;
2964259Sgblack@eecs.umich.edu
2974259Sgblack@eecs.umich.edu  public:
2984259Sgblack@eecs.umich.edu    GDBListener(BaseRemoteGDB *g, int p);
2994259Sgblack@eecs.umich.edu    ~GDBListener();
3004259Sgblack@eecs.umich.edu
3014259Sgblack@eecs.umich.edu    void accept();
3024257Sgblack@eecs.umich.edu    void listen();
3034257Sgblack@eecs.umich.edu    std::string name();
3044257Sgblack@eecs.umich.edu};
3054257Sgblack@eecs.umich.edu
3064257Sgblack@eecs.umich.edu#endif /* __REMOTE_GDB_H__ */
3074257Sgblack@eecs.umich.edu