remote_gdb.cc revision 8706
113531Sjairo.balart@metempsy.com/*
214227Sgiacomo.travaglini@arm.com * Copyright (c) 2002-2005 The Regents of The University of Michigan
314227Sgiacomo.travaglini@arm.com * All rights reserved.
414227Sgiacomo.travaglini@arm.com *
514227Sgiacomo.travaglini@arm.com * Redistribution and use in source and binary forms, with or without
614227Sgiacomo.travaglini@arm.com * modification, are permitted provided that the following conditions are
714227Sgiacomo.travaglini@arm.com * met: redistributions of source code must retain the above copyright
814227Sgiacomo.travaglini@arm.com * notice, this list of conditions and the following disclaimer;
914227Sgiacomo.travaglini@arm.com * redistributions in binary form must reproduce the above copyright
1014227Sgiacomo.travaglini@arm.com * notice, this list of conditions and the following disclaimer in the
1114227Sgiacomo.travaglini@arm.com * documentation and/or other materials provided with the distribution;
1214227Sgiacomo.travaglini@arm.com * neither the name of the copyright holders nor the names of its
1314227Sgiacomo.travaglini@arm.com * contributors may be used to endorse or promote products derived from
1413531Sjairo.balart@metempsy.com * this software without specific prior written permission.
1513531Sjairo.balart@metempsy.com *
1613531Sjairo.balart@metempsy.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1713531Sjairo.balart@metempsy.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1813531Sjairo.balart@metempsy.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1913531Sjairo.balart@metempsy.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2013531Sjairo.balart@metempsy.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2113531Sjairo.balart@metempsy.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2213531Sjairo.balart@metempsy.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2313531Sjairo.balart@metempsy.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2413531Sjairo.balart@metempsy.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2513531Sjairo.balart@metempsy.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2613531Sjairo.balart@metempsy.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2713531Sjairo.balart@metempsy.com *
2813531Sjairo.balart@metempsy.com * Authors: Nathan Binkert
2913531Sjairo.balart@metempsy.com */
3013531Sjairo.balart@metempsy.com
3113531Sjairo.balart@metempsy.com/*
3213531Sjairo.balart@metempsy.com * Copyright (c) 1990, 1993 The Regents of the University of California
3313531Sjairo.balart@metempsy.com * All rights reserved
3413531Sjairo.balart@metempsy.com *
3513531Sjairo.balart@metempsy.com * This software was developed by the Computer Systems Engineering group
3613531Sjairo.balart@metempsy.com * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
3713531Sjairo.balart@metempsy.com * contributed to Berkeley.
3813531Sjairo.balart@metempsy.com *
3913531Sjairo.balart@metempsy.com * All advertising materials mentioning features or use of this software
4013531Sjairo.balart@metempsy.com * must display the following acknowledgement:
4113531Sjairo.balart@metempsy.com *      This product includes software developed by the University of
4213531Sjairo.balart@metempsy.com *      California, Lawrence Berkeley Laboratories.
4313531Sjairo.balart@metempsy.com *
4413531Sjairo.balart@metempsy.com * Redistribution and use in source and binary forms, with or without
4513531Sjairo.balart@metempsy.com * modification, are permitted provided that the following conditions
4613531Sjairo.balart@metempsy.com * are met:
4713531Sjairo.balart@metempsy.com * 1. Redistributions of source code must retain the above copyright
4813531Sjairo.balart@metempsy.com *    notice, this list of conditions and the following disclaimer.
4913531Sjairo.balart@metempsy.com * 2. Redistributions in binary form must reproduce the above copyright
5013531Sjairo.balart@metempsy.com *    notice, this list of conditions and the following disclaimer in the
5113926Sgiacomo.travaglini@arm.com *    documentation and/or other materials provided with the distribution.
5213926Sgiacomo.travaglini@arm.com * 3. All advertising materials mentioning features or use of this software
5313926Sgiacomo.travaglini@arm.com *    must display the following acknowledgement:
5413531Sjairo.balart@metempsy.com *      This product includes software developed by the University of
5513531Sjairo.balart@metempsy.com *      California, Berkeley and its contributors.
5613531Sjairo.balart@metempsy.com * 4. Neither the name of the University nor the names of its contributors
5713531Sjairo.balart@metempsy.com *    may be used to endorse or promote products derived from this software
5813531Sjairo.balart@metempsy.com *    without specific prior written permission.
5913531Sjairo.balart@metempsy.com *
6013531Sjairo.balart@metempsy.com * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
6114258Sgiacomo.travaglini@arm.com * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
6214258Sgiacomo.travaglini@arm.com * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
6313531Sjairo.balart@metempsy.com * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
6413531Sjairo.balart@metempsy.com * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
6513531Sjairo.balart@metempsy.com * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
6613531Sjairo.balart@metempsy.com * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6713531Sjairo.balart@metempsy.com * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6813531Sjairo.balart@metempsy.com * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6913531Sjairo.balart@metempsy.com * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7013531Sjairo.balart@metempsy.com * SUCH DAMAGE.
7113531Sjairo.balart@metempsy.com *
7213531Sjairo.balart@metempsy.com *      @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94
7314259Sgiacomo.travaglini@arm.com */
7414259Sgiacomo.travaglini@arm.com
7514259Sgiacomo.travaglini@arm.com/*-
7614259Sgiacomo.travaglini@arm.com * Copyright (c) 2001 The NetBSD Foundation, Inc.
7714259Sgiacomo.travaglini@arm.com * All rights reserved.
7814259Sgiacomo.travaglini@arm.com *
7914259Sgiacomo.travaglini@arm.com * This code is derived from software contributed to The NetBSD Foundation
8013826Sgiacomo.travaglini@arm.com * by Jason R. Thorpe.
8113826Sgiacomo.travaglini@arm.com *
8213826Sgiacomo.travaglini@arm.com * Redistribution and use in source and binary forms, with or without
8313826Sgiacomo.travaglini@arm.com * modification, are permitted provided that the following conditions
8413826Sgiacomo.travaglini@arm.com * are met:
8513531Sjairo.balart@metempsy.com * 1. Redistributions of source code must retain the above copyright
8613760Sjairo.balart@metempsy.com *    notice, this list of conditions and the following disclaimer.
8713531Sjairo.balart@metempsy.com * 2. Redistributions in binary form must reproduce the above copyright
8813531Sjairo.balart@metempsy.com *    notice, this list of conditions and the following disclaimer in the
8913531Sjairo.balart@metempsy.com *    documentation and/or other materials provided with the distribution.
9013531Sjairo.balart@metempsy.com * 3. All advertising materials mentioning features or use of this software
9113531Sjairo.balart@metempsy.com *    must display the following acknowledgement:
9213531Sjairo.balart@metempsy.com *      This product includes software developed by the NetBSD
9313531Sjairo.balart@metempsy.com *      Foundation, Inc. and its contributors.
9413531Sjairo.balart@metempsy.com * 4. Neither the name of The NetBSD Foundation nor the names of its
9513531Sjairo.balart@metempsy.com *    contributors may be used to endorse or promote products derived
9613531Sjairo.balart@metempsy.com *    from this software without specific prior written permission.
9713531Sjairo.balart@metempsy.com *
9813531Sjairo.balart@metempsy.com * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
9913531Sjairo.balart@metempsy.com * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
10013760Sjairo.balart@metempsy.com * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
10113531Sjairo.balart@metempsy.com * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
10213531Sjairo.balart@metempsy.com * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
10313531Sjairo.balart@metempsy.com * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
10413531Sjairo.balart@metempsy.com * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
10513531Sjairo.balart@metempsy.com * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
10613531Sjairo.balart@metempsy.com * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
10713531Sjairo.balart@metempsy.com * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
10813531Sjairo.balart@metempsy.com * POSSIBILITY OF SUCH DAMAGE.
10913531Sjairo.balart@metempsy.com */
11013531Sjairo.balart@metempsy.com
11113531Sjairo.balart@metempsy.com/*
11213531Sjairo.balart@metempsy.com * $NetBSD: kgdb_stub.c,v 1.8 2001/07/07 22:58:00 wdk Exp $
11313580Sgabeblack@google.com *
11413531Sjairo.balart@metempsy.com * Taken from NetBSD
11513531Sjairo.balart@metempsy.com *
11613580Sgabeblack@google.com * "Stub" to allow remote cpu to debug over a serial line using gdb.
11713531Sjairo.balart@metempsy.com */
11813531Sjairo.balart@metempsy.com
11913531Sjairo.balart@metempsy.com#include <sys/signal.h>
12013531Sjairo.balart@metempsy.com#include <unistd.h>
12113760Sjairo.balart@metempsy.com
12213531Sjairo.balart@metempsy.com#include <cstdio>
12313531Sjairo.balart@metempsy.com#include <string>
12413531Sjairo.balart@metempsy.com
12513531Sjairo.balart@metempsy.com#include "config/full_system.hh"
12613531Sjairo.balart@metempsy.com
12713531Sjairo.balart@metempsy.com#if FULL_SYSTEM
12814246Sgiacomo.travaglini@arm.com#include "arch/vtophys.hh"
12913531Sjairo.balart@metempsy.com#include "mem/fs_translating_port_proxy.hh"
13013531Sjairo.balart@metempsy.com#endif
13113531Sjairo.balart@metempsy.com
13213531Sjairo.balart@metempsy.com#include "base/intmath.hh"
13313531Sjairo.balart@metempsy.com#include "base/remote_gdb.hh"
13413531Sjairo.balart@metempsy.com#include "base/socket.hh"
13513531Sjairo.balart@metempsy.com#include "base/trace.hh"
13613531Sjairo.balart@metempsy.com#include "config/the_isa.hh"
13713531Sjairo.balart@metempsy.com#include "cpu/static_inst.hh"
13813531Sjairo.balart@metempsy.com#include "cpu/thread_context.hh"
13913531Sjairo.balart@metempsy.com#include "debug/GDBAll.hh"
14013531Sjairo.balart@metempsy.com#include "mem/port.hh"
14113531Sjairo.balart@metempsy.com#include "mem/se_translating_port_proxy.hh"
14213531Sjairo.balart@metempsy.com#include "sim/system.hh"
14313531Sjairo.balart@metempsy.com
14413760Sjairo.balart@metempsy.comusing namespace std;
14513531Sjairo.balart@metempsy.comusing namespace Debug;
14613531Sjairo.balart@metempsy.comusing namespace TheISA;
14713531Sjairo.balart@metempsy.com
14813531Sjairo.balart@metempsy.com#ifndef NDEBUG
14913531Sjairo.balart@metempsy.comvector<BaseRemoteGDB *> debuggers;
15013531Sjairo.balart@metempsy.com
15113531Sjairo.balart@metempsy.comvoid
15213531Sjairo.balart@metempsy.comdebugger()
15313531Sjairo.balart@metempsy.com{
15413531Sjairo.balart@metempsy.com    static int current_debugger = -1;
15513531Sjairo.balart@metempsy.com    if (current_debugger >= 0 && current_debugger < (int)debuggers.size()) {
15613531Sjairo.balart@metempsy.com        BaseRemoteGDB *gdb = debuggers[current_debugger];
15713531Sjairo.balart@metempsy.com        if (!gdb->isattached())
15813531Sjairo.balart@metempsy.com            gdb->listener->accept();
15913531Sjairo.balart@metempsy.com        if (gdb->isattached())
16013531Sjairo.balart@metempsy.com            gdb->trap(SIGILL);
16113531Sjairo.balart@metempsy.com    }
16213531Sjairo.balart@metempsy.com}
16313531Sjairo.balart@metempsy.com#endif
16413531Sjairo.balart@metempsy.com
16513531Sjairo.balart@metempsy.com///////////////////////////////////////////////////////////
16613531Sjairo.balart@metempsy.com//
16713760Sjairo.balart@metempsy.com//
16813531Sjairo.balart@metempsy.com//
16913531Sjairo.balart@metempsy.com
17013531Sjairo.balart@metempsy.comGDBListener::Event::Event(GDBListener *l, int fd, int e)
17114057Sgiacomo.travaglini@arm.com    : PollEvent(fd, e), listener(l)
17213531Sjairo.balart@metempsy.com{}
17313531Sjairo.balart@metempsy.com
17413531Sjairo.balart@metempsy.comvoid
17513531Sjairo.balart@metempsy.comGDBListener::Event::process(int revent)
17613531Sjairo.balart@metempsy.com{
17714057Sgiacomo.travaglini@arm.com    listener->accept();
17814057Sgiacomo.travaglini@arm.com}
17914057Sgiacomo.travaglini@arm.com
18014057Sgiacomo.travaglini@arm.comGDBListener::GDBListener(BaseRemoteGDB *g, int p)
18114057Sgiacomo.travaglini@arm.com    : event(NULL), gdb(g), port(p)
18214057Sgiacomo.travaglini@arm.com{
18314057Sgiacomo.travaglini@arm.com    assert(!gdb->listener);
18413760Sjairo.balart@metempsy.com    gdb->listener = this;
18513531Sjairo.balart@metempsy.com}
18613531Sjairo.balart@metempsy.com
18713531Sjairo.balart@metempsy.comGDBListener::~GDBListener()
18814057Sgiacomo.travaglini@arm.com{
18913531Sjairo.balart@metempsy.com    if (event)
19013531Sjairo.balart@metempsy.com        delete event;
19114247Sgiacomo.travaglini@arm.com}
19213531Sjairo.balart@metempsy.com
19313531Sjairo.balart@metempsy.comstring
19413531Sjairo.balart@metempsy.comGDBListener::name()
19514057Sgiacomo.travaglini@arm.com{
19614057Sgiacomo.travaglini@arm.com    return gdb->name() + ".listener";
19714057Sgiacomo.travaglini@arm.com}
19814057Sgiacomo.travaglini@arm.com
19914057Sgiacomo.travaglini@arm.comvoid
20014057Sgiacomo.travaglini@arm.comGDBListener::listen()
20114057Sgiacomo.travaglini@arm.com{
20213760Sjairo.balart@metempsy.com    if (ListenSocket::allDisabled()) {
20313760Sjairo.balart@metempsy.com        warn_once("Sockets disabled, not accepting gdb connections");
20414254Sgiacomo.travaglini@arm.com        return;
20514254Sgiacomo.travaglini@arm.com    }
20614254Sgiacomo.travaglini@arm.com
20714254Sgiacomo.travaglini@arm.com    while (!listener.listen(port, true)) {
20814254Sgiacomo.travaglini@arm.com        DPRINTF(GDBMisc, "Can't bind port %d\n", port);
20914254Sgiacomo.travaglini@arm.com        port++;
21014254Sgiacomo.travaglini@arm.com    }
21114254Sgiacomo.travaglini@arm.com
21214254Sgiacomo.travaglini@arm.com    event = new Event(this, listener.getfd(), POLLIN);
21313739Sgiacomo.travaglini@arm.com    pollQueue.schedule(event);
21414254Sgiacomo.travaglini@arm.com
21513760Sjairo.balart@metempsy.com#ifndef NDEBUG
21613760Sjairo.balart@metempsy.com    gdb->number = debuggers.size();
21713531Sjairo.balart@metempsy.com    debuggers.push_back(gdb);
21813531Sjairo.balart@metempsy.com#endif
21913531Sjairo.balart@metempsy.com
22013760Sjairo.balart@metempsy.com#ifndef NDEBUG
22113531Sjairo.balart@metempsy.com    ccprintf(cerr, "%d: %s: listening for remote gdb #%d on port %d\n",
22213531Sjairo.balart@metempsy.com             curTick(), name(), gdb->number, port);
22313531Sjairo.balart@metempsy.com#else
22413531Sjairo.balart@metempsy.com    ccprintf(cerr, "%d: %s: listening for remote gdb on port %d\n",
22513531Sjairo.balart@metempsy.com             curTick(), name(), port);
22613531Sjairo.balart@metempsy.com#endif
22713760Sjairo.balart@metempsy.com}
22813760Sjairo.balart@metempsy.com
22913760Sjairo.balart@metempsy.comvoid
23013531Sjairo.balart@metempsy.comGDBListener::accept()
23113760Sjairo.balart@metempsy.com{
23213760Sjairo.balart@metempsy.com    if (!listener.islistening())
23313531Sjairo.balart@metempsy.com        panic("GDBListener::accept(): cannot accept if we're not listening!");
23413531Sjairo.balart@metempsy.com
23513760Sjairo.balart@metempsy.com    int sfd = listener.accept(true);
23613760Sjairo.balart@metempsy.com
23713760Sjairo.balart@metempsy.com    if (sfd != -1) {
23813531Sjairo.balart@metempsy.com        if (gdb->isattached())
23913531Sjairo.balart@metempsy.com            close(sfd);
24013531Sjairo.balart@metempsy.com        else
24113531Sjairo.balart@metempsy.com            gdb->attach(sfd);
24213531Sjairo.balart@metempsy.com    }
24313531Sjairo.balart@metempsy.com}
24413531Sjairo.balart@metempsy.com
24513531Sjairo.balart@metempsy.comBaseRemoteGDB::Event::Event(BaseRemoteGDB *g, int fd, int e)
24613760Sjairo.balart@metempsy.com    : PollEvent(fd, e), gdb(g)
24713531Sjairo.balart@metempsy.com{}
24813531Sjairo.balart@metempsy.com
24913531Sjairo.balart@metempsy.comvoid
25013531Sjairo.balart@metempsy.comBaseRemoteGDB::Event::process(int revent)
25113531Sjairo.balart@metempsy.com{
25213760Sjairo.balart@metempsy.com    if (revent & POLLIN)
25313531Sjairo.balart@metempsy.com        gdb->trap(SIGILL);
25413531Sjairo.balart@metempsy.com    else if (revent & POLLNVAL)
25513531Sjairo.balart@metempsy.com        gdb->detach();
25613531Sjairo.balart@metempsy.com}
25713531Sjairo.balart@metempsy.com
25813531Sjairo.balart@metempsy.comBaseRemoteGDB::BaseRemoteGDB(System *_system, ThreadContext *c, size_t cacheSize)
25913531Sjairo.balart@metempsy.com    : event(NULL), listener(NULL), number(-1), fd(-1),
26013531Sjairo.balart@metempsy.com      active(false), attached(false),
26113531Sjairo.balart@metempsy.com      system(_system), pmem(_system->physmem), context(c),
26213531Sjairo.balart@metempsy.com      gdbregs(cacheSize)
26313760Sjairo.balart@metempsy.com{
26413531Sjairo.balart@metempsy.com    memset(gdbregs.regs, 0, gdbregs.bytes());
26513531Sjairo.balart@metempsy.com}
26613531Sjairo.balart@metempsy.com
26713531Sjairo.balart@metempsy.comBaseRemoteGDB::~BaseRemoteGDB()
26813531Sjairo.balart@metempsy.com{
26913760Sjairo.balart@metempsy.com    if (event)
27013531Sjairo.balart@metempsy.com        delete event;
27113531Sjairo.balart@metempsy.com}
27213760Sjairo.balart@metempsy.com
27313531Sjairo.balart@metempsy.comstring
27413531Sjairo.balart@metempsy.comBaseRemoteGDB::name()
27513760Sjairo.balart@metempsy.com{
27613531Sjairo.balart@metempsy.com    return system->name() + ".remote_gdb";
27713531Sjairo.balart@metempsy.com}
27813531Sjairo.balart@metempsy.com
27913531Sjairo.balart@metempsy.combool
28013531Sjairo.balart@metempsy.comBaseRemoteGDB::isattached()
28113531Sjairo.balart@metempsy.com{ return attached; }
28213760Sjairo.balart@metempsy.com
28313531Sjairo.balart@metempsy.comvoid
28413531Sjairo.balart@metempsy.comBaseRemoteGDB::attach(int f)
28513531Sjairo.balart@metempsy.com{
28613531Sjairo.balart@metempsy.com    fd = f;
28713531Sjairo.balart@metempsy.com
28813531Sjairo.balart@metempsy.com    event = new Event(this, fd, POLLIN);
28913531Sjairo.balart@metempsy.com    pollQueue.schedule(event);
29013531Sjairo.balart@metempsy.com
29113531Sjairo.balart@metempsy.com    attached = true;
29213531Sjairo.balart@metempsy.com    DPRINTFN("remote gdb attached\n");
29313760Sjairo.balart@metempsy.com}
29413531Sjairo.balart@metempsy.com
29513531Sjairo.balart@metempsy.comvoid
29613531Sjairo.balart@metempsy.comBaseRemoteGDB::detach()
29713531Sjairo.balart@metempsy.com{
29813531Sjairo.balart@metempsy.com    attached = false;
29913760Sjairo.balart@metempsy.com    close(fd);
30013531Sjairo.balart@metempsy.com    fd = -1;
30113531Sjairo.balart@metempsy.com
30213760Sjairo.balart@metempsy.com    pollQueue.remove(event);
30313531Sjairo.balart@metempsy.com    DPRINTFN("remote gdb detached\n");
30413531Sjairo.balart@metempsy.com}
30513760Sjairo.balart@metempsy.com
30613531Sjairo.balart@metempsy.comconst char *
30713531Sjairo.balart@metempsy.comBaseRemoteGDB::gdb_command(char cmd)
30813531Sjairo.balart@metempsy.com{
30913531Sjairo.balart@metempsy.com    switch (cmd) {
31013531Sjairo.balart@metempsy.com      case GDBSignal: return "KGDB_SIGNAL";
31113531Sjairo.balart@metempsy.com      case GDBSetBaud: return "KGDB_SET_BAUD";
31213760Sjairo.balart@metempsy.com      case GDBSetBreak: return "KGDB_SET_BREAK";
31313531Sjairo.balart@metempsy.com      case GDBCont: return "KGDB_CONT";
31414237Sgiacomo.travaglini@arm.com      case GDBAsyncCont: return "KGDB_ASYNC_CONT";
31513531Sjairo.balart@metempsy.com      case GDBDebug: return "KGDB_DEBUG";
31613531Sjairo.balart@metempsy.com      case GDBDetach: return "KGDB_DETACH";
31713531Sjairo.balart@metempsy.com      case GDBRegR: return "KGDB_REG_R";
31813531Sjairo.balart@metempsy.com      case GDBRegW: return "KGDB_REG_W";
31914237Sgiacomo.travaglini@arm.com      case GDBSetThread: return "KGDB_SET_THREAD";
32014237Sgiacomo.travaglini@arm.com      case GDBCycleStep: return "KGDB_CYCLE_STEP";
32114237Sgiacomo.travaglini@arm.com      case GDBSigCycleStep: return "KGDB_SIG_CYCLE_STEP";
32213531Sjairo.balart@metempsy.com      case GDBKill: return "KGDB_KILL";
32313760Sjairo.balart@metempsy.com      case GDBMemW: return "KGDB_MEM_W";
32413531Sjairo.balart@metempsy.com      case GDBMemR: return "KGDB_MEM_R";
32513760Sjairo.balart@metempsy.com      case GDBSetReg: return "KGDB_SET_REG";
32614237Sgiacomo.travaglini@arm.com      case GDBReadReg: return "KGDB_READ_REG";
32714237Sgiacomo.travaglini@arm.com      case GDBQueryVar: return "KGDB_QUERY_VAR";
32813760Sjairo.balart@metempsy.com      case GDBSetVar: return "KGDB_SET_VAR";
32913760Sjairo.balart@metempsy.com      case GDBReset: return "KGDB_RESET";
33014237Sgiacomo.travaglini@arm.com      case GDBStep: return "KGDB_STEP";
33114237Sgiacomo.travaglini@arm.com      case GDBAsyncStep: return "KGDB_ASYNC_STEP";
33214237Sgiacomo.travaglini@arm.com      case GDBThreadAlive: return "KGDB_THREAD_ALIVE";
33314237Sgiacomo.travaglini@arm.com      case GDBTargetExit: return "KGDB_TARGET_EXIT";
33414237Sgiacomo.travaglini@arm.com      case GDBBinaryDload: return "KGDB_BINARY_DLOAD";
33514237Sgiacomo.travaglini@arm.com      case GDBClrHwBkpt: return "KGDB_CLR_HW_BKPT";
33614237Sgiacomo.travaglini@arm.com      case GDBSetHwBkpt: return "KGDB_SET_HW_BKPT";
33714237Sgiacomo.travaglini@arm.com      case GDBStart: return "KGDB_START";
33814237Sgiacomo.travaglini@arm.com      case GDBEnd: return "KGDB_END";
33913760Sjairo.balart@metempsy.com      case GDBGoodP: return "KGDB_GOODP";
34013531Sjairo.balart@metempsy.com      case GDBBadP: return "KGDB_BADP";
34114237Sgiacomo.travaglini@arm.com      default: return "KGDB_UNKNOWN";
34214237Sgiacomo.travaglini@arm.com    }
34314237Sgiacomo.travaglini@arm.com}
34414237Sgiacomo.travaglini@arm.com
34514237Sgiacomo.travaglini@arm.com/////////////////////////
34614237Sgiacomo.travaglini@arm.com//
34714237Sgiacomo.travaglini@arm.com//
34814237Sgiacomo.travaglini@arm.com
34914237Sgiacomo.travaglini@arm.comuint8_t
35014237Sgiacomo.travaglini@arm.comBaseRemoteGDB::getbyte()
35114237Sgiacomo.travaglini@arm.com{
35214237Sgiacomo.travaglini@arm.com    uint8_t b;
35313531Sjairo.balart@metempsy.com    if (::read(fd, &b, 1) != 1)
35413531Sjairo.balart@metempsy.com        warn("could not read byte from debugger");
35513760Sjairo.balart@metempsy.com    return b;
35613531Sjairo.balart@metempsy.com}
35713760Sjairo.balart@metempsy.com
35813760Sjairo.balart@metempsy.comvoid
35914057Sgiacomo.travaglini@arm.comBaseRemoteGDB::putbyte(uint8_t b)
36013531Sjairo.balart@metempsy.com{
36113531Sjairo.balart@metempsy.com    if (::write(fd, &b, 1) != 1)
36213531Sjairo.balart@metempsy.com        warn("could not write byte to debugger");
36313760Sjairo.balart@metempsy.com}
36413760Sjairo.balart@metempsy.com
36513760Sjairo.balart@metempsy.com// Send a packet to gdb
36613531Sjairo.balart@metempsy.comvoid
36713760Sjairo.balart@metempsy.comBaseRemoteGDB::send(const char *bp)
36813760Sjairo.balart@metempsy.com{
36913531Sjairo.balart@metempsy.com    const char *p;
37013531Sjairo.balart@metempsy.com    uint8_t csum, c;
37113760Sjairo.balart@metempsy.com
37213760Sjairo.balart@metempsy.com    DPRINTF(GDBSend, "send:  %s\n", bp);
37313760Sjairo.balart@metempsy.com
37413531Sjairo.balart@metempsy.com    do {
37513531Sjairo.balart@metempsy.com        p = bp;
37613531Sjairo.balart@metempsy.com        //Start sending a packet
37713531Sjairo.balart@metempsy.com        putbyte(GDBStart);
37813531Sjairo.balart@metempsy.com        //Send the contents, and also keep a check sum.
37913531Sjairo.balart@metempsy.com        for (csum = 0; (c = *p); p++) {
38014057Sgiacomo.travaglini@arm.com            putbyte(c);
38114057Sgiacomo.travaglini@arm.com            csum += c;
38214057Sgiacomo.travaglini@arm.com        }
38314057Sgiacomo.travaglini@arm.com        //Send the ending character.
38414057Sgiacomo.travaglini@arm.com        putbyte(GDBEnd);
38514057Sgiacomo.travaglini@arm.com        //Sent the checksum.
38614057Sgiacomo.travaglini@arm.com        putbyte(i2digit(csum >> 4));
38714057Sgiacomo.travaglini@arm.com        putbyte(i2digit(csum));
38813760Sjairo.balart@metempsy.com        //Try transmitting over and over again until the other end doesn't send an
38913531Sjairo.balart@metempsy.com        //error back.
39013760Sjairo.balart@metempsy.com    } while ((c = getbyte() & 0x7f) == GDBBadP);
39113531Sjairo.balart@metempsy.com}
39213531Sjairo.balart@metempsy.com
39313531Sjairo.balart@metempsy.com// Receive a packet from gdb
39413531Sjairo.balart@metempsy.comint
39513531Sjairo.balart@metempsy.comBaseRemoteGDB::recv(char *bp, int maxlen)
39613531Sjairo.balart@metempsy.com{
39713531Sjairo.balart@metempsy.com    char *p;
39813531Sjairo.balart@metempsy.com    int c, csum;
39913531Sjairo.balart@metempsy.com    int len;
40013531Sjairo.balart@metempsy.com
40113923Sgiacomo.travaglini@arm.com    do {
40213923Sgiacomo.travaglini@arm.com        p = bp;
40313531Sjairo.balart@metempsy.com        csum = len = 0;
40413531Sjairo.balart@metempsy.com        //Find the beginning of a packet
40513531Sjairo.balart@metempsy.com        while ((c = getbyte()) != GDBStart)
40613531Sjairo.balart@metempsy.com            ;
40713531Sjairo.balart@metempsy.com
40813531Sjairo.balart@metempsy.com        //Read until you find the end of the data in the packet, and keep
40913531Sjairo.balart@metempsy.com        //track of the check sum.
41013531Sjairo.balart@metempsy.com        while ((c = getbyte()) != GDBEnd && len < maxlen) {
41113531Sjairo.balart@metempsy.com            c &= 0x7f;
41213531Sjairo.balart@metempsy.com            csum += c;
41313760Sjairo.balart@metempsy.com            *p++ = c;
41413531Sjairo.balart@metempsy.com            len++;
41513531Sjairo.balart@metempsy.com        }
41613531Sjairo.balart@metempsy.com
41713531Sjairo.balart@metempsy.com        //Mask the check sum, and terminate the command string.
41813531Sjairo.balart@metempsy.com        csum &= 0xff;
41913760Sjairo.balart@metempsy.com        *p = '\0';
42013531Sjairo.balart@metempsy.com
42113531Sjairo.balart@metempsy.com        //If the command was too long, report an error.
42213760Sjairo.balart@metempsy.com        if (len >= maxlen) {
42313760Sjairo.balart@metempsy.com            putbyte(GDBBadP);
42413531Sjairo.balart@metempsy.com            continue;
42513531Sjairo.balart@metempsy.com        }
42613760Sjairo.balart@metempsy.com
42713531Sjairo.balart@metempsy.com        //Bring in the checksum. If the check sum matches, csum will be 0.
42813531Sjairo.balart@metempsy.com        csum -= digit2i(getbyte()) * 16;
42913531Sjairo.balart@metempsy.com        csum -= digit2i(getbyte());
43013531Sjairo.balart@metempsy.com
43113531Sjairo.balart@metempsy.com        //If the check sum was correct
43213760Sjairo.balart@metempsy.com        if (csum == 0) {
43313531Sjairo.balart@metempsy.com            //Report that the packet was received correctly
43413760Sjairo.balart@metempsy.com            putbyte(GDBGoodP);
43513531Sjairo.balart@metempsy.com            // Sequence present?
43613531Sjairo.balart@metempsy.com            if (bp[2] == ':') {
43713531Sjairo.balart@metempsy.com                putbyte(bp[0]);
43813531Sjairo.balart@metempsy.com                putbyte(bp[1]);
43913531Sjairo.balart@metempsy.com                len -= 3;
44013531Sjairo.balart@metempsy.com                memcpy(bp, bp+3, len);
44113531Sjairo.balart@metempsy.com            }
44213531Sjairo.balart@metempsy.com            break;
44313531Sjairo.balart@metempsy.com        }
44413760Sjairo.balart@metempsy.com        //Otherwise, report that there was a mistake.
44513531Sjairo.balart@metempsy.com        putbyte(GDBBadP);
44613760Sjairo.balart@metempsy.com    } while (1);
44713531Sjairo.balart@metempsy.com
44813531Sjairo.balart@metempsy.com    DPRINTF(GDBRecv, "recv:  %s: %s\n", gdb_command(*bp), bp);
44913531Sjairo.balart@metempsy.com
45013531Sjairo.balart@metempsy.com    return (len);
45113531Sjairo.balart@metempsy.com}
45213531Sjairo.balart@metempsy.com
45313531Sjairo.balart@metempsy.com// Read bytes from kernel address space for debugger.
45413531Sjairo.balart@metempsy.combool
45513531Sjairo.balart@metempsy.comBaseRemoteGDB::read(Addr vaddr, size_t size, char *data)
45613531Sjairo.balart@metempsy.com{
45713923Sgiacomo.travaglini@arm.com    static Addr lastaddr = 0;
45813923Sgiacomo.travaglini@arm.com    static size_t lastsize = 0;
45913531Sjairo.balart@metempsy.com
46013531Sjairo.balart@metempsy.com    if (vaddr < 10) {
46113531Sjairo.balart@metempsy.com      DPRINTF(GDBRead, "read:  reading memory location zero!\n");
46213531Sjairo.balart@metempsy.com      vaddr = lastaddr + lastsize;
46313531Sjairo.balart@metempsy.com    }
46413531Sjairo.balart@metempsy.com
46513531Sjairo.balart@metempsy.com    DPRINTF(GDBRead, "read:  addr=%#x, size=%d", vaddr, size);
46613531Sjairo.balart@metempsy.com
46713531Sjairo.balart@metempsy.com#if FULL_SYSTEM
46813531Sjairo.balart@metempsy.com    FSTranslatingPortProxy *port = context->getVirtProxy();
46913760Sjairo.balart@metempsy.com#else
47013531Sjairo.balart@metempsy.com    SETranslatingPortProxy *port = context->getMemProxy();
47113531Sjairo.balart@metempsy.com#endif
47213531Sjairo.balart@metempsy.com    port->readBlob(vaddr, (uint8_t*)data, size);
47313531Sjairo.balart@metempsy.com
47413531Sjairo.balart@metempsy.com#if TRACING_ON
47513760Sjairo.balart@metempsy.com    if (DTRACE(GDBRead)) {
47613531Sjairo.balart@metempsy.com        if (DTRACE(GDBExtra)) {
47713531Sjairo.balart@metempsy.com            char buf[1024];
47813760Sjairo.balart@metempsy.com            mem2hex(buf, data, size);
47913760Sjairo.balart@metempsy.com            DPRINTFNR(": %s\n", buf);
48013531Sjairo.balart@metempsy.com        } else
48113531Sjairo.balart@metempsy.com            DPRINTFNR("\n");
48213760Sjairo.balart@metempsy.com    }
48313531Sjairo.balart@metempsy.com#endif
48413531Sjairo.balart@metempsy.com
48513531Sjairo.balart@metempsy.com    return true;
48613531Sjairo.balart@metempsy.com}
48713531Sjairo.balart@metempsy.com
48813760Sjairo.balart@metempsy.com// Write bytes to kernel address space for debugger.
48913531Sjairo.balart@metempsy.combool
49013760Sjairo.balart@metempsy.comBaseRemoteGDB::write(Addr vaddr, size_t size, const char *data)
49113531Sjairo.balart@metempsy.com{
49213531Sjairo.balart@metempsy.com    static Addr lastaddr = 0;
49313531Sjairo.balart@metempsy.com    static size_t lastsize = 0;
49413531Sjairo.balart@metempsy.com
49513531Sjairo.balart@metempsy.com    if (vaddr < 10) {
49613531Sjairo.balart@metempsy.com      DPRINTF(GDBWrite, "write: writing memory location zero!\n");
49713531Sjairo.balart@metempsy.com      vaddr = lastaddr + lastsize;
49813531Sjairo.balart@metempsy.com    }
49913531Sjairo.balart@metempsy.com
50013760Sjairo.balart@metempsy.com    if (DTRACE(GDBWrite)) {
50113531Sjairo.balart@metempsy.com        DPRINTFN("write: addr=%#x, size=%d", vaddr, size);
50213760Sjairo.balart@metempsy.com        if (DTRACE(GDBExtra)) {
50313531Sjairo.balart@metempsy.com            char buf[1024];
50413531Sjairo.balart@metempsy.com            mem2hex(buf, data, size);
50513531Sjairo.balart@metempsy.com            DPRINTFNR(": %s\n", buf);
50613531Sjairo.balart@metempsy.com        } else
50713531Sjairo.balart@metempsy.com            DPRINTFNR("\n");
50813760Sjairo.balart@metempsy.com    }
50913760Sjairo.balart@metempsy.com#if FULL_SYSTEM
51013760Sjairo.balart@metempsy.com    FSTranslatingPortProxy *port = context->getVirtProxy();
51113760Sjairo.balart@metempsy.com#else
51213760Sjairo.balart@metempsy.com    SETranslatingPortProxy *port = context->getMemProxy();
51313760Sjairo.balart@metempsy.com#endif
51413760Sjairo.balart@metempsy.com    port->writeBlob(vaddr, (uint8_t*)data, size);
51513760Sjairo.balart@metempsy.com#if !FULL_SYSTEM
51613760Sjairo.balart@metempsy.com    delete port;
51713760Sjairo.balart@metempsy.com#endif
51813760Sjairo.balart@metempsy.com
51913531Sjairo.balart@metempsy.com    return true;
52013531Sjairo.balart@metempsy.com}
52113760Sjairo.balart@metempsy.com
52213531Sjairo.balart@metempsy.comPCEventQueue *BaseRemoteGDB::getPcEventQueue()
52313531Sjairo.balart@metempsy.com{
52413531Sjairo.balart@metempsy.com    return &system->pcEventQueue;
52513531Sjairo.balart@metempsy.com}
52613760Sjairo.balart@metempsy.com
52713760Sjairo.balart@metempsy.comBaseRemoteGDB::HardBreakpoint::HardBreakpoint(BaseRemoteGDB *_gdb, Addr pc)
52813760Sjairo.balart@metempsy.com    : PCEvent(_gdb->getPcEventQueue(), "HardBreakpoint Event", pc),
52913760Sjairo.balart@metempsy.com      gdb(_gdb), refcount(0)
53013760Sjairo.balart@metempsy.com{
53113760Sjairo.balart@metempsy.com    DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc);
53213531Sjairo.balart@metempsy.com}
53313760Sjairo.balart@metempsy.com
53413760Sjairo.balart@metempsy.comvoid
53513760Sjairo.balart@metempsy.comBaseRemoteGDB::HardBreakpoint::process(ThreadContext *tc)
53613760Sjairo.balart@metempsy.com{
53713760Sjairo.balart@metempsy.com    DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc());
53813760Sjairo.balart@metempsy.com
53913760Sjairo.balart@metempsy.com    if (tc == gdb->context)
54013760Sjairo.balart@metempsy.com        gdb->trap(SIGTRAP);
54113760Sjairo.balart@metempsy.com}
54213760Sjairo.balart@metempsy.com
54313760Sjairo.balart@metempsy.combool
54413760Sjairo.balart@metempsy.comBaseRemoteGDB::insertSoftBreak(Addr addr, size_t len)
54513760Sjairo.balart@metempsy.com{
54613760Sjairo.balart@metempsy.com    if (len != sizeof(TheISA::MachInst))
54713760Sjairo.balart@metempsy.com        panic("invalid length\n");
54813760Sjairo.balart@metempsy.com
54913760Sjairo.balart@metempsy.com    return insertHardBreak(addr, len);
55013760Sjairo.balart@metempsy.com}
55113760Sjairo.balart@metempsy.com
55213760Sjairo.balart@metempsy.combool
55313760Sjairo.balart@metempsy.comBaseRemoteGDB::removeSoftBreak(Addr addr, size_t len)
55413760Sjairo.balart@metempsy.com{
55513760Sjairo.balart@metempsy.com    if (len != sizeof(MachInst))
55613760Sjairo.balart@metempsy.com        panic("invalid length\n");
55713531Sjairo.balart@metempsy.com
55813760Sjairo.balart@metempsy.com    return removeHardBreak(addr, len);
55913760Sjairo.balart@metempsy.com}
56013531Sjairo.balart@metempsy.com
56113531Sjairo.balart@metempsy.combool
56213531Sjairo.balart@metempsy.comBaseRemoteGDB::insertHardBreak(Addr addr, size_t len)
56314245Sgiacomo.travaglini@arm.com{
56413760Sjairo.balart@metempsy.com    if (len != sizeof(MachInst))
56513760Sjairo.balart@metempsy.com        panic("invalid length\n");
56613760Sjairo.balart@metempsy.com
56713760Sjairo.balart@metempsy.com    DPRINTF(GDBMisc, "inserting hardware breakpoint at %#x\n", addr);
56813760Sjairo.balart@metempsy.com
56913760Sjairo.balart@metempsy.com    HardBreakpoint *&bkpt = hardBreakMap[addr];
57013531Sjairo.balart@metempsy.com    if (bkpt == 0)
57113531Sjairo.balart@metempsy.com        bkpt = new HardBreakpoint(this, addr);
57213760Sjairo.balart@metempsy.com
57313760Sjairo.balart@metempsy.com    bkpt->refcount++;
57413760Sjairo.balart@metempsy.com
57513760Sjairo.balart@metempsy.com    return true;
57613760Sjairo.balart@metempsy.com}
57713760Sjairo.balart@metempsy.com
57813760Sjairo.balart@metempsy.combool
57913760Sjairo.balart@metempsy.comBaseRemoteGDB::removeHardBreak(Addr addr, size_t len)
58013531Sjairo.balart@metempsy.com{
58113531Sjairo.balart@metempsy.com    if (len != sizeof(MachInst))
58213531Sjairo.balart@metempsy.com        panic("invalid length\n");
58313760Sjairo.balart@metempsy.com
58413531Sjairo.balart@metempsy.com    DPRINTF(GDBMisc, "removing hardware breakpoint at %#x\n", addr);
58513760Sjairo.balart@metempsy.com
58613760Sjairo.balart@metempsy.com    break_iter_t i = hardBreakMap.find(addr);
58713760Sjairo.balart@metempsy.com    if (i == hardBreakMap.end())
58813760Sjairo.balart@metempsy.com        return false;
58913760Sjairo.balart@metempsy.com
59013760Sjairo.balart@metempsy.com    HardBreakpoint *hbp = (*i).second;
59113760Sjairo.balart@metempsy.com    if (--hbp->refcount == 0) {
59213531Sjairo.balart@metempsy.com        delete hbp;
59313531Sjairo.balart@metempsy.com        hardBreakMap.erase(i);
59413531Sjairo.balart@metempsy.com    }
59513760Sjairo.balart@metempsy.com
59613531Sjairo.balart@metempsy.com    return true;
59713531Sjairo.balart@metempsy.com}
59813760Sjairo.balart@metempsy.com
59913760Sjairo.balart@metempsy.comvoid
60013760Sjairo.balart@metempsy.comBaseRemoteGDB::setTempBreakpoint(Addr bkpt)
60113760Sjairo.balart@metempsy.com{
60213760Sjairo.balart@metempsy.com    DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", bkpt);
60313760Sjairo.balart@metempsy.com    insertHardBreak(bkpt, sizeof(TheISA::MachInst));
60413760Sjairo.balart@metempsy.com}
60513531Sjairo.balart@metempsy.com
60613531Sjairo.balart@metempsy.comvoid
60713760Sjairo.balart@metempsy.comBaseRemoteGDB::clearTempBreakpoint(Addr &bkpt)
60813760Sjairo.balart@metempsy.com{
60913760Sjairo.balart@metempsy.com    DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", bkpt);
61013760Sjairo.balart@metempsy.com    removeHardBreak(bkpt, sizeof(TheISA::MachInst));
61113760Sjairo.balart@metempsy.com    bkpt = 0;
61213760Sjairo.balart@metempsy.com}
61313760Sjairo.balart@metempsy.com
61413760Sjairo.balart@metempsy.comconst char *
61513760Sjairo.balart@metempsy.comBaseRemoteGDB::break_type(char c)
61613531Sjairo.balart@metempsy.com{
61713531Sjairo.balart@metempsy.com    switch(c) {
61813531Sjairo.balart@metempsy.com      case '0': return "software breakpoint";
61913760Sjairo.balart@metempsy.com      case '1': return "hardware breakpoint";
62013531Sjairo.balart@metempsy.com      case '2': return "write watchpoint";
62113531Sjairo.balart@metempsy.com      case '3': return "read watchpoint";
62213531Sjairo.balart@metempsy.com      case '4': return "access watchpoint";
62313531Sjairo.balart@metempsy.com      default: return "unknown breakpoint/watchpoint";
62413760Sjairo.balart@metempsy.com    }
62513531Sjairo.balart@metempsy.com}
62613531Sjairo.balart@metempsy.com
62713531Sjairo.balart@metempsy.com// This function does all command processing for interfacing to a
62813531Sjairo.balart@metempsy.com// remote gdb.  Note that the error codes are ignored by gdb at
62914236Sgiacomo.travaglini@arm.com// present, but might eventually become meaningful. (XXX) It might
63014236Sgiacomo.travaglini@arm.com// makes sense to use POSIX errno values, because that is what the
63114236Sgiacomo.travaglini@arm.com// gdb/remote.c functions want to return.
63214236Sgiacomo.travaglini@arm.combool
63314236Sgiacomo.travaglini@arm.comBaseRemoteGDB::trap(int type)
63414236Sgiacomo.travaglini@arm.com{
63514236Sgiacomo.travaglini@arm.com    uint64_t val;
63614236Sgiacomo.travaglini@arm.com    size_t datalen, len;
63714236Sgiacomo.travaglini@arm.com    char data[GDBPacketBufLen + 1];
63814236Sgiacomo.travaglini@arm.com    char *buffer;
63914236Sgiacomo.travaglini@arm.com    size_t bufferSize;
64014236Sgiacomo.travaglini@arm.com    const char *p;
64113760Sjairo.balart@metempsy.com    char command, subcmd;
64213531Sjairo.balart@metempsy.com    string var;
64313531Sjairo.balart@metempsy.com    bool ret;
64413531Sjairo.balart@metempsy.com
64513531Sjairo.balart@metempsy.com    if (!attached)
64614236Sgiacomo.travaglini@arm.com        return false;
64714236Sgiacomo.travaglini@arm.com
64814236Sgiacomo.travaglini@arm.com    bufferSize = gdbregs.bytes() * 2 + 256;
64914236Sgiacomo.travaglini@arm.com    buffer = (char*)malloc(bufferSize);
65014236Sgiacomo.travaglini@arm.com
65114236Sgiacomo.travaglini@arm.com    DPRINTF(GDBMisc, "trap: PC=%s\n", context->pcState());
65214236Sgiacomo.travaglini@arm.com
65314236Sgiacomo.travaglini@arm.com    clearSingleStep();
65414236Sgiacomo.travaglini@arm.com
65514236Sgiacomo.travaglini@arm.com    /*
65614236Sgiacomo.travaglini@arm.com     * The first entry to this function is normally through
65714236Sgiacomo.travaglini@arm.com     * a breakpoint trap in kgdb_connect(), in which case we
65813760Sjairo.balart@metempsy.com     * must advance past the breakpoint because gdb will not.
65913531Sjairo.balart@metempsy.com     *
66013760Sjairo.balart@metempsy.com     * On the first entry here, we expect that gdb is not yet
66113760Sjairo.balart@metempsy.com     * listening to us, so just enter the interaction loop.
66213760Sjairo.balart@metempsy.com     * After the debugger is "active" (connected) it will be
66313760Sjairo.balart@metempsy.com     * waiting for a "signaled" message from us.
66413760Sjairo.balart@metempsy.com     */
66513760Sjairo.balart@metempsy.com    if (!active)
66613760Sjairo.balart@metempsy.com        active = true;
66713760Sjairo.balart@metempsy.com    else
66813760Sjairo.balart@metempsy.com        // Tell remote host that an exception has occurred.
66913760Sjairo.balart@metempsy.com        snprintf((char *)buffer, bufferSize, "S%02x", type);
67013760Sjairo.balart@metempsy.com        send(buffer);
67113760Sjairo.balart@metempsy.com
67213760Sjairo.balart@metempsy.com    // Stick frame regs into our reg cache.
67313760Sjairo.balart@metempsy.com    getregs();
67413760Sjairo.balart@metempsy.com
67513760Sjairo.balart@metempsy.com    for (;;) {
67613760Sjairo.balart@metempsy.com        datalen = recv(data, sizeof(data));
67713531Sjairo.balart@metempsy.com        data[sizeof(data) - 1] = 0; // Sentinel
67813531Sjairo.balart@metempsy.com        command = data[0];
67913760Sjairo.balart@metempsy.com        subcmd = 0;
68013531Sjairo.balart@metempsy.com        p = data + 1;
68113531Sjairo.balart@metempsy.com        switch (command) {
68213760Sjairo.balart@metempsy.com
68313531Sjairo.balart@metempsy.com          case GDBSignal:
68413531Sjairo.balart@metempsy.com            // if this command came from a running gdb, answer it --
68513760Sjairo.balart@metempsy.com            // the other guy has no way of knowing if we're in or out
68613531Sjairo.balart@metempsy.com            // of this loop when he issues a "remote-signal".
68713531Sjairo.balart@metempsy.com            snprintf((char *)buffer, bufferSize,
68813531Sjairo.balart@metempsy.com                    "S%02x", type);
68913531Sjairo.balart@metempsy.com            send(buffer);
69013531Sjairo.balart@metempsy.com            continue;
69113760Sjairo.balart@metempsy.com
69213531Sjairo.balart@metempsy.com          case GDBRegR:
69313531Sjairo.balart@metempsy.com            if (2 * gdbregs.bytes() > bufferSize)
69413760Sjairo.balart@metempsy.com                panic("buffer too small");
69513760Sjairo.balart@metempsy.com
69613531Sjairo.balart@metempsy.com            mem2hex(buffer, gdbregs.regs, gdbregs.bytes());
69713531Sjairo.balart@metempsy.com            send(buffer);
69813531Sjairo.balart@metempsy.com            continue;
69913531Sjairo.balart@metempsy.com
70013531Sjairo.balart@metempsy.com          case GDBRegW:
70113531Sjairo.balart@metempsy.com            p = hex2mem(gdbregs.regs, p, gdbregs.bytes());
70213760Sjairo.balart@metempsy.com            if (p == NULL || *p != '\0')
70313531Sjairo.balart@metempsy.com                send("E01");
70413531Sjairo.balart@metempsy.com            else {
70513531Sjairo.balart@metempsy.com                setregs();
70613531Sjairo.balart@metempsy.com                send("OK");
70713531Sjairo.balart@metempsy.com            }
70813760Sjairo.balart@metempsy.com            continue;
70913531Sjairo.balart@metempsy.com
71013531Sjairo.balart@metempsy.com#if 0
71113531Sjairo.balart@metempsy.com          case GDBSetReg:
71213531Sjairo.balart@metempsy.com            val = hex2i(&p);
71313531Sjairo.balart@metempsy.com            if (*p++ != '=') {
71413760Sjairo.balart@metempsy.com                send("E01");
71513531Sjairo.balart@metempsy.com                continue;
71613531Sjairo.balart@metempsy.com            }
71713531Sjairo.balart@metempsy.com            if (val < 0 && val >= KGDB_NUMREGS) {
71813760Sjairo.balart@metempsy.com                send("E01");
71913531Sjairo.balart@metempsy.com                continue;
72013531Sjairo.balart@metempsy.com            }
72113531Sjairo.balart@metempsy.com
72213531Sjairo.balart@metempsy.com            gdbregs.regs[val] = hex2i(&p);
72313531Sjairo.balart@metempsy.com            setregs();
72413760Sjairo.balart@metempsy.com            send("OK");
72513760Sjairo.balart@metempsy.com
72613531Sjairo.balart@metempsy.com            continue;
72713531Sjairo.balart@metempsy.com#endif
72813760Sjairo.balart@metempsy.com
72913760Sjairo.balart@metempsy.com          case GDBMemR:
73013531Sjairo.balart@metempsy.com            val = hex2i(&p);
73113531Sjairo.balart@metempsy.com            if (*p++ != ',') {
73213531Sjairo.balart@metempsy.com                send("E02");
73313531Sjairo.balart@metempsy.com                continue;
73413580Sgabeblack@google.com            }
73513531Sjairo.balart@metempsy.com            len = hex2i(&p);
73613531Sjairo.balart@metempsy.com            if (*p != '\0') {
73713760Sjairo.balart@metempsy.com                send("E03");
73813760Sjairo.balart@metempsy.com                continue;
73913531Sjairo.balart@metempsy.com            }
74013531Sjairo.balart@metempsy.com            if (len > bufferSize) {
74113531Sjairo.balart@metempsy.com                send("E04");
74213531Sjairo.balart@metempsy.com                continue;
74313760Sjairo.balart@metempsy.com            }
74413531Sjairo.balart@metempsy.com            if (!acc(val, len)) {
74513531Sjairo.balart@metempsy.com                send("E05");
74613531Sjairo.balart@metempsy.com                continue;
74713531Sjairo.balart@metempsy.com            }
74813531Sjairo.balart@metempsy.com
74913531Sjairo.balart@metempsy.com            if (read(val, (size_t)len, (char *)buffer)) {
75014246Sgiacomo.travaglini@arm.com               // variable length array would be nice, but C++ doesn't
75114246Sgiacomo.travaglini@arm.com               // officially support those...
75213531Sjairo.balart@metempsy.com               char *temp = new char[2*len+1];
75313531Sjairo.balart@metempsy.com               mem2hex(temp, buffer, len);
75413531Sjairo.balart@metempsy.com               send(temp);
75513531Sjairo.balart@metempsy.com               delete [] temp;
75613531Sjairo.balart@metempsy.com            } else {
75713531Sjairo.balart@metempsy.com               send("E05");
75813531Sjairo.balart@metempsy.com            }
75913531Sjairo.balart@metempsy.com            continue;
76013531Sjairo.balart@metempsy.com
76113531Sjairo.balart@metempsy.com          case GDBMemW:
76213531Sjairo.balart@metempsy.com            val = hex2i(&p);
76313531Sjairo.balart@metempsy.com            if (*p++ != ',') {
76413531Sjairo.balart@metempsy.com                send("E06");
76513531Sjairo.balart@metempsy.com                continue;
76613760Sjairo.balart@metempsy.com            }
76713531Sjairo.balart@metempsy.com            len = hex2i(&p);
76813531Sjairo.balart@metempsy.com            if (*p++ != ':') {
76913531Sjairo.balart@metempsy.com                send("E07");
77013531Sjairo.balart@metempsy.com                continue;
77113531Sjairo.balart@metempsy.com            }
77213531Sjairo.balart@metempsy.com            if (len > datalen - (p - data)) {
77313531Sjairo.balart@metempsy.com                send("E08");
77413531Sjairo.balart@metempsy.com                continue;
77513531Sjairo.balart@metempsy.com            }
77613531Sjairo.balart@metempsy.com            p = hex2mem(buffer, p, bufferSize);
77713531Sjairo.balart@metempsy.com            if (p == NULL) {
77813531Sjairo.balart@metempsy.com                send("E09");
77913531Sjairo.balart@metempsy.com                continue;
78013531Sjairo.balart@metempsy.com            }
78113531Sjairo.balart@metempsy.com            if (!acc(val, len)) {
78213531Sjairo.balart@metempsy.com                send("E0A");
78313531Sjairo.balart@metempsy.com                continue;
78413531Sjairo.balart@metempsy.com            }
78513531Sjairo.balart@metempsy.com            if (write(val, (size_t)len, (char *)buffer))
78613531Sjairo.balart@metempsy.com              send("OK");
78713531Sjairo.balart@metempsy.com            else
78813760Sjairo.balart@metempsy.com              send("E0B");
78913531Sjairo.balart@metempsy.com            continue;
79013531Sjairo.balart@metempsy.com
79113531Sjairo.balart@metempsy.com          case GDBSetThread:
79213531Sjairo.balart@metempsy.com            subcmd = *p++;
79313531Sjairo.balart@metempsy.com            val = hex2i(&p);
79413531Sjairo.balart@metempsy.com            if (val == 0)
79513531Sjairo.balart@metempsy.com                send("OK");
79613531Sjairo.balart@metempsy.com            else
79713531Sjairo.balart@metempsy.com                send("E01");
79813923Sgiacomo.travaglini@arm.com            continue;
79913923Sgiacomo.travaglini@arm.com
80013531Sjairo.balart@metempsy.com          case GDBDetach:
80113531Sjairo.balart@metempsy.com          case GDBKill:
80213531Sjairo.balart@metempsy.com            active = false;
80313531Sjairo.balart@metempsy.com            clearSingleStep();
80413531Sjairo.balart@metempsy.com            detach();
80513531Sjairo.balart@metempsy.com            goto out;
80613531Sjairo.balart@metempsy.com
80713531Sjairo.balart@metempsy.com          case GDBAsyncCont:
80813531Sjairo.balart@metempsy.com            subcmd = hex2i(&p);
80913531Sjairo.balart@metempsy.com            if (*p++ == ';') {
81013531Sjairo.balart@metempsy.com                val = hex2i(&p);
81113531Sjairo.balart@metempsy.com                context->pcState(val);
81213531Sjairo.balart@metempsy.com            }
81313531Sjairo.balart@metempsy.com            clearSingleStep();
81413531Sjairo.balart@metempsy.com            goto out;
81513531Sjairo.balart@metempsy.com
81613531Sjairo.balart@metempsy.com          case GDBCont:
81713531Sjairo.balart@metempsy.com            if (p - data < (ptrdiff_t)datalen) {
81813760Sjairo.balart@metempsy.com                val = hex2i(&p);
81913531Sjairo.balart@metempsy.com                context->pcState(val);
82013531Sjairo.balart@metempsy.com            }
82113531Sjairo.balart@metempsy.com            clearSingleStep();
82213531Sjairo.balart@metempsy.com            goto out;
82313531Sjairo.balart@metempsy.com
82413531Sjairo.balart@metempsy.com          case GDBAsyncStep:
82513531Sjairo.balart@metempsy.com            subcmd = hex2i(&p);
82613531Sjairo.balart@metempsy.com            if (*p++ == ';') {
82713531Sjairo.balart@metempsy.com                val = hex2i(&p);
82813531Sjairo.balart@metempsy.com                context->pcState(val);
82913531Sjairo.balart@metempsy.com            }
83013531Sjairo.balart@metempsy.com            setSingleStep();
83113531Sjairo.balart@metempsy.com            goto out;
83213531Sjairo.balart@metempsy.com
83313531Sjairo.balart@metempsy.com          case GDBStep:
83413531Sjairo.balart@metempsy.com            if (p - data < (ptrdiff_t)datalen) {
83513531Sjairo.balart@metempsy.com                val = hex2i(&p);
83613531Sjairo.balart@metempsy.com                context->pcState(val);
83713531Sjairo.balart@metempsy.com            }
83813531Sjairo.balart@metempsy.com            setSingleStep();
83913531Sjairo.balart@metempsy.com            goto out;
84013760Sjairo.balart@metempsy.com
84113531Sjairo.balart@metempsy.com          case GDBClrHwBkpt:
84213531Sjairo.balart@metempsy.com            subcmd = *p++;
84313760Sjairo.balart@metempsy.com            if (*p++ != ',') send("E0D");
84413760Sjairo.balart@metempsy.com            val = hex2i(&p);
84513531Sjairo.balart@metempsy.com            if (*p++ != ',') send("E0D");
84613531Sjairo.balart@metempsy.com            len = hex2i(&p);
84713760Sjairo.balart@metempsy.com
84813531Sjairo.balart@metempsy.com            DPRINTF(GDBMisc, "clear %s, addr=%#x, len=%d\n",
84913531Sjairo.balart@metempsy.com                    break_type(subcmd), val, len);
85013531Sjairo.balart@metempsy.com
85113531Sjairo.balart@metempsy.com            ret = false;
85213531Sjairo.balart@metempsy.com
85313531Sjairo.balart@metempsy.com            switch (subcmd) {
85413531Sjairo.balart@metempsy.com              case '0': // software breakpoint
85513531Sjairo.balart@metempsy.com                ret = removeSoftBreak(val, len);
85613531Sjairo.balart@metempsy.com                break;
85713531Sjairo.balart@metempsy.com
85813760Sjairo.balart@metempsy.com              case '1': // hardware breakpoint
85913531Sjairo.balart@metempsy.com                ret = removeHardBreak(val, len);
86013760Sjairo.balart@metempsy.com                break;
86113531Sjairo.balart@metempsy.com
86213531Sjairo.balart@metempsy.com              case '2': // write watchpoint
86313531Sjairo.balart@metempsy.com              case '3': // read watchpoint
86413531Sjairo.balart@metempsy.com              case '4': // access watchpoint
86513531Sjairo.balart@metempsy.com              default: // unknown
86613531Sjairo.balart@metempsy.com                send("");
86713531Sjairo.balart@metempsy.com                break;
86813923Sgiacomo.travaglini@arm.com            }
86913923Sgiacomo.travaglini@arm.com
87013531Sjairo.balart@metempsy.com            send(ret ? "OK" : "E0C");
87113531Sjairo.balart@metempsy.com            continue;
87213531Sjairo.balart@metempsy.com
87313760Sjairo.balart@metempsy.com          case GDBSetHwBkpt:
87413531Sjairo.balart@metempsy.com            subcmd = *p++;
87513531Sjairo.balart@metempsy.com            if (*p++ != ',') send("E0D");
87613531Sjairo.balart@metempsy.com            val = hex2i(&p);
87713531Sjairo.balart@metempsy.com            if (*p++ != ',') send("E0D");
87813531Sjairo.balart@metempsy.com            len = hex2i(&p);
87913531Sjairo.balart@metempsy.com
88013531Sjairo.balart@metempsy.com            DPRINTF(GDBMisc, "set %s, addr=%#x, len=%d\n",
88113531Sjairo.balart@metempsy.com                    break_type(subcmd), val, len);
88213531Sjairo.balart@metempsy.com
88313760Sjairo.balart@metempsy.com            ret = false;
88413531Sjairo.balart@metempsy.com
88513531Sjairo.balart@metempsy.com            switch (subcmd) {
88613531Sjairo.balart@metempsy.com              case '0': // software breakpoint
88713531Sjairo.balart@metempsy.com                ret = insertSoftBreak(val, len);
88813531Sjairo.balart@metempsy.com                break;
88913531Sjairo.balart@metempsy.com
89013531Sjairo.balart@metempsy.com              case '1': // hardware breakpoint
89113531Sjairo.balart@metempsy.com                ret = insertHardBreak(val, len);
89213531Sjairo.balart@metempsy.com                break;
89313531Sjairo.balart@metempsy.com
89413531Sjairo.balart@metempsy.com              case '2': // write watchpoint
89513531Sjairo.balart@metempsy.com              case '3': // read watchpoint
89613531Sjairo.balart@metempsy.com              case '4': // access watchpoint
89713760Sjairo.balart@metempsy.com              default: // unknown
89813531Sjairo.balart@metempsy.com                send("");
89913531Sjairo.balart@metempsy.com                break;
90013531Sjairo.balart@metempsy.com            }
90113531Sjairo.balart@metempsy.com
90213531Sjairo.balart@metempsy.com            send(ret ? "OK" : "E0C");
90313760Sjairo.balart@metempsy.com            continue;
90413531Sjairo.balart@metempsy.com
90513531Sjairo.balart@metempsy.com          case GDBQueryVar:
90613531Sjairo.balart@metempsy.com            var = string(p, datalen - 1);
90713531Sjairo.balart@metempsy.com            if (var == "C")
90813531Sjairo.balart@metempsy.com                send("QC0");
90913531Sjairo.balart@metempsy.com            else
91013531Sjairo.balart@metempsy.com                send("");
91113531Sjairo.balart@metempsy.com            continue;
91213531Sjairo.balart@metempsy.com
91313531Sjairo.balart@metempsy.com          case GDBSetBaud:
91413531Sjairo.balart@metempsy.com          case GDBSetBreak:
91513531Sjairo.balart@metempsy.com          case GDBDebug:
91613760Sjairo.balart@metempsy.com          case GDBCycleStep:
91713531Sjairo.balart@metempsy.com          case GDBSigCycleStep:
91813531Sjairo.balart@metempsy.com          case GDBReadReg:
91913760Sjairo.balart@metempsy.com          case GDBSetVar:
92013531Sjairo.balart@metempsy.com          case GDBReset:
92113531Sjairo.balart@metempsy.com          case GDBThreadAlive:
92213760Sjairo.balart@metempsy.com          case GDBTargetExit:
92313760Sjairo.balart@metempsy.com          case GDBBinaryDload:
92413531Sjairo.balart@metempsy.com            // Unsupported command
92513531Sjairo.balart@metempsy.com            DPRINTF(GDBMisc, "Unsupported command: %s\n",
92613531Sjairo.balart@metempsy.com                    gdb_command(command));
92713531Sjairo.balart@metempsy.com            DDUMP(GDBMisc, (uint8_t *)data, datalen);
92813531Sjairo.balart@metempsy.com            send("");
92913531Sjairo.balart@metempsy.com            continue;
93013531Sjairo.balart@metempsy.com
93113531Sjairo.balart@metempsy.com          default:
93213531Sjairo.balart@metempsy.com            // Unknown command.
93313531Sjairo.balart@metempsy.com            DPRINTF(GDBMisc, "Unknown command: %c(%#x)\n",
93413531Sjairo.balart@metempsy.com                    command, command);
93513531Sjairo.balart@metempsy.com            send("");
93613760Sjairo.balart@metempsy.com            continue;
93713531Sjairo.balart@metempsy.com
93813760Sjairo.balart@metempsy.com
93913531Sjairo.balart@metempsy.com        }
94013760Sjairo.balart@metempsy.com    }
94113531Sjairo.balart@metempsy.com
94213531Sjairo.balart@metempsy.com  out:
94313531Sjairo.balart@metempsy.com    free(buffer);
94413531Sjairo.balart@metempsy.com    return true;
94513531Sjairo.balart@metempsy.com}
94613760Sjairo.balart@metempsy.com
94713760Sjairo.balart@metempsy.com// Convert a hex digit into an integer.
94813760Sjairo.balart@metempsy.com// This returns -1 if the argument passed is no valid hex digit.
94913760Sjairo.balart@metempsy.comint
95013531Sjairo.balart@metempsy.comBaseRemoteGDB::digit2i(char c)
95113531Sjairo.balart@metempsy.com{
95213531Sjairo.balart@metempsy.com    if (c >= '0' && c <= '9')
95313531Sjairo.balart@metempsy.com        return (c - '0');
95413760Sjairo.balart@metempsy.com    else if (c >= 'a' && c <= 'f')
95513531Sjairo.balart@metempsy.com        return (c - 'a' + 10);
95613531Sjairo.balart@metempsy.com    else if (c >= 'A' && c <= 'F')
95713531Sjairo.balart@metempsy.com
95813531Sjairo.balart@metempsy.com        return (c - 'A' + 10);
95913531Sjairo.balart@metempsy.com    else
96013531Sjairo.balart@metempsy.com        return (-1);
96113531Sjairo.balart@metempsy.com}
96213531Sjairo.balart@metempsy.com
96313531Sjairo.balart@metempsy.com// Convert the low 4 bits of an integer into an hex digit.
96413531Sjairo.balart@metempsy.comchar
96513531Sjairo.balart@metempsy.comBaseRemoteGDB::i2digit(int n)
96613531Sjairo.balart@metempsy.com{
96713531Sjairo.balart@metempsy.com    return ("0123456789abcdef"[n & 0x0f]);
96813531Sjairo.balart@metempsy.com}
96913531Sjairo.balart@metempsy.com
97013531Sjairo.balart@metempsy.com// Convert a byte array into an hex string.
97113531Sjairo.balart@metempsy.comvoid
97213531Sjairo.balart@metempsy.comBaseRemoteGDB::mem2hex(void *vdst, const void *vsrc, int len)
97313531Sjairo.balart@metempsy.com{
97413531Sjairo.balart@metempsy.com    char *dst = (char *)vdst;
97513531Sjairo.balart@metempsy.com    const char *src = (const char *)vsrc;
97613531Sjairo.balart@metempsy.com
97713531Sjairo.balart@metempsy.com    while (len--) {
97813531Sjairo.balart@metempsy.com        *dst++ = i2digit(*src >> 4);
97913531Sjairo.balart@metempsy.com        *dst++ = i2digit(*src++);
98013531Sjairo.balart@metempsy.com    }
98113531Sjairo.balart@metempsy.com    *dst = '\0';
98213531Sjairo.balart@metempsy.com}
98313531Sjairo.balart@metempsy.com
98413531Sjairo.balart@metempsy.com// Convert an hex string into a byte array.
98513531Sjairo.balart@metempsy.com// This returns a pointer to the character following the last valid
98613531Sjairo.balart@metempsy.com// hex digit. If the string ends in the middle of a byte, NULL is
98713531Sjairo.balart@metempsy.com// returned.
98813531Sjairo.balart@metempsy.comconst char *
98913760Sjairo.balart@metempsy.comBaseRemoteGDB::hex2mem(void *vdst, const char *src, int maxlen)
99013531Sjairo.balart@metempsy.com{
99113531Sjairo.balart@metempsy.com    char *dst = (char *)vdst;
99213531Sjairo.balart@metempsy.com    int msb, lsb;
99313531Sjairo.balart@metempsy.com
99413760Sjairo.balart@metempsy.com    while (*src && maxlen--) {
99513531Sjairo.balart@metempsy.com        msb = digit2i(*src++);
99613531Sjairo.balart@metempsy.com        if (msb < 0)
99713531Sjairo.balart@metempsy.com            return (src - 1);
99813531Sjairo.balart@metempsy.com        lsb = digit2i(*src++);
99913531Sjairo.balart@metempsy.com        if (lsb < 0)
100013531Sjairo.balart@metempsy.com            return (NULL);
100113531Sjairo.balart@metempsy.com        *dst++ = (msb << 4) | lsb;
100213531Sjairo.balart@metempsy.com    }
100313760Sjairo.balart@metempsy.com    return (src);
100413760Sjairo.balart@metempsy.com}
100513531Sjairo.balart@metempsy.com
100613531Sjairo.balart@metempsy.com// Convert an hex string into an integer.
100713531Sjairo.balart@metempsy.com// This returns a pointer to the character following the last valid
100813531Sjairo.balart@metempsy.com// hex digit.
100913531Sjairo.balart@metempsy.comAddr
101013531Sjairo.balart@metempsy.comBaseRemoteGDB::hex2i(const char **srcp)
101113531Sjairo.balart@metempsy.com{
101213531Sjairo.balart@metempsy.com    const char *src = *srcp;
101313531Sjairo.balart@metempsy.com    Addr r = 0;
101413531Sjairo.balart@metempsy.com    int nibble;
101513531Sjairo.balart@metempsy.com
101613531Sjairo.balart@metempsy.com    while ((nibble = digit2i(*src)) >= 0) {
101713531Sjairo.balart@metempsy.com        r *= 16;
101813531Sjairo.balart@metempsy.com        r += nibble;
101913760Sjairo.balart@metempsy.com        src++;
102013531Sjairo.balart@metempsy.com    }
102113531Sjairo.balart@metempsy.com    *srcp = src;
102213531Sjairo.balart@metempsy.com    return (r);
102313531Sjairo.balart@metempsy.com}
102413531Sjairo.balart@metempsy.com
102513760Sjairo.balart@metempsy.com