remote_gdb.cc revision 12125:0066d9926c1a
16242Sgblack@eecs.umich.edu/*
211575SDylan.Johnson@ARM.com * Copyright 2015 LabWare
37093Sgblack@eecs.umich.edu * Copyright 2014 Google, Inc.
47093Sgblack@eecs.umich.edu * Copyright (c) 2002-2005 The Regents of The University of Michigan
57093Sgblack@eecs.umich.edu * All rights reserved.
67093Sgblack@eecs.umich.edu *
77093Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
87093Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
97093Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
107093Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
117093Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
127093Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
137093Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
146242Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
156242Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
166242Sgblack@eecs.umich.edu * this software without specific prior written permission.
176242Sgblack@eecs.umich.edu *
186242Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
196242Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
206242Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
216242Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
226242Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
236242Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
246242Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
256242Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
266242Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
276242Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
286242Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
296242Sgblack@eecs.umich.edu *
306242Sgblack@eecs.umich.edu * Authors: Nathan Binkert
316242Sgblack@eecs.umich.edu *          Boris Shingarov
326242Sgblack@eecs.umich.edu */
336242Sgblack@eecs.umich.edu
346242Sgblack@eecs.umich.edu/*
356242Sgblack@eecs.umich.edu * Copyright (c) 1990, 1993 The Regents of the University of California
366242Sgblack@eecs.umich.edu * All rights reserved
376242Sgblack@eecs.umich.edu *
386242Sgblack@eecs.umich.edu * This software was developed by the Computer Systems Engineering group
396242Sgblack@eecs.umich.edu * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
406242Sgblack@eecs.umich.edu * contributed to Berkeley.
4110037SARM gem5 Developers *
426242Sgblack@eecs.umich.edu * All advertising materials mentioning features or use of this software
436242Sgblack@eecs.umich.edu * must display the following acknowledgement:
446242Sgblack@eecs.umich.edu *      This product includes software developed by the University of
456242Sgblack@eecs.umich.edu *      California, Lawrence Berkeley Laboratories.
4610037SARM gem5 Developers *
4710037SARM gem5 Developers * Redistribution and use in source and binary forms, with or without
486242Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions
499256SAndreas.Sandberg@arm.com * are met:
506242Sgblack@eecs.umich.edu * 1. Redistributions of source code must retain the above copyright
5110037SARM gem5 Developers *    notice, this list of conditions and the following disclaimer.
5210037SARM gem5 Developers * 2. Redistributions in binary form must reproduce the above copyright
5310037SARM gem5 Developers *    notice, this list of conditions and the following disclaimer in the
546242Sgblack@eecs.umich.edu *    documentation and/or other materials provided with the distribution.
556242Sgblack@eecs.umich.edu * 3. All advertising materials mentioning features or use of this software
566242Sgblack@eecs.umich.edu *    must display the following acknowledgement:
5710037SARM gem5 Developers *      This product includes software developed by the University of
5810037SARM gem5 Developers *      California, Berkeley and its contributors.
5910037SARM gem5 Developers * 4. Neither the name of the University nor the names of its contributors
6010037SARM gem5 Developers *    may be used to endorse or promote products derived from this software
6110037SARM gem5 Developers *    without specific prior written permission.
6210037SARM gem5 Developers *
6310037SARM gem5 Developers * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
6410037SARM gem5 Developers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
6510037SARM gem5 Developers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
6610037SARM gem5 Developers * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
6710037SARM gem5 Developers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
6810037SARM gem5 Developers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
6910037SARM gem5 Developers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
7010037SARM gem5 Developers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
7110037SARM gem5 Developers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
727259Sgblack@eecs.umich.edu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7310037SARM gem5 Developers * SUCH DAMAGE.
7410037SARM gem5 Developers *
7510037SARM gem5 Developers *      @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94
7610037SARM gem5 Developers */
7710037SARM gem5 Developers
7810037SARM gem5 Developers/*-
7910037SARM gem5 Developers * Copyright (c) 2001 The NetBSD Foundation, Inc.
8010037SARM gem5 Developers * All rights reserved.
8110037SARM gem5 Developers *
8210037SARM gem5 Developers * This code is derived from software contributed to The NetBSD Foundation
8310037SARM gem5 Developers * by Jason R. Thorpe.
8410037SARM gem5 Developers *
8510037SARM gem5 Developers * Redistribution and use in source and binary forms, with or without
8610037SARM gem5 Developers * modification, are permitted provided that the following conditions
8710037SARM gem5 Developers * are met:
8810037SARM gem5 Developers * 1. Redistributions of source code must retain the above copyright
898868SMatt.Horsnell@arm.com *    notice, this list of conditions and the following disclaimer.
9010037SARM gem5 Developers * 2. Redistributions in binary form must reproduce the above copyright
9110037SARM gem5 Developers *    notice, this list of conditions and the following disclaimer in the
9210037SARM gem5 Developers *    documentation and/or other materials provided with the distribution.
9310037SARM gem5 Developers * 3. All advertising materials mentioning features or use of this software
9410037SARM gem5 Developers *    must display the following acknowledgement:
9510037SARM gem5 Developers *      This product includes software developed by the NetBSD
9610037SARM gem5 Developers *      Foundation, Inc. and its contributors.
9710037SARM gem5 Developers * 4. Neither the name of The NetBSD Foundation nor the names of its
9810037SARM gem5 Developers *    contributors may be used to endorse or promote products derived
9910037SARM gem5 Developers *    from this software without specific prior written permission.
10010037SARM gem5 Developers *
10110037SARM gem5 Developers * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
10210037SARM gem5 Developers * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
10310037SARM gem5 Developers * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
10410037SARM gem5 Developers * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
10510037SARM gem5 Developers * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
10610037SARM gem5 Developers * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
10710037SARM gem5 Developers * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
10810037SARM gem5 Developers * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
10910037SARM gem5 Developers * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
11010037SARM gem5 Developers * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
11110037SARM gem5 Developers * POSSIBILITY OF SUCH DAMAGE.
11210037SARM gem5 Developers */
11310037SARM gem5 Developers
11410037SARM gem5 Developers/*
11510037SARM gem5 Developers * $NetBSD: kgdb_stub.c,v 1.8 2001/07/07 22:58:00 wdk Exp $
11610037SARM gem5 Developers *
11710037SARM gem5 Developers * Taken from NetBSD
11810037SARM gem5 Developers *
11910037SARM gem5 Developers * "Stub" to allow remote cpu to debug over a serial line using gdb.
12010037SARM gem5 Developers */
12110037SARM gem5 Developers
12210037SARM gem5 Developers#include "base/remote_gdb.hh"
12310037SARM gem5 Developers
12410037SARM gem5 Developers#include <sys/signal.h>
12510037SARM gem5 Developers#include <unistd.h>
12610037SARM gem5 Developers
12710037SARM gem5 Developers#include <csignal>
12810037SARM gem5 Developers#include <cstdint>
12910037SARM gem5 Developers#include <cstdio>
13010037SARM gem5 Developers#include <string>
13110037SARM gem5 Developers
13210037SARM gem5 Developers#include "arch/vtophys.hh"
13310037SARM gem5 Developers#include "base/intmath.hh"
13410037SARM gem5 Developers#include "base/socket.hh"
13510037SARM gem5 Developers#include "base/trace.hh"
13610037SARM gem5 Developers#include "config/the_isa.hh"
13710037SARM gem5 Developers#include "cpu/base.hh"
13810037SARM gem5 Developers#include "cpu/static_inst.hh"
13910037SARM gem5 Developers#include "cpu/thread_context.hh"
14010037SARM gem5 Developers#include "debug/GDBAll.hh"
1417351Sgblack@eecs.umich.edu#include "mem/fs_translating_port_proxy.hh"
14210037SARM gem5 Developers#include "mem/port.hh"
14310037SARM gem5 Developers#include "mem/se_translating_port_proxy.hh"
14410037SARM gem5 Developers#include "sim/full_system.hh"
14510037SARM gem5 Developers#include "sim/system.hh"
14610037SARM gem5 Developers
14710037SARM gem5 Developersusing namespace std;
14810037SARM gem5 Developersusing namespace TheISA;
14910037SARM gem5 Developers
15010037SARM gem5 Developersstatic const char GDBStart = '$';
15110037SARM gem5 Developersstatic const char GDBEnd = '#';
15210037SARM gem5 Developersstatic const char GDBGoodP = '+';
15310037SARM gem5 Developersstatic const char GDBBadP = '-';
15410037SARM gem5 Developers
15510037SARM gem5 Developersstatic const int GDBPacketBufLen = 1024;
15610037SARM gem5 Developers
15710037SARM gem5 Developers#ifndef NDEBUG
15810037SARM gem5 Developersvector<BaseRemoteGDB *> debuggers;
15910037SARM gem5 Developers
16010037SARM gem5 Developersvoid
16110037SARM gem5 Developersdebugger()
16210037SARM gem5 Developers{
16310037SARM gem5 Developers    static int current_debugger = -1;
16410037SARM gem5 Developers    if (current_debugger >= 0 && current_debugger < (int)debuggers.size()) {
16510037SARM gem5 Developers        BaseRemoteGDB *gdb = debuggers[current_debugger];
16610037SARM gem5 Developers        if (!gdb->isattached())
16710037SARM gem5 Developers            gdb->listener->accept();
16810037SARM gem5 Developers        if (gdb->isattached())
16910037SARM gem5 Developers            gdb->trap(SIGILL);
17010037SARM gem5 Developers    }
17110037SARM gem5 Developers}
17210037SARM gem5 Developers#endif
17310037SARM gem5 Developers
17410037SARM gem5 Developers///////////////////////////////////////////////////////////
17510037SARM gem5 Developers//
17610037SARM gem5 Developers//
17710037SARM gem5 Developers//
17810037SARM gem5 Developers
17910037SARM gem5 DevelopersGDBListener::InputEvent::InputEvent(GDBListener *l, int fd, int e)
18010037SARM gem5 Developers    : PollEvent(fd, e), listener(l)
18110037SARM gem5 Developers{}
18210037SARM gem5 Developers
18310037SARM gem5 Developersvoid
18410037SARM gem5 DevelopersGDBListener::InputEvent::process(int revent)
18510037SARM gem5 Developers{
18610037SARM gem5 Developers    listener->accept();
18710037SARM gem5 Developers}
18810037SARM gem5 Developers
18910037SARM gem5 DevelopersGDBListener::GDBListener(BaseRemoteGDB *g, int p)
19010037SARM gem5 Developers    : inputEvent(NULL), gdb(g), port(p)
19110037SARM gem5 Developers{
19210037SARM gem5 Developers    assert(!gdb->listener);
19310037SARM gem5 Developers    gdb->listener = this;
19410037SARM gem5 Developers}
19510037SARM gem5 Developers
19610037SARM gem5 DevelopersGDBListener::~GDBListener()
19710037SARM gem5 Developers{
19810037SARM gem5 Developers    delete inputEvent;
19910037SARM gem5 Developers}
20010037SARM gem5 Developers
20110037SARM gem5 Developersstring
20210037SARM gem5 DevelopersGDBListener::name()
20310037SARM gem5 Developers{
20410037SARM gem5 Developers    return gdb->name() + ".listener";
20510037SARM gem5 Developers}
20610037SARM gem5 Developers
20710037SARM gem5 Developersvoid
20810037SARM gem5 DevelopersGDBListener::listen()
20910037SARM gem5 Developers{
21010037SARM gem5 Developers    if (ListenSocket::allDisabled()) {
21110037SARM gem5 Developers        warn_once("Sockets disabled, not accepting gdb connections");
21210037SARM gem5 Developers        return;
21310037SARM gem5 Developers    }
21410037SARM gem5 Developers
21510037SARM gem5 Developers    while (!listener.listen(port, true)) {
21610037SARM gem5 Developers        DPRINTF(GDBMisc, "Can't bind port %d\n", port);
21710037SARM gem5 Developers        port++;
21810037SARM gem5 Developers    }
21910037SARM gem5 Developers
22010037SARM gem5 Developers    inputEvent = new InputEvent(this, listener.getfd(), POLLIN);
22110037SARM gem5 Developers    pollQueue.schedule(inputEvent);
22210037SARM gem5 Developers
22310037SARM gem5 Developers#ifndef NDEBUG
22410037SARM gem5 Developers    gdb->number = debuggers.size();
22510037SARM gem5 Developers    debuggers.push_back(gdb);
22610037SARM gem5 Developers#endif
22710037SARM gem5 Developers
22810037SARM gem5 Developers#ifndef NDEBUG
22910037SARM gem5 Developers    ccprintf(cerr, "%d: %s: listening for remote gdb #%d on port %d\n",
23010037SARM gem5 Developers             curTick(), name(), gdb->number, port);
23110037SARM gem5 Developers#else
23210037SARM gem5 Developers    ccprintf(cerr, "%d: %s: listening for remote gdb on port %d\n",
23310037SARM gem5 Developers             curTick(), name(), port);
23410037SARM gem5 Developers#endif
23510037SARM gem5 Developers}
23610037SARM gem5 Developers
23710037SARM gem5 Developersvoid
23810037SARM gem5 DevelopersGDBListener::accept()
23910037SARM gem5 Developers{
24010037SARM gem5 Developers    if (!listener.islistening())
24110037SARM gem5 Developers        panic("GDBListener::accept(): cannot accept if we're not listening!");
24210037SARM gem5 Developers
24310037SARM gem5 Developers    int sfd = listener.accept(true);
24410037SARM gem5 Developers
24510037SARM gem5 Developers    if (sfd != -1) {
24610037SARM gem5 Developers        if (gdb->isattached())
24710037SARM gem5 Developers            close(sfd);
24810037SARM gem5 Developers        else
24910037SARM gem5 Developers            gdb->attach(sfd);
25010037SARM gem5 Developers    }
25110037SARM gem5 Developers}
25210037SARM gem5 Developers
25310037SARM gem5 Developersint
25410037SARM gem5 DevelopersGDBListener::getPort() const
25510037SARM gem5 Developers{
25610037SARM gem5 Developers    panic_if(!listener.islistening(),
25710037SARM gem5 Developers             "Remote GDB port is unknown until GDBListener::listen() has "
25810037SARM gem5 Developers             "been called.\n");
25910037SARM gem5 Developers
26010037SARM gem5 Developers    return port;
26110037SARM gem5 Developers}
26210037SARM gem5 Developers
26310037SARM gem5 DevelopersBaseRemoteGDB::InputEvent::InputEvent(BaseRemoteGDB *g, int fd, int e)
26410037SARM gem5 Developers    : PollEvent(fd, e), gdb(g)
26510037SARM gem5 Developers{}
26610037SARM gem5 Developers
26710037SARM gem5 Developersvoid
26810037SARM gem5 DevelopersBaseRemoteGDB::InputEvent::process(int revent)
26910037SARM gem5 Developers{
27010037SARM gem5 Developers    if (gdb->trapEvent.scheduled()) {
27110037SARM gem5 Developers        warn("GDB trap event has already been scheduled! "
27210037SARM gem5 Developers             "Ignoring this input event.");
27310037SARM gem5 Developers        return;
27410037SARM gem5 Developers    }
27510037SARM gem5 Developers
27610037SARM gem5 Developers    if (revent & POLLIN) {
27710037SARM gem5 Developers        gdb->trapEvent.type(SIGILL);
27810037SARM gem5 Developers        gdb->scheduleInstCommitEvent(&gdb->trapEvent, 0);
27910037SARM gem5 Developers    } else if (revent & POLLNVAL) {
28010037SARM gem5 Developers        gdb->descheduleInstCommitEvent(&gdb->trapEvent);
28110037SARM gem5 Developers        gdb->detach();
28210037SARM gem5 Developers    }
28310037SARM gem5 Developers}
28410037SARM gem5 Developers
28510037SARM gem5 Developersvoid
28610037SARM gem5 DevelopersBaseRemoteGDB::TrapEvent::process()
28710037SARM gem5 Developers{
28810037SARM gem5 Developers    gdb->trap(_type);
28910037SARM gem5 Developers}
29010037SARM gem5 Developers
29110037SARM gem5 Developersvoid
29210037SARM gem5 DevelopersBaseRemoteGDB::processSingleStepEvent()
29310037SARM gem5 Developers{
29410037SARM gem5 Developers    if (!singleStepEvent.scheduled())
29510037SARM gem5 Developers        scheduleInstCommitEvent(&singleStepEvent, 1);
29610037SARM gem5 Developers    trap(SIGTRAP);
29710037SARM gem5 Developers}
29810037SARM gem5 Developers
29910037SARM gem5 DevelopersBaseRemoteGDB::BaseRemoteGDB(System *_system, ThreadContext *c) :
30010037SARM gem5 Developers        inputEvent(NULL), trapEvent(this), listener(NULL), number(-1),
30110037SARM gem5 Developers        fd(-1), active(false), attached(false), system(_system),
30210037SARM gem5 Developers        context(c),
30310037SARM gem5 Developers        singleStepEvent([this]{ processSingleStepEvent(); }, name())
30410037SARM gem5 Developers{
30510037SARM gem5 Developers}
30610037SARM gem5 Developers
30710037SARM gem5 DevelopersBaseRemoteGDB::~BaseRemoteGDB()
30810037SARM gem5 Developers{
30910037SARM gem5 Developers    if (inputEvent)
31010037SARM gem5 Developers        delete inputEvent;
31110037SARM gem5 Developers}
31210037SARM gem5 Developers
31310037SARM gem5 Developersstring
31410037SARM gem5 DevelopersBaseRemoteGDB::name()
31510037SARM gem5 Developers{
31610037SARM gem5 Developers    return system->name() + ".remote_gdb";
31710037SARM gem5 Developers}
31810037SARM gem5 Developers
31910037SARM gem5 Developersbool
32010037SARM gem5 DevelopersBaseRemoteGDB::isattached()
32110037SARM gem5 Developers{ return attached; }
32210037SARM gem5 Developers
32310037SARM gem5 Developersvoid
32410037SARM gem5 DevelopersBaseRemoteGDB::attach(int f)
32510037SARM gem5 Developers{
32610037SARM gem5 Developers    fd = f;
32710037SARM gem5 Developers
32810037SARM gem5 Developers    inputEvent = new InputEvent(this, fd, POLLIN);
32910037SARM gem5 Developers    pollQueue.schedule(inputEvent);
33010037SARM gem5 Developers
33110037SARM gem5 Developers    attached = true;
33210037SARM gem5 Developers    DPRINTFN("remote gdb attached\n");
33310037SARM gem5 Developers}
33410037SARM gem5 Developers
33510037SARM gem5 Developersvoid
33610037SARM gem5 DevelopersBaseRemoteGDB::detach()
33710037SARM gem5 Developers{
33810037SARM gem5 Developers    attached = false;
33910037SARM gem5 Developers    active = false;
34010037SARM gem5 Developers    clearSingleStep();
34110037SARM gem5 Developers    close(fd);
34210037SARM gem5 Developers    fd = -1;
34310037SARM gem5 Developers
34410037SARM gem5 Developers    pollQueue.remove(inputEvent);
34510037SARM gem5 Developers    DPRINTFN("remote gdb detached\n");
34610037SARM gem5 Developers}
34710037SARM gem5 Developers
34810037SARM gem5 Developers/////////////////////////
34910037SARM gem5 Developers//
35010037SARM gem5 Developers//
35110037SARM gem5 Developers
35210037SARM gem5 Developersuint8_t
35310037SARM gem5 DevelopersBaseRemoteGDB::getbyte()
35410037SARM gem5 Developers{
35510037SARM gem5 Developers    uint8_t b;
35610037SARM gem5 Developers    if (::read(fd, &b, sizeof(b)) == sizeof(b))
35710037SARM gem5 Developers        return b;
35810037SARM gem5 Developers
35910037SARM gem5 Developers    throw BadClient("Couldn't read data from debugger.");
36010037SARM gem5 Developers}
36110037SARM gem5 Developers
36210037SARM gem5 Developersvoid
36310037SARM gem5 DevelopersBaseRemoteGDB::putbyte(uint8_t b)
36410037SARM gem5 Developers{
36510037SARM gem5 Developers    if (::write(fd, &b, sizeof(b)) == sizeof(b))
36610037SARM gem5 Developers        return;
36710037SARM gem5 Developers
36810037SARM gem5 Developers    throw BadClient("Couldn't write data to the debugger.");
36910037SARM gem5 Developers}
37010037SARM gem5 Developers
37110037SARM gem5 Developers// Send a packet to gdb
37210037SARM gem5 Developersvoid
37310037SARM gem5 DevelopersBaseRemoteGDB::send(const char *bp)
37410037SARM gem5 Developers{
37510037SARM gem5 Developers    const char *p;
37610037SARM gem5 Developers    uint8_t csum, c;
37710037SARM gem5 Developers
37810037SARM gem5 Developers    DPRINTF(GDBSend, "send:  %s\n", bp);
37910037SARM gem5 Developers
38010037SARM gem5 Developers    do {
38110037SARM gem5 Developers        p = bp;
38210037SARM gem5 Developers        // Start sending a packet
3837259Sgblack@eecs.umich.edu        putbyte(GDBStart);
38410037SARM gem5 Developers        // Send the contents, and also keep a check sum.
38510037SARM gem5 Developers        for (csum = 0; (c = *p); p++) {
38610037SARM gem5 Developers            putbyte(c);
38710037SARM gem5 Developers            csum += c;
38810037SARM gem5 Developers        }
38910037SARM gem5 Developers        // Send the ending character.
39010037SARM gem5 Developers        putbyte(GDBEnd);
39110037SARM gem5 Developers        // Send the checksum.
39210037SARM gem5 Developers        putbyte(i2digit(csum >> 4));
39310037SARM gem5 Developers        putbyte(i2digit(csum));
39410037SARM gem5 Developers        // Try transmitting over and over again until the other end doesn't
39510037SARM gem5 Developers        // send an error back.
39610037SARM gem5 Developers        c = getbyte();
39710037SARM gem5 Developers    } while ((c & 0x7f) == GDBBadP);
39810037SARM gem5 Developers}
39910037SARM gem5 Developers
40010037SARM gem5 Developers// Receive a packet from gdb
40110037SARM gem5 Developersint
40210037SARM gem5 DevelopersBaseRemoteGDB::recv(char *bp, int maxlen)
40310037SARM gem5 Developers{
40410037SARM gem5 Developers    char *p;
40510037SARM gem5 Developers    uint8_t c;
40610037SARM gem5 Developers    int csum;
40710037SARM gem5 Developers    int len;
40810037SARM gem5 Developers
40910037SARM gem5 Developers    do {
41010037SARM gem5 Developers        p = bp;
41110037SARM gem5 Developers        csum = len = 0;
41210037SARM gem5 Developers        // Find the beginning of a packet
41310037SARM gem5 Developers        while ((c = getbyte()) != GDBStart);
41410037SARM gem5 Developers
41510037SARM gem5 Developers        // Read until you find the end of the data in the packet, and keep
41610037SARM gem5 Developers        // track of the check sum.
41710037SARM gem5 Developers        while (len < maxlen) {
41810037SARM gem5 Developers            c = getbyte();
41910037SARM gem5 Developers            if (c == GDBEnd)
42010037SARM gem5 Developers                break;
42110037SARM gem5 Developers            c &= 0x7f;
42210037SARM gem5 Developers            csum += c;
42310037SARM gem5 Developers            *p++ = c;
42410037SARM gem5 Developers            len++;
4257259Sgblack@eecs.umich.edu        }
42610037SARM gem5 Developers
42710037SARM gem5 Developers        // Mask the check sum, and terminate the command string.
42810037SARM gem5 Developers        csum &= 0xff;
42910037SARM gem5 Developers        *p = '\0';
43010037SARM gem5 Developers
43110037SARM gem5 Developers        // If the command was too long, report an error.
43210037SARM gem5 Developers        if (len >= maxlen) {
43310037SARM gem5 Developers            putbyte(GDBBadP);
43410037SARM gem5 Developers            continue;
43510037SARM gem5 Developers        }
43610037SARM gem5 Developers
43710037SARM gem5 Developers        // Bring in the checksum. If the check sum matches, csum will be 0.
43810037SARM gem5 Developers        csum -= digit2i(getbyte()) * 16;
43910037SARM gem5 Developers        csum -= digit2i(getbyte());
44010037SARM gem5 Developers
44110037SARM gem5 Developers        // If the check sum was correct
44210037SARM gem5 Developers        if (csum == 0) {
44310037SARM gem5 Developers            // Report that the packet was received correctly
44410037SARM gem5 Developers            putbyte(GDBGoodP);
44510037SARM gem5 Developers            // Sequence present?
44610037SARM gem5 Developers            if (bp[2] == ':') {
44710037SARM gem5 Developers                putbyte(bp[0]);
44810037SARM gem5 Developers                putbyte(bp[1]);
44910037SARM gem5 Developers                len -= 3;
45010037SARM gem5 Developers                memcpy(bp, bp+3, len);
45110037SARM gem5 Developers            }
45210037SARM gem5 Developers            break;
45310037SARM gem5 Developers        }
45410037SARM gem5 Developers        // Otherwise, report that there was a mistake.
45510037SARM gem5 Developers        putbyte(GDBBadP);
45610037SARM gem5 Developers    } while (1);
45710037SARM gem5 Developers
45810037SARM gem5 Developers    DPRINTF(GDBRecv, "recv:  %s\n", bp);
45910037SARM gem5 Developers
46010037SARM gem5 Developers    return len;
46110037SARM gem5 Developers}
46210037SARM gem5 Developers
46310037SARM gem5 Developers// Read bytes from kernel address space for debugger.
46410037SARM gem5 Developersbool
46510037SARM gem5 DevelopersBaseRemoteGDB::read(Addr vaddr, size_t size, char *data)
46610037SARM gem5 Developers{
46710037SARM gem5 Developers    static Addr lastaddr = 0;
46810037SARM gem5 Developers    static size_t lastsize = 0;
46910037SARM gem5 Developers
47010037SARM gem5 Developers    if (vaddr < 10) {
47110037SARM gem5 Developers      DPRINTF(GDBRead, "read:  reading memory location zero!\n");
47210037SARM gem5 Developers      vaddr = lastaddr + lastsize;
47310037SARM gem5 Developers    }
47410037SARM gem5 Developers
47510037SARM gem5 Developers    DPRINTF(GDBRead, "read:  addr=%#x, size=%d", vaddr, size);
47610037SARM gem5 Developers
47710037SARM gem5 Developers    if (FullSystem) {
47810037SARM gem5 Developers        FSTranslatingPortProxy &proxy = context->getVirtProxy();
47910037SARM gem5 Developers        proxy.readBlob(vaddr, (uint8_t*)data, size);
48010037SARM gem5 Developers    } else {
48110037SARM gem5 Developers        SETranslatingPortProxy &proxy = context->getMemProxy();
48210037SARM gem5 Developers        proxy.readBlob(vaddr, (uint8_t*)data, size);
48310037SARM gem5 Developers    }
48410037SARM gem5 Developers
48510037SARM gem5 Developers#if TRACING_ON
48610037SARM gem5 Developers    if (DTRACE(GDBRead)) {
48710037SARM gem5 Developers        if (DTRACE(GDBExtra)) {
48810037SARM gem5 Developers            char buf[1024];
48910037SARM gem5 Developers            mem2hex(buf, data, size);
49010037SARM gem5 Developers            DPRINTFNR(": %s\n", buf);
49110037SARM gem5 Developers        } else
49210037SARM gem5 Developers            DPRINTFNR("\n");
49310037SARM gem5 Developers    }
49410037SARM gem5 Developers#endif
49510037SARM gem5 Developers
49610037SARM gem5 Developers    return true;
49710037SARM gem5 Developers}
49810037SARM gem5 Developers
49910037SARM gem5 Developers// Write bytes to kernel address space for debugger.
50010037SARM gem5 Developersbool
50110037SARM gem5 DevelopersBaseRemoteGDB::write(Addr vaddr, size_t size, const char *data)
50210037SARM gem5 Developers{
50310037SARM gem5 Developers    static Addr lastaddr = 0;
50410037SARM gem5 Developers    static size_t lastsize = 0;
50510037SARM gem5 Developers
50610037SARM gem5 Developers    if (vaddr < 10) {
50710037SARM gem5 Developers      DPRINTF(GDBWrite, "write: writing memory location zero!\n");
50810037SARM gem5 Developers      vaddr = lastaddr + lastsize;
50910037SARM gem5 Developers    }
51010037SARM gem5 Developers
51110037SARM gem5 Developers    if (DTRACE(GDBWrite)) {
51210037SARM gem5 Developers        DPRINTFN("write: addr=%#x, size=%d", vaddr, size);
51310037SARM gem5 Developers        if (DTRACE(GDBExtra)) {
51410037SARM gem5 Developers            char buf[1024];
51510037SARM gem5 Developers            mem2hex(buf, data, size);
51610037SARM gem5 Developers            DPRINTFNR(": %s\n", buf);
51710037SARM gem5 Developers        } else
51810037SARM gem5 Developers            DPRINTFNR("\n");
51910037SARM gem5 Developers    }
52010037SARM gem5 Developers    if (FullSystem) {
52110037SARM gem5 Developers        FSTranslatingPortProxy &proxy = context->getVirtProxy();
52210037SARM gem5 Developers        proxy.writeBlob(vaddr, (uint8_t*)data, size);
52310037SARM gem5 Developers    } else {
52410037SARM gem5 Developers        SETranslatingPortProxy &proxy = context->getMemProxy();
52510037SARM gem5 Developers        proxy.writeBlob(vaddr, (uint8_t*)data, size);
52610037SARM gem5 Developers    }
52710037SARM gem5 Developers
52810037SARM gem5 Developers    return true;
52910037SARM gem5 Developers}
53010037SARM gem5 Developers
53110037SARM gem5 Developersvoid
53210037SARM gem5 DevelopersBaseRemoteGDB::clearSingleStep()
53310037SARM gem5 Developers{
53410037SARM gem5 Developers    descheduleInstCommitEvent(&singleStepEvent);
53510037SARM gem5 Developers}
53610037SARM gem5 Developers
53710037SARM gem5 Developersvoid
53810037SARM gem5 DevelopersBaseRemoteGDB::setSingleStep()
53910037SARM gem5 Developers{
54010037SARM gem5 Developers    if (!singleStepEvent.scheduled())
54110037SARM gem5 Developers        scheduleInstCommitEvent(&singleStepEvent, 1);
54210037SARM gem5 Developers}
54310037SARM gem5 Developers
54410037SARM gem5 DevelopersPCEventQueue *BaseRemoteGDB::getPcEventQueue()
54510037SARM gem5 Developers{
54610037SARM gem5 Developers    return &system->pcEventQueue;
54710037SARM gem5 Developers}
54810037SARM gem5 Developers
54910037SARM gem5 DevelopersEventQueue *
55010037SARM gem5 DevelopersBaseRemoteGDB::getComInstEventQueue()
55110037SARM gem5 Developers{
55210037SARM gem5 Developers    BaseCPU *cpu = context->getCpuPtr();
55310037SARM gem5 Developers    return cpu->comInstEventQueue[context->threadId()];
55410037SARM gem5 Developers}
55510037SARM gem5 Developers
55610037SARM gem5 Developersvoid
55710037SARM gem5 DevelopersBaseRemoteGDB::scheduleInstCommitEvent(Event *ev, int delta)
55810037SARM gem5 Developers{
55910037SARM gem5 Developers    EventQueue *eq = getComInstEventQueue();
56010037SARM gem5 Developers    // Here "ticks" aren't simulator ticks which measure time, they're
56110037SARM gem5 Developers    // instructions committed by the CPU.
56210037SARM gem5 Developers    eq->schedule(ev, eq->getCurTick() + delta);
56310037SARM gem5 Developers}
56410037SARM gem5 Developers
56510037SARM gem5 Developersvoid
56610037SARM gem5 DevelopersBaseRemoteGDB::descheduleInstCommitEvent(Event *ev)
56710037SARM gem5 Developers{
56810037SARM gem5 Developers    if (ev->scheduled())
56910037SARM gem5 Developers        getComInstEventQueue()->deschedule(ev);
57010037SARM gem5 Developers}
57110037SARM gem5 Developers
57210037SARM gem5 Developersbool
57310037SARM gem5 DevelopersBaseRemoteGDB::checkBpLen(size_t len)
57410037SARM gem5 Developers{
57510037SARM gem5 Developers    return len == sizeof(MachInst);
57610037SARM gem5 Developers}
57710037SARM gem5 Developers
57810037SARM gem5 DevelopersBaseRemoteGDB::HardBreakpoint::HardBreakpoint(BaseRemoteGDB *_gdb, Addr pc)
57910037SARM gem5 Developers    : PCEvent(_gdb->getPcEventQueue(), "HardBreakpoint Event", pc),
58010037SARM gem5 Developers      gdb(_gdb), refcount(0)
58110037SARM gem5 Developers{
58210037SARM gem5 Developers    DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc);
58310037SARM gem5 Developers}
58410037SARM gem5 Developers
58510037SARM gem5 Developersvoid
58610037SARM gem5 DevelopersBaseRemoteGDB::HardBreakpoint::process(ThreadContext *tc)
58710037SARM gem5 Developers{
58810037SARM gem5 Developers    DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc());
58910037SARM gem5 Developers
59010037SARM gem5 Developers    if (tc == gdb->context)
59110037SARM gem5 Developers        gdb->trap(SIGTRAP);
59210037SARM gem5 Developers}
59310037SARM gem5 Developers
59410037SARM gem5 Developersvoid
59510037SARM gem5 DevelopersBaseRemoteGDB::insertSoftBreak(Addr addr, size_t len)
59610037SARM gem5 Developers{
59710037SARM gem5 Developers    if (!checkBpLen(len))
59810037SARM gem5 Developers        throw BadClient("Invalid breakpoint length\n");
59910037SARM gem5 Developers
60010037SARM gem5 Developers    return insertHardBreak(addr, len);
60110037SARM gem5 Developers}
60210037SARM gem5 Developers
60310037SARM gem5 Developersvoid
60410037SARM gem5 DevelopersBaseRemoteGDB::removeSoftBreak(Addr addr, size_t len)
60510037SARM gem5 Developers{
60610037SARM gem5 Developers    if (!checkBpLen(len))
60710037SARM gem5 Developers        throw BadClient("Invalid breakpoint length.\n");
60810037SARM gem5 Developers
60910037SARM gem5 Developers    return removeHardBreak(addr, len);
61010037SARM gem5 Developers}
61110037SARM gem5 Developers
61210037SARM gem5 Developersvoid
61310037SARM gem5 DevelopersBaseRemoteGDB::insertHardBreak(Addr addr, size_t len)
61410037SARM gem5 Developers{
61510037SARM gem5 Developers    if (!checkBpLen(len))
61610037SARM gem5 Developers        throw BadClient("Invalid breakpoint length\n");
61710037SARM gem5 Developers
61810037SARM gem5 Developers    DPRINTF(GDBMisc, "Inserting hardware breakpoint at %#x\n", addr);
61910037SARM gem5 Developers
62010037SARM gem5 Developers    HardBreakpoint *&bkpt = hardBreakMap[addr];
62110037SARM gem5 Developers    if (bkpt == 0)
62210037SARM gem5 Developers        bkpt = new HardBreakpoint(this, addr);
62310037SARM gem5 Developers
62410037SARM gem5 Developers    bkpt->refcount++;
62510037SARM gem5 Developers}
62610037SARM gem5 Developers
62710037SARM gem5 Developersvoid
62810037SARM gem5 DevelopersBaseRemoteGDB::removeHardBreak(Addr addr, size_t len)
62910037SARM gem5 Developers{
63010037SARM gem5 Developers    if (!checkBpLen(len))
63110037SARM gem5 Developers        throw BadClient("Invalid breakpoint length\n");
63210037SARM gem5 Developers
63310037SARM gem5 Developers    DPRINTF(GDBMisc, "Removing hardware breakpoint at %#x\n", addr);
63410037SARM gem5 Developers
63510037SARM gem5 Developers    break_iter_t i = hardBreakMap.find(addr);
63610037SARM gem5 Developers    if (i == hardBreakMap.end())
63710037SARM gem5 Developers        throw CmdError("E0C");
63810037SARM gem5 Developers
63910037SARM gem5 Developers    HardBreakpoint *hbp = (*i).second;
64010037SARM gem5 Developers    if (--hbp->refcount == 0) {
64110037SARM gem5 Developers        delete hbp;
64210037SARM gem5 Developers        hardBreakMap.erase(i);
64310037SARM gem5 Developers    }
64410037SARM gem5 Developers}
64510037SARM gem5 Developers
64610037SARM gem5 Developersvoid
64710037SARM gem5 DevelopersBaseRemoteGDB::setTempBreakpoint(Addr bkpt)
64810037SARM gem5 Developers{
64910037SARM gem5 Developers    DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", bkpt);
65010037SARM gem5 Developers    insertHardBreak(bkpt, sizeof(TheISA::MachInst));
65110037SARM gem5 Developers}
65210037SARM gem5 Developers
65310037SARM gem5 Developersvoid
65410037SARM gem5 DevelopersBaseRemoteGDB::clearTempBreakpoint(Addr &bkpt)
65510037SARM gem5 Developers{
65610037SARM gem5 Developers    DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", bkpt);
65710037SARM gem5 Developers    removeHardBreak(bkpt, sizeof(TheISA::MachInst));
65810037SARM gem5 Developers    bkpt = 0;
65910037SARM gem5 Developers}
66010037SARM gem5 Developers
66110037SARM gem5 Developersenum GdbBreakpointType {
66210037SARM gem5 Developers    GdbSoftBp = '0',
66310037SARM gem5 Developers    GdbHardBp = '1',
66410037SARM gem5 Developers    GdbWriteWp = '2',
66510037SARM gem5 Developers    GdbReadWp = '3',
66610856SCurtis.Dunham@arm.com    GdbAccWp = '4',
6677259Sgblack@eecs.umich.edu};
66810037SARM gem5 Developers
66910856SCurtis.Dunham@arm.comconst char *
67010856SCurtis.Dunham@arm.comBaseRemoteGDB::break_type(char c)
67110856SCurtis.Dunham@arm.com{
67210856SCurtis.Dunham@arm.com    switch(c) {
67310856SCurtis.Dunham@arm.com      case GdbSoftBp: return "software breakpoint";
67410856SCurtis.Dunham@arm.com      case GdbHardBp: return "hardware breakpoint";
67510037SARM gem5 Developers      case GdbWriteWp: return "write watchpoint";
67610856SCurtis.Dunham@arm.com      case GdbReadWp: return "read watchpoint";
6776261Sgblack@eecs.umich.edu      case GdbAccWp: return "access watchpoint";
6786261Sgblack@eecs.umich.edu      default: return "unknown breakpoint/watchpoint";
67910037SARM gem5 Developers    }
68010037SARM gem5 Developers}
68110506SAli.Saidi@ARM.com
68210506SAli.Saidi@ARM.comstd::map<char, GdbCommand> BaseRemoteGDB::command_map = {
68310037SARM gem5 Developers    // last signal
68410037SARM gem5 Developers    { '?', { "KGDB_SIGNAL", &BaseRemoteGDB::cmd_signal } },
68510037SARM gem5 Developers    // set baud (deprecated)
68610037SARM gem5 Developers    { 'b', { "KGDB_SET_BAUD", &BaseRemoteGDB::cmd_unsupported } },
68710037SARM gem5 Developers    // set breakpoint (deprecated)
68810037SARM gem5 Developers    { 'B', { "KGDB_SET_BREAK", &BaseRemoteGDB::cmd_unsupported } },
68910037SARM gem5 Developers    // resume
69010037SARM gem5 Developers    { 'c', { "KGDB_CONT", &BaseRemoteGDB::cmd_cont } },
69110037SARM gem5 Developers    // continue with signal
69210037SARM gem5 Developers    { 'C', { "KGDB_ASYNC_CONT", &BaseRemoteGDB::cmd_async_cont } },
69310037SARM gem5 Developers    // toggle debug flags (deprecated)
69410037SARM gem5 Developers    { 'd', { "KGDB_DEBUG", &BaseRemoteGDB::cmd_unsupported } },
69510037SARM gem5 Developers    // detach remote gdb
69610037SARM gem5 Developers    { 'D', { "KGDB_DETACH", &BaseRemoteGDB::cmd_detach } },
69710037SARM gem5 Developers    // read general registers
69810037SARM gem5 Developers    { 'g', { "KGDB_REG_R", &BaseRemoteGDB::cmd_reg_r } },
69910037SARM gem5 Developers    // write general registers
70010037SARM gem5 Developers    { 'G', { "KGDB_REG_W", &BaseRemoteGDB::cmd_reg_w } },
70110037SARM gem5 Developers    // set thread
70210037SARM gem5 Developers    { 'H', { "KGDB_SET_THREAD", &BaseRemoteGDB::cmd_set_thread } },
70310037SARM gem5 Developers    // step a single cycle
70410037SARM gem5 Developers    { 'i', { "KGDB_CYCLE_STEP", &BaseRemoteGDB::cmd_unsupported } },
70510037SARM gem5 Developers    // signal then cycle step
70610037SARM gem5 Developers    { 'I', { "KGDB_SIG_CYCLE_STEP", &BaseRemoteGDB::cmd_unsupported } },
70710037SARM gem5 Developers    // kill program
70810037SARM gem5 Developers    { 'k', { "KGDB_KILL", &BaseRemoteGDB::cmd_detach } },
70910037SARM gem5 Developers    // read memory
71010037SARM gem5 Developers    { 'm', { "KGDB_MEM_R", &BaseRemoteGDB::cmd_mem_r } },
71110037SARM gem5 Developers    // write memory
71210037SARM gem5 Developers    { 'M', { "KGDB_MEM_W", &BaseRemoteGDB::cmd_mem_w } },
71310037SARM gem5 Developers    // read register
71410037SARM gem5 Developers    { 'p', { "KGDB_READ_REG", &BaseRemoteGDB::cmd_unsupported } },
71510037SARM gem5 Developers    // write register
71610037SARM gem5 Developers    { 'P', { "KGDB_SET_REG", &BaseRemoteGDB::cmd_unsupported } },
71710037SARM gem5 Developers    // query variable
71810037SARM gem5 Developers    { 'q', { "KGDB_QUERY_VAR", &BaseRemoteGDB::cmd_query_var } },
71910037SARM gem5 Developers    // set variable
72010037SARM gem5 Developers    { 'Q', { "KGDB_SET_VAR", &BaseRemoteGDB::cmd_unsupported } },
72110037SARM gem5 Developers    // reset system (deprecated)
7228868SMatt.Horsnell@arm.com    { 'r', { "KGDB_RESET", &BaseRemoteGDB::cmd_unsupported } },
7238868SMatt.Horsnell@arm.com    // step
72410037SARM gem5 Developers    { 's', { "KGDB_STEP", &BaseRemoteGDB::cmd_step } },
72510037SARM gem5 Developers    // signal and step
72610037SARM gem5 Developers    { 'S', { "KGDB_ASYNC_STEP", &BaseRemoteGDB::cmd_async_step } },
72710037SARM gem5 Developers    // find out if the thread is alive
72810037SARM gem5 Developers    { 'T', { "KGDB_THREAD_ALIVE", &BaseRemoteGDB::cmd_unsupported } },
7298868SMatt.Horsnell@arm.com    // target exited
73010037SARM gem5 Developers    { 'W', { "KGDB_TARGET_EXIT", &BaseRemoteGDB::cmd_unsupported } },
7317259Sgblack@eecs.umich.edu    // write memory
7327259Sgblack@eecs.umich.edu    { 'X', { "KGDB_BINARY_DLOAD", &BaseRemoteGDB::cmd_unsupported } },
7337259Sgblack@eecs.umich.edu    // remove breakpoint or watchpoint
73410037SARM gem5 Developers    { 'z', { "KGDB_CLR_HW_BKPT", &BaseRemoteGDB::cmd_clr_hw_bkpt } },
73510037SARM gem5 Developers    // insert breakpoint or watchpoint
73610037SARM gem5 Developers    { 'Z', { "KGDB_SET_HW_BKPT", &BaseRemoteGDB::cmd_set_hw_bkpt } },
7378868SMatt.Horsnell@arm.com};
7389256SAndreas.Sandberg@arm.com
73910037SARM gem5 Developers
74010037SARM gem5 Developersbool
74110037SARM gem5 DevelopersBaseRemoteGDB::cmd_unsupported(GdbCommand::Context &ctx)
74210037SARM gem5 Developers{
74310037SARM gem5 Developers    DPRINTF(GDBMisc, "Unsupported command: %s\n", ctx.cmd->name);
74410037SARM gem5 Developers    DDUMP(GDBMisc, ctx.data, ctx.len);
74510037SARM gem5 Developers    throw Unsupported();
74610037SARM gem5 Developers}
74710037SARM gem5 Developers
74810037SARM gem5 Developers
74910037SARM gem5 Developersbool
75010037SARM gem5 DevelopersBaseRemoteGDB::cmd_signal(GdbCommand::Context &ctx)
75110037SARM gem5 Developers{
75210037SARM gem5 Developers    send(csprintf("S%02x", ctx.type).c_str());
75310037SARM gem5 Developers    return true;
75410037SARM gem5 Developers}
75510037SARM gem5 Developers
75610037SARM gem5 Developersbool
75710037SARM gem5 DevelopersBaseRemoteGDB::cmd_cont(GdbCommand::Context &ctx)
75810037SARM gem5 Developers{
75910037SARM gem5 Developers    const char *p = ctx.data;
76010037SARM gem5 Developers    if (ctx.len) {
76110037SARM gem5 Developers        Addr newPc = hex2i(&p);
76210037SARM gem5 Developers        context->pcState(newPc);
76310037SARM gem5 Developers    }
76410037SARM gem5 Developers    clearSingleStep();
76510037SARM gem5 Developers    return false;
76610037SARM gem5 Developers}
76710037SARM gem5 Developers
76810037SARM gem5 Developersbool
76910037SARM gem5 DevelopersBaseRemoteGDB::cmd_async_cont(GdbCommand::Context &ctx)
77010037SARM gem5 Developers{
77110037SARM gem5 Developers    const char *p = ctx.data;
77210037SARM gem5 Developers    hex2i(&p);
77310037SARM gem5 Developers    if (*p++ == ';') {
77410037SARM gem5 Developers        Addr newPc = hex2i(&p);
77510037SARM gem5 Developers        context->pcState(newPc);
77610037SARM gem5 Developers    }
77710037SARM gem5 Developers    clearSingleStep();
77810037SARM gem5 Developers    return false;
77910037SARM gem5 Developers}
78010037SARM gem5 Developers
78110037SARM gem5 Developersbool
78210037SARM gem5 DevelopersBaseRemoteGDB::cmd_detach(GdbCommand::Context &ctx)
78310037SARM gem5 Developers{
78410037SARM gem5 Developers    detach();
78510037SARM gem5 Developers    return false;
78610037SARM gem5 Developers}
78710037SARM gem5 Developers
78810037SARM gem5 Developersbool
78910037SARM gem5 DevelopersBaseRemoteGDB::cmd_reg_r(GdbCommand::Context &ctx)
79010037SARM gem5 Developers{
79110037SARM gem5 Developers    char buf[2 * regCachePtr->size() + 1];
79210037SARM gem5 Developers    buf[2 * regCachePtr->size()] = '\0';
79310037SARM gem5 Developers    mem2hex(buf, regCachePtr->data(), regCachePtr->size());
79410037SARM gem5 Developers    send(buf);
79510037SARM gem5 Developers    return true;
79610037SARM gem5 Developers}
79710037SARM gem5 Developers
79810037SARM gem5 Developersbool
79910037SARM gem5 DevelopersBaseRemoteGDB::cmd_reg_w(GdbCommand::Context &ctx)
80010037SARM gem5 Developers{
80110037SARM gem5 Developers    const char *p = ctx.data;
80210037SARM gem5 Developers    p = hex2mem(regCachePtr->data(), p, regCachePtr->size());
80310037SARM gem5 Developers    if (p == NULL || *p != '\0')
80410037SARM gem5 Developers        throw CmdError("E01");
80510037SARM gem5 Developers
80610037SARM gem5 Developers    regCachePtr->setRegs(context);
80710037SARM gem5 Developers    send("OK");
80810037SARM gem5 Developers
80910037SARM gem5 Developers    return true;
81010037SARM gem5 Developers}
81110037SARM gem5 Developers
81210037SARM gem5 Developersbool
81310037SARM gem5 DevelopersBaseRemoteGDB::cmd_set_thread(GdbCommand::Context &ctx)
81410037SARM gem5 Developers{
81510037SARM gem5 Developers    const char *p = ctx.data + 1; // Ignore the subcommand byte.
81610037SARM gem5 Developers    if (hex2i(&p) != 0)
81710037SARM gem5 Developers        throw CmdError("E01");
81810037SARM gem5 Developers    send("OK");
81910037SARM gem5 Developers    return true;
82010037SARM gem5 Developers}
82110037SARM gem5 Developers
82210037SARM gem5 Developersbool
82310037SARM gem5 DevelopersBaseRemoteGDB::cmd_mem_r(GdbCommand::Context &ctx)
82410037SARM gem5 Developers{
82510037SARM gem5 Developers    const char *p = ctx.data;
82610037SARM gem5 Developers    Addr addr = hex2i(&p);
82710037SARM gem5 Developers    if (*p++ != ',')
82810037SARM gem5 Developers        throw CmdError("E02");
82910037SARM gem5 Developers    size_t len = hex2i(&p);
83010037SARM gem5 Developers    if (*p != '\0')
83110037SARM gem5 Developers        throw CmdError("E03");
83210037SARM gem5 Developers    if (!acc(addr, len))
83310037SARM gem5 Developers        throw CmdError("E05");
83410037SARM gem5 Developers
83510037SARM gem5 Developers    char buf[len];
83610037SARM gem5 Developers    if (!read(addr, len, buf))
83710037SARM gem5 Developers        throw CmdError("E05");
83810037SARM gem5 Developers
83910037SARM gem5 Developers    char temp[2 * len + 1];
84010037SARM gem5 Developers    temp[2 * len] = '\0';
84110037SARM gem5 Developers    mem2hex(temp, buf, len);
84210037SARM gem5 Developers    send(temp);
84310037SARM gem5 Developers    return true;
84410037SARM gem5 Developers}
84510037SARM gem5 Developers
84610037SARM gem5 Developersbool
84710037SARM gem5 DevelopersBaseRemoteGDB::cmd_mem_w(GdbCommand::Context &ctx)
84810037SARM gem5 Developers{
84910037SARM gem5 Developers    const char *p = ctx.data;
85010037SARM gem5 Developers    Addr addr = hex2i(&p);
85110037SARM gem5 Developers    if (*p++ != ',')
85210037SARM gem5 Developers        throw CmdError("E06");
85310037SARM gem5 Developers    size_t len = hex2i(&p);
85410037SARM gem5 Developers    if (*p++ != ':')
85510037SARM gem5 Developers        throw CmdError("E07");
85610037SARM gem5 Developers    if (len * 2 > ctx.len - (p - ctx.data))
85710037SARM gem5 Developers        throw CmdError("E08");
85810037SARM gem5 Developers    char buf[len];
85910037SARM gem5 Developers    p = (char *)hex2mem(buf, p, len);
86010037SARM gem5 Developers    if (p == NULL)
86110037SARM gem5 Developers        throw CmdError("E09");
86210037SARM gem5 Developers    if (!acc(addr, len))
86310037SARM gem5 Developers        throw CmdError("E0A");
86410037SARM gem5 Developers    if (!write(addr, len, buf))
86510037SARM gem5 Developers        throw CmdError("E0B");
86610037SARM gem5 Developers    send("OK");
86710037SARM gem5 Developers    return true;
86810037SARM gem5 Developers}
86910037SARM gem5 Developers
87010037SARM gem5 Developersbool
87110037SARM gem5 DevelopersBaseRemoteGDB::cmd_query_var(GdbCommand::Context &ctx)
87210037SARM gem5 Developers{
87310037SARM gem5 Developers    if (string(ctx.data, ctx.len - 1) != "C")
87410037SARM gem5 Developers        throw Unsupported();
87510037SARM gem5 Developers    send("QC0");
87610037SARM gem5 Developers    return true;
87710037SARM gem5 Developers}
87810037SARM gem5 Developers
87910037SARM gem5 Developersbool
88010037SARM gem5 DevelopersBaseRemoteGDB::cmd_async_step(GdbCommand::Context &ctx)
88110037SARM gem5 Developers{
88210037SARM gem5 Developers    const char *p = ctx.data;
88310037SARM gem5 Developers    hex2i(&p); // Ignore the subcommand byte.
88410037SARM gem5 Developers    if (*p++ == ';') {
88510037SARM gem5 Developers        Addr newPc = hex2i(&p);
88610037SARM gem5 Developers        context->pcState(newPc);
88710037SARM gem5 Developers    }
88810037SARM gem5 Developers    setSingleStep();
88910037SARM gem5 Developers    return false;
89010037SARM gem5 Developers}
89110037SARM gem5 Developers
89210037SARM gem5 Developersbool
89310037SARM gem5 DevelopersBaseRemoteGDB::cmd_step(GdbCommand::Context &ctx)
89410037SARM gem5 Developers{
89510037SARM gem5 Developers    if (ctx.len) {
89610037SARM gem5 Developers        const char *p = ctx.data;
89710037SARM gem5 Developers        Addr newPc = hex2i(&p);
89810037SARM gem5 Developers        context->pcState(newPc);
89910037SARM gem5 Developers    }
90010037SARM gem5 Developers    setSingleStep();
90110037SARM gem5 Developers    return false;
90210037SARM gem5 Developers}
90310037SARM gem5 Developers
90410037SARM gem5 Developersbool
90510037SARM gem5 DevelopersBaseRemoteGDB::cmd_clr_hw_bkpt(GdbCommand::Context &ctx)
90610037SARM gem5 Developers{
90710037SARM gem5 Developers    const char *p = ctx.data;
90810037SARM gem5 Developers    char subcmd = *p++;
90910037SARM gem5 Developers    if (*p++ != ',')
91010037SARM gem5 Developers        throw CmdError("E0D");
91110037SARM gem5 Developers    Addr addr = hex2i(&p);
91210037SARM gem5 Developers    if (*p++ != ',')
91310037SARM gem5 Developers        throw CmdError("E0D");
91410037SARM gem5 Developers    size_t len = hex2i(&p);
91510037SARM gem5 Developers
91610037SARM gem5 Developers    DPRINTF(GDBMisc, "clear %s, addr=%#x, len=%d\n",
91710037SARM gem5 Developers            break_type(subcmd), addr, len);
91810037SARM gem5 Developers
91910037SARM gem5 Developers    switch (subcmd) {
92010037SARM gem5 Developers      case GdbSoftBp:
92110037SARM gem5 Developers        removeSoftBreak(addr, len);
92210037SARM gem5 Developers        break;
92310037SARM gem5 Developers      case GdbHardBp:
92410037SARM gem5 Developers        removeHardBreak(addr, len);
92510037SARM gem5 Developers        break;
92610037SARM gem5 Developers      case GdbWriteWp:
92710037SARM gem5 Developers      case GdbReadWp:
92810037SARM gem5 Developers      case GdbAccWp:
92910037SARM gem5 Developers      default: // unknown
93010037SARM gem5 Developers        throw Unsupported();
93110037SARM gem5 Developers    }
93210037SARM gem5 Developers    send("OK");
93310037SARM gem5 Developers
93410037SARM gem5 Developers    return true;
93510037SARM gem5 Developers}
93610037SARM gem5 Developers
93710037SARM gem5 Developersbool
93810037SARM gem5 DevelopersBaseRemoteGDB::cmd_set_hw_bkpt(GdbCommand::Context &ctx)
93910037SARM gem5 Developers{
94010037SARM gem5 Developers    const char *p = ctx.data;
94110037SARM gem5 Developers    char subcmd = *p++;
94210037SARM gem5 Developers    if (*p++ != ',')
94310037SARM gem5 Developers        throw CmdError("E0D");
94410037SARM gem5 Developers    Addr addr = hex2i(&p);
94510037SARM gem5 Developers    if (*p++ != ',')
94610037SARM gem5 Developers        throw CmdError("E0D");
94710037SARM gem5 Developers    size_t len = hex2i(&p);
94810037SARM gem5 Developers
94910037SARM gem5 Developers    DPRINTF(GDBMisc, "set %s, addr=%#x, len=%d\n",
95010037SARM gem5 Developers            break_type(subcmd), addr, len);
95110037SARM gem5 Developers
95210037SARM gem5 Developers    switch (subcmd) {
95310037SARM gem5 Developers      case GdbSoftBp:
95410037SARM gem5 Developers        insertSoftBreak(addr, len);
95510037SARM gem5 Developers        break;
95610037SARM gem5 Developers      case GdbHardBp:
95710037SARM gem5 Developers        insertHardBreak(addr, len);
95810037SARM gem5 Developers        break;
95910037SARM gem5 Developers      case GdbWriteWp:
96010037SARM gem5 Developers      case GdbReadWp:
96110037SARM gem5 Developers      case GdbAccWp:
96210037SARM gem5 Developers      default: // unknown
96310037SARM gem5 Developers        throw Unsupported();
96410037SARM gem5 Developers    }
96510037SARM gem5 Developers    send("OK");
96610037SARM gem5 Developers
96710037SARM gem5 Developers    return true;
96810037SARM gem5 Developers}
96910037SARM gem5 Developers
97010037SARM gem5 Developers
97110037SARM gem5 Developers// This function does all command processing for interfacing to a
97210037SARM gem5 Developers// remote gdb.  Note that the error codes are ignored by gdb at
97310037SARM gem5 Developers// present, but might eventually become meaningful. (XXX) It might
97410037SARM gem5 Developers// makes sense to use POSIX errno values, because that is what the
97510037SARM gem5 Developers// gdb/remote.c functions want to return.
97610037SARM gem5 Developersbool
97710037SARM gem5 DevelopersBaseRemoteGDB::trap(int type)
97810037SARM gem5 Developers{
97910037SARM gem5 Developers
98010037SARM gem5 Developers    if (!attached)
98110037SARM gem5 Developers        return false;
98210037SARM gem5 Developers
9838549Sdaniel.johnson@arm.com    DPRINTF(GDBMisc, "trap: PC=%s\n", context->pcState());
98410037SARM gem5 Developers
98510037SARM gem5 Developers    clearSingleStep();
98610037SARM gem5 Developers
98710037SARM gem5 Developers    /*
98810037SARM gem5 Developers     * The first entry to this function is normally through
98910037SARM gem5 Developers     * a breakpoint trap in kgdb_connect(), in which case we
99010037SARM gem5 Developers     * must advance past the breakpoint because gdb will not.
99110037SARM gem5 Developers     *
99210037SARM gem5 Developers     * On the first entry here, we expect that gdb is not yet
99310037SARM gem5 Developers     * listening to us, so just enter the interaction loop.
99410037SARM gem5 Developers     * After the debugger is "active" (connected) it will be
99510037SARM gem5 Developers     * waiting for a "signaled" message from us.
99610037SARM gem5 Developers     */
99710037SARM gem5 Developers    if (!active) {
99810037SARM gem5 Developers        active = true;
99910037SARM gem5 Developers    } else {
100010037SARM gem5 Developers        // Tell remote host that an exception has occurred.
100110037SARM gem5 Developers        send(csprintf("S%02x", type).c_str());
100210037SARM gem5 Developers    }
100310037SARM gem5 Developers
100410037SARM gem5 Developers    // Stick frame regs into our reg cache.
100510037SARM gem5 Developers    regCachePtr = gdbRegs();
100610037SARM gem5 Developers    regCachePtr->getRegs(context);
100710037SARM gem5 Developers
100810037SARM gem5 Developers    char data[GDBPacketBufLen + 1];
100910037SARM gem5 Developers    GdbCommand::Context cmdCtx;
101010037SARM gem5 Developers    cmdCtx.type = type;
101110037SARM gem5 Developers    cmdCtx.data = &data[1];
101210037SARM gem5 Developers
101310037SARM gem5 Developers    for (;;) {
101410037SARM gem5 Developers        try {
101510037SARM gem5 Developers            size_t datalen = recv(data, sizeof(data));
101610037SARM gem5 Developers            if (datalen < 1)
101710037SARM gem5 Developers                throw BadClient();
101810037SARM gem5 Developers
101910037SARM gem5 Developers            data[datalen] = 0; // Sentinel
102010037SARM gem5 Developers            cmdCtx.cmd_byte = data[0];
102110037SARM gem5 Developers            cmdCtx.len = datalen - 1;
102210037SARM gem5 Developers
102310037SARM gem5 Developers            auto cmdIt = command_map.find(cmdCtx.cmd_byte);
102410037SARM gem5 Developers            if (cmdIt == command_map.end()) {
102510037SARM gem5 Developers                DPRINTF(GDBMisc, "Unknown command: %c(%#x)\n",
102610037SARM gem5 Developers                        cmdCtx.cmd_byte, cmdCtx.cmd_byte);
102710037SARM gem5 Developers                throw Unsupported();
102810037SARM gem5 Developers            }
102910037SARM gem5 Developers            cmdCtx.cmd = &(cmdIt->second);
103010037SARM gem5 Developers
103110037SARM gem5 Developers            if (!(this->*(cmdCtx.cmd->func))(cmdCtx))
103210037SARM gem5 Developers                break;
103310037SARM gem5 Developers
103410037SARM gem5 Developers        } catch (BadClient &e) {
103510037SARM gem5 Developers            if (e.warning)
103610037SARM gem5 Developers                warn(e.warning);
103710037SARM gem5 Developers            detach();
103810037SARM gem5 Developers            break;
103910037SARM gem5 Developers        } catch (Unsupported &e) {
104010037SARM gem5 Developers            send("");
104110037SARM gem5 Developers        } catch (CmdError &e) {
104210037SARM gem5 Developers            send(e.error.c_str());
104310037SARM gem5 Developers        } catch (...) {
104410037SARM gem5 Developers            panic("Unrecognzied GDB exception.");
104510037SARM gem5 Developers        }
104610037SARM gem5 Developers    }
104710037SARM gem5 Developers
104810037SARM gem5 Developers    return true;
104910037SARM gem5 Developers}
105010037SARM gem5 Developers
105110037SARM gem5 Developers// Convert a hex digit into an integer.
105210037SARM gem5 Developers// This returns -1 if the argument passed is no valid hex digit.
105310037SARM gem5 Developersint
105410037SARM gem5 DevelopersBaseRemoteGDB::digit2i(char c)
105510037SARM gem5 Developers{
105610037SARM gem5 Developers    if (c >= '0' && c <= '9')
105710037SARM gem5 Developers        return (c - '0');
105810037SARM gem5 Developers    else if (c >= 'a' && c <= 'f')
105910037SARM gem5 Developers        return (c - 'a' + 10);
106010037SARM gem5 Developers    else if (c >= 'A' && c <= 'F')
106110037SARM gem5 Developers        return (c - 'A' + 10);
106210037SARM gem5 Developers    else
106310037SARM gem5 Developers        return (-1);
106410037SARM gem5 Developers}
106510037SARM gem5 Developers
106610037SARM gem5 Developers// Convert the low 4 bits of an integer into an hex digit.
106710037SARM gem5 Developerschar
106810037SARM gem5 DevelopersBaseRemoteGDB::i2digit(int n)
106910037SARM gem5 Developers{
107010037SARM gem5 Developers    return ("0123456789abcdef"[n & 0x0f]);
107110037SARM gem5 Developers}
107210037SARM gem5 Developers
107310037SARM gem5 Developers// Convert a byte array into an hex string.
107410037SARM gem5 Developersvoid
107510037SARM gem5 DevelopersBaseRemoteGDB::mem2hex(char *vdst, const char *vsrc, int len)
107610037SARM gem5 Developers{
107710037SARM gem5 Developers    char *dst = vdst;
107810037SARM gem5 Developers    const char *src = vsrc;
107910037SARM gem5 Developers
108010037SARM gem5 Developers    while (len--) {
108110037SARM gem5 Developers        *dst++ = i2digit(*src >> 4);
108210037SARM gem5 Developers        *dst++ = i2digit(*src++);
108310037SARM gem5 Developers    }
108410037SARM gem5 Developers    *dst = '\0';
108510037SARM gem5 Developers}
108610037SARM gem5 Developers
108710037SARM gem5 Developers// Convert an hex string into a byte array.
108810037SARM gem5 Developers// This returns a pointer to the character following the last valid
108910037SARM gem5 Developers// hex digit. If the string ends in the middle of a byte, NULL is
109010037SARM gem5 Developers// returned.
109110037SARM gem5 Developersconst char *
109210037SARM gem5 DevelopersBaseRemoteGDB::hex2mem(char *vdst, const char *src, int maxlen)
109310037SARM gem5 Developers{
109410037SARM gem5 Developers    char *dst = vdst;
109510037SARM gem5 Developers    int msb, lsb;
109610037SARM gem5 Developers
109710037SARM gem5 Developers    while (*src && maxlen--) {
109810037SARM gem5 Developers        msb = digit2i(*src++);
109910037SARM gem5 Developers        if (msb < 0)
110010037SARM gem5 Developers            return (src - 1);
110110037SARM gem5 Developers        lsb = digit2i(*src++);
110210037SARM gem5 Developers        if (lsb < 0)
110310037SARM gem5 Developers            return (NULL);
110410037SARM gem5 Developers        *dst++ = (msb << 4) | lsb;
110510037SARM gem5 Developers    }
110610037SARM gem5 Developers    return src;
110710037SARM gem5 Developers}
110810037SARM gem5 Developers
110910037SARM gem5 Developers// Convert an hex string into an integer.
111010037SARM gem5 Developers// This returns a pointer to the character following the last valid
111110037SARM gem5 Developers// hex digit.
111210037SARM gem5 DevelopersAddr
111310037SARM gem5 DevelopersBaseRemoteGDB::hex2i(const char **srcp)
111410037SARM gem5 Developers{
111510037SARM gem5 Developers    const char *src = *srcp;
111610037SARM gem5 Developers    Addr r = 0;
111710037SARM gem5 Developers    int nibble;
111810037SARM gem5 Developers
111910037SARM gem5 Developers    while ((nibble = digit2i(*src)) >= 0) {
112010037SARM gem5 Developers        r *= 16;
112110037SARM gem5 Developers        r += nibble;
112210037SARM gem5 Developers        src++;
112310037SARM gem5 Developers    }
112410037SARM gem5 Developers    *srcp = src;
112510037SARM gem5 Developers    return r;
112610037SARM gem5 Developers}
112710037SARM gem5 Developers