remote_gdb.cc revision 8332
112854Sgabeblack@google.com/*
212854Sgabeblack@google.com * Copyright (c) 2002-2005 The Regents of The University of Michigan
312854Sgabeblack@google.com * All rights reserved.
412854Sgabeblack@google.com *
512854Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
612854Sgabeblack@google.com * modification, are permitted provided that the following conditions are
712854Sgabeblack@google.com * met: redistributions of source code must retain the above copyright
812854Sgabeblack@google.com * notice, this list of conditions and the following disclaimer;
912854Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright
1012854Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the
1112854Sgabeblack@google.com * documentation and/or other materials provided with the distribution;
1212854Sgabeblack@google.com * neither the name of the copyright holders nor the names of its
1312854Sgabeblack@google.com * contributors may be used to endorse or promote products derived from
1412854Sgabeblack@google.com * this software without specific prior written permission.
1512854Sgabeblack@google.com *
1612854Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1712854Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1812854Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1912854Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2012854Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2112854Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2212854Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2312854Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2412854Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2512854Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2612854Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2712854Sgabeblack@google.com *
2812854Sgabeblack@google.com * Authors: Nathan Binkert
2912854Sgabeblack@google.com */
3012854Sgabeblack@google.com
3112854Sgabeblack@google.com/*
3212854Sgabeblack@google.com * Copyright (c) 1990, 1993 The Regents of the University of California
3312854Sgabeblack@google.com * All rights reserved
3412854Sgabeblack@google.com *
3512854Sgabeblack@google.com * This software was developed by the Computer Systems Engineering group
3612854Sgabeblack@google.com * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
3712854Sgabeblack@google.com * contributed to Berkeley.
3812854Sgabeblack@google.com *
3912854Sgabeblack@google.com * All advertising materials mentioning features or use of this software
4012854Sgabeblack@google.com * must display the following acknowledgement:
4112854Sgabeblack@google.com *      This product includes software developed by the University of
4212854Sgabeblack@google.com *      California, Lawrence Berkeley Laboratories.
4312854Sgabeblack@google.com *
4412854Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
4512854Sgabeblack@google.com * modification, are permitted provided that the following conditions
4612854Sgabeblack@google.com * are met:
4712854Sgabeblack@google.com * 1. Redistributions of source code must retain the above copyright
4812854Sgabeblack@google.com *    notice, this list of conditions and the following disclaimer.
4912854Sgabeblack@google.com * 2. Redistributions in binary form must reproduce the above copyright
5012854Sgabeblack@google.com *    notice, this list of conditions and the following disclaimer in the
5112854Sgabeblack@google.com *    documentation and/or other materials provided with the distribution.
5212854Sgabeblack@google.com * 3. All advertising materials mentioning features or use of this software
5312854Sgabeblack@google.com *    must display the following acknowledgement:
5412854Sgabeblack@google.com *      This product includes software developed by the University of
5512854Sgabeblack@google.com *      California, Berkeley and its contributors.
5612854Sgabeblack@google.com * 4. Neither the name of the University nor the names of its contributors
5712854Sgabeblack@google.com *    may be used to endorse or promote products derived from this software
5812854Sgabeblack@google.com *    without specific prior written permission.
5912854Sgabeblack@google.com *
6012854Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
6112854Sgabeblack@google.com * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
6212854Sgabeblack@google.com * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
6312854Sgabeblack@google.com * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
6412854Sgabeblack@google.com * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
6512854Sgabeblack@google.com * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
6612854Sgabeblack@google.com * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6712854Sgabeblack@google.com * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6812854Sgabeblack@google.com * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6912854Sgabeblack@google.com * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7012854Sgabeblack@google.com * SUCH DAMAGE.
7112854Sgabeblack@google.com *
7212854Sgabeblack@google.com *      @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94
7312854Sgabeblack@google.com */
7412854Sgabeblack@google.com
7512854Sgabeblack@google.com/*-
7612854Sgabeblack@google.com * Copyright (c) 2001 The NetBSD Foundation, Inc.
7712854Sgabeblack@google.com * All rights reserved.
7812854Sgabeblack@google.com *
7912854Sgabeblack@google.com * This code is derived from software contributed to The NetBSD Foundation
8012854Sgabeblack@google.com * by Jason R. Thorpe.
8112854Sgabeblack@google.com *
8212854Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
8312854Sgabeblack@google.com * modification, are permitted provided that the following conditions
8412854Sgabeblack@google.com * are met:
8513325Sgabeblack@google.com * 1. Redistributions of source code must retain the above copyright
8612854Sgabeblack@google.com *    notice, this list of conditions and the following disclaimer.
8712854Sgabeblack@google.com * 2. Redistributions in binary form must reproduce the above copyright
8812854Sgabeblack@google.com *    notice, this list of conditions and the following disclaimer in the
8912854Sgabeblack@google.com *    documentation and/or other materials provided with the distribution.
9012854Sgabeblack@google.com * 3. All advertising materials mentioning features or use of this software
9112854Sgabeblack@google.com *    must display the following acknowledgement:
9212854Sgabeblack@google.com *      This product includes software developed by the NetBSD
9312854Sgabeblack@google.com *      Foundation, Inc. and its contributors.
9412854Sgabeblack@google.com * 4. Neither the name of The NetBSD Foundation nor the names of its
9512854Sgabeblack@google.com *    contributors may be used to endorse or promote products derived
9612854Sgabeblack@google.com *    from this software without specific prior written permission.
9712854Sgabeblack@google.com *
9812854Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
9912854Sgabeblack@google.com * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
10012854Sgabeblack@google.com * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
10112854Sgabeblack@google.com * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
10212854Sgabeblack@google.com * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
10312854Sgabeblack@google.com * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
10412854Sgabeblack@google.com * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
10512854Sgabeblack@google.com * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
10612854Sgabeblack@google.com * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
10712854Sgabeblack@google.com * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
10812854Sgabeblack@google.com * POSSIBILITY OF SUCH DAMAGE.
10912854Sgabeblack@google.com */
11012854Sgabeblack@google.com
11112854Sgabeblack@google.com/*
11212854Sgabeblack@google.com * $NetBSD: kgdb_stub.c,v 1.8 2001/07/07 22:58:00 wdk Exp $
11312854Sgabeblack@google.com *
11413325Sgabeblack@google.com * Taken from NetBSD
11512854Sgabeblack@google.com *
11612854Sgabeblack@google.com * "Stub" to allow remote cpu to debug over a serial line using gdb.
11712854Sgabeblack@google.com */
11812854Sgabeblack@google.com
11912854Sgabeblack@google.com#include <sys/signal.h>
12012854Sgabeblack@google.com#include <unistd.h>
12112854Sgabeblack@google.com
12212854Sgabeblack@google.com#include <cstdio>
12312854Sgabeblack@google.com#include <string>
12412854Sgabeblack@google.com
12512854Sgabeblack@google.com#include "config/full_system.hh"
12612854Sgabeblack@google.com
12713322Sgabeblack@google.com#if FULL_SYSTEM
12812854Sgabeblack@google.com#include "arch/vtophys.hh"
12912854Sgabeblack@google.com#include "mem/vport.hh"
13012854Sgabeblack@google.com#endif
13112854Sgabeblack@google.com
13212854Sgabeblack@google.com#include "base/intmath.hh"
13312854Sgabeblack@google.com#include "base/remote_gdb.hh"
13412854Sgabeblack@google.com#include "base/socket.hh"
13512854Sgabeblack@google.com#include "base/trace.hh"
13613160Sgabeblack@google.com#include "config/the_isa.hh"
13712854Sgabeblack@google.com#include "cpu/static_inst.hh"
13812854Sgabeblack@google.com#include "cpu/thread_context.hh"
13913322Sgabeblack@google.com#include "debug/GDBAll.hh"
14012854Sgabeblack@google.com#include "mem/port.hh"
14112854Sgabeblack@google.com#include "mem/translating_port.hh"
14212854Sgabeblack@google.com#include "sim/system.hh"
14312854Sgabeblack@google.com
14412854Sgabeblack@google.comusing namespace std;
14512854Sgabeblack@google.comusing namespace Debug;
14612854Sgabeblack@google.comusing namespace TheISA;
14712854Sgabeblack@google.com
14812854Sgabeblack@google.com#ifndef NDEBUG
14912854Sgabeblack@google.comvector<BaseRemoteGDB *> debuggers;
15012854Sgabeblack@google.com
15112854Sgabeblack@google.comvoid
15212854Sgabeblack@google.comdebugger()
15312854Sgabeblack@google.com{
15412854Sgabeblack@google.com    static int current_debugger = -1;
15512854Sgabeblack@google.com    if (current_debugger >= 0 && current_debugger < (int)debuggers.size()) {
15612854Sgabeblack@google.com        BaseRemoteGDB *gdb = debuggers[current_debugger];
15712854Sgabeblack@google.com        if (!gdb->isattached())
15812854Sgabeblack@google.com            gdb->listener->accept();
15912854Sgabeblack@google.com        if (gdb->isattached())
16012854Sgabeblack@google.com            gdb->trap(SIGILL);
16112854Sgabeblack@google.com    }
16212854Sgabeblack@google.com}
16312854Sgabeblack@google.com#endif
16412854Sgabeblack@google.com
16512854Sgabeblack@google.com///////////////////////////////////////////////////////////
16612854Sgabeblack@google.com//
16712854Sgabeblack@google.com//
16812854Sgabeblack@google.com//
16912854Sgabeblack@google.com
17012854Sgabeblack@google.comGDBListener::Event::Event(GDBListener *l, int fd, int e)
17112854Sgabeblack@google.com    : PollEvent(fd, e), listener(l)
17212854Sgabeblack@google.com{}
17312854Sgabeblack@google.com
17412854Sgabeblack@google.comvoid
17512854Sgabeblack@google.comGDBListener::Event::process(int revent)
17612854Sgabeblack@google.com{
17712854Sgabeblack@google.com    listener->accept();
17812854Sgabeblack@google.com}
17912854Sgabeblack@google.com
18012854Sgabeblack@google.comGDBListener::GDBListener(BaseRemoteGDB *g, int p)
18112854Sgabeblack@google.com    : event(NULL), gdb(g), port(p)
18212854Sgabeblack@google.com{
18312854Sgabeblack@google.com    assert(!gdb->listener);
18412854Sgabeblack@google.com    gdb->listener = this;
18512854Sgabeblack@google.com}
18612854Sgabeblack@google.com
18712854Sgabeblack@google.comGDBListener::~GDBListener()
18812854Sgabeblack@google.com{
18912854Sgabeblack@google.com    if (event)
19012854Sgabeblack@google.com        delete event;
19112854Sgabeblack@google.com}
19212854Sgabeblack@google.com
19312854Sgabeblack@google.comstring
19412854Sgabeblack@google.comGDBListener::name()
19512854Sgabeblack@google.com{
19612854Sgabeblack@google.com    return gdb->name() + ".listener";
19712854Sgabeblack@google.com}
19812854Sgabeblack@google.com
19912854Sgabeblack@google.comvoid
20012854Sgabeblack@google.comGDBListener::listen()
20112854Sgabeblack@google.com{
20212854Sgabeblack@google.com    if (ListenSocket::allDisabled()) {
20312854Sgabeblack@google.com        warn_once("Sockets disabled, not accepting gdb connections");
20412854Sgabeblack@google.com        return;
20512854Sgabeblack@google.com    }
20612854Sgabeblack@google.com
20712854Sgabeblack@google.com    while (!listener.listen(port, true)) {
20812854Sgabeblack@google.com        DPRINTF(GDBMisc, "Can't bind port %d\n", port);
20912854Sgabeblack@google.com        port++;
21012854Sgabeblack@google.com    }
21112854Sgabeblack@google.com
21212854Sgabeblack@google.com    event = new Event(this, listener.getfd(), POLLIN);
21312854Sgabeblack@google.com    pollQueue.schedule(event);
21412854Sgabeblack@google.com
21512854Sgabeblack@google.com#ifndef NDEBUG
21612854Sgabeblack@google.com    gdb->number = debuggers.size();
21712854Sgabeblack@google.com    debuggers.push_back(gdb);
21812854Sgabeblack@google.com#endif
21912854Sgabeblack@google.com
22012854Sgabeblack@google.com#ifndef NDEBUG
22112854Sgabeblack@google.com    ccprintf(cerr, "%d: %s: listening for remote gdb #%d on port %d\n",
22212854Sgabeblack@google.com             curTick(), name(), gdb->number, port);
22312854Sgabeblack@google.com#else
22412854Sgabeblack@google.com    ccprintf(cerr, "%d: %s: listening for remote gdb on port %d\n",
22512854Sgabeblack@google.com             curTick(), name(), port);
22612854Sgabeblack@google.com#endif
22712854Sgabeblack@google.com}
22812854Sgabeblack@google.com
22912854Sgabeblack@google.comvoid
23012854Sgabeblack@google.comGDBListener::accept()
23112854Sgabeblack@google.com{
23212854Sgabeblack@google.com    if (!listener.islistening())
23312854Sgabeblack@google.com        panic("GDBListener::accept(): cannot accept if we're not listening!");
23412854Sgabeblack@google.com
23512854Sgabeblack@google.com    int sfd = listener.accept(true);
23612854Sgabeblack@google.com
23712854Sgabeblack@google.com    if (sfd != -1) {
23812854Sgabeblack@google.com        if (gdb->isattached())
23912854Sgabeblack@google.com            close(sfd);
24012854Sgabeblack@google.com        else
24112854Sgabeblack@google.com            gdb->attach(sfd);
24212854Sgabeblack@google.com    }
24312854Sgabeblack@google.com}
24412854Sgabeblack@google.com
24512854Sgabeblack@google.comBaseRemoteGDB::Event::Event(BaseRemoteGDB *g, int fd, int e)
24612854Sgabeblack@google.com    : PollEvent(fd, e), gdb(g)
24712854Sgabeblack@google.com{}
24812854Sgabeblack@google.com
24912854Sgabeblack@google.comvoid
25012854Sgabeblack@google.comBaseRemoteGDB::Event::process(int revent)
25112854Sgabeblack@google.com{
25212854Sgabeblack@google.com    if (revent & POLLIN)
25312854Sgabeblack@google.com        gdb->trap(SIGILL);
25412854Sgabeblack@google.com    else if (revent & POLLNVAL)
25512854Sgabeblack@google.com        gdb->detach();
25612854Sgabeblack@google.com}
25712854Sgabeblack@google.com
25812854Sgabeblack@google.comBaseRemoteGDB::BaseRemoteGDB(System *_system, ThreadContext *c, size_t cacheSize)
25912854Sgabeblack@google.com    : event(NULL), listener(NULL), number(-1), fd(-1),
26012854Sgabeblack@google.com      active(false), attached(false),
26112854Sgabeblack@google.com      system(_system), pmem(_system->physmem), context(c),
26212854Sgabeblack@google.com      gdbregs(cacheSize)
26312854Sgabeblack@google.com{
26412854Sgabeblack@google.com    memset(gdbregs.regs, 0, gdbregs.bytes());
26512854Sgabeblack@google.com}
26612854Sgabeblack@google.com
26712854Sgabeblack@google.comBaseRemoteGDB::~BaseRemoteGDB()
26812854Sgabeblack@google.com{
26912854Sgabeblack@google.com    if (event)
27012854Sgabeblack@google.com        delete event;
27112854Sgabeblack@google.com}
27212854Sgabeblack@google.com
27312854Sgabeblack@google.comstring
27412854Sgabeblack@google.comBaseRemoteGDB::name()
27512854Sgabeblack@google.com{
27612854Sgabeblack@google.com    return system->name() + ".remote_gdb";
27712854Sgabeblack@google.com}
27812854Sgabeblack@google.com
27912854Sgabeblack@google.combool
28012854Sgabeblack@google.comBaseRemoteGDB::isattached()
28112854Sgabeblack@google.com{ return attached; }
28212854Sgabeblack@google.com
28312854Sgabeblack@google.comvoid
28412854Sgabeblack@google.comBaseRemoteGDB::attach(int f)
28512854Sgabeblack@google.com{
28612854Sgabeblack@google.com    fd = f;
28712854Sgabeblack@google.com
28812854Sgabeblack@google.com    event = new Event(this, fd, POLLIN);
28912854Sgabeblack@google.com    pollQueue.schedule(event);
29012854Sgabeblack@google.com
29112854Sgabeblack@google.com    attached = true;
29212854Sgabeblack@google.com    DPRINTFN("remote gdb attached\n");
29312854Sgabeblack@google.com}
29412854Sgabeblack@google.com
29512854Sgabeblack@google.comvoid
29612854Sgabeblack@google.comBaseRemoteGDB::detach()
29712854Sgabeblack@google.com{
29812854Sgabeblack@google.com    attached = false;
29912854Sgabeblack@google.com    close(fd);
30012854Sgabeblack@google.com    fd = -1;
30112854Sgabeblack@google.com
30212854Sgabeblack@google.com    pollQueue.remove(event);
30312854Sgabeblack@google.com    DPRINTFN("remote gdb detached\n");
30412854Sgabeblack@google.com}
30512854Sgabeblack@google.com
30612854Sgabeblack@google.comconst char *
30712854Sgabeblack@google.comBaseRemoteGDB::gdb_command(char cmd)
30812854Sgabeblack@google.com{
30912854Sgabeblack@google.com    switch (cmd) {
31012854Sgabeblack@google.com      case GDBSignal: return "KGDB_SIGNAL";
31112854Sgabeblack@google.com      case GDBSetBaud: return "KGDB_SET_BAUD";
31212854Sgabeblack@google.com      case GDBSetBreak: return "KGDB_SET_BREAK";
31312854Sgabeblack@google.com      case GDBCont: return "KGDB_CONT";
31412854Sgabeblack@google.com      case GDBAsyncCont: return "KGDB_ASYNC_CONT";
31512854Sgabeblack@google.com      case GDBDebug: return "KGDB_DEBUG";
31612854Sgabeblack@google.com      case GDBDetach: return "KGDB_DETACH";
31712854Sgabeblack@google.com      case GDBRegR: return "KGDB_REG_R";
31812854Sgabeblack@google.com      case GDBRegW: return "KGDB_REG_W";
31912854Sgabeblack@google.com      case GDBSetThread: return "KGDB_SET_THREAD";
32012854Sgabeblack@google.com      case GDBCycleStep: return "KGDB_CYCLE_STEP";
32112854Sgabeblack@google.com      case GDBSigCycleStep: return "KGDB_SIG_CYCLE_STEP";
32212854Sgabeblack@google.com      case GDBKill: return "KGDB_KILL";
32312854Sgabeblack@google.com      case GDBMemW: return "KGDB_MEM_W";
32412854Sgabeblack@google.com      case GDBMemR: return "KGDB_MEM_R";
32512854Sgabeblack@google.com      case GDBSetReg: return "KGDB_SET_REG";
32612854Sgabeblack@google.com      case GDBReadReg: return "KGDB_READ_REG";
32712854Sgabeblack@google.com      case GDBQueryVar: return "KGDB_QUERY_VAR";
32812854Sgabeblack@google.com      case GDBSetVar: return "KGDB_SET_VAR";
32912854Sgabeblack@google.com      case GDBReset: return "KGDB_RESET";
33012854Sgabeblack@google.com      case GDBStep: return "KGDB_STEP";
33112854Sgabeblack@google.com      case GDBAsyncStep: return "KGDB_ASYNC_STEP";
33212854Sgabeblack@google.com      case GDBThreadAlive: return "KGDB_THREAD_ALIVE";
33312854Sgabeblack@google.com      case GDBTargetExit: return "KGDB_TARGET_EXIT";
33412854Sgabeblack@google.com      case GDBBinaryDload: return "KGDB_BINARY_DLOAD";
33512854Sgabeblack@google.com      case GDBClrHwBkpt: return "KGDB_CLR_HW_BKPT";
33612854Sgabeblack@google.com      case GDBSetHwBkpt: return "KGDB_SET_HW_BKPT";
33712854Sgabeblack@google.com      case GDBStart: return "KGDB_START";
33812854Sgabeblack@google.com      case GDBEnd: return "KGDB_END";
33912854Sgabeblack@google.com      case GDBGoodP: return "KGDB_GOODP";
34012854Sgabeblack@google.com      case GDBBadP: return "KGDB_BADP";
34112854Sgabeblack@google.com      default: return "KGDB_UNKNOWN";
34212854Sgabeblack@google.com    }
34312854Sgabeblack@google.com}
34412854Sgabeblack@google.com
34512854Sgabeblack@google.com/////////////////////////
34612854Sgabeblack@google.com//
34712854Sgabeblack@google.com//
34812854Sgabeblack@google.com
34912854Sgabeblack@google.comuint8_t
35012854Sgabeblack@google.comBaseRemoteGDB::getbyte()
35112854Sgabeblack@google.com{
35212854Sgabeblack@google.com    uint8_t b;
35312854Sgabeblack@google.com    if (::read(fd, &b, 1) != 1)
35412854Sgabeblack@google.com        warn("could not read byte from debugger");
35512854Sgabeblack@google.com    return b;
35612854Sgabeblack@google.com}
35712854Sgabeblack@google.com
35812854Sgabeblack@google.comvoid
35912854Sgabeblack@google.comBaseRemoteGDB::putbyte(uint8_t b)
36012854Sgabeblack@google.com{
36112854Sgabeblack@google.com    if (::write(fd, &b, 1) != 1)
36212854Sgabeblack@google.com        warn("could not write byte to debugger");
36312854Sgabeblack@google.com}
36412854Sgabeblack@google.com
36512854Sgabeblack@google.com// Send a packet to gdb
36612854Sgabeblack@google.comvoid
36712854Sgabeblack@google.comBaseRemoteGDB::send(const char *bp)
36812854Sgabeblack@google.com{
36912854Sgabeblack@google.com    const char *p;
37012854Sgabeblack@google.com    uint8_t csum, c;
37112854Sgabeblack@google.com
37212854Sgabeblack@google.com    DPRINTF(GDBSend, "send:  %s\n", bp);
37312854Sgabeblack@google.com
37412854Sgabeblack@google.com    do {
37512854Sgabeblack@google.com        p = bp;
37612854Sgabeblack@google.com        //Start sending a packet
37712854Sgabeblack@google.com        putbyte(GDBStart);
37812854Sgabeblack@google.com        //Send the contents, and also keep a check sum.
37912854Sgabeblack@google.com        for (csum = 0; (c = *p); p++) {
38012854Sgabeblack@google.com            putbyte(c);
38112854Sgabeblack@google.com            csum += c;
38212854Sgabeblack@google.com        }
38312854Sgabeblack@google.com        //Send the ending character.
38412854Sgabeblack@google.com        putbyte(GDBEnd);
38512854Sgabeblack@google.com        //Sent the checksum.
38612854Sgabeblack@google.com        putbyte(i2digit(csum >> 4));
38712854Sgabeblack@google.com        putbyte(i2digit(csum));
38812854Sgabeblack@google.com        //Try transmitting over and over again until the other end doesn't send an
38912854Sgabeblack@google.com        //error back.
39012854Sgabeblack@google.com    } while ((c = getbyte() & 0x7f) == GDBBadP);
39112854Sgabeblack@google.com}
39212854Sgabeblack@google.com
39312854Sgabeblack@google.com// Receive a packet from gdb
39412854Sgabeblack@google.comint
39512854Sgabeblack@google.comBaseRemoteGDB::recv(char *bp, int maxlen)
39612854Sgabeblack@google.com{
39712854Sgabeblack@google.com    char *p;
39812854Sgabeblack@google.com    int c, csum;
39912854Sgabeblack@google.com    int len;
40012854Sgabeblack@google.com
40112854Sgabeblack@google.com    do {
40212854Sgabeblack@google.com        p = bp;
40312854Sgabeblack@google.com        csum = len = 0;
40412854Sgabeblack@google.com        //Find the beginning of a packet
40512854Sgabeblack@google.com        while ((c = getbyte()) != GDBStart)
40612854Sgabeblack@google.com            ;
40712854Sgabeblack@google.com
40812854Sgabeblack@google.com        //Read until you find the end of the data in the packet, and keep
40912854Sgabeblack@google.com        //track of the check sum.
41012854Sgabeblack@google.com        while ((c = getbyte()) != GDBEnd && len < maxlen) {
41112854Sgabeblack@google.com            c &= 0x7f;
41212854Sgabeblack@google.com            csum += c;
41312854Sgabeblack@google.com            *p++ = c;
41412854Sgabeblack@google.com            len++;
41512854Sgabeblack@google.com        }
41612854Sgabeblack@google.com
41712854Sgabeblack@google.com        //Mask the check sum, and terminate the command string.
41812854Sgabeblack@google.com        csum &= 0xff;
41912854Sgabeblack@google.com        *p = '\0';
42012854Sgabeblack@google.com
42112854Sgabeblack@google.com        //If the command was too long, report an error.
42212854Sgabeblack@google.com        if (len >= maxlen) {
42312854Sgabeblack@google.com            putbyte(GDBBadP);
42412854Sgabeblack@google.com            continue;
42512854Sgabeblack@google.com        }
42612854Sgabeblack@google.com
42712854Sgabeblack@google.com        //Bring in the checksum. If the check sum matches, csum will be 0.
42812854Sgabeblack@google.com        csum -= digit2i(getbyte()) * 16;
42912854Sgabeblack@google.com        csum -= digit2i(getbyte());
43012854Sgabeblack@google.com
43112854Sgabeblack@google.com        //If the check sum was correct
43212854Sgabeblack@google.com        if (csum == 0) {
43312854Sgabeblack@google.com            //Report that the packet was received correctly
43412854Sgabeblack@google.com            putbyte(GDBGoodP);
43512854Sgabeblack@google.com            // Sequence present?
43612854Sgabeblack@google.com            if (bp[2] == ':') {
43712854Sgabeblack@google.com                putbyte(bp[0]);
43812854Sgabeblack@google.com                putbyte(bp[1]);
43912854Sgabeblack@google.com                len -= 3;
44012854Sgabeblack@google.com                memcpy(bp, bp+3, len);
44112854Sgabeblack@google.com            }
44212854Sgabeblack@google.com            break;
44312854Sgabeblack@google.com        }
44413325Sgabeblack@google.com        //Otherwise, report that there was a mistake.
44512854Sgabeblack@google.com        putbyte(GDBBadP);
44612854Sgabeblack@google.com    } while (1);
44713325Sgabeblack@google.com
44812854Sgabeblack@google.com    DPRINTF(GDBRecv, "recv:  %s: %s\n", gdb_command(*bp), bp);
44912854Sgabeblack@google.com
45012854Sgabeblack@google.com    return (len);
45112854Sgabeblack@google.com}
45212854Sgabeblack@google.com
45312854Sgabeblack@google.com// Read bytes from kernel address space for debugger.
45412854Sgabeblack@google.combool
45512854Sgabeblack@google.comBaseRemoteGDB::read(Addr vaddr, size_t size, char *data)
45613325Sgabeblack@google.com{
45712854Sgabeblack@google.com    static Addr lastaddr = 0;
45812854Sgabeblack@google.com    static size_t lastsize = 0;
45912854Sgabeblack@google.com
46012854Sgabeblack@google.com    if (vaddr < 10) {
46112854Sgabeblack@google.com      DPRINTF(GDBRead, "read:  reading memory location zero!\n");
46212854Sgabeblack@google.com      vaddr = lastaddr + lastsize;
46312854Sgabeblack@google.com    }
46412854Sgabeblack@google.com
46512854Sgabeblack@google.com    DPRINTF(GDBRead, "read:  addr=%#x, size=%d", vaddr, size);
46612854Sgabeblack@google.com
46712854Sgabeblack@google.com#if FULL_SYSTEM
46812854Sgabeblack@google.com    VirtualPort *port = context->getVirtPort();
46912854Sgabeblack@google.com#else
47012854Sgabeblack@google.com    TranslatingPort *port = context->getMemPort();
47112854Sgabeblack@google.com#endif
47212854Sgabeblack@google.com    port->readBlob(vaddr, (uint8_t*)data, size);
47312854Sgabeblack@google.com
47412854Sgabeblack@google.com#if TRACING_ON
47512854Sgabeblack@google.com    if (DTRACE(GDBRead)) {
47612854Sgabeblack@google.com        if (DTRACE(GDBExtra)) {
47712854Sgabeblack@google.com            char buf[1024];
47812854Sgabeblack@google.com            mem2hex(buf, data, size);
47912854Sgabeblack@google.com            DPRINTFNR(": %s\n", buf);
48012854Sgabeblack@google.com        } else
48112854Sgabeblack@google.com            DPRINTFNR("\n");
48212854Sgabeblack@google.com    }
48312854Sgabeblack@google.com#endif
48412854Sgabeblack@google.com
48512854Sgabeblack@google.com    return true;
48612854Sgabeblack@google.com}
48712854Sgabeblack@google.com
48812854Sgabeblack@google.com// Write bytes to kernel address space for debugger.
48912854Sgabeblack@google.combool
49012854Sgabeblack@google.comBaseRemoteGDB::write(Addr vaddr, size_t size, const char *data)
49112854Sgabeblack@google.com{
49212854Sgabeblack@google.com    static Addr lastaddr = 0;
49312854Sgabeblack@google.com    static size_t lastsize = 0;
49412854Sgabeblack@google.com
49512854Sgabeblack@google.com    if (vaddr < 10) {
49612854Sgabeblack@google.com      DPRINTF(GDBWrite, "write: writing memory location zero!\n");
49712854Sgabeblack@google.com      vaddr = lastaddr + lastsize;
49812854Sgabeblack@google.com    }
49912854Sgabeblack@google.com
50012854Sgabeblack@google.com    if (DTRACE(GDBWrite)) {
50112854Sgabeblack@google.com        DPRINTFN("write: addr=%#x, size=%d", vaddr, size);
50212854Sgabeblack@google.com        if (DTRACE(GDBExtra)) {
50312854Sgabeblack@google.com            char buf[1024];
50412854Sgabeblack@google.com            mem2hex(buf, data, size);
50512854Sgabeblack@google.com            DPRINTFNR(": %s\n", buf);
50612854Sgabeblack@google.com        } else
50712854Sgabeblack@google.com            DPRINTFNR("\n");
50812854Sgabeblack@google.com    }
50912854Sgabeblack@google.com#if FULL_SYSTEM
51012854Sgabeblack@google.com    VirtualPort *port = context->getVirtPort();
51112854Sgabeblack@google.com#else
51212854Sgabeblack@google.com    TranslatingPort *port = context->getMemPort();
51312854Sgabeblack@google.com#endif
51412854Sgabeblack@google.com    port->writeBlob(vaddr, (uint8_t*)data, size);
51512854Sgabeblack@google.com#if !FULL_SYSTEM
51612854Sgabeblack@google.com    delete port;
51712854Sgabeblack@google.com#endif
51812854Sgabeblack@google.com
51912854Sgabeblack@google.com    return true;
52012854Sgabeblack@google.com}
52112854Sgabeblack@google.com
52212854Sgabeblack@google.comPCEventQueue *BaseRemoteGDB::getPcEventQueue()
52312854Sgabeblack@google.com{
52412854Sgabeblack@google.com    return &system->pcEventQueue;
52512854Sgabeblack@google.com}
52612854Sgabeblack@google.com
52712854Sgabeblack@google.comBaseRemoteGDB::HardBreakpoint::HardBreakpoint(BaseRemoteGDB *_gdb, Addr pc)
52812854Sgabeblack@google.com    : PCEvent(_gdb->getPcEventQueue(), "HardBreakpoint Event", pc),
52912854Sgabeblack@google.com      gdb(_gdb), refcount(0)
53012854Sgabeblack@google.com{
53112854Sgabeblack@google.com    DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc);
53212854Sgabeblack@google.com}
53312854Sgabeblack@google.com
53412854Sgabeblack@google.comvoid
53512854Sgabeblack@google.comBaseRemoteGDB::HardBreakpoint::process(ThreadContext *tc)
53612854Sgabeblack@google.com{
53712854Sgabeblack@google.com    DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc());
53812854Sgabeblack@google.com
53912854Sgabeblack@google.com    if (tc == gdb->context)
54012854Sgabeblack@google.com        gdb->trap(SIGTRAP);
54112854Sgabeblack@google.com}
54212854Sgabeblack@google.com
54312854Sgabeblack@google.combool
54412854Sgabeblack@google.comBaseRemoteGDB::insertSoftBreak(Addr addr, size_t len)
54512854Sgabeblack@google.com{
54612854Sgabeblack@google.com    if (len != sizeof(TheISA::MachInst))
54712854Sgabeblack@google.com        panic("invalid length\n");
54812854Sgabeblack@google.com
54912854Sgabeblack@google.com    return insertHardBreak(addr, len);
55012854Sgabeblack@google.com}
55112854Sgabeblack@google.com
55212854Sgabeblack@google.combool
55312854Sgabeblack@google.comBaseRemoteGDB::removeSoftBreak(Addr addr, size_t len)
55412854Sgabeblack@google.com{
55512854Sgabeblack@google.com    if (len != sizeof(MachInst))
55612854Sgabeblack@google.com        panic("invalid length\n");
55712854Sgabeblack@google.com
55812854Sgabeblack@google.com    return removeHardBreak(addr, len);
55912854Sgabeblack@google.com}
56012854Sgabeblack@google.com
56112854Sgabeblack@google.combool
56212854Sgabeblack@google.comBaseRemoteGDB::insertHardBreak(Addr addr, size_t len)
56312854Sgabeblack@google.com{
56412854Sgabeblack@google.com    if (len != sizeof(MachInst))
56512854Sgabeblack@google.com        panic("invalid length\n");
56612854Sgabeblack@google.com
56712854Sgabeblack@google.com    DPRINTF(GDBMisc, "inserting hardware breakpoint at %#x\n", addr);
56812854Sgabeblack@google.com
56912854Sgabeblack@google.com    HardBreakpoint *&bkpt = hardBreakMap[addr];
57012854Sgabeblack@google.com    if (bkpt == 0)
57112854Sgabeblack@google.com        bkpt = new HardBreakpoint(this, addr);
57212854Sgabeblack@google.com
57312854Sgabeblack@google.com    bkpt->refcount++;
57412854Sgabeblack@google.com
57512854Sgabeblack@google.com    return true;
57612854Sgabeblack@google.com}
57712854Sgabeblack@google.com
57812854Sgabeblack@google.combool
57912854Sgabeblack@google.comBaseRemoteGDB::removeHardBreak(Addr addr, size_t len)
58012854Sgabeblack@google.com{
58112854Sgabeblack@google.com    if (len != sizeof(MachInst))
58212854Sgabeblack@google.com        panic("invalid length\n");
58312854Sgabeblack@google.com
58412854Sgabeblack@google.com    DPRINTF(GDBMisc, "removing hardware breakpoint at %#x\n", addr);
58512854Sgabeblack@google.com
58612854Sgabeblack@google.com    break_iter_t i = hardBreakMap.find(addr);
58712854Sgabeblack@google.com    if (i == hardBreakMap.end())
58812854Sgabeblack@google.com        return false;
58912854Sgabeblack@google.com
59012854Sgabeblack@google.com    HardBreakpoint *hbp = (*i).second;
59112854Sgabeblack@google.com    if (--hbp->refcount == 0) {
59212854Sgabeblack@google.com        delete hbp;
59312854Sgabeblack@google.com        hardBreakMap.erase(i);
59412854Sgabeblack@google.com    }
59512854Sgabeblack@google.com
59612854Sgabeblack@google.com    return true;
59712854Sgabeblack@google.com}
59812854Sgabeblack@google.com
59912854Sgabeblack@google.comvoid
60012854Sgabeblack@google.comBaseRemoteGDB::setTempBreakpoint(Addr bkpt)
60112854Sgabeblack@google.com{
60212854Sgabeblack@google.com    DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", bkpt);
60312854Sgabeblack@google.com    insertHardBreak(bkpt, sizeof(TheISA::MachInst));
60412854Sgabeblack@google.com}
60512854Sgabeblack@google.com
60612854Sgabeblack@google.comvoid
60712854Sgabeblack@google.comBaseRemoteGDB::clearTempBreakpoint(Addr &bkpt)
60812854Sgabeblack@google.com{
60912854Sgabeblack@google.com    DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", bkpt);
61012854Sgabeblack@google.com    removeHardBreak(bkpt, sizeof(TheISA::MachInst));
61112854Sgabeblack@google.com    bkpt = 0;
61212854Sgabeblack@google.com}
61312854Sgabeblack@google.com
61412854Sgabeblack@google.comconst char *
61512854Sgabeblack@google.comBaseRemoteGDB::break_type(char c)
61612854Sgabeblack@google.com{
61712854Sgabeblack@google.com    switch(c) {
61812854Sgabeblack@google.com      case '0': return "software breakpoint";
61912854Sgabeblack@google.com      case '1': return "hardware breakpoint";
62012854Sgabeblack@google.com      case '2': return "write watchpoint";
62112854Sgabeblack@google.com      case '3': return "read watchpoint";
62212854Sgabeblack@google.com      case '4': return "access watchpoint";
62312854Sgabeblack@google.com      default: return "unknown breakpoint/watchpoint";
62412854Sgabeblack@google.com    }
62512854Sgabeblack@google.com}
62612854Sgabeblack@google.com
62712854Sgabeblack@google.com// This function does all command processing for interfacing to a
62812854Sgabeblack@google.com// remote gdb.  Note that the error codes are ignored by gdb at
62912854Sgabeblack@google.com// present, but might eventually become meaningful. (XXX) It might
63012854Sgabeblack@google.com// makes sense to use POSIX errno values, because that is what the
63112854Sgabeblack@google.com// gdb/remote.c functions want to return.
63212854Sgabeblack@google.combool
63312854Sgabeblack@google.comBaseRemoteGDB::trap(int type)
63412854Sgabeblack@google.com{
63512854Sgabeblack@google.com    uint64_t val;
63612854Sgabeblack@google.com    size_t datalen, len;
63712854Sgabeblack@google.com    char data[GDBPacketBufLen + 1];
63812854Sgabeblack@google.com    char *buffer;
63912854Sgabeblack@google.com    size_t bufferSize;
64012854Sgabeblack@google.com    const char *p;
64112854Sgabeblack@google.com    char command, subcmd;
64212854Sgabeblack@google.com    string var;
64312854Sgabeblack@google.com    bool ret;
64412854Sgabeblack@google.com
64512854Sgabeblack@google.com    if (!attached)
64612854Sgabeblack@google.com        return false;
64712854Sgabeblack@google.com
64812854Sgabeblack@google.com    bufferSize = gdbregs.bytes() * 2 + 256;
64912854Sgabeblack@google.com    buffer = (char*)malloc(bufferSize);
65012854Sgabeblack@google.com
65112854Sgabeblack@google.com    TheISA::PCState pc = context->pcState();
65212854Sgabeblack@google.com    DPRINTF(GDBMisc, "trap: PC=%s\n", pc);
65312854Sgabeblack@google.com
65412854Sgabeblack@google.com    clearSingleStep();
65512854Sgabeblack@google.com
65612854Sgabeblack@google.com    /*
65712854Sgabeblack@google.com     * The first entry to this function is normally through
65812854Sgabeblack@google.com     * a breakpoint trap in kgdb_connect(), in which case we
65912854Sgabeblack@google.com     * must advance past the breakpoint because gdb will not.
66012854Sgabeblack@google.com     *
66112854Sgabeblack@google.com     * On the first entry here, we expect that gdb is not yet
66212854Sgabeblack@google.com     * listening to us, so just enter the interaction loop.
66312854Sgabeblack@google.com     * After the debugger is "active" (connected) it will be
66412854Sgabeblack@google.com     * waiting for a "signaled" message from us.
66512854Sgabeblack@google.com     */
66612854Sgabeblack@google.com    if (!active)
66712854Sgabeblack@google.com        active = true;
66812854Sgabeblack@google.com    else
66912854Sgabeblack@google.com        // Tell remote host that an exception has occurred.
67012854Sgabeblack@google.com        snprintf((char *)buffer, bufferSize, "S%02x", type);
67112854Sgabeblack@google.com        send(buffer);
67212854Sgabeblack@google.com
67312854Sgabeblack@google.com    // Stick frame regs into our reg cache.
67412854Sgabeblack@google.com    getregs();
67512854Sgabeblack@google.com
67612854Sgabeblack@google.com    for (;;) {
67712854Sgabeblack@google.com        datalen = recv(data, sizeof(data));
67812854Sgabeblack@google.com        data[sizeof(data) - 1] = 0; // Sentinel
67912854Sgabeblack@google.com        command = data[0];
68012854Sgabeblack@google.com        subcmd = 0;
68112854Sgabeblack@google.com        p = data + 1;
68212854Sgabeblack@google.com        switch (command) {
68312854Sgabeblack@google.com
68412854Sgabeblack@google.com          case GDBSignal:
68512854Sgabeblack@google.com            // if this command came from a running gdb, answer it --
68612854Sgabeblack@google.com            // the other guy has no way of knowing if we're in or out
68712854Sgabeblack@google.com            // of this loop when he issues a "remote-signal".
68812854Sgabeblack@google.com            snprintf((char *)buffer, bufferSize,
68912854Sgabeblack@google.com                    "S%02x", type);
69012854Sgabeblack@google.com            send(buffer);
69112854Sgabeblack@google.com            continue;
69212854Sgabeblack@google.com
69312854Sgabeblack@google.com          case GDBRegR:
69412854Sgabeblack@google.com            if (2 * gdbregs.bytes() > bufferSize)
69512854Sgabeblack@google.com                panic("buffer too small");
69612854Sgabeblack@google.com
69712854Sgabeblack@google.com            mem2hex(buffer, gdbregs.regs, gdbregs.bytes());
69812854Sgabeblack@google.com            send(buffer);
69912854Sgabeblack@google.com            continue;
70012854Sgabeblack@google.com
70112854Sgabeblack@google.com          case GDBRegW:
70212854Sgabeblack@google.com            p = hex2mem(gdbregs.regs, p, gdbregs.bytes());
70312854Sgabeblack@google.com            if (p == NULL || *p != '\0')
70412854Sgabeblack@google.com                send("E01");
70512854Sgabeblack@google.com            else {
70612854Sgabeblack@google.com                setregs();
70712854Sgabeblack@google.com                send("OK");
70812854Sgabeblack@google.com            }
70912854Sgabeblack@google.com            continue;
71012854Sgabeblack@google.com
71112854Sgabeblack@google.com#if 0
71212854Sgabeblack@google.com          case GDBSetReg:
71312854Sgabeblack@google.com            val = hex2i(&p);
71412854Sgabeblack@google.com            if (*p++ != '=') {
71512854Sgabeblack@google.com                send("E01");
71612854Sgabeblack@google.com                continue;
71712854Sgabeblack@google.com            }
71812854Sgabeblack@google.com            if (val < 0 && val >= KGDB_NUMREGS) {
71912854Sgabeblack@google.com                send("E01");
72012854Sgabeblack@google.com                continue;
72112854Sgabeblack@google.com            }
72212854Sgabeblack@google.com
72312854Sgabeblack@google.com            gdbregs.regs[val] = hex2i(&p);
72412854Sgabeblack@google.com            setregs();
72512854Sgabeblack@google.com            send("OK");
72612854Sgabeblack@google.com
72712854Sgabeblack@google.com            continue;
72812854Sgabeblack@google.com#endif
72912854Sgabeblack@google.com
73012854Sgabeblack@google.com          case GDBMemR:
73112854Sgabeblack@google.com            val = hex2i(&p);
73212854Sgabeblack@google.com            if (*p++ != ',') {
73312854Sgabeblack@google.com                send("E02");
73412854Sgabeblack@google.com                continue;
73512854Sgabeblack@google.com            }
73612854Sgabeblack@google.com            len = hex2i(&p);
73712854Sgabeblack@google.com            if (*p != '\0') {
73812854Sgabeblack@google.com                send("E03");
73912854Sgabeblack@google.com                continue;
74012854Sgabeblack@google.com            }
74112854Sgabeblack@google.com            if (len > bufferSize) {
74212854Sgabeblack@google.com                send("E04");
74312854Sgabeblack@google.com                continue;
74412854Sgabeblack@google.com            }
74512854Sgabeblack@google.com            if (!acc(val, len)) {
74612854Sgabeblack@google.com                send("E05");
74712854Sgabeblack@google.com                continue;
74812854Sgabeblack@google.com            }
74912854Sgabeblack@google.com
75012854Sgabeblack@google.com            if (read(val, (size_t)len, (char *)buffer)) {
75112854Sgabeblack@google.com               // variable length array would be nice, but C++ doesn't
75212854Sgabeblack@google.com               // officially support those...
75312854Sgabeblack@google.com               char *temp = new char[2*len+1];
75412854Sgabeblack@google.com               mem2hex(temp, buffer, len);
75512854Sgabeblack@google.com               send(temp);
75612854Sgabeblack@google.com               delete [] temp;
75712854Sgabeblack@google.com            } else {
75812854Sgabeblack@google.com               send("E05");
75912854Sgabeblack@google.com            }
76012854Sgabeblack@google.com            continue;
76112854Sgabeblack@google.com
76212854Sgabeblack@google.com          case GDBMemW:
76312854Sgabeblack@google.com            val = hex2i(&p);
76412854Sgabeblack@google.com            if (*p++ != ',') {
76512854Sgabeblack@google.com                send("E06");
76612854Sgabeblack@google.com                continue;
76712854Sgabeblack@google.com            }
76812854Sgabeblack@google.com            len = hex2i(&p);
76912854Sgabeblack@google.com            if (*p++ != ':') {
77012854Sgabeblack@google.com                send("E07");
77112854Sgabeblack@google.com                continue;
77212854Sgabeblack@google.com            }
77312854Sgabeblack@google.com            if (len > datalen - (p - data)) {
77412854Sgabeblack@google.com                send("E08");
77512854Sgabeblack@google.com                continue;
77612854Sgabeblack@google.com            }
77712854Sgabeblack@google.com            p = hex2mem(buffer, p, bufferSize);
77812854Sgabeblack@google.com            if (p == NULL) {
77912854Sgabeblack@google.com                send("E09");
78012854Sgabeblack@google.com                continue;
78112854Sgabeblack@google.com            }
78212854Sgabeblack@google.com            if (!acc(val, len)) {
78312854Sgabeblack@google.com                send("E0A");
78412854Sgabeblack@google.com                continue;
78512854Sgabeblack@google.com            }
78612854Sgabeblack@google.com            if (write(val, (size_t)len, (char *)buffer))
78712854Sgabeblack@google.com              send("OK");
78812854Sgabeblack@google.com            else
78912854Sgabeblack@google.com              send("E0B");
79012854Sgabeblack@google.com            continue;
79112854Sgabeblack@google.com
79212854Sgabeblack@google.com          case GDBSetThread:
79312854Sgabeblack@google.com            subcmd = *p++;
79412854Sgabeblack@google.com            val = hex2i(&p);
79512854Sgabeblack@google.com            if (val == 0)
79612854Sgabeblack@google.com                send("OK");
79712854Sgabeblack@google.com            else
79812854Sgabeblack@google.com                send("E01");
79912854Sgabeblack@google.com            continue;
80012854Sgabeblack@google.com
80112854Sgabeblack@google.com          case GDBDetach:
80212854Sgabeblack@google.com          case GDBKill:
80312854Sgabeblack@google.com            active = false;
80412854Sgabeblack@google.com            clearSingleStep();
80512854Sgabeblack@google.com            detach();
80612854Sgabeblack@google.com            goto out;
80712854Sgabeblack@google.com
80812854Sgabeblack@google.com          case GDBAsyncCont:
80912854Sgabeblack@google.com            subcmd = hex2i(&p);
81012854Sgabeblack@google.com            if (*p++ == ';') {
81112854Sgabeblack@google.com                val = hex2i(&p);
81212854Sgabeblack@google.com                context->pcState(val);
81312854Sgabeblack@google.com            }
81412854Sgabeblack@google.com            clearSingleStep();
81512854Sgabeblack@google.com            goto out;
81612854Sgabeblack@google.com
81712854Sgabeblack@google.com          case GDBCont:
81812854Sgabeblack@google.com            if (p - data < (ptrdiff_t)datalen) {
81912854Sgabeblack@google.com                val = hex2i(&p);
82012854Sgabeblack@google.com                context->pcState(val);
82112854Sgabeblack@google.com            }
82212854Sgabeblack@google.com            clearSingleStep();
82312854Sgabeblack@google.com            goto out;
82412854Sgabeblack@google.com
82512854Sgabeblack@google.com          case GDBAsyncStep:
82612854Sgabeblack@google.com            subcmd = hex2i(&p);
82712854Sgabeblack@google.com            if (*p++ == ';') {
82812854Sgabeblack@google.com                val = hex2i(&p);
82912854Sgabeblack@google.com                context->pcState(val);
83012854Sgabeblack@google.com            }
83112854Sgabeblack@google.com            setSingleStep();
83212854Sgabeblack@google.com            goto out;
83312854Sgabeblack@google.com
83412854Sgabeblack@google.com          case GDBStep:
83512854Sgabeblack@google.com            if (p - data < (ptrdiff_t)datalen) {
83612854Sgabeblack@google.com                val = hex2i(&p);
83712854Sgabeblack@google.com                context->pcState(val);
83812854Sgabeblack@google.com            }
83912854Sgabeblack@google.com            setSingleStep();
84012854Sgabeblack@google.com            goto out;
84112854Sgabeblack@google.com
84212854Sgabeblack@google.com          case GDBClrHwBkpt:
84312854Sgabeblack@google.com            subcmd = *p++;
84412854Sgabeblack@google.com            if (*p++ != ',') send("E0D");
84512854Sgabeblack@google.com            val = hex2i(&p);
84612854Sgabeblack@google.com            if (*p++ != ',') send("E0D");
84712854Sgabeblack@google.com            len = hex2i(&p);
84812854Sgabeblack@google.com
84912854Sgabeblack@google.com            DPRINTF(GDBMisc, "clear %s, addr=%#x, len=%d\n",
85012854Sgabeblack@google.com                    break_type(subcmd), val, len);
85112854Sgabeblack@google.com
85212854Sgabeblack@google.com            ret = false;
85312854Sgabeblack@google.com
85412854Sgabeblack@google.com            switch (subcmd) {
85512854Sgabeblack@google.com              case '0': // software breakpoint
85612854Sgabeblack@google.com                ret = removeSoftBreak(val, len);
85712854Sgabeblack@google.com                break;
85812854Sgabeblack@google.com
85912854Sgabeblack@google.com              case '1': // hardware breakpoint
86012854Sgabeblack@google.com                ret = removeHardBreak(val, len);
86112854Sgabeblack@google.com                break;
86212854Sgabeblack@google.com
86312854Sgabeblack@google.com              case '2': // write watchpoint
86412854Sgabeblack@google.com              case '3': // read watchpoint
86512854Sgabeblack@google.com              case '4': // access watchpoint
86612854Sgabeblack@google.com              default: // unknown
86712854Sgabeblack@google.com                send("");
86812854Sgabeblack@google.com                break;
86912854Sgabeblack@google.com            }
87012854Sgabeblack@google.com
87112854Sgabeblack@google.com            send(ret ? "OK" : "E0C");
87212854Sgabeblack@google.com            continue;
87312854Sgabeblack@google.com
87412854Sgabeblack@google.com          case GDBSetHwBkpt:
87512854Sgabeblack@google.com            subcmd = *p++;
87612854Sgabeblack@google.com            if (*p++ != ',') send("E0D");
87712854Sgabeblack@google.com            val = hex2i(&p);
87812854Sgabeblack@google.com            if (*p++ != ',') send("E0D");
87912854Sgabeblack@google.com            len = hex2i(&p);
88012854Sgabeblack@google.com
88112854Sgabeblack@google.com            DPRINTF(GDBMisc, "set %s, addr=%#x, len=%d\n",
88212854Sgabeblack@google.com                    break_type(subcmd), val, len);
88312854Sgabeblack@google.com
88412854Sgabeblack@google.com            ret = false;
88512854Sgabeblack@google.com
88612854Sgabeblack@google.com            switch (subcmd) {
88712854Sgabeblack@google.com              case '0': // software breakpoint
88812854Sgabeblack@google.com                ret = insertSoftBreak(val, len);
88912854Sgabeblack@google.com                break;
89012854Sgabeblack@google.com
89112854Sgabeblack@google.com              case '1': // hardware breakpoint
89212854Sgabeblack@google.com                ret = insertHardBreak(val, len);
89312854Sgabeblack@google.com                break;
89412854Sgabeblack@google.com
89512854Sgabeblack@google.com              case '2': // write watchpoint
89612854Sgabeblack@google.com              case '3': // read watchpoint
89712854Sgabeblack@google.com              case '4': // access watchpoint
89812854Sgabeblack@google.com              default: // unknown
89912854Sgabeblack@google.com                send("");
90012854Sgabeblack@google.com                break;
90112854Sgabeblack@google.com            }
90212854Sgabeblack@google.com
90312854Sgabeblack@google.com            send(ret ? "OK" : "E0C");
90412854Sgabeblack@google.com            continue;
90512854Sgabeblack@google.com
90612854Sgabeblack@google.com          case GDBQueryVar:
90712854Sgabeblack@google.com            var = string(p, datalen - 1);
90812854Sgabeblack@google.com            if (var == "C")
90912854Sgabeblack@google.com                send("QC0");
91012854Sgabeblack@google.com            else
91112854Sgabeblack@google.com                send("");
91212854Sgabeblack@google.com            continue;
91312854Sgabeblack@google.com
91412854Sgabeblack@google.com          case GDBSetBaud:
91512854Sgabeblack@google.com          case GDBSetBreak:
91612854Sgabeblack@google.com          case GDBDebug:
91712854Sgabeblack@google.com          case GDBCycleStep:
91812854Sgabeblack@google.com          case GDBSigCycleStep:
91912854Sgabeblack@google.com          case GDBReadReg:
92012854Sgabeblack@google.com          case GDBSetVar:
92112854Sgabeblack@google.com          case GDBReset:
92212854Sgabeblack@google.com          case GDBThreadAlive:
92312854Sgabeblack@google.com          case GDBTargetExit:
92412854Sgabeblack@google.com          case GDBBinaryDload:
92512854Sgabeblack@google.com            // Unsupported command
92612854Sgabeblack@google.com            DPRINTF(GDBMisc, "Unsupported command: %s\n",
92712854Sgabeblack@google.com                    gdb_command(command));
92812854Sgabeblack@google.com            DDUMP(GDBMisc, (uint8_t *)data, datalen);
92912854Sgabeblack@google.com            send("");
93012854Sgabeblack@google.com            continue;
93112854Sgabeblack@google.com
93212854Sgabeblack@google.com          default:
93312854Sgabeblack@google.com            // Unknown command.
93412854Sgabeblack@google.com            DPRINTF(GDBMisc, "Unknown command: %c(%#x)\n",
93512854Sgabeblack@google.com                    command, command);
93612854Sgabeblack@google.com            send("");
93712854Sgabeblack@google.com            continue;
93812854Sgabeblack@google.com
93912854Sgabeblack@google.com
94012854Sgabeblack@google.com        }
94112854Sgabeblack@google.com    }
94212854Sgabeblack@google.com
94312854Sgabeblack@google.com  out:
94412854Sgabeblack@google.com    free(buffer);
94512854Sgabeblack@google.com    return true;
94612854Sgabeblack@google.com}
94712854Sgabeblack@google.com
94812854Sgabeblack@google.com// Convert a hex digit into an integer.
94912854Sgabeblack@google.com// This returns -1 if the argument passed is no valid hex digit.
95012854Sgabeblack@google.comint
95112854Sgabeblack@google.comBaseRemoteGDB::digit2i(char c)
95212854Sgabeblack@google.com{
95312854Sgabeblack@google.com    if (c >= '0' && c <= '9')
95412854Sgabeblack@google.com        return (c - '0');
95512854Sgabeblack@google.com    else if (c >= 'a' && c <= 'f')
95612854Sgabeblack@google.com        return (c - 'a' + 10);
95712854Sgabeblack@google.com    else if (c >= 'A' && c <= 'F')
95812854Sgabeblack@google.com
95912854Sgabeblack@google.com        return (c - 'A' + 10);
96012854Sgabeblack@google.com    else
96112854Sgabeblack@google.com        return (-1);
96212854Sgabeblack@google.com}
96312854Sgabeblack@google.com
96412854Sgabeblack@google.com// Convert the low 4 bits of an integer into an hex digit.
96512854Sgabeblack@google.comchar
96612854Sgabeblack@google.comBaseRemoteGDB::i2digit(int n)
96712854Sgabeblack@google.com{
96812854Sgabeblack@google.com    return ("0123456789abcdef"[n & 0x0f]);
96912854Sgabeblack@google.com}
97012854Sgabeblack@google.com
97112854Sgabeblack@google.com// Convert a byte array into an hex string.
97212854Sgabeblack@google.comvoid
97312854Sgabeblack@google.comBaseRemoteGDB::mem2hex(void *vdst, const void *vsrc, int len)
97412854Sgabeblack@google.com{
97512854Sgabeblack@google.com    char *dst = (char *)vdst;
97612854Sgabeblack@google.com    const char *src = (const char *)vsrc;
97712854Sgabeblack@google.com
97812854Sgabeblack@google.com    while (len--) {
97912854Sgabeblack@google.com        *dst++ = i2digit(*src >> 4);
98012854Sgabeblack@google.com        *dst++ = i2digit(*src++);
98112854Sgabeblack@google.com    }
98212854Sgabeblack@google.com    *dst = '\0';
98312854Sgabeblack@google.com}
98412854Sgabeblack@google.com
98512854Sgabeblack@google.com// Convert an hex string into a byte array.
98612854Sgabeblack@google.com// This returns a pointer to the character following the last valid
98712854Sgabeblack@google.com// hex digit. If the string ends in the middle of a byte, NULL is
98812854Sgabeblack@google.com// returned.
98912854Sgabeblack@google.comconst char *
99012854Sgabeblack@google.comBaseRemoteGDB::hex2mem(void *vdst, const char *src, int maxlen)
99112854Sgabeblack@google.com{
99212854Sgabeblack@google.com    char *dst = (char *)vdst;
99312854Sgabeblack@google.com    int msb, lsb;
99412854Sgabeblack@google.com
99512854Sgabeblack@google.com    while (*src && maxlen--) {
99612854Sgabeblack@google.com        msb = digit2i(*src++);
99712854Sgabeblack@google.com        if (msb < 0)
99812854Sgabeblack@google.com            return (src - 1);
99912854Sgabeblack@google.com        lsb = digit2i(*src++);
100012854Sgabeblack@google.com        if (lsb < 0)
100112854Sgabeblack@google.com            return (NULL);
100212854Sgabeblack@google.com        *dst++ = (msb << 4) | lsb;
100312854Sgabeblack@google.com    }
100412854Sgabeblack@google.com    return (src);
100512854Sgabeblack@google.com}
100612854Sgabeblack@google.com
100712854Sgabeblack@google.com// Convert an hex string into an integer.
100812854Sgabeblack@google.com// This returns a pointer to the character following the last valid
100912854Sgabeblack@google.com// hex digit.
101012854Sgabeblack@google.comAddr
101112854Sgabeblack@google.comBaseRemoteGDB::hex2i(const char **srcp)
101212854Sgabeblack@google.com{
101312854Sgabeblack@google.com    const char *src = *srcp;
101412854Sgabeblack@google.com    Addr r = 0;
101512854Sgabeblack@google.com    int nibble;
101612854Sgabeblack@google.com
101712854Sgabeblack@google.com    while ((nibble = digit2i(*src)) >= 0) {
101812854Sgabeblack@google.com        r *= 16;
101912854Sgabeblack@google.com        r += nibble;
102012854Sgabeblack@google.com        src++;
102112854Sgabeblack@google.com    }
102212854Sgabeblack@google.com    *srcp = src;
102312854Sgabeblack@google.com    return (r);
102412854Sgabeblack@google.com}
102512854Sgabeblack@google.com
102612854Sgabeblack@google.com