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