remote_gdb.cc revision 14024:abe47b13653d
12SN/A/*
210905Sandreas.sandberg@arm.com * Copyright (c) 2018 ARM Limited
310905Sandreas.sandberg@arm.com *
410905Sandreas.sandberg@arm.com * The license below extends only to copyright in the software and shall
510905Sandreas.sandberg@arm.com * not be construed as granting a license to any other intellectual
610905Sandreas.sandberg@arm.com * property including but not limited to intellectual property relating
710905Sandreas.sandberg@arm.com * to a hardware implementation of the functionality of the software
810905Sandreas.sandberg@arm.com * licensed hereunder.  You may use the software subject to the license
910905Sandreas.sandberg@arm.com * terms below provided that you ensure that this notice is replicated
1010905Sandreas.sandberg@arm.com * unmodified and in its entirety in all distributions of the software,
1110905Sandreas.sandberg@arm.com * modified or unmodified, in source code or in binary form.
1210905Sandreas.sandberg@arm.com *
1310905Sandreas.sandberg@arm.com * Copyright 2015 LabWare
141762SN/A * Copyright 2014 Google, Inc.
152SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
162SN/A * All rights reserved.
172SN/A *
182SN/A * Redistribution and use in source and binary forms, with or without
192SN/A * modification, are permitted provided that the following conditions are
202SN/A * met: redistributions of source code must retain the above copyright
212SN/A * notice, this list of conditions and the following disclaimer;
222SN/A * redistributions in binary form must reproduce the above copyright
232SN/A * notice, this list of conditions and the following disclaimer in the
242SN/A * documentation and/or other materials provided with the distribution;
252SN/A * neither the name of the copyright holders nor the names of its
262SN/A * contributors may be used to endorse or promote products derived from
272SN/A * this software without specific prior written permission.
282SN/A *
292SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
302SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
312SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
322SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
332SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
342SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
352SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
362SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
372SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
382SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
392665Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
402760Sbinkertn@umich.edu *
412760Sbinkertn@umich.edu * Authors: Nathan Binkert
422665Ssaidi@eecs.umich.edu *          Boris Shingarov
4310905Sandreas.sandberg@arm.com */
442SN/A
452SN/A/*
462SN/A * Copyright (c) 1990, 1993 The Regents of the University of California
472SN/A * All rights reserved
482SN/A *
492SN/A * This software was developed by the Computer Systems Engineering group
502SN/A * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
512SN/A * contributed to Berkeley.
522SN/A *
532SN/A * All advertising materials mentioning features or use of this software
548229Snate@binkert.org * must display the following acknowledgement:
552SN/A *      This product includes software developed by the University of
568229Snate@binkert.org *      California, Lawrence Berkeley Laboratories.
5710905Sandreas.sandberg@arm.com *
584841Ssaidi@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
592SN/A * modification, are permitted provided that the following conditions
6010459SAndreas.Sandberg@ARM.com * are met:
616214Snate@binkert.org * 1. Redistributions of source code must retain the above copyright
622SN/A *    notice, this list of conditions and the following disclaimer.
632738Sstever@eecs.umich.edu * 2. Redistributions in binary form must reproduce the above copyright
64395SN/A *    notice, this list of conditions and the following disclaimer in the
6510905Sandreas.sandberg@arm.com *    documentation and/or other materials provided with the distribution.
664000Ssaidi@eecs.umich.edu * 3. All advertising materials mentioning features or use of this software
6711067Sandreas.sandberg@arm.com *    must display the following acknowledgement:
689983Sstever@gmail.com *      This product includes software developed by the University of
692SN/A *      California, Berkeley and its contributors.
7010905Sandreas.sandberg@arm.com * 4. Neither the name of the University nor the names of its contributors
7110905Sandreas.sandberg@arm.com *    may be used to endorse or promote products derived from this software
7210905Sandreas.sandberg@arm.com *    without specific prior written permission.
739048SAli.Saidi@ARM.com *
749048SAli.Saidi@ARM.com * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
759056SAli.Saidi@ARM.com * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
769048SAli.Saidi@ARM.com * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
779048SAli.Saidi@ARM.com * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
789056SAli.Saidi@ARM.com * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
799048SAli.Saidi@ARM.com * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
8010930Sbrandon.potter@amd.com * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
819048SAli.Saidi@ARM.com * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
82217SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
8310905Sandreas.sandberg@arm.com * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
84217SN/A * SUCH DAMAGE.
8510459SAndreas.Sandberg@ARM.com *
8610905Sandreas.sandberg@arm.com *      @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94
8710459SAndreas.Sandberg@ARM.com */
8810459SAndreas.Sandberg@ARM.com
8910905Sandreas.sandberg@arm.com/*-
9010459SAndreas.Sandberg@ARM.com * Copyright (c) 2001 The NetBSD Foundation, Inc.
9110459SAndreas.Sandberg@ARM.com * All rights reserved.
92217SN/A *
9310905Sandreas.sandberg@arm.com * This code is derived from software contributed to The NetBSD Foundation
94217SN/A * by Jason R. Thorpe.
9510459SAndreas.Sandberg@ARM.com *
9610905Sandreas.sandberg@arm.com * Redistribution and use in source and binary forms, with or without
9710459SAndreas.Sandberg@ARM.com * modification, are permitted provided that the following conditions
9810459SAndreas.Sandberg@ARM.com * are met:
9910905Sandreas.sandberg@arm.com * 1. Redistributions of source code must retain the above copyright
10010459SAndreas.Sandberg@ARM.com *    notice, this list of conditions and the following disclaimer.
10110459SAndreas.Sandberg@ARM.com * 2. Redistributions in binary form must reproduce the above copyright
102217SN/A *    notice, this list of conditions and the following disclaimer in the
10310905Sandreas.sandberg@arm.com *    documentation and/or other materials provided with the distribution.
1046820SLisa.Hsu@amd.com * 3. All advertising materials mentioning features or use of this software
10510459SAndreas.Sandberg@ARM.com *    must display the following acknowledgement:
10610905Sandreas.sandberg@arm.com *      This product includes software developed by the NetBSD
10710459SAndreas.Sandberg@ARM.com *      Foundation, Inc. and its contributors.
10810459SAndreas.Sandberg@ARM.com * 4. Neither the name of The NetBSD Foundation nor the names of its
10910905Sandreas.sandberg@arm.com *    contributors may be used to endorse or promote products derived
11010459SAndreas.Sandberg@ARM.com *    from this software without specific prior written permission.
11110459SAndreas.Sandberg@ARM.com *
1126820SLisa.Hsu@amd.com * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
11310905Sandreas.sandberg@arm.com * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1146227Snate@binkert.org * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
115217SN/A * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
116217SN/A * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
11710905Sandreas.sandberg@arm.com * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1184841Ssaidi@eecs.umich.edu * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1194841Ssaidi@eecs.umich.edu * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1204841Ssaidi@eecs.umich.edu * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
12110905Sandreas.sandberg@arm.com * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
1227948SAli.Saidi@ARM.com * POSSIBILITY OF SUCH DAMAGE.
1237948SAli.Saidi@ARM.com */
1247948SAli.Saidi@ARM.com
12510905Sandreas.sandberg@arm.com/*
12610905Sandreas.sandberg@arm.com * $NetBSD: kgdb_stub.c,v 1.8 2001/07/07 22:58:00 wdk Exp $
127217SN/A *
1284841Ssaidi@eecs.umich.edu * Taken from NetBSD
12910905Sandreas.sandberg@arm.com *
13010905Sandreas.sandberg@arm.com * "Stub" to allow remote cpu to debug over a serial line using gdb.
1314841Ssaidi@eecs.umich.edu */
1327948SAli.Saidi@ARM.com
13310905Sandreas.sandberg@arm.com#include "base/remote_gdb.hh"
13410905Sandreas.sandberg@arm.com
1357948SAli.Saidi@ARM.com#include <sys/signal.h>
136237SN/A#include <unistd.h>
13710905Sandreas.sandberg@arm.com
138237SN/A#include <csignal>
1398902Sandreas.hansson@arm.com#include <cstdint>
1408902Sandreas.hansson@arm.com#include <cstdio>
1418902Sandreas.hansson@arm.com#include <sstream>
1428902Sandreas.hansson@arm.com#include <string>
1438902Sandreas.hansson@arm.com
1448902Sandreas.hansson@arm.com#include "arch/vtophys.hh"
1458902Sandreas.hansson@arm.com#include "base/intmath.hh"
1468902Sandreas.hansson@arm.com#include "base/socket.hh"
1478902Sandreas.hansson@arm.com#include "base/trace.hh"
1488902Sandreas.hansson@arm.com#include "config/the_isa.hh"
1498902Sandreas.hansson@arm.com#include "cpu/base.hh"
150237SN/A#include "cpu/static_inst.hh"
151217SN/A#include "cpu/thread_context.hh"
152217SN/A#include "debug/GDBAll.hh"
153217SN/A#include "mem/fs_translating_port_proxy.hh"
154237SN/A#include "mem/port.hh"
15510905Sandreas.sandberg@arm.com#include "mem/se_translating_port_proxy.hh"
156217SN/A#include "sim/full_system.hh"
15710905Sandreas.sandberg@arm.com#include "sim/system.hh"
15810905Sandreas.sandberg@arm.com
159217SN/Ausing namespace std;
160223SN/Ausing namespace TheISA;
16110905Sandreas.sandberg@arm.com
162223SN/Astatic const char GDBStart = '$';
1635543Ssaidi@eecs.umich.edustatic const char GDBEnd = '#';
1645543Ssaidi@eecs.umich.edustatic const char GDBGoodP = '+';
1655543Ssaidi@eecs.umich.edustatic const char GDBBadP = '-';
16610905Sandreas.sandberg@arm.com
16710905Sandreas.sandberg@arm.comvector<BaseRemoteGDB *> debuggers;
168223SN/A
169223SN/Aclass HardBreakpoint : public PCEvent
1705543Ssaidi@eecs.umich.edu{
17110905Sandreas.sandberg@arm.com  private:
172217SN/A    BaseRemoteGDB *gdb;
1735543Ssaidi@eecs.umich.edu
17410905Sandreas.sandberg@arm.com  public:
175237SN/A    int refcount;
17610903Sandreas.sandberg@arm.com
17710905Sandreas.sandberg@arm.com  public:
17810903Sandreas.sandberg@arm.com    HardBreakpoint(BaseRemoteGDB *_gdb, PCEventQueue *q, Addr pc)
17910903Sandreas.sandberg@arm.com        : PCEvent(q, "HardBreakpoint Event", pc),
18010905Sandreas.sandberg@arm.com          gdb(_gdb), refcount(0)
18110903Sandreas.sandberg@arm.com    {
18210906Sandreas.sandberg@arm.com        DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc);
18310906Sandreas.sandberg@arm.com    }
18410906Sandreas.sandberg@arm.com
18510906Sandreas.sandberg@arm.com    const std::string name() const override { return gdb->name() + ".hwbkpt"; }
18610906Sandreas.sandberg@arm.com
18710906Sandreas.sandberg@arm.com    void
18810906Sandreas.sandberg@arm.com    process(ThreadContext *tc) override
18910906Sandreas.sandberg@arm.com    {
19010908Sandreas.sandberg@arm.com        DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc());
19110908Sandreas.sandberg@arm.com
19210906Sandreas.sandberg@arm.com        if (tc == gdb->tc)
19310905Sandreas.sandberg@arm.com            gdb->trap(SIGTRAP);
194237SN/A    }
1955543Ssaidi@eecs.umich.edu};
1965543Ssaidi@eecs.umich.edu
1975543Ssaidi@eecs.umich.edunamespace {
19810905Sandreas.sandberg@arm.com
1998902Sandreas.hansson@arm.com// Exception to throw when the connection to the client is broken.
200237SN/Astruct BadClient
201217SN/A{
2029342SAndreas.Sandberg@arm.com    const char *warning;
2032SN/A    BadClient(const char *_warning=NULL) : warning(_warning)
2049342SAndreas.Sandberg@arm.com    {}
20510905Sandreas.sandberg@arm.com};
20610905Sandreas.sandberg@arm.com
20710905Sandreas.sandberg@arm.com// Exception to throw when an error needs to be reported to the client.
20810905Sandreas.sandberg@arm.comstruct CmdError
20910905Sandreas.sandberg@arm.com{
21010905Sandreas.sandberg@arm.com    string error;
21110905Sandreas.sandberg@arm.com    CmdError(std::string _error) : error(_error)
21210905Sandreas.sandberg@arm.com    {}
21310905Sandreas.sandberg@arm.com};
21410905Sandreas.sandberg@arm.com
21510905Sandreas.sandberg@arm.com// Exception to throw when something isn't supported.
21610905Sandreas.sandberg@arm.comclass Unsupported {};
21710905Sandreas.sandberg@arm.com
21810905Sandreas.sandberg@arm.com// Convert a hex digit into an integer.
21910905Sandreas.sandberg@arm.com// This returns -1 if the argument passed is no valid hex digit.
22010905Sandreas.sandberg@arm.comint
22110905Sandreas.sandberg@arm.comdigit2i(char c)
22210905Sandreas.sandberg@arm.com{
22310905Sandreas.sandberg@arm.com    if (c >= '0' && c <= '9')
22410905Sandreas.sandberg@arm.com        return (c - '0');
22510905Sandreas.sandberg@arm.com    else if (c >= 'a' && c <= 'f')
2269342SAndreas.Sandberg@arm.com        return (c - 'a' + 10);
2279342SAndreas.Sandberg@arm.com    else if (c >= 'A' && c <= 'F')
2289342SAndreas.Sandberg@arm.com        return (c - 'A' + 10);
2299342SAndreas.Sandberg@arm.com    else
2309342SAndreas.Sandberg@arm.com        return (-1);
2312SN/A}
232395SN/A
2332SN/A// Convert the low 4 bits of an integer into an hex digit.
2342SN/Achar
23510905Sandreas.sandberg@arm.comi2digit(int n)
23610905Sandreas.sandberg@arm.com{
23710905Sandreas.sandberg@arm.com    return ("0123456789abcdef"[n & 0x0f]);
23810905Sandreas.sandberg@arm.com}
23910905Sandreas.sandberg@arm.com
24010905Sandreas.sandberg@arm.com// Convert a byte array into an hex string.
24110905Sandreas.sandberg@arm.comvoid
24210905Sandreas.sandberg@arm.commem2hex(char *vdst, const char *vsrc, int len)
24310905Sandreas.sandberg@arm.com{
24410905Sandreas.sandberg@arm.com    char *dst = vdst;
24510905Sandreas.sandberg@arm.com    const char *src = vsrc;
24610905Sandreas.sandberg@arm.com
24710905Sandreas.sandberg@arm.com    while (len--) {
24810905Sandreas.sandberg@arm.com        *dst++ = i2digit(*src >> 4);
24910905Sandreas.sandberg@arm.com        *dst++ = i2digit(*src++);
25010905Sandreas.sandberg@arm.com    }
25110905Sandreas.sandberg@arm.com    *dst = '\0';
25210905Sandreas.sandberg@arm.com}
25310905Sandreas.sandberg@arm.com
25410905Sandreas.sandberg@arm.com// Convert an hex string into a byte array.
25510905Sandreas.sandberg@arm.com// This returns a pointer to the character following the last valid
25610905Sandreas.sandberg@arm.com// hex digit. If the string ends in the middle of a byte, NULL is
25710905Sandreas.sandberg@arm.com// returned.
25810905Sandreas.sandberg@arm.comconst char *
25910905Sandreas.sandberg@arm.comhex2mem(char *vdst, const char *src, int maxlen)
26010905Sandreas.sandberg@arm.com{
26110905Sandreas.sandberg@arm.com    char *dst = vdst;
26210905Sandreas.sandberg@arm.com    int msb, lsb;
26310905Sandreas.sandberg@arm.com
26410905Sandreas.sandberg@arm.com    while (*src && maxlen--) {
26510905Sandreas.sandberg@arm.com        msb = digit2i(*src++);
26610905Sandreas.sandberg@arm.com        if (msb < 0)
26710905Sandreas.sandberg@arm.com            return (src - 1);
26810905Sandreas.sandberg@arm.com        lsb = digit2i(*src++);
26910905Sandreas.sandberg@arm.com        if (lsb < 0)
27010905Sandreas.sandberg@arm.com            return (NULL);
27110905Sandreas.sandberg@arm.com        *dst++ = (msb << 4) | lsb;
27210905Sandreas.sandberg@arm.com    }
27310905Sandreas.sandberg@arm.com    return src;
27410905Sandreas.sandberg@arm.com}
27510905Sandreas.sandberg@arm.com
27610905Sandreas.sandberg@arm.com// Convert an hex string into an integer.
27710905Sandreas.sandberg@arm.com// This returns a pointer to the character following the last valid
27810905Sandreas.sandberg@arm.com// hex digit.
27910905Sandreas.sandberg@arm.comAddr
2802SN/Ahex2i(const char **srcp)
2812SN/A{
2825739Snate@binkert.org    const char *src = *srcp;
2835739Snate@binkert.org    Addr r = 0;
2842SN/A    int nibble;
28510905Sandreas.sandberg@arm.com
28610905Sandreas.sandberg@arm.com    while ((nibble = digit2i(*src)) >= 0) {
28710905Sandreas.sandberg@arm.com        r *= 16;
28810905Sandreas.sandberg@arm.com        r += nibble;
28910905Sandreas.sandberg@arm.com        src++;
29010905Sandreas.sandberg@arm.com    }
29110905Sandreas.sandberg@arm.com    *srcp = src;
29210905Sandreas.sandberg@arm.com    return r;
2932SN/A}
29410905Sandreas.sandberg@arm.com
29510905Sandreas.sandberg@arm.comenum GdbBreakpointType {
29610905Sandreas.sandberg@arm.com    GdbSoftBp = '0',
29710905Sandreas.sandberg@arm.com    GdbHardBp = '1',
29810905Sandreas.sandberg@arm.com    GdbWriteWp = '2',
29910905Sandreas.sandberg@arm.com    GdbReadWp = '3',
30010905Sandreas.sandberg@arm.com    GdbAccWp = '4',
30110905Sandreas.sandberg@arm.com};
302237SN/A
30310905Sandreas.sandberg@arm.com#ifndef NDEBUG
30410905Sandreas.sandberg@arm.comconst char *
30510905Sandreas.sandberg@arm.combreak_type(char c)
30610905Sandreas.sandberg@arm.com{
30710905Sandreas.sandberg@arm.com    switch(c) {
30810905Sandreas.sandberg@arm.com      case GdbSoftBp: return "software breakpoint";
30910905Sandreas.sandberg@arm.com      case GdbHardBp: return "hardware breakpoint";
31010905Sandreas.sandberg@arm.com      case GdbWriteWp: return "write watchpoint";
31110905Sandreas.sandberg@arm.com      case GdbReadWp: return "read watchpoint";
31210905Sandreas.sandberg@arm.com      case GdbAccWp: return "access watchpoint";
31310905Sandreas.sandberg@arm.com      default: return "unknown breakpoint/watchpoint";
31410905Sandreas.sandberg@arm.com    }
31510905Sandreas.sandberg@arm.com}
31610905Sandreas.sandberg@arm.com#endif
31710905Sandreas.sandberg@arm.com
31810905Sandreas.sandberg@arm.comstd::map<Addr, HardBreakpoint *> hardBreakMap;
31910905Sandreas.sandberg@arm.com
32010905Sandreas.sandberg@arm.comEventQueue *
32110905Sandreas.sandberg@arm.comgetComInstEventQueue(ThreadContext *tc)
32210905Sandreas.sandberg@arm.com{
32310905Sandreas.sandberg@arm.com    return tc->getCpuPtr()->comInstEventQueue[tc->threadId()];
32410905Sandreas.sandberg@arm.com}
32510905Sandreas.sandberg@arm.com
32610905Sandreas.sandberg@arm.com}
32710905Sandreas.sandberg@arm.com
32810905Sandreas.sandberg@arm.comBaseRemoteGDB::BaseRemoteGDB(System *_system, ThreadContext *c, int _port) :
32910905Sandreas.sandberg@arm.com        connectEvent(nullptr), dataEvent(nullptr), _port(_port), fd(-1),
33010905Sandreas.sandberg@arm.com        active(false), attached(false), sys(_system), tc(c),
33110905Sandreas.sandberg@arm.com        trapEvent(this), singleStepEvent(*this)
33210905Sandreas.sandberg@arm.com{
33310905Sandreas.sandberg@arm.com    debuggers.push_back(this);
33410905Sandreas.sandberg@arm.com}
33510905Sandreas.sandberg@arm.com
33610905Sandreas.sandberg@arm.comBaseRemoteGDB::~BaseRemoteGDB()
33710905Sandreas.sandberg@arm.com{
33810905Sandreas.sandberg@arm.com    delete connectEvent;
33910905Sandreas.sandberg@arm.com    delete dataEvent;
34010905Sandreas.sandberg@arm.com}
34110905Sandreas.sandberg@arm.com
34210905Sandreas.sandberg@arm.comstring
34310905Sandreas.sandberg@arm.comBaseRemoteGDB::name()
34410905Sandreas.sandberg@arm.com{
34510905Sandreas.sandberg@arm.com    return sys->name() + ".remote_gdb";
34610905Sandreas.sandberg@arm.com}
34710905Sandreas.sandberg@arm.com
34810905Sandreas.sandberg@arm.comvoid
34910905Sandreas.sandberg@arm.comBaseRemoteGDB::listen()
35010905Sandreas.sandberg@arm.com{
35110905Sandreas.sandberg@arm.com    if (ListenSocket::allDisabled()) {
35210905Sandreas.sandberg@arm.com        warn_once("Sockets disabled, not accepting gdb connections");
35310905Sandreas.sandberg@arm.com        return;
35410905Sandreas.sandberg@arm.com    }
35510905Sandreas.sandberg@arm.com
35610905Sandreas.sandberg@arm.com    while (!listener.listen(_port, true)) {
35710905Sandreas.sandberg@arm.com        DPRINTF(GDBMisc, "Can't bind port %d\n", _port);
35810905Sandreas.sandberg@arm.com        _port++;
35910905Sandreas.sandberg@arm.com    }
36010905Sandreas.sandberg@arm.com
36110905Sandreas.sandberg@arm.com    connectEvent = new ConnectEvent(this, listener.getfd(), POLLIN);
36210905Sandreas.sandberg@arm.com    pollQueue.schedule(connectEvent);
36310905Sandreas.sandberg@arm.com
36410905Sandreas.sandberg@arm.com    ccprintf(cerr, "%d: %s: listening for remote gdb on port %d\n",
36510905Sandreas.sandberg@arm.com             curTick(), name(), _port);
3662SN/A}
3672287SN/A
3682287SN/Avoid
3692287SN/ABaseRemoteGDB::connect()
3702868Sktlim@umich.edu{
37110905Sandreas.sandberg@arm.com    panic_if(!listener.islistening(),
37210905Sandreas.sandberg@arm.com             "Cannot accept GDB connections if we're not listening!");
37310905Sandreas.sandberg@arm.com
37410905Sandreas.sandberg@arm.com    int sfd = listener.accept(true);
3752SN/A
3762SN/A    if (sfd != -1) {
3779554Sandreas.hansson@arm.com        if (isAttached())
3789554Sandreas.hansson@arm.com            close(sfd);
3792SN/A        else
380395SN/A            attach(sfd);
381395SN/A    }
3822SN/A}
3832SN/A
3842SN/Aint
385395SN/ABaseRemoteGDB::port() const
3862SN/A{
387395SN/A    panic_if(!listener.islistening(),
3882SN/A             "Remote GDB port is unknown until listen() has been called.\n");
3892SN/A    return _port;
390395SN/A}
3912SN/A
392395SN/Avoid
3932SN/ABaseRemoteGDB::attach(int f)
3942SN/A{
3952SN/A    fd = f;
396395SN/A
3972SN/A    dataEvent = new DataEvent(this, fd, POLLIN);
398395SN/A    pollQueue.schedule(dataEvent);
3992SN/A
400395SN/A    attached = true;
4012SN/A    DPRINTFN("remote gdb attached\n");
4022SN/A}
403395SN/A
404395SN/Avoid
4052SN/ABaseRemoteGDB::detach()
4062SN/A{
4072SN/A    attached = false;
408395SN/A    active = false;
409395SN/A    clearSingleStep();
4102SN/A    close(fd);
4112SN/A    fd = -1;
4122SN/A
4132SN/A    pollQueue.remove(dataEvent);
4142SN/A    DPRINTFN("remote gdb detached\n");
4152SN/A}
416395SN/A
4172SN/A// This function does all command processing for interfacing to a
4182SN/A// remote gdb.  Note that the error codes are ignored by gdb at
4192SN/A// present, but might eventually become meaningful. (XXX) It might
4202SN/A// makes sense to use POSIX errno values, because that is what the
4212SN/A// gdb/remote.c functions want to return.
4222SN/Abool
4232SN/ABaseRemoteGDB::trap(int type)
4242SN/A{
425395SN/A
42610905Sandreas.sandberg@arm.com    if (!attached)
4272738Sstever@eecs.umich.edu        return false;
4282SN/A
4292SN/A    DPRINTF(GDBMisc, "trap: PC=%s\n", tc->pcState());
4302SN/A
4312SN/A    clearSingleStep();
4322SN/A
433395SN/A    /*
434395SN/A     * The first entry to this function is normally through
4352SN/A     * a breakpoint trap in kgdb_connect(), in which case we
436395SN/A     * must advance past the breakpoint because gdb will not.
4372SN/A     *
438395SN/A     * On the first entry here, we expect that gdb is not yet
4392SN/A     * listening to us, so just enter the interaction loop.
44010905Sandreas.sandberg@arm.com     * After the debugger is "active" (connected) it will be
4412738Sstever@eecs.umich.edu     * waiting for a "signaled" message from us.
4422SN/A     */
4432SN/A    if (!active) {
4442SN/A        active = true;
4452SN/A    } else {
446395SN/A        // Tell remote host that an exception has occurred.
4472SN/A        send(csprintf("S%02x", type).c_str());
4482SN/A    }
4495543Ssaidi@eecs.umich.edu
4505543Ssaidi@eecs.umich.edu    // Stick frame regs into our reg cache.
451237SN/A    regCachePtr = gdbRegs();
4522SN/A    regCachePtr->getRegs(tc);
45310453SAndrew.Bardsley@arm.com
45410905Sandreas.sandberg@arm.com    GdbCommand::Context cmdCtx;
455237SN/A    cmdCtx.type = type;
456237SN/A    std::vector<char> data;
457237SN/A
458237SN/A    for (;;) {
459237SN/A        try {
46010453SAndrew.Bardsley@arm.com            recv(data);
46110453SAndrew.Bardsley@arm.com            if (data.size() == 1)
462237SN/A                throw BadClient();
46310905Sandreas.sandberg@arm.com            cmdCtx.cmd_byte = data[0];
46410905Sandreas.sandberg@arm.com            cmdCtx.data = data.data() + 1;
465237SN/A            // One for sentinel, one for cmd_byte.
466937SN/A            cmdCtx.len = data.size() - 2;
467937SN/A
468237SN/A            auto cmdIt = command_map.find(cmdCtx.cmd_byte);
469237SN/A            if (cmdIt == command_map.end()) {
470237SN/A                DPRINTF(GDBMisc, "Unknown command: %c(%#x)\n",
471237SN/A                        cmdCtx.cmd_byte, cmdCtx.cmd_byte);
4724000Ssaidi@eecs.umich.edu                throw Unsupported();
473304SN/A            }
474304SN/A            cmdCtx.cmd = &(cmdIt->second);
475449SN/A
476449SN/A            if (!(this->*(cmdCtx.cmd->func))(cmdCtx))
477449SN/A                break;
4787491Ssteve.reinhardt@amd.com
4797491Ssteve.reinhardt@amd.com        } catch (BadClient &e) {
4807491Ssteve.reinhardt@amd.com            if (e.warning)
4817491Ssteve.reinhardt@amd.com                warn(e.warning);
4827491Ssteve.reinhardt@amd.com            detach();
4837491Ssteve.reinhardt@amd.com            break;
4847491Ssteve.reinhardt@amd.com        } catch (Unsupported &e) {
4857491Ssteve.reinhardt@amd.com            send("");
4867491Ssteve.reinhardt@amd.com        } catch (CmdError &e) {
4877491Ssteve.reinhardt@amd.com            send(e.error.c_str());
4887491Ssteve.reinhardt@amd.com        } catch (...) {
4897823Ssteve.reinhardt@amd.com            panic("Unrecognzied GDB exception.");
4907491Ssteve.reinhardt@amd.com        }
4917491Ssteve.reinhardt@amd.com    }
492449SN/A
493449SN/A    return true;
494449SN/A}
495449SN/A
496449SN/Avoid
497449SN/ABaseRemoteGDB::incomingData(int revent)
498449SN/A{
499449SN/A    if (trapEvent.scheduled()) {
500449SN/A        warn("GDB trap event has already been scheduled!");
501237SN/A        return;
5022SN/A    }
5032SN/A
504    if (revent & POLLIN) {
505        trapEvent.type(SIGILL);
506        scheduleInstCommitEvent(&trapEvent, 0);
507    } else if (revent & POLLNVAL) {
508        descheduleInstCommitEvent(&trapEvent);
509        detach();
510    }
511}
512
513uint8_t
514BaseRemoteGDB::getbyte()
515{
516    uint8_t b;
517    if (::read(fd, &b, sizeof(b)) == sizeof(b))
518        return b;
519
520    throw BadClient("Couldn't read data from debugger.");
521}
522
523void
524BaseRemoteGDB::putbyte(uint8_t b)
525{
526    if (::write(fd, &b, sizeof(b)) == sizeof(b))
527        return;
528
529    throw BadClient("Couldn't write data to the debugger.");
530}
531
532// Receive a packet from gdb
533void
534BaseRemoteGDB::recv(std::vector<char>& bp)
535{
536    uint8_t c;
537    int csum;
538    bp.resize(0);
539
540    do {
541        csum = 0;
542        // Find the beginning of a packet
543        while ((c = getbyte()) != GDBStart);
544
545        // Read until you find the end of the data in the packet, and keep
546        // track of the check sum.
547        while (true) {
548            c = getbyte();
549            if (c == GDBEnd)
550                break;
551            c &= 0x7f;
552            csum += c;
553            bp.push_back(c);
554        }
555
556        // Mask the check sum.
557        csum &= 0xff;
558
559        // Bring in the checksum. If the check sum matches, csum will be 0.
560        csum -= digit2i(getbyte()) * 16;
561        csum -= digit2i(getbyte());
562
563        // If the check sum was correct
564        if (csum == 0) {
565            // Report that the packet was received correctly
566            putbyte(GDBGoodP);
567            // Sequence present?
568            if (bp.size() > 2 && bp[2] == ':') {
569                putbyte(bp[0]);
570                putbyte(bp[1]);
571                auto begin = std::begin(bp);
572                bp.erase(begin, std::next(begin, 3));
573            }
574            break;
575        }
576        // Otherwise, report that there was a mistake.
577        putbyte(GDBBadP);
578    } while (1);
579    // Sentinel.
580    bp.push_back('\0');
581    DPRINTF(GDBRecv, "recv:  %s\n", bp.data());
582}
583
584// Send a packet to gdb
585void
586BaseRemoteGDB::send(const char *bp)
587{
588    const char *p;
589    uint8_t csum, c;
590
591    DPRINTF(GDBSend, "send:  %s\n", bp);
592
593    do {
594        p = bp;
595        // Start sending a packet
596        putbyte(GDBStart);
597        // Send the contents, and also keep a check sum.
598        for (csum = 0; (c = *p); p++) {
599            putbyte(c);
600            csum += c;
601        }
602        // Send the ending character.
603        putbyte(GDBEnd);
604        // Send the checksum.
605        putbyte(i2digit(csum >> 4));
606        putbyte(i2digit(csum));
607        // Try transmitting over and over again until the other end doesn't
608        // send an error back.
609        c = getbyte();
610    } while ((c & 0x7f) == GDBBadP);
611}
612
613// Read bytes from kernel address space for debugger.
614bool
615BaseRemoteGDB::read(Addr vaddr, size_t size, char *data)
616{
617    static Addr lastaddr = 0;
618    static size_t lastsize = 0;
619
620    if (vaddr < 10) {
621      DPRINTF(GDBRead, "read:  reading memory location zero!\n");
622      vaddr = lastaddr + lastsize;
623    }
624
625    DPRINTF(GDBRead, "read:  addr=%#x, size=%d", vaddr, size);
626
627    PortProxy &proxy = tc->getVirtProxy();
628    proxy.readBlob(vaddr, data, size);
629
630#if TRACING_ON
631    if (DTRACE(GDBRead)) {
632        if (DTRACE(GDBExtra)) {
633            char buf[1024];
634            mem2hex(buf, data, size);
635            DPRINTFNR(": %s\n", buf);
636        } else
637            DPRINTFNR("\n");
638    }
639#endif
640
641    return true;
642}
643
644// Write bytes to kernel address space for debugger.
645bool
646BaseRemoteGDB::write(Addr vaddr, size_t size, const char *data)
647{
648    static Addr lastaddr = 0;
649    static size_t lastsize = 0;
650
651    if (vaddr < 10) {
652      DPRINTF(GDBWrite, "write: writing memory location zero!\n");
653      vaddr = lastaddr + lastsize;
654    }
655
656    if (DTRACE(GDBWrite)) {
657        DPRINTFN("write: addr=%#x, size=%d", vaddr, size);
658        if (DTRACE(GDBExtra)) {
659            char buf[1024];
660            mem2hex(buf, data, size);
661            DPRINTFNR(": %s\n", buf);
662        } else
663            DPRINTFNR("\n");
664    }
665    PortProxy &proxy = tc->getVirtProxy();
666    proxy.writeBlob(vaddr, data, size);
667
668    return true;
669}
670
671void
672BaseRemoteGDB::singleStep()
673{
674    if (!singleStepEvent.scheduled())
675        scheduleInstCommitEvent(&singleStepEvent, 1);
676    trap(SIGTRAP);
677}
678
679void
680BaseRemoteGDB::clearSingleStep()
681{
682    descheduleInstCommitEvent(&singleStepEvent);
683}
684
685void
686BaseRemoteGDB::setSingleStep()
687{
688    if (!singleStepEvent.scheduled())
689        scheduleInstCommitEvent(&singleStepEvent, 1);
690}
691
692void
693BaseRemoteGDB::insertSoftBreak(Addr addr, size_t len)
694{
695    if (!checkBpLen(len))
696        throw BadClient("Invalid breakpoint length\n");
697
698    return insertHardBreak(addr, len);
699}
700
701void
702BaseRemoteGDB::removeSoftBreak(Addr addr, size_t len)
703{
704    if (!checkBpLen(len))
705        throw BadClient("Invalid breakpoint length.\n");
706
707    return removeHardBreak(addr, len);
708}
709
710void
711BaseRemoteGDB::insertHardBreak(Addr addr, size_t len)
712{
713    if (!checkBpLen(len))
714        throw BadClient("Invalid breakpoint length\n");
715
716    DPRINTF(GDBMisc, "Inserting hardware breakpoint at %#x\n", addr);
717
718    HardBreakpoint *&bkpt = hardBreakMap[addr];
719    if (bkpt == 0)
720        bkpt = new HardBreakpoint(this, &sys->pcEventQueue, addr);
721
722    bkpt->refcount++;
723}
724
725void
726BaseRemoteGDB::removeHardBreak(Addr addr, size_t len)
727{
728    if (!checkBpLen(len))
729        throw BadClient("Invalid breakpoint length\n");
730
731    DPRINTF(GDBMisc, "Removing hardware breakpoint at %#x\n", addr);
732
733    auto i = hardBreakMap.find(addr);
734    if (i == hardBreakMap.end())
735        throw CmdError("E0C");
736
737    HardBreakpoint *hbp = (*i).second;
738    if (--hbp->refcount == 0) {
739        delete hbp;
740        hardBreakMap.erase(i);
741    }
742}
743
744void
745BaseRemoteGDB::clearTempBreakpoint(Addr &bkpt)
746{
747    DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", bkpt);
748    removeHardBreak(bkpt, sizeof(TheISA::MachInst));
749    bkpt = 0;
750}
751
752void
753BaseRemoteGDB::setTempBreakpoint(Addr bkpt)
754{
755    DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", bkpt);
756    insertHardBreak(bkpt, sizeof(TheISA::MachInst));
757}
758
759void
760BaseRemoteGDB::scheduleInstCommitEvent(Event *ev, int delta)
761{
762    EventQueue *eq = getComInstEventQueue(tc);
763    // Here "ticks" aren't simulator ticks which measure time, they're
764    // instructions committed by the CPU.
765    eq->schedule(ev, eq->getCurTick() + delta);
766}
767
768void
769BaseRemoteGDB::descheduleInstCommitEvent(Event *ev)
770{
771    if (ev->scheduled())
772        getComInstEventQueue(tc)->deschedule(ev);
773}
774
775std::map<char, BaseRemoteGDB::GdbCommand> BaseRemoteGDB::command_map = {
776    // last signal
777    { '?', { "KGDB_SIGNAL", &BaseRemoteGDB::cmd_signal } },
778    // set baud (deprecated)
779    { 'b', { "KGDB_SET_BAUD", &BaseRemoteGDB::cmd_unsupported } },
780    // set breakpoint (deprecated)
781    { 'B', { "KGDB_SET_BREAK", &BaseRemoteGDB::cmd_unsupported } },
782    // resume
783    { 'c', { "KGDB_CONT", &BaseRemoteGDB::cmd_cont } },
784    // continue with signal
785    { 'C', { "KGDB_ASYNC_CONT", &BaseRemoteGDB::cmd_async_cont } },
786    // toggle debug flags (deprecated)
787    { 'd', { "KGDB_DEBUG", &BaseRemoteGDB::cmd_unsupported } },
788    // detach remote gdb
789    { 'D', { "KGDB_DETACH", &BaseRemoteGDB::cmd_detach } },
790    // read general registers
791    { 'g', { "KGDB_REG_R", &BaseRemoteGDB::cmd_reg_r } },
792    // write general registers
793    { 'G', { "KGDB_REG_W", &BaseRemoteGDB::cmd_reg_w } },
794    // set thread
795    { 'H', { "KGDB_SET_THREAD", &BaseRemoteGDB::cmd_set_thread } },
796    // step a single cycle
797    { 'i', { "KGDB_CYCLE_STEP", &BaseRemoteGDB::cmd_unsupported } },
798    // signal then cycle step
799    { 'I', { "KGDB_SIG_CYCLE_STEP", &BaseRemoteGDB::cmd_unsupported } },
800    // kill program
801    { 'k', { "KGDB_KILL", &BaseRemoteGDB::cmd_detach } },
802    // read memory
803    { 'm', { "KGDB_MEM_R", &BaseRemoteGDB::cmd_mem_r } },
804    // write memory
805    { 'M', { "KGDB_MEM_W", &BaseRemoteGDB::cmd_mem_w } },
806    // read register
807    { 'p', { "KGDB_READ_REG", &BaseRemoteGDB::cmd_unsupported } },
808    // write register
809    { 'P', { "KGDB_SET_REG", &BaseRemoteGDB::cmd_unsupported } },
810    // query variable
811    { 'q', { "KGDB_QUERY_VAR", &BaseRemoteGDB::cmd_query_var } },
812    // set variable
813    { 'Q', { "KGDB_SET_VAR", &BaseRemoteGDB::cmd_unsupported } },
814    // reset system (deprecated)
815    { 'r', { "KGDB_RESET", &BaseRemoteGDB::cmd_unsupported } },
816    // step
817    { 's', { "KGDB_STEP", &BaseRemoteGDB::cmd_step } },
818    // signal and step
819    { 'S', { "KGDB_ASYNC_STEP", &BaseRemoteGDB::cmd_async_step } },
820    // find out if the thread is alive
821    { 'T', { "KGDB_THREAD_ALIVE", &BaseRemoteGDB::cmd_unsupported } },
822    // target exited
823    { 'W', { "KGDB_TARGET_EXIT", &BaseRemoteGDB::cmd_unsupported } },
824    // write memory
825    { 'X', { "KGDB_BINARY_DLOAD", &BaseRemoteGDB::cmd_unsupported } },
826    // remove breakpoint or watchpoint
827    { 'z', { "KGDB_CLR_HW_BKPT", &BaseRemoteGDB::cmd_clr_hw_bkpt } },
828    // insert breakpoint or watchpoint
829    { 'Z', { "KGDB_SET_HW_BKPT", &BaseRemoteGDB::cmd_set_hw_bkpt } },
830};
831
832bool
833BaseRemoteGDB::checkBpLen(size_t len)
834{
835    return len == sizeof(MachInst);
836}
837
838bool
839BaseRemoteGDB::cmd_unsupported(GdbCommand::Context &ctx)
840{
841    DPRINTF(GDBMisc, "Unsupported command: %s\n", ctx.cmd->name);
842    DDUMP(GDBMisc, ctx.data, ctx.len);
843    throw Unsupported();
844}
845
846
847bool
848BaseRemoteGDB::cmd_signal(GdbCommand::Context &ctx)
849{
850    send(csprintf("S%02x", ctx.type).c_str());
851    return true;
852}
853
854bool
855BaseRemoteGDB::cmd_cont(GdbCommand::Context &ctx)
856{
857    const char *p = ctx.data;
858    if (ctx.len) {
859        Addr newPc = hex2i(&p);
860        tc->pcState(newPc);
861    }
862    clearSingleStep();
863    return false;
864}
865
866bool
867BaseRemoteGDB::cmd_async_cont(GdbCommand::Context &ctx)
868{
869    const char *p = ctx.data;
870    hex2i(&p);
871    if (*p++ == ';') {
872        Addr newPc = hex2i(&p);
873        tc->pcState(newPc);
874    }
875    clearSingleStep();
876    return false;
877}
878
879bool
880BaseRemoteGDB::cmd_detach(GdbCommand::Context &ctx)
881{
882    detach();
883    return false;
884}
885
886bool
887BaseRemoteGDB::cmd_reg_r(GdbCommand::Context &ctx)
888{
889    char buf[2 * regCachePtr->size() + 1];
890    buf[2 * regCachePtr->size()] = '\0';
891    mem2hex(buf, regCachePtr->data(), regCachePtr->size());
892    send(buf);
893    return true;
894}
895
896bool
897BaseRemoteGDB::cmd_reg_w(GdbCommand::Context &ctx)
898{
899    const char *p = ctx.data;
900    p = hex2mem(regCachePtr->data(), p, regCachePtr->size());
901    if (p == NULL || *p != '\0')
902        throw CmdError("E01");
903
904    regCachePtr->setRegs(tc);
905    send("OK");
906
907    return true;
908}
909
910bool
911BaseRemoteGDB::cmd_set_thread(GdbCommand::Context &ctx)
912{
913    const char *p = ctx.data + 1; // Ignore the subcommand byte.
914    if (hex2i(&p) != 0)
915        throw CmdError("E01");
916    send("OK");
917    return true;
918}
919
920bool
921BaseRemoteGDB::cmd_mem_r(GdbCommand::Context &ctx)
922{
923    const char *p = ctx.data;
924    Addr addr = hex2i(&p);
925    if (*p++ != ',')
926        throw CmdError("E02");
927    size_t len = hex2i(&p);
928    if (*p != '\0')
929        throw CmdError("E03");
930    if (!acc(addr, len))
931        throw CmdError("E05");
932
933    char buf[len];
934    if (!read(addr, len, buf))
935        throw CmdError("E05");
936
937    char temp[2 * len + 1];
938    temp[2 * len] = '\0';
939    mem2hex(temp, buf, len);
940    send(temp);
941    return true;
942}
943
944bool
945BaseRemoteGDB::cmd_mem_w(GdbCommand::Context &ctx)
946{
947    const char *p = ctx.data;
948    Addr addr = hex2i(&p);
949    if (*p++ != ',')
950        throw CmdError("E06");
951    size_t len = hex2i(&p);
952    if (*p++ != ':')
953        throw CmdError("E07");
954    if (len * 2 > ctx.len - (p - ctx.data))
955        throw CmdError("E08");
956    char buf[len];
957    p = (char *)hex2mem(buf, p, len);
958    if (p == NULL)
959        throw CmdError("E09");
960    if (!acc(addr, len))
961        throw CmdError("E0A");
962    if (!write(addr, len, buf))
963        throw CmdError("E0B");
964    send("OK");
965    return true;
966}
967
968bool
969BaseRemoteGDB::cmd_query_var(GdbCommand::Context &ctx)
970{
971    string s(ctx.data, ctx.len - 1);
972    string xfer_read_prefix = "Xfer:features:read:";
973    if (s.rfind("Supported:", 0) == 0) {
974        std::ostringstream oss;
975        // This reply field mandatory. We can receive arbitrarily
976        // long packets, so we could choose it to be arbitrarily large.
977        // This is just an arbitrary filler value that seems to work.
978        oss << "PacketSize=1024";
979        for (const auto& feature : availableFeatures())
980            oss << ';' << feature;
981        send(oss.str().c_str());
982    } else if (s.rfind(xfer_read_prefix, 0) == 0) {
983        size_t offset, length;
984        auto value_string = s.substr(xfer_read_prefix.length());
985        auto colon_pos = value_string.find(':');
986        auto comma_pos = value_string.find(',');
987        if (colon_pos == std::string::npos || comma_pos == std::string::npos)
988            throw CmdError("E00");
989        std::string annex;
990        if (!getXferFeaturesRead(value_string.substr(0, colon_pos), annex))
991            throw CmdError("E00");
992        try {
993            offset = std::stoull(
994                value_string.substr(colon_pos + 1, comma_pos), NULL, 16);
995            length = std::stoull(
996                value_string.substr(comma_pos + 1), NULL, 16);
997        } catch (std::invalid_argument& e) {
998            throw CmdError("E00");
999        } catch (std::out_of_range& e) {
1000            throw CmdError("E00");
1001        }
1002        std::string encoded;
1003        encodeXferResponse(annex, encoded, offset, length);
1004        send(encoded.c_str());
1005    } else if (s == "C") {
1006        send("QC0");
1007    } else {
1008        throw Unsupported();
1009    }
1010    return true;
1011}
1012
1013std::vector<std::string>
1014BaseRemoteGDB::availableFeatures() const
1015{
1016    return {};
1017};
1018
1019bool
1020BaseRemoteGDB::getXferFeaturesRead(
1021    const std::string &annex, std::string &output)
1022{
1023    return false;
1024}
1025
1026void
1027BaseRemoteGDB::encodeBinaryData(
1028    const std::string &unencoded, std::string &encoded) const
1029{
1030    for (const char& c : unencoded) {
1031        if (c == '$' || c == '#' || c == '}' || c == '*') {
1032            encoded += '}';
1033            encoded += c ^ 0x20;
1034        } else {
1035            encoded += c;
1036        }
1037    }
1038}
1039
1040void
1041BaseRemoteGDB::encodeXferResponse(const std::string &unencoded,
1042    std::string &encoded, size_t offset, size_t unencoded_length) const
1043{
1044    if (offset + unencoded_length < unencoded.length())
1045        encoded += 'm';
1046    else
1047        encoded += 'l';
1048    encodeBinaryData(unencoded.substr(offset, unencoded_length), encoded);
1049}
1050
1051bool
1052BaseRemoteGDB::cmd_async_step(GdbCommand::Context &ctx)
1053{
1054    const char *p = ctx.data;
1055    hex2i(&p); // Ignore the subcommand byte.
1056    if (*p++ == ';') {
1057        Addr newPc = hex2i(&p);
1058        tc->pcState(newPc);
1059    }
1060    setSingleStep();
1061    return false;
1062}
1063
1064bool
1065BaseRemoteGDB::cmd_step(GdbCommand::Context &ctx)
1066{
1067    if (ctx.len) {
1068        const char *p = ctx.data;
1069        Addr newPc = hex2i(&p);
1070        tc->pcState(newPc);
1071    }
1072    setSingleStep();
1073    return false;
1074}
1075
1076bool
1077BaseRemoteGDB::cmd_clr_hw_bkpt(GdbCommand::Context &ctx)
1078{
1079    const char *p = ctx.data;
1080    char subcmd = *p++;
1081    if (*p++ != ',')
1082        throw CmdError("E0D");
1083    Addr addr = hex2i(&p);
1084    if (*p++ != ',')
1085        throw CmdError("E0D");
1086    size_t len = hex2i(&p);
1087
1088    DPRINTF(GDBMisc, "clear %s, addr=%#x, len=%d\n",
1089            break_type(subcmd), addr, len);
1090
1091    switch (subcmd) {
1092      case GdbSoftBp:
1093        removeSoftBreak(addr, len);
1094        break;
1095      case GdbHardBp:
1096        removeHardBreak(addr, len);
1097        break;
1098      case GdbWriteWp:
1099      case GdbReadWp:
1100      case GdbAccWp:
1101      default: // unknown
1102        throw Unsupported();
1103    }
1104    send("OK");
1105
1106    return true;
1107}
1108
1109bool
1110BaseRemoteGDB::cmd_set_hw_bkpt(GdbCommand::Context &ctx)
1111{
1112    const char *p = ctx.data;
1113    char subcmd = *p++;
1114    if (*p++ != ',')
1115        throw CmdError("E0D");
1116    Addr addr = hex2i(&p);
1117    if (*p++ != ',')
1118        throw CmdError("E0D");
1119    size_t len = hex2i(&p);
1120
1121    DPRINTF(GDBMisc, "set %s, addr=%#x, len=%d\n",
1122            break_type(subcmd), addr, len);
1123
1124    switch (subcmd) {
1125      case GdbSoftBp:
1126        insertSoftBreak(addr, len);
1127        break;
1128      case GdbHardBp:
1129        insertHardBreak(addr, len);
1130        break;
1131      case GdbWriteWp:
1132      case GdbReadWp:
1133      case GdbAccWp:
1134      default: // unknown
1135        throw Unsupported();
1136    }
1137    send("OK");
1138
1139    return true;
1140}
1141