remote_gdb.cc revision 12125:0066d9926c1a
16242Sgblack@eecs.umich.edu/* 211575SDylan.Johnson@ARM.com * Copyright 2015 LabWare 37093Sgblack@eecs.umich.edu * Copyright 2014 Google, Inc. 47093Sgblack@eecs.umich.edu * Copyright (c) 2002-2005 The Regents of The University of Michigan 57093Sgblack@eecs.umich.edu * All rights reserved. 67093Sgblack@eecs.umich.edu * 77093Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 87093Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 97093Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 107093Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 117093Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 127093Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 137093Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 146242Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 156242Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 166242Sgblack@eecs.umich.edu * this software without specific prior written permission. 176242Sgblack@eecs.umich.edu * 186242Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 196242Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 206242Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 216242Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 226242Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 236242Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 246242Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 256242Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 266242Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 276242Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 286242Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 296242Sgblack@eecs.umich.edu * 306242Sgblack@eecs.umich.edu * Authors: Nathan Binkert 316242Sgblack@eecs.umich.edu * Boris Shingarov 326242Sgblack@eecs.umich.edu */ 336242Sgblack@eecs.umich.edu 346242Sgblack@eecs.umich.edu/* 356242Sgblack@eecs.umich.edu * Copyright (c) 1990, 1993 The Regents of the University of California 366242Sgblack@eecs.umich.edu * All rights reserved 376242Sgblack@eecs.umich.edu * 386242Sgblack@eecs.umich.edu * This software was developed by the Computer Systems Engineering group 396242Sgblack@eecs.umich.edu * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 406242Sgblack@eecs.umich.edu * contributed to Berkeley. 4110037SARM gem5 Developers * 426242Sgblack@eecs.umich.edu * All advertising materials mentioning features or use of this software 436242Sgblack@eecs.umich.edu * must display the following acknowledgement: 446242Sgblack@eecs.umich.edu * This product includes software developed by the University of 456242Sgblack@eecs.umich.edu * California, Lawrence Berkeley Laboratories. 4610037SARM gem5 Developers * 4710037SARM gem5 Developers * Redistribution and use in source and binary forms, with or without 486242Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions 499256SAndreas.Sandberg@arm.com * are met: 506242Sgblack@eecs.umich.edu * 1. Redistributions of source code must retain the above copyright 5110037SARM gem5 Developers * notice, this list of conditions and the following disclaimer. 5210037SARM gem5 Developers * 2. Redistributions in binary form must reproduce the above copyright 5310037SARM gem5 Developers * notice, this list of conditions and the following disclaimer in the 546242Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution. 556242Sgblack@eecs.umich.edu * 3. All advertising materials mentioning features or use of this software 566242Sgblack@eecs.umich.edu * must display the following acknowledgement: 5710037SARM gem5 Developers * This product includes software developed by the University of 5810037SARM gem5 Developers * California, Berkeley and its contributors. 5910037SARM gem5 Developers * 4. Neither the name of the University nor the names of its contributors 6010037SARM gem5 Developers * may be used to endorse or promote products derived from this software 6110037SARM gem5 Developers * without specific prior written permission. 6210037SARM gem5 Developers * 6310037SARM gem5 Developers * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 6410037SARM gem5 Developers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 6510037SARM gem5 Developers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 6610037SARM gem5 Developers * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 6710037SARM gem5 Developers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 6810037SARM gem5 Developers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 6910037SARM gem5 Developers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 7010037SARM gem5 Developers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 7110037SARM gem5 Developers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 727259Sgblack@eecs.umich.edu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 7310037SARM gem5 Developers * SUCH DAMAGE. 7410037SARM gem5 Developers * 7510037SARM gem5 Developers * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94 7610037SARM gem5 Developers */ 7710037SARM gem5 Developers 7810037SARM gem5 Developers/*- 7910037SARM gem5 Developers * Copyright (c) 2001 The NetBSD Foundation, Inc. 8010037SARM gem5 Developers * All rights reserved. 8110037SARM gem5 Developers * 8210037SARM gem5 Developers * This code is derived from software contributed to The NetBSD Foundation 8310037SARM gem5 Developers * by Jason R. Thorpe. 8410037SARM gem5 Developers * 8510037SARM gem5 Developers * Redistribution and use in source and binary forms, with or without 8610037SARM gem5 Developers * modification, are permitted provided that the following conditions 8710037SARM gem5 Developers * are met: 8810037SARM gem5 Developers * 1. Redistributions of source code must retain the above copyright 898868SMatt.Horsnell@arm.com * notice, this list of conditions and the following disclaimer. 9010037SARM gem5 Developers * 2. Redistributions in binary form must reproduce the above copyright 9110037SARM gem5 Developers * notice, this list of conditions and the following disclaimer in the 9210037SARM gem5 Developers * documentation and/or other materials provided with the distribution. 9310037SARM gem5 Developers * 3. All advertising materials mentioning features or use of this software 9410037SARM gem5 Developers * must display the following acknowledgement: 9510037SARM gem5 Developers * This product includes software developed by the NetBSD 9610037SARM gem5 Developers * Foundation, Inc. and its contributors. 9710037SARM gem5 Developers * 4. Neither the name of The NetBSD Foundation nor the names of its 9810037SARM gem5 Developers * contributors may be used to endorse or promote products derived 9910037SARM gem5 Developers * from this software without specific prior written permission. 10010037SARM gem5 Developers * 10110037SARM gem5 Developers * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 10210037SARM gem5 Developers * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 10310037SARM gem5 Developers * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 10410037SARM gem5 Developers * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 10510037SARM gem5 Developers * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 10610037SARM gem5 Developers * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 10710037SARM gem5 Developers * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 10810037SARM gem5 Developers * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 10910037SARM gem5 Developers * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 11010037SARM gem5 Developers * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 11110037SARM gem5 Developers * POSSIBILITY OF SUCH DAMAGE. 11210037SARM gem5 Developers */ 11310037SARM gem5 Developers 11410037SARM gem5 Developers/* 11510037SARM gem5 Developers * $NetBSD: kgdb_stub.c,v 1.8 2001/07/07 22:58:00 wdk Exp $ 11610037SARM gem5 Developers * 11710037SARM gem5 Developers * Taken from NetBSD 11810037SARM gem5 Developers * 11910037SARM gem5 Developers * "Stub" to allow remote cpu to debug over a serial line using gdb. 12010037SARM gem5 Developers */ 12110037SARM gem5 Developers 12210037SARM gem5 Developers#include "base/remote_gdb.hh" 12310037SARM gem5 Developers 12410037SARM gem5 Developers#include <sys/signal.h> 12510037SARM gem5 Developers#include <unistd.h> 12610037SARM gem5 Developers 12710037SARM gem5 Developers#include <csignal> 12810037SARM gem5 Developers#include <cstdint> 12910037SARM gem5 Developers#include <cstdio> 13010037SARM gem5 Developers#include <string> 13110037SARM gem5 Developers 13210037SARM gem5 Developers#include "arch/vtophys.hh" 13310037SARM gem5 Developers#include "base/intmath.hh" 13410037SARM gem5 Developers#include "base/socket.hh" 13510037SARM gem5 Developers#include "base/trace.hh" 13610037SARM gem5 Developers#include "config/the_isa.hh" 13710037SARM gem5 Developers#include "cpu/base.hh" 13810037SARM gem5 Developers#include "cpu/static_inst.hh" 13910037SARM gem5 Developers#include "cpu/thread_context.hh" 14010037SARM gem5 Developers#include "debug/GDBAll.hh" 1417351Sgblack@eecs.umich.edu#include "mem/fs_translating_port_proxy.hh" 14210037SARM gem5 Developers#include "mem/port.hh" 14310037SARM gem5 Developers#include "mem/se_translating_port_proxy.hh" 14410037SARM gem5 Developers#include "sim/full_system.hh" 14510037SARM gem5 Developers#include "sim/system.hh" 14610037SARM gem5 Developers 14710037SARM gem5 Developersusing namespace std; 14810037SARM gem5 Developersusing namespace TheISA; 14910037SARM gem5 Developers 15010037SARM gem5 Developersstatic const char GDBStart = '$'; 15110037SARM gem5 Developersstatic const char GDBEnd = '#'; 15210037SARM gem5 Developersstatic const char GDBGoodP = '+'; 15310037SARM gem5 Developersstatic const char GDBBadP = '-'; 15410037SARM gem5 Developers 15510037SARM gem5 Developersstatic const int GDBPacketBufLen = 1024; 15610037SARM gem5 Developers 15710037SARM gem5 Developers#ifndef NDEBUG 15810037SARM gem5 Developersvector<BaseRemoteGDB *> debuggers; 15910037SARM gem5 Developers 16010037SARM gem5 Developersvoid 16110037SARM gem5 Developersdebugger() 16210037SARM gem5 Developers{ 16310037SARM gem5 Developers static int current_debugger = -1; 16410037SARM gem5 Developers if (current_debugger >= 0 && current_debugger < (int)debuggers.size()) { 16510037SARM gem5 Developers BaseRemoteGDB *gdb = debuggers[current_debugger]; 16610037SARM gem5 Developers if (!gdb->isattached()) 16710037SARM gem5 Developers gdb->listener->accept(); 16810037SARM gem5 Developers if (gdb->isattached()) 16910037SARM gem5 Developers gdb->trap(SIGILL); 17010037SARM gem5 Developers } 17110037SARM gem5 Developers} 17210037SARM gem5 Developers#endif 17310037SARM gem5 Developers 17410037SARM gem5 Developers/////////////////////////////////////////////////////////// 17510037SARM gem5 Developers// 17610037SARM gem5 Developers// 17710037SARM gem5 Developers// 17810037SARM gem5 Developers 17910037SARM gem5 DevelopersGDBListener::InputEvent::InputEvent(GDBListener *l, int fd, int e) 18010037SARM gem5 Developers : PollEvent(fd, e), listener(l) 18110037SARM gem5 Developers{} 18210037SARM gem5 Developers 18310037SARM gem5 Developersvoid 18410037SARM gem5 DevelopersGDBListener::InputEvent::process(int revent) 18510037SARM gem5 Developers{ 18610037SARM gem5 Developers listener->accept(); 18710037SARM gem5 Developers} 18810037SARM gem5 Developers 18910037SARM gem5 DevelopersGDBListener::GDBListener(BaseRemoteGDB *g, int p) 19010037SARM gem5 Developers : inputEvent(NULL), gdb(g), port(p) 19110037SARM gem5 Developers{ 19210037SARM gem5 Developers assert(!gdb->listener); 19310037SARM gem5 Developers gdb->listener = this; 19410037SARM gem5 Developers} 19510037SARM gem5 Developers 19610037SARM gem5 DevelopersGDBListener::~GDBListener() 19710037SARM gem5 Developers{ 19810037SARM gem5 Developers delete inputEvent; 19910037SARM gem5 Developers} 20010037SARM gem5 Developers 20110037SARM gem5 Developersstring 20210037SARM gem5 DevelopersGDBListener::name() 20310037SARM gem5 Developers{ 20410037SARM gem5 Developers return gdb->name() + ".listener"; 20510037SARM gem5 Developers} 20610037SARM gem5 Developers 20710037SARM gem5 Developersvoid 20810037SARM gem5 DevelopersGDBListener::listen() 20910037SARM gem5 Developers{ 21010037SARM gem5 Developers if (ListenSocket::allDisabled()) { 21110037SARM gem5 Developers warn_once("Sockets disabled, not accepting gdb connections"); 21210037SARM gem5 Developers return; 21310037SARM gem5 Developers } 21410037SARM gem5 Developers 21510037SARM gem5 Developers while (!listener.listen(port, true)) { 21610037SARM gem5 Developers DPRINTF(GDBMisc, "Can't bind port %d\n", port); 21710037SARM gem5 Developers port++; 21810037SARM gem5 Developers } 21910037SARM gem5 Developers 22010037SARM gem5 Developers inputEvent = new InputEvent(this, listener.getfd(), POLLIN); 22110037SARM gem5 Developers pollQueue.schedule(inputEvent); 22210037SARM gem5 Developers 22310037SARM gem5 Developers#ifndef NDEBUG 22410037SARM gem5 Developers gdb->number = debuggers.size(); 22510037SARM gem5 Developers debuggers.push_back(gdb); 22610037SARM gem5 Developers#endif 22710037SARM gem5 Developers 22810037SARM gem5 Developers#ifndef NDEBUG 22910037SARM gem5 Developers ccprintf(cerr, "%d: %s: listening for remote gdb #%d on port %d\n", 23010037SARM gem5 Developers curTick(), name(), gdb->number, port); 23110037SARM gem5 Developers#else 23210037SARM gem5 Developers ccprintf(cerr, "%d: %s: listening for remote gdb on port %d\n", 23310037SARM gem5 Developers curTick(), name(), port); 23410037SARM gem5 Developers#endif 23510037SARM gem5 Developers} 23610037SARM gem5 Developers 23710037SARM gem5 Developersvoid 23810037SARM gem5 DevelopersGDBListener::accept() 23910037SARM gem5 Developers{ 24010037SARM gem5 Developers if (!listener.islistening()) 24110037SARM gem5 Developers panic("GDBListener::accept(): cannot accept if we're not listening!"); 24210037SARM gem5 Developers 24310037SARM gem5 Developers int sfd = listener.accept(true); 24410037SARM gem5 Developers 24510037SARM gem5 Developers if (sfd != -1) { 24610037SARM gem5 Developers if (gdb->isattached()) 24710037SARM gem5 Developers close(sfd); 24810037SARM gem5 Developers else 24910037SARM gem5 Developers gdb->attach(sfd); 25010037SARM gem5 Developers } 25110037SARM gem5 Developers} 25210037SARM gem5 Developers 25310037SARM gem5 Developersint 25410037SARM gem5 DevelopersGDBListener::getPort() const 25510037SARM gem5 Developers{ 25610037SARM gem5 Developers panic_if(!listener.islistening(), 25710037SARM gem5 Developers "Remote GDB port is unknown until GDBListener::listen() has " 25810037SARM gem5 Developers "been called.\n"); 25910037SARM gem5 Developers 26010037SARM gem5 Developers return port; 26110037SARM gem5 Developers} 26210037SARM gem5 Developers 26310037SARM gem5 DevelopersBaseRemoteGDB::InputEvent::InputEvent(BaseRemoteGDB *g, int fd, int e) 26410037SARM gem5 Developers : PollEvent(fd, e), gdb(g) 26510037SARM gem5 Developers{} 26610037SARM gem5 Developers 26710037SARM gem5 Developersvoid 26810037SARM gem5 DevelopersBaseRemoteGDB::InputEvent::process(int revent) 26910037SARM gem5 Developers{ 27010037SARM gem5 Developers if (gdb->trapEvent.scheduled()) { 27110037SARM gem5 Developers warn("GDB trap event has already been scheduled! " 27210037SARM gem5 Developers "Ignoring this input event."); 27310037SARM gem5 Developers return; 27410037SARM gem5 Developers } 27510037SARM gem5 Developers 27610037SARM gem5 Developers if (revent & POLLIN) { 27710037SARM gem5 Developers gdb->trapEvent.type(SIGILL); 27810037SARM gem5 Developers gdb->scheduleInstCommitEvent(&gdb->trapEvent, 0); 27910037SARM gem5 Developers } else if (revent & POLLNVAL) { 28010037SARM gem5 Developers gdb->descheduleInstCommitEvent(&gdb->trapEvent); 28110037SARM gem5 Developers gdb->detach(); 28210037SARM gem5 Developers } 28310037SARM gem5 Developers} 28410037SARM gem5 Developers 28510037SARM gem5 Developersvoid 28610037SARM gem5 DevelopersBaseRemoteGDB::TrapEvent::process() 28710037SARM gem5 Developers{ 28810037SARM gem5 Developers gdb->trap(_type); 28910037SARM gem5 Developers} 29010037SARM gem5 Developers 29110037SARM gem5 Developersvoid 29210037SARM gem5 DevelopersBaseRemoteGDB::processSingleStepEvent() 29310037SARM gem5 Developers{ 29410037SARM gem5 Developers if (!singleStepEvent.scheduled()) 29510037SARM gem5 Developers scheduleInstCommitEvent(&singleStepEvent, 1); 29610037SARM gem5 Developers trap(SIGTRAP); 29710037SARM gem5 Developers} 29810037SARM gem5 Developers 29910037SARM gem5 DevelopersBaseRemoteGDB::BaseRemoteGDB(System *_system, ThreadContext *c) : 30010037SARM gem5 Developers inputEvent(NULL), trapEvent(this), listener(NULL), number(-1), 30110037SARM gem5 Developers fd(-1), active(false), attached(false), system(_system), 30210037SARM gem5 Developers context(c), 30310037SARM gem5 Developers singleStepEvent([this]{ processSingleStepEvent(); }, name()) 30410037SARM gem5 Developers{ 30510037SARM gem5 Developers} 30610037SARM gem5 Developers 30710037SARM gem5 DevelopersBaseRemoteGDB::~BaseRemoteGDB() 30810037SARM gem5 Developers{ 30910037SARM gem5 Developers if (inputEvent) 31010037SARM gem5 Developers delete inputEvent; 31110037SARM gem5 Developers} 31210037SARM gem5 Developers 31310037SARM gem5 Developersstring 31410037SARM gem5 DevelopersBaseRemoteGDB::name() 31510037SARM gem5 Developers{ 31610037SARM gem5 Developers return system->name() + ".remote_gdb"; 31710037SARM gem5 Developers} 31810037SARM gem5 Developers 31910037SARM gem5 Developersbool 32010037SARM gem5 DevelopersBaseRemoteGDB::isattached() 32110037SARM gem5 Developers{ return attached; } 32210037SARM gem5 Developers 32310037SARM gem5 Developersvoid 32410037SARM gem5 DevelopersBaseRemoteGDB::attach(int f) 32510037SARM gem5 Developers{ 32610037SARM gem5 Developers fd = f; 32710037SARM gem5 Developers 32810037SARM gem5 Developers inputEvent = new InputEvent(this, fd, POLLIN); 32910037SARM gem5 Developers pollQueue.schedule(inputEvent); 33010037SARM gem5 Developers 33110037SARM gem5 Developers attached = true; 33210037SARM gem5 Developers DPRINTFN("remote gdb attached\n"); 33310037SARM gem5 Developers} 33410037SARM gem5 Developers 33510037SARM gem5 Developersvoid 33610037SARM gem5 DevelopersBaseRemoteGDB::detach() 33710037SARM gem5 Developers{ 33810037SARM gem5 Developers attached = false; 33910037SARM gem5 Developers active = false; 34010037SARM gem5 Developers clearSingleStep(); 34110037SARM gem5 Developers close(fd); 34210037SARM gem5 Developers fd = -1; 34310037SARM gem5 Developers 34410037SARM gem5 Developers pollQueue.remove(inputEvent); 34510037SARM gem5 Developers DPRINTFN("remote gdb detached\n"); 34610037SARM gem5 Developers} 34710037SARM gem5 Developers 34810037SARM gem5 Developers///////////////////////// 34910037SARM gem5 Developers// 35010037SARM gem5 Developers// 35110037SARM gem5 Developers 35210037SARM gem5 Developersuint8_t 35310037SARM gem5 DevelopersBaseRemoteGDB::getbyte() 35410037SARM gem5 Developers{ 35510037SARM gem5 Developers uint8_t b; 35610037SARM gem5 Developers if (::read(fd, &b, sizeof(b)) == sizeof(b)) 35710037SARM gem5 Developers return b; 35810037SARM gem5 Developers 35910037SARM gem5 Developers throw BadClient("Couldn't read data from debugger."); 36010037SARM gem5 Developers} 36110037SARM gem5 Developers 36210037SARM gem5 Developersvoid 36310037SARM gem5 DevelopersBaseRemoteGDB::putbyte(uint8_t b) 36410037SARM gem5 Developers{ 36510037SARM gem5 Developers if (::write(fd, &b, sizeof(b)) == sizeof(b)) 36610037SARM gem5 Developers return; 36710037SARM gem5 Developers 36810037SARM gem5 Developers throw BadClient("Couldn't write data to the debugger."); 36910037SARM gem5 Developers} 37010037SARM gem5 Developers 37110037SARM gem5 Developers// Send a packet to gdb 37210037SARM gem5 Developersvoid 37310037SARM gem5 DevelopersBaseRemoteGDB::send(const char *bp) 37410037SARM gem5 Developers{ 37510037SARM gem5 Developers const char *p; 37610037SARM gem5 Developers uint8_t csum, c; 37710037SARM gem5 Developers 37810037SARM gem5 Developers DPRINTF(GDBSend, "send: %s\n", bp); 37910037SARM gem5 Developers 38010037SARM gem5 Developers do { 38110037SARM gem5 Developers p = bp; 38210037SARM gem5 Developers // Start sending a packet 3837259Sgblack@eecs.umich.edu putbyte(GDBStart); 38410037SARM gem5 Developers // Send the contents, and also keep a check sum. 38510037SARM gem5 Developers for (csum = 0; (c = *p); p++) { 38610037SARM gem5 Developers putbyte(c); 38710037SARM gem5 Developers csum += c; 38810037SARM gem5 Developers } 38910037SARM gem5 Developers // Send the ending character. 39010037SARM gem5 Developers putbyte(GDBEnd); 39110037SARM gem5 Developers // Send the checksum. 39210037SARM gem5 Developers putbyte(i2digit(csum >> 4)); 39310037SARM gem5 Developers putbyte(i2digit(csum)); 39410037SARM gem5 Developers // Try transmitting over and over again until the other end doesn't 39510037SARM gem5 Developers // send an error back. 39610037SARM gem5 Developers c = getbyte(); 39710037SARM gem5 Developers } while ((c & 0x7f) == GDBBadP); 39810037SARM gem5 Developers} 39910037SARM gem5 Developers 40010037SARM gem5 Developers// Receive a packet from gdb 40110037SARM gem5 Developersint 40210037SARM gem5 DevelopersBaseRemoteGDB::recv(char *bp, int maxlen) 40310037SARM gem5 Developers{ 40410037SARM gem5 Developers char *p; 40510037SARM gem5 Developers uint8_t c; 40610037SARM gem5 Developers int csum; 40710037SARM gem5 Developers int len; 40810037SARM gem5 Developers 40910037SARM gem5 Developers do { 41010037SARM gem5 Developers p = bp; 41110037SARM gem5 Developers csum = len = 0; 41210037SARM gem5 Developers // Find the beginning of a packet 41310037SARM gem5 Developers while ((c = getbyte()) != GDBStart); 41410037SARM gem5 Developers 41510037SARM gem5 Developers // Read until you find the end of the data in the packet, and keep 41610037SARM gem5 Developers // track of the check sum. 41710037SARM gem5 Developers while (len < maxlen) { 41810037SARM gem5 Developers c = getbyte(); 41910037SARM gem5 Developers if (c == GDBEnd) 42010037SARM gem5 Developers break; 42110037SARM gem5 Developers c &= 0x7f; 42210037SARM gem5 Developers csum += c; 42310037SARM gem5 Developers *p++ = c; 42410037SARM gem5 Developers len++; 4257259Sgblack@eecs.umich.edu } 42610037SARM gem5 Developers 42710037SARM gem5 Developers // Mask the check sum, and terminate the command string. 42810037SARM gem5 Developers csum &= 0xff; 42910037SARM gem5 Developers *p = '\0'; 43010037SARM gem5 Developers 43110037SARM gem5 Developers // If the command was too long, report an error. 43210037SARM gem5 Developers if (len >= maxlen) { 43310037SARM gem5 Developers putbyte(GDBBadP); 43410037SARM gem5 Developers continue; 43510037SARM gem5 Developers } 43610037SARM gem5 Developers 43710037SARM gem5 Developers // Bring in the checksum. If the check sum matches, csum will be 0. 43810037SARM gem5 Developers csum -= digit2i(getbyte()) * 16; 43910037SARM gem5 Developers csum -= digit2i(getbyte()); 44010037SARM gem5 Developers 44110037SARM gem5 Developers // If the check sum was correct 44210037SARM gem5 Developers if (csum == 0) { 44310037SARM gem5 Developers // Report that the packet was received correctly 44410037SARM gem5 Developers putbyte(GDBGoodP); 44510037SARM gem5 Developers // Sequence present? 44610037SARM gem5 Developers if (bp[2] == ':') { 44710037SARM gem5 Developers putbyte(bp[0]); 44810037SARM gem5 Developers putbyte(bp[1]); 44910037SARM gem5 Developers len -= 3; 45010037SARM gem5 Developers memcpy(bp, bp+3, len); 45110037SARM gem5 Developers } 45210037SARM gem5 Developers break; 45310037SARM gem5 Developers } 45410037SARM gem5 Developers // Otherwise, report that there was a mistake. 45510037SARM gem5 Developers putbyte(GDBBadP); 45610037SARM gem5 Developers } while (1); 45710037SARM gem5 Developers 45810037SARM gem5 Developers DPRINTF(GDBRecv, "recv: %s\n", bp); 45910037SARM gem5 Developers 46010037SARM gem5 Developers return len; 46110037SARM gem5 Developers} 46210037SARM gem5 Developers 46310037SARM gem5 Developers// Read bytes from kernel address space for debugger. 46410037SARM gem5 Developersbool 46510037SARM gem5 DevelopersBaseRemoteGDB::read(Addr vaddr, size_t size, char *data) 46610037SARM gem5 Developers{ 46710037SARM gem5 Developers static Addr lastaddr = 0; 46810037SARM gem5 Developers static size_t lastsize = 0; 46910037SARM gem5 Developers 47010037SARM gem5 Developers if (vaddr < 10) { 47110037SARM gem5 Developers DPRINTF(GDBRead, "read: reading memory location zero!\n"); 47210037SARM gem5 Developers vaddr = lastaddr + lastsize; 47310037SARM gem5 Developers } 47410037SARM gem5 Developers 47510037SARM gem5 Developers DPRINTF(GDBRead, "read: addr=%#x, size=%d", vaddr, size); 47610037SARM gem5 Developers 47710037SARM gem5 Developers if (FullSystem) { 47810037SARM gem5 Developers FSTranslatingPortProxy &proxy = context->getVirtProxy(); 47910037SARM gem5 Developers proxy.readBlob(vaddr, (uint8_t*)data, size); 48010037SARM gem5 Developers } else { 48110037SARM gem5 Developers SETranslatingPortProxy &proxy = context->getMemProxy(); 48210037SARM gem5 Developers proxy.readBlob(vaddr, (uint8_t*)data, size); 48310037SARM gem5 Developers } 48410037SARM gem5 Developers 48510037SARM gem5 Developers#if TRACING_ON 48610037SARM gem5 Developers if (DTRACE(GDBRead)) { 48710037SARM gem5 Developers if (DTRACE(GDBExtra)) { 48810037SARM gem5 Developers char buf[1024]; 48910037SARM gem5 Developers mem2hex(buf, data, size); 49010037SARM gem5 Developers DPRINTFNR(": %s\n", buf); 49110037SARM gem5 Developers } else 49210037SARM gem5 Developers DPRINTFNR("\n"); 49310037SARM gem5 Developers } 49410037SARM gem5 Developers#endif 49510037SARM gem5 Developers 49610037SARM gem5 Developers return true; 49710037SARM gem5 Developers} 49810037SARM gem5 Developers 49910037SARM gem5 Developers// Write bytes to kernel address space for debugger. 50010037SARM gem5 Developersbool 50110037SARM gem5 DevelopersBaseRemoteGDB::write(Addr vaddr, size_t size, const char *data) 50210037SARM gem5 Developers{ 50310037SARM gem5 Developers static Addr lastaddr = 0; 50410037SARM gem5 Developers static size_t lastsize = 0; 50510037SARM gem5 Developers 50610037SARM gem5 Developers if (vaddr < 10) { 50710037SARM gem5 Developers DPRINTF(GDBWrite, "write: writing memory location zero!\n"); 50810037SARM gem5 Developers vaddr = lastaddr + lastsize; 50910037SARM gem5 Developers } 51010037SARM gem5 Developers 51110037SARM gem5 Developers if (DTRACE(GDBWrite)) { 51210037SARM gem5 Developers DPRINTFN("write: addr=%#x, size=%d", vaddr, size); 51310037SARM gem5 Developers if (DTRACE(GDBExtra)) { 51410037SARM gem5 Developers char buf[1024]; 51510037SARM gem5 Developers mem2hex(buf, data, size); 51610037SARM gem5 Developers DPRINTFNR(": %s\n", buf); 51710037SARM gem5 Developers } else 51810037SARM gem5 Developers DPRINTFNR("\n"); 51910037SARM gem5 Developers } 52010037SARM gem5 Developers if (FullSystem) { 52110037SARM gem5 Developers FSTranslatingPortProxy &proxy = context->getVirtProxy(); 52210037SARM gem5 Developers proxy.writeBlob(vaddr, (uint8_t*)data, size); 52310037SARM gem5 Developers } else { 52410037SARM gem5 Developers SETranslatingPortProxy &proxy = context->getMemProxy(); 52510037SARM gem5 Developers proxy.writeBlob(vaddr, (uint8_t*)data, size); 52610037SARM gem5 Developers } 52710037SARM gem5 Developers 52810037SARM gem5 Developers return true; 52910037SARM gem5 Developers} 53010037SARM gem5 Developers 53110037SARM gem5 Developersvoid 53210037SARM gem5 DevelopersBaseRemoteGDB::clearSingleStep() 53310037SARM gem5 Developers{ 53410037SARM gem5 Developers descheduleInstCommitEvent(&singleStepEvent); 53510037SARM gem5 Developers} 53610037SARM gem5 Developers 53710037SARM gem5 Developersvoid 53810037SARM gem5 DevelopersBaseRemoteGDB::setSingleStep() 53910037SARM gem5 Developers{ 54010037SARM gem5 Developers if (!singleStepEvent.scheduled()) 54110037SARM gem5 Developers scheduleInstCommitEvent(&singleStepEvent, 1); 54210037SARM gem5 Developers} 54310037SARM gem5 Developers 54410037SARM gem5 DevelopersPCEventQueue *BaseRemoteGDB::getPcEventQueue() 54510037SARM gem5 Developers{ 54610037SARM gem5 Developers return &system->pcEventQueue; 54710037SARM gem5 Developers} 54810037SARM gem5 Developers 54910037SARM gem5 DevelopersEventQueue * 55010037SARM gem5 DevelopersBaseRemoteGDB::getComInstEventQueue() 55110037SARM gem5 Developers{ 55210037SARM gem5 Developers BaseCPU *cpu = context->getCpuPtr(); 55310037SARM gem5 Developers return cpu->comInstEventQueue[context->threadId()]; 55410037SARM gem5 Developers} 55510037SARM gem5 Developers 55610037SARM gem5 Developersvoid 55710037SARM gem5 DevelopersBaseRemoteGDB::scheduleInstCommitEvent(Event *ev, int delta) 55810037SARM gem5 Developers{ 55910037SARM gem5 Developers EventQueue *eq = getComInstEventQueue(); 56010037SARM gem5 Developers // Here "ticks" aren't simulator ticks which measure time, they're 56110037SARM gem5 Developers // instructions committed by the CPU. 56210037SARM gem5 Developers eq->schedule(ev, eq->getCurTick() + delta); 56310037SARM gem5 Developers} 56410037SARM gem5 Developers 56510037SARM gem5 Developersvoid 56610037SARM gem5 DevelopersBaseRemoteGDB::descheduleInstCommitEvent(Event *ev) 56710037SARM gem5 Developers{ 56810037SARM gem5 Developers if (ev->scheduled()) 56910037SARM gem5 Developers getComInstEventQueue()->deschedule(ev); 57010037SARM gem5 Developers} 57110037SARM gem5 Developers 57210037SARM gem5 Developersbool 57310037SARM gem5 DevelopersBaseRemoteGDB::checkBpLen(size_t len) 57410037SARM gem5 Developers{ 57510037SARM gem5 Developers return len == sizeof(MachInst); 57610037SARM gem5 Developers} 57710037SARM gem5 Developers 57810037SARM gem5 DevelopersBaseRemoteGDB::HardBreakpoint::HardBreakpoint(BaseRemoteGDB *_gdb, Addr pc) 57910037SARM gem5 Developers : PCEvent(_gdb->getPcEventQueue(), "HardBreakpoint Event", pc), 58010037SARM gem5 Developers gdb(_gdb), refcount(0) 58110037SARM gem5 Developers{ 58210037SARM gem5 Developers DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc); 58310037SARM gem5 Developers} 58410037SARM gem5 Developers 58510037SARM gem5 Developersvoid 58610037SARM gem5 DevelopersBaseRemoteGDB::HardBreakpoint::process(ThreadContext *tc) 58710037SARM gem5 Developers{ 58810037SARM gem5 Developers DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc()); 58910037SARM gem5 Developers 59010037SARM gem5 Developers if (tc == gdb->context) 59110037SARM gem5 Developers gdb->trap(SIGTRAP); 59210037SARM gem5 Developers} 59310037SARM gem5 Developers 59410037SARM gem5 Developersvoid 59510037SARM gem5 DevelopersBaseRemoteGDB::insertSoftBreak(Addr addr, size_t len) 59610037SARM gem5 Developers{ 59710037SARM gem5 Developers if (!checkBpLen(len)) 59810037SARM gem5 Developers throw BadClient("Invalid breakpoint length\n"); 59910037SARM gem5 Developers 60010037SARM gem5 Developers return insertHardBreak(addr, len); 60110037SARM gem5 Developers} 60210037SARM gem5 Developers 60310037SARM gem5 Developersvoid 60410037SARM gem5 DevelopersBaseRemoteGDB::removeSoftBreak(Addr addr, size_t len) 60510037SARM gem5 Developers{ 60610037SARM gem5 Developers if (!checkBpLen(len)) 60710037SARM gem5 Developers throw BadClient("Invalid breakpoint length.\n"); 60810037SARM gem5 Developers 60910037SARM gem5 Developers return removeHardBreak(addr, len); 61010037SARM gem5 Developers} 61110037SARM gem5 Developers 61210037SARM gem5 Developersvoid 61310037SARM gem5 DevelopersBaseRemoteGDB::insertHardBreak(Addr addr, size_t len) 61410037SARM gem5 Developers{ 61510037SARM gem5 Developers if (!checkBpLen(len)) 61610037SARM gem5 Developers throw BadClient("Invalid breakpoint length\n"); 61710037SARM gem5 Developers 61810037SARM gem5 Developers DPRINTF(GDBMisc, "Inserting hardware breakpoint at %#x\n", addr); 61910037SARM gem5 Developers 62010037SARM gem5 Developers HardBreakpoint *&bkpt = hardBreakMap[addr]; 62110037SARM gem5 Developers if (bkpt == 0) 62210037SARM gem5 Developers bkpt = new HardBreakpoint(this, addr); 62310037SARM gem5 Developers 62410037SARM gem5 Developers bkpt->refcount++; 62510037SARM gem5 Developers} 62610037SARM gem5 Developers 62710037SARM gem5 Developersvoid 62810037SARM gem5 DevelopersBaseRemoteGDB::removeHardBreak(Addr addr, size_t len) 62910037SARM gem5 Developers{ 63010037SARM gem5 Developers if (!checkBpLen(len)) 63110037SARM gem5 Developers throw BadClient("Invalid breakpoint length\n"); 63210037SARM gem5 Developers 63310037SARM gem5 Developers DPRINTF(GDBMisc, "Removing hardware breakpoint at %#x\n", addr); 63410037SARM gem5 Developers 63510037SARM gem5 Developers break_iter_t i = hardBreakMap.find(addr); 63610037SARM gem5 Developers if (i == hardBreakMap.end()) 63710037SARM gem5 Developers throw CmdError("E0C"); 63810037SARM gem5 Developers 63910037SARM gem5 Developers HardBreakpoint *hbp = (*i).second; 64010037SARM gem5 Developers if (--hbp->refcount == 0) { 64110037SARM gem5 Developers delete hbp; 64210037SARM gem5 Developers hardBreakMap.erase(i); 64310037SARM gem5 Developers } 64410037SARM gem5 Developers} 64510037SARM gem5 Developers 64610037SARM gem5 Developersvoid 64710037SARM gem5 DevelopersBaseRemoteGDB::setTempBreakpoint(Addr bkpt) 64810037SARM gem5 Developers{ 64910037SARM gem5 Developers DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", bkpt); 65010037SARM gem5 Developers insertHardBreak(bkpt, sizeof(TheISA::MachInst)); 65110037SARM gem5 Developers} 65210037SARM gem5 Developers 65310037SARM gem5 Developersvoid 65410037SARM gem5 DevelopersBaseRemoteGDB::clearTempBreakpoint(Addr &bkpt) 65510037SARM gem5 Developers{ 65610037SARM gem5 Developers DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", bkpt); 65710037SARM gem5 Developers removeHardBreak(bkpt, sizeof(TheISA::MachInst)); 65810037SARM gem5 Developers bkpt = 0; 65910037SARM gem5 Developers} 66010037SARM gem5 Developers 66110037SARM gem5 Developersenum GdbBreakpointType { 66210037SARM gem5 Developers GdbSoftBp = '0', 66310037SARM gem5 Developers GdbHardBp = '1', 66410037SARM gem5 Developers GdbWriteWp = '2', 66510037SARM gem5 Developers GdbReadWp = '3', 66610856SCurtis.Dunham@arm.com GdbAccWp = '4', 6677259Sgblack@eecs.umich.edu}; 66810037SARM gem5 Developers 66910856SCurtis.Dunham@arm.comconst char * 67010856SCurtis.Dunham@arm.comBaseRemoteGDB::break_type(char c) 67110856SCurtis.Dunham@arm.com{ 67210856SCurtis.Dunham@arm.com switch(c) { 67310856SCurtis.Dunham@arm.com case GdbSoftBp: return "software breakpoint"; 67410856SCurtis.Dunham@arm.com case GdbHardBp: return "hardware breakpoint"; 67510037SARM gem5 Developers case GdbWriteWp: return "write watchpoint"; 67610856SCurtis.Dunham@arm.com case GdbReadWp: return "read watchpoint"; 6776261Sgblack@eecs.umich.edu case GdbAccWp: return "access watchpoint"; 6786261Sgblack@eecs.umich.edu default: return "unknown breakpoint/watchpoint"; 67910037SARM gem5 Developers } 68010037SARM gem5 Developers} 68110506SAli.Saidi@ARM.com 68210506SAli.Saidi@ARM.comstd::map<char, GdbCommand> BaseRemoteGDB::command_map = { 68310037SARM gem5 Developers // last signal 68410037SARM gem5 Developers { '?', { "KGDB_SIGNAL", &BaseRemoteGDB::cmd_signal } }, 68510037SARM gem5 Developers // set baud (deprecated) 68610037SARM gem5 Developers { 'b', { "KGDB_SET_BAUD", &BaseRemoteGDB::cmd_unsupported } }, 68710037SARM gem5 Developers // set breakpoint (deprecated) 68810037SARM gem5 Developers { 'B', { "KGDB_SET_BREAK", &BaseRemoteGDB::cmd_unsupported } }, 68910037SARM gem5 Developers // resume 69010037SARM gem5 Developers { 'c', { "KGDB_CONT", &BaseRemoteGDB::cmd_cont } }, 69110037SARM gem5 Developers // continue with signal 69210037SARM gem5 Developers { 'C', { "KGDB_ASYNC_CONT", &BaseRemoteGDB::cmd_async_cont } }, 69310037SARM gem5 Developers // toggle debug flags (deprecated) 69410037SARM gem5 Developers { 'd', { "KGDB_DEBUG", &BaseRemoteGDB::cmd_unsupported } }, 69510037SARM gem5 Developers // detach remote gdb 69610037SARM gem5 Developers { 'D', { "KGDB_DETACH", &BaseRemoteGDB::cmd_detach } }, 69710037SARM gem5 Developers // read general registers 69810037SARM gem5 Developers { 'g', { "KGDB_REG_R", &BaseRemoteGDB::cmd_reg_r } }, 69910037SARM gem5 Developers // write general registers 70010037SARM gem5 Developers { 'G', { "KGDB_REG_W", &BaseRemoteGDB::cmd_reg_w } }, 70110037SARM gem5 Developers // set thread 70210037SARM gem5 Developers { 'H', { "KGDB_SET_THREAD", &BaseRemoteGDB::cmd_set_thread } }, 70310037SARM gem5 Developers // step a single cycle 70410037SARM gem5 Developers { 'i', { "KGDB_CYCLE_STEP", &BaseRemoteGDB::cmd_unsupported } }, 70510037SARM gem5 Developers // signal then cycle step 70610037SARM gem5 Developers { 'I', { "KGDB_SIG_CYCLE_STEP", &BaseRemoteGDB::cmd_unsupported } }, 70710037SARM gem5 Developers // kill program 70810037SARM gem5 Developers { 'k', { "KGDB_KILL", &BaseRemoteGDB::cmd_detach } }, 70910037SARM gem5 Developers // read memory 71010037SARM gem5 Developers { 'm', { "KGDB_MEM_R", &BaseRemoteGDB::cmd_mem_r } }, 71110037SARM gem5 Developers // write memory 71210037SARM gem5 Developers { 'M', { "KGDB_MEM_W", &BaseRemoteGDB::cmd_mem_w } }, 71310037SARM gem5 Developers // read register 71410037SARM gem5 Developers { 'p', { "KGDB_READ_REG", &BaseRemoteGDB::cmd_unsupported } }, 71510037SARM gem5 Developers // write register 71610037SARM gem5 Developers { 'P', { "KGDB_SET_REG", &BaseRemoteGDB::cmd_unsupported } }, 71710037SARM gem5 Developers // query variable 71810037SARM gem5 Developers { 'q', { "KGDB_QUERY_VAR", &BaseRemoteGDB::cmd_query_var } }, 71910037SARM gem5 Developers // set variable 72010037SARM gem5 Developers { 'Q', { "KGDB_SET_VAR", &BaseRemoteGDB::cmd_unsupported } }, 72110037SARM gem5 Developers // reset system (deprecated) 7228868SMatt.Horsnell@arm.com { 'r', { "KGDB_RESET", &BaseRemoteGDB::cmd_unsupported } }, 7238868SMatt.Horsnell@arm.com // step 72410037SARM gem5 Developers { 's', { "KGDB_STEP", &BaseRemoteGDB::cmd_step } }, 72510037SARM gem5 Developers // signal and step 72610037SARM gem5 Developers { 'S', { "KGDB_ASYNC_STEP", &BaseRemoteGDB::cmd_async_step } }, 72710037SARM gem5 Developers // find out if the thread is alive 72810037SARM gem5 Developers { 'T', { "KGDB_THREAD_ALIVE", &BaseRemoteGDB::cmd_unsupported } }, 7298868SMatt.Horsnell@arm.com // target exited 73010037SARM gem5 Developers { 'W', { "KGDB_TARGET_EXIT", &BaseRemoteGDB::cmd_unsupported } }, 7317259Sgblack@eecs.umich.edu // write memory 7327259Sgblack@eecs.umich.edu { 'X', { "KGDB_BINARY_DLOAD", &BaseRemoteGDB::cmd_unsupported } }, 7337259Sgblack@eecs.umich.edu // remove breakpoint or watchpoint 73410037SARM gem5 Developers { 'z', { "KGDB_CLR_HW_BKPT", &BaseRemoteGDB::cmd_clr_hw_bkpt } }, 73510037SARM gem5 Developers // insert breakpoint or watchpoint 73610037SARM gem5 Developers { 'Z', { "KGDB_SET_HW_BKPT", &BaseRemoteGDB::cmd_set_hw_bkpt } }, 7378868SMatt.Horsnell@arm.com}; 7389256SAndreas.Sandberg@arm.com 73910037SARM gem5 Developers 74010037SARM gem5 Developersbool 74110037SARM gem5 DevelopersBaseRemoteGDB::cmd_unsupported(GdbCommand::Context &ctx) 74210037SARM gem5 Developers{ 74310037SARM gem5 Developers DPRINTF(GDBMisc, "Unsupported command: %s\n", ctx.cmd->name); 74410037SARM gem5 Developers DDUMP(GDBMisc, ctx.data, ctx.len); 74510037SARM gem5 Developers throw Unsupported(); 74610037SARM gem5 Developers} 74710037SARM gem5 Developers 74810037SARM gem5 Developers 74910037SARM gem5 Developersbool 75010037SARM gem5 DevelopersBaseRemoteGDB::cmd_signal(GdbCommand::Context &ctx) 75110037SARM gem5 Developers{ 75210037SARM gem5 Developers send(csprintf("S%02x", ctx.type).c_str()); 75310037SARM gem5 Developers return true; 75410037SARM gem5 Developers} 75510037SARM gem5 Developers 75610037SARM gem5 Developersbool 75710037SARM gem5 DevelopersBaseRemoteGDB::cmd_cont(GdbCommand::Context &ctx) 75810037SARM gem5 Developers{ 75910037SARM gem5 Developers const char *p = ctx.data; 76010037SARM gem5 Developers if (ctx.len) { 76110037SARM gem5 Developers Addr newPc = hex2i(&p); 76210037SARM gem5 Developers context->pcState(newPc); 76310037SARM gem5 Developers } 76410037SARM gem5 Developers clearSingleStep(); 76510037SARM gem5 Developers return false; 76610037SARM gem5 Developers} 76710037SARM gem5 Developers 76810037SARM gem5 Developersbool 76910037SARM gem5 DevelopersBaseRemoteGDB::cmd_async_cont(GdbCommand::Context &ctx) 77010037SARM gem5 Developers{ 77110037SARM gem5 Developers const char *p = ctx.data; 77210037SARM gem5 Developers hex2i(&p); 77310037SARM gem5 Developers if (*p++ == ';') { 77410037SARM gem5 Developers Addr newPc = hex2i(&p); 77510037SARM gem5 Developers context->pcState(newPc); 77610037SARM gem5 Developers } 77710037SARM gem5 Developers clearSingleStep(); 77810037SARM gem5 Developers return false; 77910037SARM gem5 Developers} 78010037SARM gem5 Developers 78110037SARM gem5 Developersbool 78210037SARM gem5 DevelopersBaseRemoteGDB::cmd_detach(GdbCommand::Context &ctx) 78310037SARM gem5 Developers{ 78410037SARM gem5 Developers detach(); 78510037SARM gem5 Developers return false; 78610037SARM gem5 Developers} 78710037SARM gem5 Developers 78810037SARM gem5 Developersbool 78910037SARM gem5 DevelopersBaseRemoteGDB::cmd_reg_r(GdbCommand::Context &ctx) 79010037SARM gem5 Developers{ 79110037SARM gem5 Developers char buf[2 * regCachePtr->size() + 1]; 79210037SARM gem5 Developers buf[2 * regCachePtr->size()] = '\0'; 79310037SARM gem5 Developers mem2hex(buf, regCachePtr->data(), regCachePtr->size()); 79410037SARM gem5 Developers send(buf); 79510037SARM gem5 Developers return true; 79610037SARM gem5 Developers} 79710037SARM gem5 Developers 79810037SARM gem5 Developersbool 79910037SARM gem5 DevelopersBaseRemoteGDB::cmd_reg_w(GdbCommand::Context &ctx) 80010037SARM gem5 Developers{ 80110037SARM gem5 Developers const char *p = ctx.data; 80210037SARM gem5 Developers p = hex2mem(regCachePtr->data(), p, regCachePtr->size()); 80310037SARM gem5 Developers if (p == NULL || *p != '\0') 80410037SARM gem5 Developers throw CmdError("E01"); 80510037SARM gem5 Developers 80610037SARM gem5 Developers regCachePtr->setRegs(context); 80710037SARM gem5 Developers send("OK"); 80810037SARM gem5 Developers 80910037SARM gem5 Developers return true; 81010037SARM gem5 Developers} 81110037SARM gem5 Developers 81210037SARM gem5 Developersbool 81310037SARM gem5 DevelopersBaseRemoteGDB::cmd_set_thread(GdbCommand::Context &ctx) 81410037SARM gem5 Developers{ 81510037SARM gem5 Developers const char *p = ctx.data + 1; // Ignore the subcommand byte. 81610037SARM gem5 Developers if (hex2i(&p) != 0) 81710037SARM gem5 Developers throw CmdError("E01"); 81810037SARM gem5 Developers send("OK"); 81910037SARM gem5 Developers return true; 82010037SARM gem5 Developers} 82110037SARM gem5 Developers 82210037SARM gem5 Developersbool 82310037SARM gem5 DevelopersBaseRemoteGDB::cmd_mem_r(GdbCommand::Context &ctx) 82410037SARM gem5 Developers{ 82510037SARM gem5 Developers const char *p = ctx.data; 82610037SARM gem5 Developers Addr addr = hex2i(&p); 82710037SARM gem5 Developers if (*p++ != ',') 82810037SARM gem5 Developers throw CmdError("E02"); 82910037SARM gem5 Developers size_t len = hex2i(&p); 83010037SARM gem5 Developers if (*p != '\0') 83110037SARM gem5 Developers throw CmdError("E03"); 83210037SARM gem5 Developers if (!acc(addr, len)) 83310037SARM gem5 Developers throw CmdError("E05"); 83410037SARM gem5 Developers 83510037SARM gem5 Developers char buf[len]; 83610037SARM gem5 Developers if (!read(addr, len, buf)) 83710037SARM gem5 Developers throw CmdError("E05"); 83810037SARM gem5 Developers 83910037SARM gem5 Developers char temp[2 * len + 1]; 84010037SARM gem5 Developers temp[2 * len] = '\0'; 84110037SARM gem5 Developers mem2hex(temp, buf, len); 84210037SARM gem5 Developers send(temp); 84310037SARM gem5 Developers return true; 84410037SARM gem5 Developers} 84510037SARM gem5 Developers 84610037SARM gem5 Developersbool 84710037SARM gem5 DevelopersBaseRemoteGDB::cmd_mem_w(GdbCommand::Context &ctx) 84810037SARM gem5 Developers{ 84910037SARM gem5 Developers const char *p = ctx.data; 85010037SARM gem5 Developers Addr addr = hex2i(&p); 85110037SARM gem5 Developers if (*p++ != ',') 85210037SARM gem5 Developers throw CmdError("E06"); 85310037SARM gem5 Developers size_t len = hex2i(&p); 85410037SARM gem5 Developers if (*p++ != ':') 85510037SARM gem5 Developers throw CmdError("E07"); 85610037SARM gem5 Developers if (len * 2 > ctx.len - (p - ctx.data)) 85710037SARM gem5 Developers throw CmdError("E08"); 85810037SARM gem5 Developers char buf[len]; 85910037SARM gem5 Developers p = (char *)hex2mem(buf, p, len); 86010037SARM gem5 Developers if (p == NULL) 86110037SARM gem5 Developers throw CmdError("E09"); 86210037SARM gem5 Developers if (!acc(addr, len)) 86310037SARM gem5 Developers throw CmdError("E0A"); 86410037SARM gem5 Developers if (!write(addr, len, buf)) 86510037SARM gem5 Developers throw CmdError("E0B"); 86610037SARM gem5 Developers send("OK"); 86710037SARM gem5 Developers return true; 86810037SARM gem5 Developers} 86910037SARM gem5 Developers 87010037SARM gem5 Developersbool 87110037SARM gem5 DevelopersBaseRemoteGDB::cmd_query_var(GdbCommand::Context &ctx) 87210037SARM gem5 Developers{ 87310037SARM gem5 Developers if (string(ctx.data, ctx.len - 1) != "C") 87410037SARM gem5 Developers throw Unsupported(); 87510037SARM gem5 Developers send("QC0"); 87610037SARM gem5 Developers return true; 87710037SARM gem5 Developers} 87810037SARM gem5 Developers 87910037SARM gem5 Developersbool 88010037SARM gem5 DevelopersBaseRemoteGDB::cmd_async_step(GdbCommand::Context &ctx) 88110037SARM gem5 Developers{ 88210037SARM gem5 Developers const char *p = ctx.data; 88310037SARM gem5 Developers hex2i(&p); // Ignore the subcommand byte. 88410037SARM gem5 Developers if (*p++ == ';') { 88510037SARM gem5 Developers Addr newPc = hex2i(&p); 88610037SARM gem5 Developers context->pcState(newPc); 88710037SARM gem5 Developers } 88810037SARM gem5 Developers setSingleStep(); 88910037SARM gem5 Developers return false; 89010037SARM gem5 Developers} 89110037SARM gem5 Developers 89210037SARM gem5 Developersbool 89310037SARM gem5 DevelopersBaseRemoteGDB::cmd_step(GdbCommand::Context &ctx) 89410037SARM gem5 Developers{ 89510037SARM gem5 Developers if (ctx.len) { 89610037SARM gem5 Developers const char *p = ctx.data; 89710037SARM gem5 Developers Addr newPc = hex2i(&p); 89810037SARM gem5 Developers context->pcState(newPc); 89910037SARM gem5 Developers } 90010037SARM gem5 Developers setSingleStep(); 90110037SARM gem5 Developers return false; 90210037SARM gem5 Developers} 90310037SARM gem5 Developers 90410037SARM gem5 Developersbool 90510037SARM gem5 DevelopersBaseRemoteGDB::cmd_clr_hw_bkpt(GdbCommand::Context &ctx) 90610037SARM gem5 Developers{ 90710037SARM gem5 Developers const char *p = ctx.data; 90810037SARM gem5 Developers char subcmd = *p++; 90910037SARM gem5 Developers if (*p++ != ',') 91010037SARM gem5 Developers throw CmdError("E0D"); 91110037SARM gem5 Developers Addr addr = hex2i(&p); 91210037SARM gem5 Developers if (*p++ != ',') 91310037SARM gem5 Developers throw CmdError("E0D"); 91410037SARM gem5 Developers size_t len = hex2i(&p); 91510037SARM gem5 Developers 91610037SARM gem5 Developers DPRINTF(GDBMisc, "clear %s, addr=%#x, len=%d\n", 91710037SARM gem5 Developers break_type(subcmd), addr, len); 91810037SARM gem5 Developers 91910037SARM gem5 Developers switch (subcmd) { 92010037SARM gem5 Developers case GdbSoftBp: 92110037SARM gem5 Developers removeSoftBreak(addr, len); 92210037SARM gem5 Developers break; 92310037SARM gem5 Developers case GdbHardBp: 92410037SARM gem5 Developers removeHardBreak(addr, len); 92510037SARM gem5 Developers break; 92610037SARM gem5 Developers case GdbWriteWp: 92710037SARM gem5 Developers case GdbReadWp: 92810037SARM gem5 Developers case GdbAccWp: 92910037SARM gem5 Developers default: // unknown 93010037SARM gem5 Developers throw Unsupported(); 93110037SARM gem5 Developers } 93210037SARM gem5 Developers send("OK"); 93310037SARM gem5 Developers 93410037SARM gem5 Developers return true; 93510037SARM gem5 Developers} 93610037SARM gem5 Developers 93710037SARM gem5 Developersbool 93810037SARM gem5 DevelopersBaseRemoteGDB::cmd_set_hw_bkpt(GdbCommand::Context &ctx) 93910037SARM gem5 Developers{ 94010037SARM gem5 Developers const char *p = ctx.data; 94110037SARM gem5 Developers char subcmd = *p++; 94210037SARM gem5 Developers if (*p++ != ',') 94310037SARM gem5 Developers throw CmdError("E0D"); 94410037SARM gem5 Developers Addr addr = hex2i(&p); 94510037SARM gem5 Developers if (*p++ != ',') 94610037SARM gem5 Developers throw CmdError("E0D"); 94710037SARM gem5 Developers size_t len = hex2i(&p); 94810037SARM gem5 Developers 94910037SARM gem5 Developers DPRINTF(GDBMisc, "set %s, addr=%#x, len=%d\n", 95010037SARM gem5 Developers break_type(subcmd), addr, len); 95110037SARM gem5 Developers 95210037SARM gem5 Developers switch (subcmd) { 95310037SARM gem5 Developers case GdbSoftBp: 95410037SARM gem5 Developers insertSoftBreak(addr, len); 95510037SARM gem5 Developers break; 95610037SARM gem5 Developers case GdbHardBp: 95710037SARM gem5 Developers insertHardBreak(addr, len); 95810037SARM gem5 Developers break; 95910037SARM gem5 Developers case GdbWriteWp: 96010037SARM gem5 Developers case GdbReadWp: 96110037SARM gem5 Developers case GdbAccWp: 96210037SARM gem5 Developers default: // unknown 96310037SARM gem5 Developers throw Unsupported(); 96410037SARM gem5 Developers } 96510037SARM gem5 Developers send("OK"); 96610037SARM gem5 Developers 96710037SARM gem5 Developers return true; 96810037SARM gem5 Developers} 96910037SARM gem5 Developers 97010037SARM gem5 Developers 97110037SARM gem5 Developers// This function does all command processing for interfacing to a 97210037SARM gem5 Developers// remote gdb. Note that the error codes are ignored by gdb at 97310037SARM gem5 Developers// present, but might eventually become meaningful. (XXX) It might 97410037SARM gem5 Developers// makes sense to use POSIX errno values, because that is what the 97510037SARM gem5 Developers// gdb/remote.c functions want to return. 97610037SARM gem5 Developersbool 97710037SARM gem5 DevelopersBaseRemoteGDB::trap(int type) 97810037SARM gem5 Developers{ 97910037SARM gem5 Developers 98010037SARM gem5 Developers if (!attached) 98110037SARM gem5 Developers return false; 98210037SARM gem5 Developers 9838549Sdaniel.johnson@arm.com DPRINTF(GDBMisc, "trap: PC=%s\n", context->pcState()); 98410037SARM gem5 Developers 98510037SARM gem5 Developers clearSingleStep(); 98610037SARM gem5 Developers 98710037SARM gem5 Developers /* 98810037SARM gem5 Developers * The first entry to this function is normally through 98910037SARM gem5 Developers * a breakpoint trap in kgdb_connect(), in which case we 99010037SARM gem5 Developers * must advance past the breakpoint because gdb will not. 99110037SARM gem5 Developers * 99210037SARM gem5 Developers * On the first entry here, we expect that gdb is not yet 99310037SARM gem5 Developers * listening to us, so just enter the interaction loop. 99410037SARM gem5 Developers * After the debugger is "active" (connected) it will be 99510037SARM gem5 Developers * waiting for a "signaled" message from us. 99610037SARM gem5 Developers */ 99710037SARM gem5 Developers if (!active) { 99810037SARM gem5 Developers active = true; 99910037SARM gem5 Developers } else { 100010037SARM gem5 Developers // Tell remote host that an exception has occurred. 100110037SARM gem5 Developers send(csprintf("S%02x", type).c_str()); 100210037SARM gem5 Developers } 100310037SARM gem5 Developers 100410037SARM gem5 Developers // Stick frame regs into our reg cache. 100510037SARM gem5 Developers regCachePtr = gdbRegs(); 100610037SARM gem5 Developers regCachePtr->getRegs(context); 100710037SARM gem5 Developers 100810037SARM gem5 Developers char data[GDBPacketBufLen + 1]; 100910037SARM gem5 Developers GdbCommand::Context cmdCtx; 101010037SARM gem5 Developers cmdCtx.type = type; 101110037SARM gem5 Developers cmdCtx.data = &data[1]; 101210037SARM gem5 Developers 101310037SARM gem5 Developers for (;;) { 101410037SARM gem5 Developers try { 101510037SARM gem5 Developers size_t datalen = recv(data, sizeof(data)); 101610037SARM gem5 Developers if (datalen < 1) 101710037SARM gem5 Developers throw BadClient(); 101810037SARM gem5 Developers 101910037SARM gem5 Developers data[datalen] = 0; // Sentinel 102010037SARM gem5 Developers cmdCtx.cmd_byte = data[0]; 102110037SARM gem5 Developers cmdCtx.len = datalen - 1; 102210037SARM gem5 Developers 102310037SARM gem5 Developers auto cmdIt = command_map.find(cmdCtx.cmd_byte); 102410037SARM gem5 Developers if (cmdIt == command_map.end()) { 102510037SARM gem5 Developers DPRINTF(GDBMisc, "Unknown command: %c(%#x)\n", 102610037SARM gem5 Developers cmdCtx.cmd_byte, cmdCtx.cmd_byte); 102710037SARM gem5 Developers throw Unsupported(); 102810037SARM gem5 Developers } 102910037SARM gem5 Developers cmdCtx.cmd = &(cmdIt->second); 103010037SARM gem5 Developers 103110037SARM gem5 Developers if (!(this->*(cmdCtx.cmd->func))(cmdCtx)) 103210037SARM gem5 Developers break; 103310037SARM gem5 Developers 103410037SARM gem5 Developers } catch (BadClient &e) { 103510037SARM gem5 Developers if (e.warning) 103610037SARM gem5 Developers warn(e.warning); 103710037SARM gem5 Developers detach(); 103810037SARM gem5 Developers break; 103910037SARM gem5 Developers } catch (Unsupported &e) { 104010037SARM gem5 Developers send(""); 104110037SARM gem5 Developers } catch (CmdError &e) { 104210037SARM gem5 Developers send(e.error.c_str()); 104310037SARM gem5 Developers } catch (...) { 104410037SARM gem5 Developers panic("Unrecognzied GDB exception."); 104510037SARM gem5 Developers } 104610037SARM gem5 Developers } 104710037SARM gem5 Developers 104810037SARM gem5 Developers return true; 104910037SARM gem5 Developers} 105010037SARM gem5 Developers 105110037SARM gem5 Developers// Convert a hex digit into an integer. 105210037SARM gem5 Developers// This returns -1 if the argument passed is no valid hex digit. 105310037SARM gem5 Developersint 105410037SARM gem5 DevelopersBaseRemoteGDB::digit2i(char c) 105510037SARM gem5 Developers{ 105610037SARM gem5 Developers if (c >= '0' && c <= '9') 105710037SARM gem5 Developers return (c - '0'); 105810037SARM gem5 Developers else if (c >= 'a' && c <= 'f') 105910037SARM gem5 Developers return (c - 'a' + 10); 106010037SARM gem5 Developers else if (c >= 'A' && c <= 'F') 106110037SARM gem5 Developers return (c - 'A' + 10); 106210037SARM gem5 Developers else 106310037SARM gem5 Developers return (-1); 106410037SARM gem5 Developers} 106510037SARM gem5 Developers 106610037SARM gem5 Developers// Convert the low 4 bits of an integer into an hex digit. 106710037SARM gem5 Developerschar 106810037SARM gem5 DevelopersBaseRemoteGDB::i2digit(int n) 106910037SARM gem5 Developers{ 107010037SARM gem5 Developers return ("0123456789abcdef"[n & 0x0f]); 107110037SARM gem5 Developers} 107210037SARM gem5 Developers 107310037SARM gem5 Developers// Convert a byte array into an hex string. 107410037SARM gem5 Developersvoid 107510037SARM gem5 DevelopersBaseRemoteGDB::mem2hex(char *vdst, const char *vsrc, int len) 107610037SARM gem5 Developers{ 107710037SARM gem5 Developers char *dst = vdst; 107810037SARM gem5 Developers const char *src = vsrc; 107910037SARM gem5 Developers 108010037SARM gem5 Developers while (len--) { 108110037SARM gem5 Developers *dst++ = i2digit(*src >> 4); 108210037SARM gem5 Developers *dst++ = i2digit(*src++); 108310037SARM gem5 Developers } 108410037SARM gem5 Developers *dst = '\0'; 108510037SARM gem5 Developers} 108610037SARM gem5 Developers 108710037SARM gem5 Developers// Convert an hex string into a byte array. 108810037SARM gem5 Developers// This returns a pointer to the character following the last valid 108910037SARM gem5 Developers// hex digit. If the string ends in the middle of a byte, NULL is 109010037SARM gem5 Developers// returned. 109110037SARM gem5 Developersconst char * 109210037SARM gem5 DevelopersBaseRemoteGDB::hex2mem(char *vdst, const char *src, int maxlen) 109310037SARM gem5 Developers{ 109410037SARM gem5 Developers char *dst = vdst; 109510037SARM gem5 Developers int msb, lsb; 109610037SARM gem5 Developers 109710037SARM gem5 Developers while (*src && maxlen--) { 109810037SARM gem5 Developers msb = digit2i(*src++); 109910037SARM gem5 Developers if (msb < 0) 110010037SARM gem5 Developers return (src - 1); 110110037SARM gem5 Developers lsb = digit2i(*src++); 110210037SARM gem5 Developers if (lsb < 0) 110310037SARM gem5 Developers return (NULL); 110410037SARM gem5 Developers *dst++ = (msb << 4) | lsb; 110510037SARM gem5 Developers } 110610037SARM gem5 Developers return src; 110710037SARM gem5 Developers} 110810037SARM gem5 Developers 110910037SARM gem5 Developers// Convert an hex string into an integer. 111010037SARM gem5 Developers// This returns a pointer to the character following the last valid 111110037SARM gem5 Developers// hex digit. 111210037SARM gem5 DevelopersAddr 111310037SARM gem5 DevelopersBaseRemoteGDB::hex2i(const char **srcp) 111410037SARM gem5 Developers{ 111510037SARM gem5 Developers const char *src = *srcp; 111610037SARM gem5 Developers Addr r = 0; 111710037SARM gem5 Developers int nibble; 111810037SARM gem5 Developers 111910037SARM gem5 Developers while ((nibble = digit2i(*src)) >= 0) { 112010037SARM gem5 Developers r *= 16; 112110037SARM gem5 Developers r += nibble; 112210037SARM gem5 Developers src++; 112310037SARM gem5 Developers } 112410037SARM gem5 Developers *srcp = src; 112510037SARM gem5 Developers return r; 112610037SARM gem5 Developers} 112710037SARM gem5 Developers