remote_gdb.cc revision 8332
11689SN/A/* 22326SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 31689SN/A * All rights reserved. 41689SN/A * 51689SN/A * Redistribution and use in source and binary forms, with or without 61689SN/A * modification, are permitted provided that the following conditions are 71689SN/A * met: redistributions of source code must retain the above copyright 81689SN/A * notice, this list of conditions and the following disclaimer; 91689SN/A * redistributions in binary form must reproduce the above copyright 101689SN/A * notice, this list of conditions and the following disclaimer in the 111689SN/A * documentation and/or other materials provided with the distribution; 121689SN/A * neither the name of the copyright holders nor the names of its 131689SN/A * contributors may be used to endorse or promote products derived from 141689SN/A * this software without specific prior written permission. 151689SN/A * 161689SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 171689SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 181689SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 191689SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 201689SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 211689SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 221689SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 231689SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 241689SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 251689SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 261689SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu * 282665Ssaidi@eecs.umich.edu * Authors: Nathan Binkert 292831Sksewell@umich.edu */ 301689SN/A 311689SN/A/* 322064SN/A * Copyright (c) 1990, 1993 The Regents of the University of California 331060SN/A * All rights reserved 341060SN/A * 352292SN/A * This software was developed by the Computer Systems Engineering group 361717SN/A * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 374762Snate@binkert.org * contributed to Berkeley. 386221Snate@binkert.org * 394762Snate@binkert.org * All advertising materials mentioning features or use of this software 401060SN/A * must display the following acknowledgement: 416221Snate@binkert.org * This product includes software developed by the University of 425529Snate@binkert.org * California, Lawrence Berkeley Laboratories. 431061SN/A * 442292SN/A * Redistribution and use in source and binary forms, with or without 455606Snate@binkert.org * modification, are permitted provided that the following conditions 465606Snate@binkert.org * are met: 475606Snate@binkert.org * 1. Redistributions of source code must retain the above copyright 481060SN/A * notice, this list of conditions and the following disclaimer. 492292SN/A * 2. Redistributions in binary form must reproduce the above copyright 502292SN/A * notice, this list of conditions and the following disclaimer in the 512292SN/A * documentation and/or other materials provided with the distribution. 522292SN/A * 3. All advertising materials mentioning features or use of this software 532292SN/A * must display the following acknowledgement: 542292SN/A * This product includes software developed by the University of 552292SN/A * California, Berkeley and its contributors. 562326SN/A * 4. Neither the name of the University nor the names of its contributors 572292SN/A * may be used to endorse or promote products derived from this software 582292SN/A * without specific prior written permission. 592292SN/A * 602292SN/A * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 612292SN/A * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 622292SN/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 635336Shines@cs.fsu.edu * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 642292SN/A * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 654873Sstever@eecs.umich.edu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 662292SN/A * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 672292SN/A * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 682292SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 694329Sktlim@umich.edu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 705529Snate@binkert.org * SUCH DAMAGE. 714329Sktlim@umich.edu * 724329Sktlim@umich.edu * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94 734329Sktlim@umich.edu */ 742292SN/A 752292SN/A/*- 762292SN/A * Copyright (c) 2001 The NetBSD Foundation, Inc. 772292SN/A * All rights reserved. 782292SN/A * 792292SN/A * This code is derived from software contributed to The NetBSD Foundation 802292SN/A * by Jason R. Thorpe. 812292SN/A * 822307SN/A * Redistribution and use in source and binary forms, with or without 832307SN/A * modification, are permitted provided that the following conditions 845529Snate@binkert.org * are met: 851060SN/A * 1. Redistributions of source code must retain the above copyright 861060SN/A * notice, this list of conditions and the following disclaimer. 871060SN/A * 2. Redistributions in binary form must reproduce the above copyright 881060SN/A * notice, this list of conditions and the following disclaimer in the 891060SN/A * documentation and/or other materials provided with the distribution. 901060SN/A * 3. All advertising materials mentioning features or use of this software 912326SN/A * must display the following acknowledgement: 921060SN/A * This product includes software developed by the NetBSD 931060SN/A * Foundation, Inc. and its contributors. 941060SN/A * 4. Neither the name of The NetBSD Foundation nor the names of its 951060SN/A * contributors may be used to endorse or promote products derived 962292SN/A * from this software without specific prior written permission. 976221Snate@binkert.org * 986221Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 996221Snate@binkert.org * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 1001060SN/A * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 1011060SN/A * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 1022307SN/A * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1032292SN/A * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1042980Sgblack@eecs.umich.edu * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1052292SN/A * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1062292SN/A * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1072292SN/A * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 1082292SN/A * POSSIBILITY OF SUCH DAMAGE. 1092292SN/A */ 1102292SN/A 1112292SN/A/* 1122292SN/A * $NetBSD: kgdb_stub.c,v 1.8 2001/07/07 22:58:00 wdk Exp $ 1132292SN/A * 1142292SN/A * Taken from NetBSD 1156221Snate@binkert.org * 1166221Snate@binkert.org * "Stub" to allow remote cpu to debug over a serial line using gdb. 1172292SN/A */ 1182292SN/A 1192292SN/A#include <sys/signal.h> 1202292SN/A#include <unistd.h> 1212292SN/A 1222292SN/A#include <cstdio> 1232292SN/A#include <string> 1242292SN/A 1252292SN/A#include "config/full_system.hh" 1266221Snate@binkert.org 1276221Snate@binkert.org#if FULL_SYSTEM 1282292SN/A#include "arch/vtophys.hh" 1292292SN/A#include "mem/vport.hh" 1302831Sksewell@umich.edu#endif 1312292SN/A 1322292SN/A#include "base/intmath.hh" 1332292SN/A#include "base/remote_gdb.hh" 1342292SN/A#include "base/socket.hh" 1352292SN/A#include "base/trace.hh" 1362292SN/A#include "config/the_isa.hh" 1372292SN/A#include "cpu/static_inst.hh" 1382292SN/A#include "cpu/thread_context.hh" 1392292SN/A#include "debug/GDBAll.hh" 1406221Snate@binkert.org#include "mem/port.hh" 1416221Snate@binkert.org#include "mem/translating_port.hh" 1422292SN/A#include "sim/system.hh" 1432292SN/A 1442831Sksewell@umich.eduusing namespace std; 1452292SN/Ausing namespace Debug; 1462292SN/Ausing namespace TheISA; 1472292SN/A 1482292SN/A#ifndef NDEBUG 1492292SN/Avector<BaseRemoteGDB *> debuggers; 1502292SN/A 1512292SN/Avoid 1522292SN/Adebugger() 1532292SN/A{ 1542292SN/A static int current_debugger = -1; 1552326SN/A if (current_debugger >= 0 && current_debugger < (int)debuggers.size()) { 1562348SN/A BaseRemoteGDB *gdb = debuggers[current_debugger]; 1572326SN/A if (!gdb->isattached()) 1582326SN/A gdb->listener->accept(); 1592348SN/A if (gdb->isattached()) 1602292SN/A gdb->trap(SIGILL); 1612292SN/A } 1622292SN/A} 1632292SN/A#endif 1642292SN/A 1652292SN/A/////////////////////////////////////////////////////////// 1662292SN/A// 1671060SN/A// 1681060SN/A// 1691061SN/A 1701060SN/AGDBListener::Event::Event(GDBListener *l, int fd, int e) 1711062SN/A : PollEvent(fd, e), listener(l) 1721062SN/A{} 1732301SN/A 1741062SN/Avoid 1751062SN/AGDBListener::Event::process(int revent) 1761062SN/A{ 1771062SN/A listener->accept(); 1781062SN/A} 1791062SN/A 1801062SN/AGDBListener::GDBListener(BaseRemoteGDB *g, int p) 1811062SN/A : event(NULL), gdb(g), port(p) 1821062SN/A{ 1831062SN/A assert(!gdb->listener); 1842301SN/A gdb->listener = this; 1852301SN/A} 1862301SN/A 1872301SN/AGDBListener::~GDBListener() 1881062SN/A{ 1891062SN/A if (event) 1901062SN/A delete event; 1911062SN/A} 1921062SN/A 1931062SN/Astring 1941062SN/AGDBListener::name() 1951062SN/A{ 1961062SN/A return gdb->name() + ".listener"; 1971062SN/A} 1981062SN/A 1991062SN/Avoid 2001062SN/AGDBListener::listen() 2011062SN/A{ 2021062SN/A if (ListenSocket::allDisabled()) { 2031062SN/A warn_once("Sockets disabled, not accepting gdb connections"); 2041062SN/A return; 2051062SN/A } 2061062SN/A 2071062SN/A while (!listener.listen(port, true)) { 2081062SN/A DPRINTF(GDBMisc, "Can't bind port %d\n", port); 2091062SN/A port++; 2101062SN/A } 2111062SN/A 2121062SN/A event = new Event(this, listener.getfd(), POLLIN); 2131062SN/A pollQueue.schedule(event); 2141062SN/A 2151062SN/A#ifndef NDEBUG 2161062SN/A gdb->number = debuggers.size(); 2171062SN/A debuggers.push_back(gdb); 2181062SN/A#endif 2191062SN/A 2201062SN/A#ifndef NDEBUG 2211062SN/A ccprintf(cerr, "%d: %s: listening for remote gdb #%d on port %d\n", 2221062SN/A curTick(), name(), gdb->number, port); 2231062SN/A#else 2241062SN/A ccprintf(cerr, "%d: %s: listening for remote gdb on port %d\n", 2251062SN/A curTick(), name(), port); 2261062SN/A#endif 2271062SN/A} 2281062SN/A 2291062SN/Avoid 2301062SN/AGDBListener::accept() 2311062SN/A{ 2321062SN/A if (!listener.islistening()) 2331062SN/A panic("GDBListener::accept(): cannot accept if we're not listening!"); 2341062SN/A 2352361SN/A int sfd = listener.accept(true); 2362326SN/A 2372301SN/A if (sfd != -1) { 2382301SN/A if (gdb->isattached()) 2392301SN/A close(sfd); 2402301SN/A else 2412301SN/A gdb->attach(sfd); 2422301SN/A } 2432326SN/A} 2442301SN/A 2452361SN/ABaseRemoteGDB::Event::Event(BaseRemoteGDB *g, int fd, int e) 2462326SN/A : PollEvent(fd, e), gdb(g) 2472307SN/A{} 2482301SN/A 2492301SN/Avoid 2502307SN/ABaseRemoteGDB::Event::process(int revent) 2512301SN/A{ 2522301SN/A if (revent & POLLIN) 2532301SN/A gdb->trap(SIGILL); 2542301SN/A else if (revent & POLLNVAL) 2552301SN/A gdb->detach(); 2562301SN/A} 2572301SN/A 2582301SN/ABaseRemoteGDB::BaseRemoteGDB(System *_system, ThreadContext *c, size_t cacheSize) 2592301SN/A : event(NULL), listener(NULL), number(-1), fd(-1), 2602301SN/A active(false), attached(false), 2612301SN/A system(_system), pmem(_system->physmem), context(c), 2622301SN/A gdbregs(cacheSize) 2632326SN/A{ 2644762Snate@binkert.org memset(gdbregs.regs, 0, gdbregs.bytes()); 2652301SN/A} 2662301SN/A 2672301SN/ABaseRemoteGDB::~BaseRemoteGDB() 2682301SN/A{ 2694762Snate@binkert.org if (event) 2702301SN/A delete event; 2712301SN/A} 2722301SN/A 2732301SN/Astring 2742361SN/ABaseRemoteGDB::name() 2752326SN/A{ 2762301SN/A return system->name() + ".remote_gdb"; 2772301SN/A} 2782301SN/A 2792301SN/Abool 2802301SN/ABaseRemoteGDB::isattached() 2812301SN/A{ return attached; } 2822301SN/A 2832980Sgblack@eecs.umich.eduvoid 2842301SN/ABaseRemoteGDB::attach(int f) 2852326SN/A{ 2862301SN/A fd = f; 2872361SN/A 2882326SN/A event = new Event(this, fd, POLLIN); 2892301SN/A pollQueue.schedule(event); 2902301SN/A 2912301SN/A attached = true; 2922301SN/A DPRINTFN("remote gdb attached\n"); 2932326SN/A} 2942727Sktlim@umich.edu 2952326SN/Avoid 2962301SN/ABaseRemoteGDB::detach() 2972301SN/A{ 2982301SN/A attached = false; 2992301SN/A close(fd); 3002301SN/A fd = -1; 3012301SN/A 3024762Snate@binkert.org pollQueue.remove(event); 3032301SN/A DPRINTFN("remote gdb detached\n"); 3042301SN/A} 3052326SN/A 3062301SN/Aconst char * 3072301SN/ABaseRemoteGDB::gdb_command(char cmd) 3082301SN/A{ 3092301SN/A switch (cmd) { 3102301SN/A case GDBSignal: return "KGDB_SIGNAL"; 3112301SN/A case GDBSetBaud: return "KGDB_SET_BAUD"; 3122326SN/A case GDBSetBreak: return "KGDB_SET_BREAK"; 3132301SN/A case GDBCont: return "KGDB_CONT"; 3142301SN/A case GDBAsyncCont: return "KGDB_ASYNC_CONT"; 3152301SN/A case GDBDebug: return "KGDB_DEBUG"; 3162301SN/A case GDBDetach: return "KGDB_DETACH"; 3172326SN/A case GDBRegR: return "KGDB_REG_R"; 3182301SN/A case GDBRegW: return "KGDB_REG_W"; 3196221Snate@binkert.org case GDBSetThread: return "KGDB_SET_THREAD"; 3202292SN/A case GDBCycleStep: return "KGDB_CYCLE_STEP"; 3216221Snate@binkert.org case GDBSigCycleStep: return "KGDB_SIG_CYCLE_STEP"; 3222292SN/A case GDBKill: return "KGDB_KILL"; 3237897Shestness@cs.utexas.edu case GDBMemW: return "KGDB_MEM_W"; 3247897Shestness@cs.utexas.edu case GDBMemR: return "KGDB_MEM_R"; 3257897Shestness@cs.utexas.edu case GDBSetReg: return "KGDB_SET_REG"; 3267897Shestness@cs.utexas.edu case GDBReadReg: return "KGDB_READ_REG"; 3277897Shestness@cs.utexas.edu case GDBQueryVar: return "KGDB_QUERY_VAR"; 3287897Shestness@cs.utexas.edu case GDBSetVar: return "KGDB_SET_VAR"; 3297897Shestness@cs.utexas.edu case GDBReset: return "KGDB_RESET"; 3307897Shestness@cs.utexas.edu case GDBStep: return "KGDB_STEP"; 3317897Shestness@cs.utexas.edu case GDBAsyncStep: return "KGDB_ASYNC_STEP"; 3327897Shestness@cs.utexas.edu case GDBThreadAlive: return "KGDB_THREAD_ALIVE"; 3337897Shestness@cs.utexas.edu case GDBTargetExit: return "KGDB_TARGET_EXIT"; 3347897Shestness@cs.utexas.edu case GDBBinaryDload: return "KGDB_BINARY_DLOAD"; 3357897Shestness@cs.utexas.edu case GDBClrHwBkpt: return "KGDB_CLR_HW_BKPT"; 3367897Shestness@cs.utexas.edu case GDBSetHwBkpt: return "KGDB_SET_HW_BKPT"; 3377897Shestness@cs.utexas.edu case GDBStart: return "KGDB_START"; 3387897Shestness@cs.utexas.edu case GDBEnd: return "KGDB_END"; 3397897Shestness@cs.utexas.edu case GDBGoodP: return "KGDB_GOODP"; 3407897Shestness@cs.utexas.edu case GDBBadP: return "KGDB_BADP"; 3417897Shestness@cs.utexas.edu default: return "KGDB_UNKNOWN"; 3427897Shestness@cs.utexas.edu } 3437897Shestness@cs.utexas.edu} 3447897Shestness@cs.utexas.edu 3457897Shestness@cs.utexas.edu///////////////////////// 3467897Shestness@cs.utexas.edu// 3477897Shestness@cs.utexas.edu// 3487897Shestness@cs.utexas.edu 3497897Shestness@cs.utexas.eduuint8_t 3507897Shestness@cs.utexas.eduBaseRemoteGDB::getbyte() 3517897Shestness@cs.utexas.edu{ 3527897Shestness@cs.utexas.edu uint8_t b; 3537897Shestness@cs.utexas.edu if (::read(fd, &b, 1) != 1) 3547897Shestness@cs.utexas.edu warn("could not read byte from debugger"); 3557897Shestness@cs.utexas.edu return b; 3567897Shestness@cs.utexas.edu} 3577897Shestness@cs.utexas.edu 3587897Shestness@cs.utexas.eduvoid 3597897Shestness@cs.utexas.eduBaseRemoteGDB::putbyte(uint8_t b) 3607897Shestness@cs.utexas.edu{ 3617897Shestness@cs.utexas.edu if (::write(fd, &b, 1) != 1) 3627897Shestness@cs.utexas.edu warn("could not write byte to debugger"); 3637897Shestness@cs.utexas.edu} 3641062SN/A 3651062SN/A// Send a packet to gdb 3661062SN/Avoid 3671062SN/ABaseRemoteGDB::send(const char *bp) 3682307SN/A{ 3691060SN/A const char *p; 3702307SN/A uint8_t csum, c; 3716221Snate@binkert.org 3726221Snate@binkert.org DPRINTF(GDBSend, "send: %s\n", bp); 3736221Snate@binkert.org 3742307SN/A do { 3751060SN/A p = bp; 3762307SN/A //Start sending a packet 3772307SN/A putbyte(GDBStart); 3782307SN/A //Send the contents, and also keep a check sum. 3792307SN/A for (csum = 0; (c = *p); p++) { 3802307SN/A putbyte(c); 3812307SN/A csum += c; 3822307SN/A } 3832307SN/A //Send the ending character. 3842307SN/A putbyte(GDBEnd); 3852307SN/A //Sent the checksum. 3862307SN/A putbyte(i2digit(csum >> 4)); 3872307SN/A putbyte(i2digit(csum)); 3886221Snate@binkert.org //Try transmitting over and over again until the other end doesn't send an 3896221Snate@binkert.org //error back. 3902307SN/A } while ((c = getbyte() & 0x7f) == GDBBadP); 3912307SN/A} 3922307SN/A 3932307SN/A// Receive a packet from gdb 3942307SN/Aint 3952307SN/ABaseRemoteGDB::recv(char *bp, int maxlen) 3962307SN/A{ 3972307SN/A char *p; 3982307SN/A int c, csum; 3992307SN/A int len; 4001060SN/A 4011060SN/A do { 4021061SN/A p = bp; 4031060SN/A csum = len = 0; 4046221Snate@binkert.org //Find the beginning of a packet 4051060SN/A while ((c = getbyte()) != GDBStart) 4062292SN/A ; 4072064SN/A 4082064SN/A //Read until you find the end of the data in the packet, and keep 4092064SN/A //track of the check sum. 4102064SN/A while ((c = getbyte()) != GDBEnd && len < maxlen) { 4112292SN/A c &= 0x7f; 4122064SN/A csum += c; 4134318Sktlim@umich.edu *p++ = c; 4141060SN/A len++; 4151060SN/A } 4161061SN/A 4171060SN/A //Mask the check sum, and terminate the command string. 4181060SN/A csum &= 0xff; 4191060SN/A *p = '\0'; 4201060SN/A 4211060SN/A //If the command was too long, report an error. 4221060SN/A if (len >= maxlen) { 4231060SN/A putbyte(GDBBadP); 4241060SN/A continue; 4251684SN/A } 4262307SN/A 4272307SN/A //Bring in the checksum. If the check sum matches, csum will be 0. 4282307SN/A csum -= digit2i(getbyte()) * 16; 4292367SN/A csum -= digit2i(getbyte()); 4302367SN/A 4312367SN/A //If the check sum was correct 4322367SN/A if (csum == 0) { 4332367SN/A //Report that the packet was received correctly 4342367SN/A putbyte(GDBGoodP); 4352367SN/A // Sequence present? 4362307SN/A if (bp[2] == ':') { 4372326SN/A putbyte(bp[0]); 4382367SN/A putbyte(bp[1]); 4392307SN/A len -= 3; 4406221Snate@binkert.org memcpy(bp, bp+3, len); 4416221Snate@binkert.org } 4422307SN/A break; 4432307SN/A } 4442307SN/A //Otherwise, report that there was a mistake. 4452307SN/A putbyte(GDBBadP); 4462307SN/A } while (1); 4472307SN/A 4482307SN/A DPRINTF(GDBRecv, "recv: %s: %s\n", gdb_command(*bp), bp); 4492307SN/A 4502307SN/A return (len); 4512307SN/A} 4522307SN/A 4532292SN/A// Read bytes from kernel address space for debugger. 4546221Snate@binkert.orgbool 4552292SN/ABaseRemoteGDB::read(Addr vaddr, size_t size, char *data) 4562292SN/A{ 4572292SN/A static Addr lastaddr = 0; 4582292SN/A static size_t lastsize = 0; 4592292SN/A 4602292SN/A if (vaddr < 10) { 4612292SN/A DPRINTF(GDBRead, "read: reading memory location zero!\n"); 4622292SN/A vaddr = lastaddr + lastsize; 4632292SN/A } 4642292SN/A 4652292SN/A DPRINTF(GDBRead, "read: addr=%#x, size=%d", vaddr, size); 4662292SN/A 4672292SN/A#if FULL_SYSTEM 4682292SN/A VirtualPort *port = context->getVirtPort(); 4693867Sbinkertn@umich.edu#else 4702292SN/A TranslatingPort *port = context->getMemPort(); 4716221Snate@binkert.org#endif 4726221Snate@binkert.org port->readBlob(vaddr, (uint8_t*)data, size); 4732292SN/A 4743867Sbinkertn@umich.edu#if TRACING_ON 4756221Snate@binkert.org if (DTRACE(GDBRead)) { 4763867Sbinkertn@umich.edu if (DTRACE(GDBExtra)) { 4772292SN/A char buf[1024]; 4783867Sbinkertn@umich.edu mem2hex(buf, data, size); 4792292SN/A DPRINTFNR(": %s\n", buf); 4803867Sbinkertn@umich.edu } else 4812292SN/A DPRINTFNR("\n"); 4822292SN/A } 4832292SN/A#endif 4842292SN/A 4852292SN/A return true; 4862292SN/A} 4871684SN/A 4881684SN/A// Write bytes to kernel address space for debugger. 4891684SN/Abool 4901684SN/ABaseRemoteGDB::write(Addr vaddr, size_t size, const char *data) 4911684SN/A{ 4921684SN/A static Addr lastaddr = 0; 4932292SN/A static size_t lastsize = 0; 4942292SN/A 4956221Snate@binkert.org if (vaddr < 10) { 4962292SN/A DPRINTF(GDBWrite, "write: writing memory location zero!\n"); 4972292SN/A vaddr = lastaddr + lastsize; 4982292SN/A } 4992292SN/A 5001060SN/A if (DTRACE(GDBWrite)) { 5011060SN/A DPRINTFN("write: addr=%#x, size=%d", vaddr, size); 5021061SN/A if (DTRACE(GDBExtra)) { 5031060SN/A char buf[1024]; 5041060SN/A mem2hex(buf, data, size); 5051060SN/A DPRINTFNR(": %s\n", buf); 5061060SN/A } else 5071060SN/A DPRINTFNR("\n"); 5081060SN/A } 5091060SN/A#if FULL_SYSTEM 5101060SN/A VirtualPort *port = context->getVirtPort(); 5111060SN/A#else 5121060SN/A TranslatingPort *port = context->getMemPort(); 5131061SN/A#endif 5142292SN/A port->writeBlob(vaddr, (uint8_t*)data, size); 5156221Snate@binkert.org#if !FULL_SYSTEM 5162292SN/A delete port; 5172292SN/A#endif 5182292SN/A 5192292SN/A return true; 5202292SN/A} 5212292SN/A 5222292SN/APCEventQueue *BaseRemoteGDB::getPcEventQueue() 5232292SN/A{ 5242292SN/A return &system->pcEventQueue; 5252292SN/A} 5262292SN/A 5272292SN/ABaseRemoteGDB::HardBreakpoint::HardBreakpoint(BaseRemoteGDB *_gdb, Addr pc) 5282292SN/A : PCEvent(_gdb->getPcEventQueue(), "HardBreakpoint Event", pc), 5292292SN/A gdb(_gdb), refcount(0) 5302292SN/A{ 5312292SN/A DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc); 5322292SN/A} 5332292SN/A 5342292SN/Avoid 5352292SN/ABaseRemoteGDB::HardBreakpoint::process(ThreadContext *tc) 5362292SN/A{ 5372292SN/A DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc()); 5382292SN/A 5392292SN/A if (tc == gdb->context) 5402292SN/A gdb->trap(SIGTRAP); 5412292SN/A} 5421060SN/A 5431061SN/Abool 5441060SN/ABaseRemoteGDB::insertSoftBreak(Addr addr, size_t len) 5457897Shestness@cs.utexas.edu{ 5461060SN/A if (len != sizeof(TheISA::MachInst)) 5471060SN/A panic("invalid length\n"); 5481060SN/A 5497720Sgblack@eecs.umich.edu return insertHardBreak(addr, len); 5507720Sgblack@eecs.umich.edu} 5511060SN/A 5521060SN/Abool 5531060SN/ABaseRemoteGDB::removeSoftBreak(Addr addr, size_t len) 5542292SN/A{ 5551060SN/A if (len != sizeof(MachInst)) 5562064SN/A panic("invalid length\n"); 5571060SN/A 5582292SN/A return removeHardBreak(addr, len); 5591060SN/A} 5601060SN/A 5611060SN/Abool 5621060SN/ABaseRemoteGDB::insertHardBreak(Addr addr, size_t len) 5631060SN/A{ 5641060SN/A if (len != sizeof(MachInst)) 5651060SN/A panic("invalid length\n"); 5662326SN/A 5671060SN/A DPRINTF(GDBMisc, "inserting hardware breakpoint at %#x\n", addr); 5681061SN/A 5692292SN/A HardBreakpoint *&bkpt = hardBreakMap[addr]; 5701062SN/A if (bkpt == 0) 5711062SN/A bkpt = new HardBreakpoint(this, addr); 5721061SN/A 5731061SN/A bkpt->refcount++; 5741062SN/A 5751060SN/A return true; 5762292SN/A} 5772292SN/A 5781060SN/Abool 5791060SN/ABaseRemoteGDB::removeHardBreak(Addr addr, size_t len) 5801060SN/A{ 5811061SN/A if (len != sizeof(MachInst)) 5821061SN/A panic("invalid length\n"); 5832292SN/A 5841061SN/A DPRINTF(GDBMisc, "removing hardware breakpoint at %#x\n", addr); 5851061SN/A 5861061SN/A break_iter_t i = hardBreakMap.find(addr); 5877897Shestness@cs.utexas.edu if (i == hardBreakMap.end()) 5881061SN/A return false; 5892292SN/A 5901061SN/A HardBreakpoint *hbp = (*i).second; 5912292SN/A if (--hbp->refcount == 0) { 5921061SN/A delete hbp; 5937720Sgblack@eecs.umich.edu hardBreakMap.erase(i); 5942326SN/A } 5957720Sgblack@eecs.umich.edu 5962064SN/A return true; 5971061SN/A} 5981061SN/A 5992292SN/Avoid 6001061SN/ABaseRemoteGDB::setTempBreakpoint(Addr bkpt) 6012064SN/A{ 6021061SN/A DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", bkpt); 6032292SN/A insertHardBreak(bkpt, sizeof(TheISA::MachInst)); 6041061SN/A} 6051061SN/A 6061061SN/Avoid 6072326SN/ABaseRemoteGDB::clearTempBreakpoint(Addr &bkpt) 6081061SN/A{ 6091061SN/A DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", bkpt); 6101061SN/A removeHardBreak(bkpt, sizeof(TheISA::MachInst)); 6112292SN/A bkpt = 0; 6122292SN/A} 6131061SN/A 6141062SN/Aconst char * 6151062SN/ABaseRemoteGDB::break_type(char c) 6162292SN/A{ 6172292SN/A switch(c) { 6182292SN/A case '0': return "software breakpoint"; 6192292SN/A case '1': return "hardware breakpoint"; 6201061SN/A case '2': return "write watchpoint"; 6211061SN/A case '3': return "read watchpoint"; 6221061SN/A case '4': return "access watchpoint"; 6231060SN/A default: return "unknown breakpoint/watchpoint"; 6242292SN/A } 6251060SN/A} 6262292SN/A 6271060SN/A// This function does all command processing for interfacing to a 6282292SN/A// remote gdb. Note that the error codes are ignored by gdb at 6292292SN/A// present, but might eventually become meaningful. (XXX) It might 6301060SN/A// makes sense to use POSIX errno values, because that is what the 6312064SN/A// gdb/remote.c functions want to return. 6322333SN/Abool 6332333SN/ABaseRemoteGDB::trap(int type) 6342333SN/A{ 6352333SN/A uint64_t val; 6362333SN/A size_t datalen, len; 6372333SN/A char data[GDBPacketBufLen + 1]; 6387897Shestness@cs.utexas.edu char *buffer; 6397897Shestness@cs.utexas.edu size_t bufferSize; 6407897Shestness@cs.utexas.edu const char *p; 6417897Shestness@cs.utexas.edu char command, subcmd; 6427897Shestness@cs.utexas.edu string var; 6432333SN/A bool ret; 6442333SN/A 6451060SN/A if (!attached) 6462333SN/A return false; 6472064SN/A 6482292SN/A bufferSize = gdbregs.bytes() * 2 + 256; 6492292SN/A buffer = (char*)malloc(bufferSize); 6502292SN/A 6512292SN/A TheISA::PCState pc = context->pcState(); 6522292SN/A DPRINTF(GDBMisc, "trap: PC=%s\n", pc); 6532292SN/A 6542292SN/A clearSingleStep(); 6552292SN/A 6562292SN/A /* 6572292SN/A * The first entry to this function is normally through 6582292SN/A * a breakpoint trap in kgdb_connect(), in which case we 6592292SN/A * must advance past the breakpoint because gdb will not. 6602292SN/A * 6612292SN/A * On the first entry here, we expect that gdb is not yet 6622292SN/A * listening to us, so just enter the interaction loop. 6632292SN/A * After the debugger is "active" (connected) it will be 6642292SN/A * waiting for a "signaled" message from us. 6652292SN/A */ 6662292SN/A if (!active) 6671060SN/A active = true; 6681060SN/A else 6692292SN/A // Tell remote host that an exception has occurred. 6702292SN/A snprintf((char *)buffer, bufferSize, "S%02x", type); 6712292SN/A send(buffer); 6721060SN/A 6732292SN/A // Stick frame regs into our reg cache. 6742292SN/A getregs(); 6752292SN/A 6762292SN/A for (;;) { 6772292SN/A datalen = recv(data, sizeof(data)); 6782292SN/A data[sizeof(data) - 1] = 0; // Sentinel 6792292SN/A command = data[0]; 6802292SN/A subcmd = 0; 6812292SN/A p = data + 1; 6822292SN/A switch (command) { 6832292SN/A 6842292SN/A case GDBSignal: 6852292SN/A // if this command came from a running gdb, answer it -- 6862292SN/A // the other guy has no way of knowing if we're in or out 6872292SN/A // of this loop when he issues a "remote-signal". 6882292SN/A snprintf((char *)buffer, bufferSize, 6892292SN/A "S%02x", type); 6902292SN/A send(buffer); 6912292SN/A continue; 6922292SN/A 6932292SN/A case GDBRegR: 6941060SN/A if (2 * gdbregs.bytes() > bufferSize) 6951060SN/A panic("buffer too small"); 6962292SN/A 6971060SN/A mem2hex(buffer, gdbregs.regs, gdbregs.bytes()); 6981060SN/A send(buffer); 6992292SN/A continue; 7002292SN/A 7012292SN/A case GDBRegW: 7022292SN/A p = hex2mem(gdbregs.regs, p, gdbregs.bytes()); 7032367SN/A if (p == NULL || *p != '\0') 7042292SN/A send("E01"); 7052292SN/A else { 7062307SN/A setregs(); 7072367SN/A send("OK"); 7082367SN/A } 7092307SN/A continue; 7102307SN/A 7112307SN/A#if 0 7122292SN/A case GDBSetReg: 7132292SN/A val = hex2i(&p); 7142326SN/A if (*p++ != '=') { 7152326SN/A send("E01"); 7162292SN/A continue; 7172326SN/A } 7182326SN/A if (val < 0 && val >= KGDB_NUMREGS) { 7192326SN/A send("E01"); 7205327Smengke97@hotmail.com continue; 7212333SN/A } 7222292SN/A 7232292SN/A gdbregs.regs[val] = hex2i(&p); 7241061SN/A setregs(); 7251061SN/A send("OK"); 7261061SN/A 7271061SN/A continue; 7281060SN/A#endif 7291060SN/A 7301060SN/A case GDBMemR: 7312292SN/A val = hex2i(&p); 7322292SN/A if (*p++ != ',') { 7331060SN/A send("E02"); 7341060SN/A continue; 7351060SN/A } 7362292SN/A len = hex2i(&p); 7372292SN/A if (*p != '\0') { 7382292SN/A send("E03"); 7392292SN/A continue; 7402292SN/A } 7412292SN/A if (len > bufferSize) { 7422292SN/A send("E04"); 7432292SN/A continue; 7442292SN/A } 7452292SN/A if (!acc(val, len)) { 7462292SN/A send("E05"); 7471060SN/A continue; 7482333SN/A } 7492820Sktlim@umich.edu 7502326SN/A if (read(val, (size_t)len, (char *)buffer)) { 7512292SN/A // variable length array would be nice, but C++ doesn't 7521060SN/A // officially support those... 7532292SN/A char *temp = new char[2*len+1]; 7541060SN/A mem2hex(temp, buffer, len); 7552292SN/A send(temp); 7561060SN/A delete [] temp; 7577897Shestness@cs.utexas.edu } else { 7587897Shestness@cs.utexas.edu send("E05"); 7592292SN/A } 7601060SN/A continue; 7612292SN/A 7622292SN/A case GDBMemW: 7631060SN/A val = hex2i(&p); 7642292SN/A if (*p++ != ',') { 7652292SN/A send("E06"); 7662292SN/A continue; 7672292SN/A } 7682292SN/A len = hex2i(&p); 7691060SN/A if (*p++ != ':') { 7701060SN/A send("E07"); 7712292SN/A continue; 7721060SN/A } 7732292SN/A if (len > datalen - (p - data)) { 7742292SN/A send("E08"); 7752292SN/A continue; 7761060SN/A } 7771060SN/A p = hex2mem(buffer, p, bufferSize); 7782326SN/A if (p == NULL) { 7792326SN/A send("E09"); 7806221Snate@binkert.org continue; 7811060SN/A } 7822326SN/A if (!acc(val, len)) { 7832326SN/A send("E0A"); 7847897Shestness@cs.utexas.edu continue; 7852326SN/A } 7862326SN/A if (write(val, (size_t)len, (char *)buffer)) 7871060SN/A send("OK"); 7881060SN/A else 7891060SN/A send("E0B"); 7902348SN/A continue; 7912348SN/A 7922326SN/A case GDBSetThread: 7932292SN/A subcmd = *p++; 7942292SN/A val = hex2i(&p); 7952333SN/A if (val == 0) 7961060SN/A send("OK"); 7972326SN/A else 7982326SN/A send("E01"); 7992326SN/A continue; 8002326SN/A 8012292SN/A case GDBDetach: 8022292SN/A case GDBKill: 8032326SN/A active = false; 8042326SN/A clearSingleStep(); 8052326SN/A detach(); 8061060SN/A goto out; 8077823Ssteve.reinhardt@amd.com 8081060SN/A case GDBAsyncCont: 8092326SN/A subcmd = hex2i(&p); 8102292SN/A if (*p++ == ';') { 8112348SN/A val = hex2i(&p); 8122348SN/A context->pcState(val); 8132326SN/A } 8142292SN/A clearSingleStep(); 8152292SN/A goto out; 8162326SN/A 8172292SN/A case GDBCont: 8181060SN/A if (p - data < (ptrdiff_t)datalen) { 8191060SN/A val = hex2i(&p); 8207720Sgblack@eecs.umich.edu context->pcState(val); 8212292SN/A } 8227720Sgblack@eecs.umich.edu clearSingleStep(); 8232292SN/A goto out; 8241060SN/A 8252292SN/A case GDBAsyncStep: 8261061SN/A subcmd = hex2i(&p); 8272292SN/A if (*p++ == ';') { 8282292SN/A val = hex2i(&p); 8292292SN/A context->pcState(val); 8302292SN/A } 8312292SN/A setSingleStep(); 8321060SN/A goto out; 8331060SN/A 8342064SN/A case GDBStep: 8352292SN/A if (p - data < (ptrdiff_t)datalen) { 8362064SN/A val = hex2i(&p); 8372292SN/A context->pcState(val); 8382292SN/A } 8392292SN/A setSingleStep(); 8402292SN/A goto out; 8412301SN/A 8422731Sktlim@umich.edu case GDBClrHwBkpt: 8432292SN/A subcmd = *p++; 8442301SN/A if (*p++ != ',') send("E0D"); 8452292SN/A val = hex2i(&p); 8462292SN/A if (*p++ != ',') send("E0D"); 8472292SN/A len = hex2i(&p); 8482326SN/A 8492820Sktlim@umich.edu DPRINTF(GDBMisc, "clear %s, addr=%#x, len=%d\n", 8502292SN/A break_type(subcmd), val, len); 8512326SN/A 8522326SN/A ret = false; 8532292SN/A 8541060SN/A switch (subcmd) { 8551060SN/A case '0': // software breakpoint 8561062SN/A ret = removeSoftBreak(val, len); 8572326SN/A break; 8582326SN/A 8592307SN/A case '1': // hardware breakpoint 8602348SN/A ret = removeHardBreak(val, len); 8612292SN/A break; 8622292SN/A 8632292SN/A case '2': // write watchpoint 8642292SN/A case '3': // read watchpoint 8652292SN/A case '4': // access watchpoint 8661060SN/A default: // unknown 8671060SN/A send(""); 8681061SN/A break; 8691060SN/A } 8701061SN/A 8711060SN/A send(ret ? "OK" : "E0C"); 8722292SN/A continue; 8732292SN/A 8741062SN/A case GDBSetHwBkpt: 8752292SN/A subcmd = *p++; 8761060SN/A if (*p++ != ',') send("E0D"); 8771061SN/A val = hex2i(&p); 8781060SN/A if (*p++ != ',') send("E0D"); 8796221Snate@binkert.org len = hex2i(&p); 8802292SN/A 8814033Sktlim@umich.edu DPRINTF(GDBMisc, "set %s, addr=%#x, len=%d\n", 8824033Sktlim@umich.edu break_type(subcmd), val, len); 8831061SN/A 8841060SN/A ret = false; 8851062SN/A 8861062SN/A switch (subcmd) { 8871062SN/A case '0': // software breakpoint 8882292SN/A ret = insertSoftBreak(val, len); 8891062SN/A break; 8901060SN/A 8912292SN/A case '1': // hardware breakpoint 8922292SN/A ret = insertHardBreak(val, len); 8931061SN/A break; 8941060SN/A 8951060SN/A case '2': // write watchpoint 8961061SN/A case '3': // read watchpoint 8971061SN/A case '4': // access watchpoint 8986221Snate@binkert.org default: // unknown 8992292SN/A send(""); 9002292SN/A break; 9012292SN/A } 9022292SN/A 9032292SN/A send(ret ? "OK" : "E0C"); 9042292SN/A continue; 9052292SN/A 9062292SN/A case GDBQueryVar: 9072292SN/A var = string(p, datalen - 1); 9082292SN/A if (var == "C") 9092292SN/A send("QC0"); 9102292SN/A else 9112292SN/A send(""); 9122292SN/A continue; 9132292SN/A 9142292SN/A case GDBSetBaud: 9152301SN/A case GDBSetBreak: 9161684SN/A case GDBDebug: 9171684SN/A case GDBCycleStep: 9182301SN/A case GDBSigCycleStep: 9192301SN/A case GDBReadReg: 9207897Shestness@cs.utexas.edu case GDBSetVar: 9217897Shestness@cs.utexas.edu case GDBReset: 9227897Shestness@cs.utexas.edu case GDBThreadAlive: 9237897Shestness@cs.utexas.edu case GDBTargetExit: 9247897Shestness@cs.utexas.edu case GDBBinaryDload: 9257897Shestness@cs.utexas.edu // Unsupported command 9267897Shestness@cs.utexas.edu DPRINTF(GDBMisc, "Unsupported command: %s\n", 9272292SN/A gdb_command(command)); 9282292SN/A DDUMP(GDBMisc, (uint8_t *)data, datalen); 9292292SN/A send(""); 9301684SN/A continue; 9311684SN/A 9322292SN/A default: 9332326SN/A // Unknown command. 9342326SN/A DPRINTF(GDBMisc, "Unknown command: %c(%#x)\n", 9352326SN/A command, command); 9362326SN/A send(""); 9371684SN/A continue; 9382292SN/A 9392292SN/A 9402292SN/A } 9412292SN/A } 9422292SN/A 9431684SN/A out: 9441684SN/A free(buffer); 9451684SN/A return true; 9461684SN/A} 9471684SN/A 9481684SN/A// Convert a hex digit into an integer. 9491684SN/A// This returns -1 if the argument passed is no valid hex digit. 9501684SN/Aint 9511684SN/ABaseRemoteGDB::digit2i(char c) 9521684SN/A{ 9531684SN/A if (c >= '0' && c <= '9') 9541684SN/A return (c - '0'); 9551684SN/A else if (c >= 'a' && c <= 'f') 9567599Sminkyu.jeong@arm.com return (c - 'a' + 10); 9577599Sminkyu.jeong@arm.com else if (c >= 'A' && c <= 'F') 9581684SN/A 9591684SN/A return (c - 'A' + 10); 9601684SN/A else 9612292SN/A return (-1); 9621684SN/A} 9631684SN/A 9642326SN/A// Convert the low 4 bits of an integer into an hex digit. 9652326SN/Achar 9662326SN/ABaseRemoteGDB::i2digit(int n) 9671684SN/A{ 9682326SN/A return ("0123456789abcdef"[n & 0x0f]); 9697599Sminkyu.jeong@arm.com} 9707720Sgblack@eecs.umich.edu 9711684SN/A// Convert a byte array into an hex string. 9721684SN/Avoid 9732326SN/ABaseRemoteGDB::mem2hex(void *vdst, const void *vsrc, int len) 9742326SN/A{ 9752326SN/A char *dst = (char *)vdst; 9762326SN/A const char *src = (const char *)vsrc; 9771684SN/A 9782326SN/A while (len--) { 9791684SN/A *dst++ = i2digit(*src >> 4); 9802326SN/A *dst++ = i2digit(*src++); 9811684SN/A } 9822301SN/A *dst = '\0'; 9831684SN/A} 9841684SN/A 9852326SN/A// Convert an hex string into a byte array. 9862326SN/A// This returns a pointer to the character following the last valid 9872326SN/A// hex digit. If the string ends in the middle of a byte, NULL is 9882326SN/A// returned. 9891684SN/Aconst char * 9901684SN/ABaseRemoteGDB::hex2mem(void *vdst, const char *src, int maxlen) 9911684SN/A{ 9921684SN/A char *dst = (char *)vdst; 9932301SN/A int msb, lsb; 9942064SN/A 9952064SN/A while (*src && maxlen--) { 9962064SN/A msb = digit2i(*src++); 9972064SN/A if (msb < 0) 9982292SN/A return (src - 1); 9992064SN/A lsb = digit2i(*src++); 10002292SN/A if (lsb < 0) 10012292SN/A return (NULL); 10022292SN/A *dst++ = (msb << 4) | lsb; 10032292SN/A } 10042326SN/A return (src); 10052326SN/A} 10062326SN/A 10072326SN/A// Convert an hex string into an integer. 10082326SN/A// This returns a pointer to the character following the last valid 10092326SN/A// hex digit. 10102326SN/AAddr 10112326SN/ABaseRemoteGDB::hex2i(const char **srcp) 10122326SN/A{ 10132326SN/A const char *src = *srcp; 10142292SN/A Addr r = 0; 10157720Sgblack@eecs.umich.edu int nibble; 10167720Sgblack@eecs.umich.edu 10172064SN/A while ((nibble = digit2i(*src)) >= 0) { 10182064SN/A r *= 16; 10192064SN/A r += nibble; 10202064SN/A src++; 10212292SN/A } 10222064SN/A *srcp = src; 10234033Sktlim@umich.edu return (r); 10244033Sktlim@umich.edu} 10252292SN/A 10262064SN/A