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