remote_gdb.cc revision 1762
12391SN/A/* 28931Sandreas.hansson@arm.com * Copyright (c) 2002-2005 The Regents of The University of Michigan 38931Sandreas.hansson@arm.com * All rights reserved. 48931Sandreas.hansson@arm.com * 58931Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without 68931Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are 78931Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright 88931Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer; 98931Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright 108931Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the 118931Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution; 128931Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its 132391SN/A * contributors may be used to endorse or promote products derived from 142391SN/A * this software without specific prior written permission. 152391SN/A * 162391SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172391SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182391SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192391SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202391SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212391SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222391SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232391SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242391SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252391SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262391SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272391SN/A */ 282391SN/A 292391SN/A/* 302391SN/A * Copyright (c) 1990, 1993 312391SN/A * The Regents of the University of California. All rights reserved. 322391SN/A * 332391SN/A * This software was developed by the Computer Systems Engineering group 342391SN/A * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 352391SN/A * contributed to Berkeley. 362665Ssaidi@eecs.umich.edu * 378931Sandreas.hansson@arm.com * All advertising materials mentioning features or use of this software 382391SN/A * must display the following acknowledgement: 392391SN/A * This product includes software developed by the University of 4010482Sandreas.hansson@arm.com * California, Lawrence Berkeley Laboratories. 4110482Sandreas.hansson@arm.com * 422391SN/A * Redistribution and use in source and binary forms, with or without 439235Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions 4410482Sandreas.hansson@arm.com * are met: 459293Sandreas.hansson@arm.com * 1. Redistributions of source code must retain the above copyright 469293Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer. 479293Sandreas.hansson@arm.com * 2. Redistributions in binary form must reproduce the above copyright 489293Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the 499293Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution. 504762Snate@binkert.org * 3. All advertising materials mentioning features or use of this software 518931Sandreas.hansson@arm.com * must display the following acknowledgement: 528931Sandreas.hansson@arm.com * This product includes software developed by the University of 538931Sandreas.hansson@arm.com * California, Berkeley and its contributors. 548931Sandreas.hansson@arm.com * 4. Neither the name of the University nor the names of its contributors 559293Sandreas.hansson@arm.com * may be used to endorse or promote products derived from this software 569293Sandreas.hansson@arm.com * without specific prior written permission. 579293Sandreas.hansson@arm.com * 589293Sandreas.hansson@arm.com * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 599293Sandreas.hansson@arm.com * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 6010482Sandreas.hansson@arm.com * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 619293Sandreas.hansson@arm.com * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 629293Sandreas.hansson@arm.com * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 639293Sandreas.hansson@arm.com * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 649293Sandreas.hansson@arm.com * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 659293Sandreas.hansson@arm.com * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 668931Sandreas.hansson@arm.com * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 679293Sandreas.hansson@arm.com * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 682391SN/A * SUCH DAMAGE. 692413SN/A * 702391SN/A * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94 712391SN/A */ 729293Sandreas.hansson@arm.com 739293Sandreas.hansson@arm.com/*- 749293Sandreas.hansson@arm.com * Copyright (c) 2001 The NetBSD Foundation, Inc. 758931Sandreas.hansson@arm.com * All rights reserved. 769235Sandreas.hansson@arm.com * 773170Sstever@eecs.umich.edu * This code is derived from software contributed to The NetBSD Foundation 7810699Sandreas.hansson@arm.com * by Jason R. Thorpe. 7910699Sandreas.hansson@arm.com * 8010699Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without 813170Sstever@eecs.umich.edu * modification, are permitted provided that the following conditions 828931Sandreas.hansson@arm.com * are met: 838931Sandreas.hansson@arm.com * 1. Redistributions of source code must retain the above copyright 843170Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer. 858931Sandreas.hansson@arm.com * 2. Redistributions in binary form must reproduce the above copyright 868931Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the 873170Sstever@eecs.umich.edu * documentation and/or other materials provided with the distribution. 8810700Sandreas.hansson@arm.com * 3. All advertising materials mentioning features or use of this software 8910700Sandreas.hansson@arm.com * must display the following acknowledgement: 9010700Sandreas.hansson@arm.com * This product includes software developed by the NetBSD 919293Sandreas.hansson@arm.com * Foundation, Inc. and its contributors. 929293Sandreas.hansson@arm.com * 4. Neither the name of The NetBSD Foundation nor the names of its 9310482Sandreas.hansson@arm.com * contributors may be used to endorse or promote products derived 949293Sandreas.hansson@arm.com * from this software without specific prior written permission. 958931Sandreas.hansson@arm.com * 968931Sandreas.hansson@arm.com * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 973170Sstever@eecs.umich.edu * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 988931Sandreas.hansson@arm.com * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 998931Sandreas.hansson@arm.com * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 1008719SAli.Saidi@ARM.com * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1019293Sandreas.hansson@arm.com * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1029293Sandreas.hansson@arm.com * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1039293Sandreas.hansson@arm.com * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1049293Sandreas.hansson@arm.com * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1059293Sandreas.hansson@arm.com * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 1069293Sandreas.hansson@arm.com * POSSIBILITY OF SUCH DAMAGE. 1079293Sandreas.hansson@arm.com */ 1089293Sandreas.hansson@arm.com 1099293Sandreas.hansson@arm.com/* 1109293Sandreas.hansson@arm.com * $NetBSD: kgdb_stub.c,v 1.8 2001/07/07 22:58:00 wdk Exp $ 1119293Sandreas.hansson@arm.com * 1122391SN/A * Taken from NetBSD 1132391SN/A * 1148931Sandreas.hansson@arm.com * "Stub" to allow remote cpu to debug over a serial line using gdb. 1158931Sandreas.hansson@arm.com */ 1168931Sandreas.hansson@arm.com 1179293Sandreas.hansson@arm.com#include <sys/signal.h> 11810700Sandreas.hansson@arm.com 11910700Sandreas.hansson@arm.com#include <cstdio> 1202391SN/A#include <string> 1218931Sandreas.hansson@arm.com#include <unistd.h> 1229293Sandreas.hansson@arm.com 1238931Sandreas.hansson@arm.com#include "base/intmath.hh" 1249293Sandreas.hansson@arm.com#include "base/kgdb.h" 1259293Sandreas.hansson@arm.com#include "base/remote_gdb.hh" 1269293Sandreas.hansson@arm.com#include "base/socket.hh" 1279293Sandreas.hansson@arm.com#include "base/trace.hh" 1289293Sandreas.hansson@arm.com#include "cpu/exec_context.hh" 1299293Sandreas.hansson@arm.com#include "cpu/static_inst.hh" 1309293Sandreas.hansson@arm.com#include "mem/functional/physical.hh" 1314762Snate@binkert.org#include "sim/system.hh" 1328931Sandreas.hansson@arm.com#include "targetarch/vtophys.hh" 1338931Sandreas.hansson@arm.com 1348931Sandreas.hansson@arm.comusing namespace std; 1358931Sandreas.hansson@arm.com 1368931Sandreas.hansson@arm.com#ifdef DEBUG 1378931Sandreas.hansson@arm.comRemoteGDB *theDebugger = NULL; 1388931Sandreas.hansson@arm.com 1398931Sandreas.hansson@arm.comvoid 1402391SN/Adebugger() 1418931Sandreas.hansson@arm.com{ 1428931Sandreas.hansson@arm.com if (theDebugger) 1439413Sandreas.hansson@arm.com theDebugger->trap(ALPHA_KENTRY_IF); 1449413Sandreas.hansson@arm.com} 1459413Sandreas.hansson@arm.com#endif 1468931Sandreas.hansson@arm.com 1478931Sandreas.hansson@arm.com/////////////////////////////////////////////////////////// 1488931Sandreas.hansson@arm.com// 1498931Sandreas.hansson@arm.com// 1508923Sandreas.hansson@arm.com// 1518931Sandreas.hansson@arm.com 1528931Sandreas.hansson@arm.comGDBListener::Event::Event(GDBListener *l, int fd, int e) 1538931Sandreas.hansson@arm.com : PollEvent(fd, e), listener(l) 1548931Sandreas.hansson@arm.com{} 1558931Sandreas.hansson@arm.com 1568931Sandreas.hansson@arm.comvoid 1578923Sandreas.hansson@arm.comGDBListener::Event::process(int revent) 1589293Sandreas.hansson@arm.com{ 1599293Sandreas.hansson@arm.com listener->accept(); 1609293Sandreas.hansson@arm.com} 1619293Sandreas.hansson@arm.com 1629293Sandreas.hansson@arm.comGDBListener::GDBListener(RemoteGDB *g, int p) 1639293Sandreas.hansson@arm.com : event(NULL), gdb(g), port(p) 1649293Sandreas.hansson@arm.com{} 1659293Sandreas.hansson@arm.com 1669293Sandreas.hansson@arm.comGDBListener::~GDBListener() 1679293Sandreas.hansson@arm.com{ 1689293Sandreas.hansson@arm.com if (event) 1699293Sandreas.hansson@arm.com delete event; 17010482Sandreas.hansson@arm.com} 1719293Sandreas.hansson@arm.com 1729293Sandreas.hansson@arm.comstring 1738931Sandreas.hansson@arm.comGDBListener::name() 1749293Sandreas.hansson@arm.com{ 1759293Sandreas.hansson@arm.com return gdb->name() + ".listener"; 1769293Sandreas.hansson@arm.com} 1778931Sandreas.hansson@arm.com 1789293Sandreas.hansson@arm.comvoid 1798719SAli.Saidi@ARM.comGDBListener::listen() 1808931Sandreas.hansson@arm.com{ 1819293Sandreas.hansson@arm.com while (!listener.listen(port, true)) { 1829293Sandreas.hansson@arm.com DPRINTF(GDBMisc, "Can't bind port %d\n", port); 1839293Sandreas.hansson@arm.com port++; 1849293Sandreas.hansson@arm.com } 1859293Sandreas.hansson@arm.com 1869293Sandreas.hansson@arm.com cerr << "Listening for remote gdb connection on port " << port << endl; 1879293Sandreas.hansson@arm.com event = new Event(this, listener.getfd(), POLLIN); 1889293Sandreas.hansson@arm.com pollQueue.schedule(event); 1899293Sandreas.hansson@arm.com} 1908931Sandreas.hansson@arm.com 1919293Sandreas.hansson@arm.comvoid 1929293Sandreas.hansson@arm.comGDBListener::accept() 1939293Sandreas.hansson@arm.com{ 1949293Sandreas.hansson@arm.com if (!listener.islistening()) 1959293Sandreas.hansson@arm.com panic("GDBListener::accept(): cannot accept if we're not listening!"); 1969293Sandreas.hansson@arm.com 1979293Sandreas.hansson@arm.com int sfd = listener.accept(true); 1989293Sandreas.hansson@arm.com 1999293Sandreas.hansson@arm.com if (sfd != -1) { 20010905Sandreas.sandberg@arm.com if (gdb->isattached()) 2019293Sandreas.hansson@arm.com close(sfd); 2029293Sandreas.hansson@arm.com else 2039293Sandreas.hansson@arm.com gdb->attach(sfd); 2049293Sandreas.hansson@arm.com } 2059293Sandreas.hansson@arm.com} 2069293Sandreas.hansson@arm.com 2079293Sandreas.hansson@arm.com/////////////////////////////////////////////////////////// 2089293Sandreas.hansson@arm.com// 20910905Sandreas.sandberg@arm.com// 21010905Sandreas.sandberg@arm.com// 2119293Sandreas.hansson@arm.comint digit2i(char); 2129293Sandreas.hansson@arm.comchar i2digit(int); 2139293Sandreas.hansson@arm.comvoid mem2hex(void *, const void *, int); 2149293Sandreas.hansson@arm.comconst char *hex2mem(void *, const char *, int); 2159293Sandreas.hansson@arm.comAddr hex2i(const char **); 2169293Sandreas.hansson@arm.com 21710905Sandreas.sandberg@arm.comRemoteGDB::Event::Event(RemoteGDB *g, int fd, int e) 2189293Sandreas.hansson@arm.com : PollEvent(fd, e), gdb(g) 2199293Sandreas.hansson@arm.com{} 2209293Sandreas.hansson@arm.com 2219293Sandreas.hansson@arm.comvoid 22210905Sandreas.sandberg@arm.comRemoteGDB::Event::process(int revent) 2239293Sandreas.hansson@arm.com{ 2242391SN/A if (revent & POLLIN) 2252391SN/A gdb->trap(ALPHA_KENTRY_IF); 22610482Sandreas.hansson@arm.com else if (revent & POLLNVAL) 227 gdb->detach(); 228} 229 230RemoteGDB::RemoteGDB(System *_system, ExecContext *c) 231 : event(NULL), fd(-1), active(false), attached(false), 232 system(_system), pmem(_system->physmem), context(c) 233{ 234 memset(gdbregs, 0, sizeof(gdbregs)); 235} 236 237RemoteGDB::~RemoteGDB() 238{ 239 if (event) 240 delete event; 241} 242 243string 244RemoteGDB::name() 245{ 246 return system->name() + ".remote_gdb"; 247} 248 249bool 250RemoteGDB::isattached() 251{ return attached; } 252 253void 254RemoteGDB::attach(int f) 255{ 256 fd = f; 257 258 event = new Event(this, fd, POLLIN); 259 pollQueue.schedule(event); 260 261 attached = true; 262 DPRINTFN("remote gdb attached\n"); 263#ifdef DEBUG 264 theDebugger = this; 265#endif 266} 267 268void 269RemoteGDB::detach() 270{ 271 attached = false; 272 close(fd); 273 fd = -1; 274 275 pollQueue.remove(event); 276 DPRINTFN("remote gdb detached\n"); 277} 278 279const char * 280gdb_command(char cmd) 281{ 282 switch (cmd) { 283 case KGDB_SIGNAL: return "KGDB_SIGNAL"; 284 case KGDB_SET_BAUD: return "KGDB_SET_BAUD"; 285 case KGDB_SET_BREAK: return "KGDB_SET_BREAK"; 286 case KGDB_CONT: return "KGDB_CONT"; 287 case KGDB_ASYNC_CONT: return "KGDB_ASYNC_CONT"; 288 case KGDB_DEBUG: return "KGDB_DEBUG"; 289 case KGDB_DETACH: return "KGDB_DETACH"; 290 case KGDB_REG_R: return "KGDB_REG_R"; 291 case KGDB_REG_W: return "KGDB_REG_W"; 292 case KGDB_SET_THREAD: return "KGDB_SET_THREAD"; 293 case KGDB_CYCLE_STEP: return "KGDB_CYCLE_STEP"; 294 case KGDB_SIG_CYCLE_STEP: return "KGDB_SIG_CYCLE_STEP"; 295 case KGDB_KILL: return "KGDB_KILL"; 296 case KGDB_MEM_W: return "KGDB_MEM_W"; 297 case KGDB_MEM_R: return "KGDB_MEM_R"; 298 case KGDB_SET_REG: return "KGDB_SET_REG"; 299 case KGDB_READ_REG: return "KGDB_READ_REG"; 300 case KGDB_QUERY_VAR: return "KGDB_QUERY_VAR"; 301 case KGDB_SET_VAR: return "KGDB_SET_VAR"; 302 case KGDB_RESET: return "KGDB_RESET"; 303 case KGDB_STEP: return "KGDB_STEP"; 304 case KGDB_ASYNC_STEP: return "KGDB_ASYNC_STEP"; 305 case KGDB_THREAD_ALIVE: return "KGDB_THREAD_ALIVE"; 306 case KGDB_TARGET_EXIT: return "KGDB_TARGET_EXIT"; 307 case KGDB_BINARY_DLOAD: return "KGDB_BINARY_DLOAD"; 308 case KGDB_CLR_HW_BKPT: return "KGDB_CLR_HW_BKPT"; 309 case KGDB_SET_HW_BKPT: return "KGDB_SET_HW_BKPT"; 310 case KGDB_START: return "KGDB_START"; 311 case KGDB_END: return "KGDB_END"; 312 case KGDB_GOODP: return "KGDB_GOODP"; 313 case KGDB_BADP: return "KGDB_BADP"; 314 default: return "KGDB_UNKNOWN"; 315 } 316} 317 318/////////////////////////////////////////////////////////// 319// RemoteGDB::acc 320// 321// Determine if the mapping at va..(va+len) is valid. 322// 323bool 324RemoteGDB::acc(Addr va, size_t len) 325{ 326 Addr last_va; 327 328 va = TheISA::TruncPage(va); 329 last_va = TheISA::RoundPage(va + len); 330 331 do { 332 if (TheISA::IsK0Seg(va)) { 333 if (va < (TheISA::K0SegBase + pmem->size())) { 334 DPRINTF(GDBAcc, "acc: Mapping is valid K0SEG <= " 335 "%#x < K0SEG + size\n", va); 336 return true; 337 } else { 338 DPRINTF(GDBAcc, "acc: Mapping invalid %#x > K0SEG + size\n", 339 va); 340 return false; 341 } 342 } 343 344 /** 345 * This code says that all accesses to palcode (instruction and data) 346 * are valid since there isn't a va->pa mapping because palcode is 347 * accessed physically. At some point this should probably be cleaned up 348 * but there is no easy way to do it. 349 */ 350 351 if (AlphaISA::PcPAL(va) || va < 0x10000) 352 return true; 353 354 Addr ptbr = context->regs.ipr[AlphaISA::IPR_PALtemp20]; 355 TheISA::PageTableEntry pte = kernel_pte_lookup(pmem, ptbr, va); 356 if (!pte.valid()) { 357 DPRINTF(GDBAcc, "acc: %#x pte is invalid\n", va); 358 return false; 359 } 360 va += TheISA::PageBytes; 361 } while (va < last_va); 362 363 DPRINTF(GDBAcc, "acc: %#x mapping is valid\n", va); 364 return true; 365} 366 367/////////////////////////////////////////////////////////// 368// RemoteGDB::signal 369// 370// Translate a trap number into a Unix-compatible signal number. 371// (GDB only understands Unix signal numbers.) 372// 373int 374RemoteGDB::signal(int type) 375{ 376 switch (type) { 377 case ALPHA_KENTRY_INT: 378 return (SIGTRAP); 379 380 case ALPHA_KENTRY_UNA: 381 return (SIGBUS); 382 383 case ALPHA_KENTRY_ARITH: 384 return (SIGFPE); 385 386 case ALPHA_KENTRY_IF: 387 return (SIGILL); 388 389 case ALPHA_KENTRY_MM: 390 return (SIGSEGV); 391 392 default: 393 panic("unknown signal type"); 394 return 0; 395 } 396} 397 398/////////////////////////////////////////////////////////// 399// RemoteGDB::getregs 400// 401// Translate the kernel debugger register format into 402// the GDB register format. 403void 404RemoteGDB::getregs() 405{ 406 memset(gdbregs, 0, sizeof(gdbregs)); 407 memcpy(&gdbregs[KGDB_REG_V0], context->regs.intRegFile, 32 * sizeof(uint64_t)); 408#ifdef KGDB_FP_REGS 409 memcpy(&gdbregs[KGDB_REG_F0], context->regs.floatRegFile.q, 410 32 * sizeof(uint64_t)); 411#endif 412 gdbregs[KGDB_REG_PC] = context->regs.pc; 413} 414 415/////////////////////////////////////////////////////////// 416// RemoteGDB::setregs 417// 418// Translate the GDB register format into the kernel 419// debugger register format. 420// 421void 422RemoteGDB::setregs() 423{ 424 memcpy(context->regs.intRegFile, &gdbregs[KGDB_REG_V0], 425 32 * sizeof(uint64_t)); 426#ifdef KGDB_FP_REGS 427 memcpy(context->regs.floatRegFile.q, &gdbregs[KGDB_REG_F0], 428 32 * sizeof(uint64_t)); 429#endif 430 context->regs.pc = gdbregs[KGDB_REG_PC]; 431} 432 433void 434RemoteGDB::setTempBreakpoint(TempBreakpoint &bkpt, Addr addr) 435{ 436 DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", addr); 437 438 bkpt.address = addr; 439 insertHardBreak(addr, 4); 440} 441 442void 443RemoteGDB::clearTempBreakpoint(TempBreakpoint &bkpt) 444{ 445 DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", 446 bkpt.address); 447 448 449 removeHardBreak(bkpt.address, 4); 450 bkpt.address = 0; 451} 452 453void 454RemoteGDB::clearSingleStep() 455{ 456 DPRINTF(GDBMisc, "clearSingleStep bt_addr=%#x nt_addr=%#x\n", 457 takenBkpt.address, notTakenBkpt.address); 458 459 if (takenBkpt.address != 0) 460 clearTempBreakpoint(takenBkpt); 461 462 if (notTakenBkpt.address != 0) 463 clearTempBreakpoint(notTakenBkpt); 464} 465 466void 467RemoteGDB::setSingleStep() 468{ 469 Addr pc = context->regs.pc; 470 Addr npc, bpc; 471 bool set_bt = false; 472 473 npc = pc + sizeof(MachInst); 474 475 // User was stopped at pc, e.g. the instruction at pc was not 476 // executed. 477 MachInst inst = read<MachInst>(pc); 478 StaticInstPtr<TheISA> si(inst); 479 if (si->hasBranchTarget(pc, context, bpc)) { 480 // Don't bother setting a breakpoint on the taken branch if it 481 // is the same as the next pc 482 if (bpc != npc) 483 set_bt = true; 484 } 485 486 DPRINTF(GDBMisc, "setSingleStep bt_addr=%#x nt_addr=%#x\n", 487 takenBkpt.address, notTakenBkpt.address); 488 489 setTempBreakpoint(notTakenBkpt, npc); 490 491 if (set_bt) 492 setTempBreakpoint(takenBkpt, bpc); 493} 494 495///////////////////////// 496// 497// 498 499uint8_t 500RemoteGDB::getbyte() 501{ 502 uint8_t b; 503 ::read(fd, &b, 1); 504 return b; 505} 506 507void 508RemoteGDB::putbyte(uint8_t b) 509{ 510 ::write(fd, &b, 1); 511} 512 513// Send a packet to gdb 514void 515RemoteGDB::send(const char *bp) 516{ 517 const char *p; 518 uint8_t csum, c; 519 520 DPRINTF(GDBSend, "send: %s\n", bp); 521 522 do { 523 p = bp; 524 putbyte(KGDB_START); 525 for (csum = 0; (c = *p); p++) { 526 putbyte(c); 527 csum += c; 528 } 529 putbyte(KGDB_END); 530 putbyte(i2digit(csum >> 4)); 531 putbyte(i2digit(csum)); 532 } while ((c = getbyte() & 0x7f) == KGDB_BADP); 533} 534 535// Receive a packet from gdb 536int 537RemoteGDB::recv(char *bp, int maxlen) 538{ 539 char *p; 540 int c, csum; 541 int len; 542 543 do { 544 p = bp; 545 csum = len = 0; 546 while ((c = getbyte()) != KGDB_START) 547 ; 548 549 while ((c = getbyte()) != KGDB_END && len < maxlen) { 550 c &= 0x7f; 551 csum += c; 552 *p++ = c; 553 len++; 554 } 555 csum &= 0xff; 556 *p = '\0'; 557 558 if (len >= maxlen) { 559 putbyte(KGDB_BADP); 560 continue; 561 } 562 563 csum -= digit2i(getbyte()) * 16; 564 csum -= digit2i(getbyte()); 565 566 if (csum == 0) { 567 putbyte(KGDB_GOODP); 568 // Sequence present? 569 if (bp[2] == ':') { 570 putbyte(bp[0]); 571 putbyte(bp[1]); 572 len -= 3; 573 bcopy(bp + 3, bp, len); 574 } 575 break; 576 } 577 putbyte(KGDB_BADP); 578 } while (1); 579 580 DPRINTF(GDBRecv, "recv: %s: %s\n", gdb_command(*bp), bp); 581 582 return (len); 583} 584 585// Read bytes from kernel address space for debugger. 586bool 587RemoteGDB::read(Addr vaddr, size_t size, char *data) 588{ 589 static Addr lastaddr = 0; 590 static size_t lastsize = 0; 591 592 uint8_t *maddr; 593 594 if (vaddr < 10) { 595 DPRINTF(GDBRead, "read: reading memory location zero!\n"); 596 vaddr = lastaddr + lastsize; 597 } 598 599 DPRINTF(GDBRead, "read: addr=%#x, size=%d", vaddr, size); 600#if TRACING_ON 601 char *d = data; 602 size_t s = size; 603#endif 604 605 lastaddr = vaddr; 606 lastsize = size; 607 608 size_t count = min((Addr)size, 609 VMPageSize - (vaddr & (VMPageSize - 1))); 610 611 maddr = vtomem(context, vaddr, count); 612 memcpy(data, maddr, count); 613 614 vaddr += count; 615 data += count; 616 size -= count; 617 618 while (size >= VMPageSize) { 619 maddr = vtomem(context, vaddr, count); 620 memcpy(data, maddr, VMPageSize); 621 622 vaddr += VMPageSize; 623 data += VMPageSize; 624 size -= VMPageSize; 625 } 626 627 if (size > 0) { 628 maddr = vtomem(context, vaddr, count); 629 memcpy(data, maddr, size); 630 } 631 632#if TRACING_ON 633 if (DTRACE(GDBRead)) { 634 if (DTRACE(GDBExtra)) { 635 char buf[1024]; 636 mem2hex(buf, d, s); 637 DPRINTFNR(": %s\n", buf); 638 } else 639 DPRINTFNR("\n"); 640 } 641#endif 642 643 return true; 644} 645 646// Write bytes to kernel address space for debugger. 647bool 648RemoteGDB::write(Addr vaddr, size_t size, const char *data) 649{ 650 static Addr lastaddr = 0; 651 static size_t lastsize = 0; 652 653 uint8_t *maddr; 654 655 if (vaddr < 10) { 656 DPRINTF(GDBWrite, "write: writing memory location zero!\n"); 657 vaddr = lastaddr + lastsize; 658 } 659 660 if (DTRACE(GDBWrite)) { 661 DPRINTFN("write: addr=%#x, size=%d", vaddr, size); 662 if (DTRACE(GDBExtra)) { 663 char buf[1024]; 664 mem2hex(buf, data, size); 665 DPRINTFNR(": %s\n", buf); 666 } else 667 DPRINTFNR("\n"); 668 } 669 670 lastaddr = vaddr; 671 lastsize = size; 672 673 size_t count = min((Addr)size, 674 VMPageSize - (vaddr & (VMPageSize - 1))); 675 676 maddr = vtomem(context, vaddr, count); 677 memcpy(maddr, data, count); 678 679 vaddr += count; 680 data += count; 681 size -= count; 682 683 while (size >= VMPageSize) { 684 maddr = vtomem(context, vaddr, count); 685 memcpy(maddr, data, VMPageSize); 686 687 vaddr += VMPageSize; 688 data += VMPageSize; 689 size -= VMPageSize; 690 } 691 692 if (size > 0) { 693 maddr = vtomem(context, vaddr, count); 694 memcpy(maddr, data, size); 695 } 696 697#ifdef IMB 698 alpha_pal_imb(); 699#endif 700 701 return true; 702} 703 704 705PCEventQueue *RemoteGDB::getPcEventQueue() 706{ 707 return &system->pcEventQueue; 708} 709 710 711RemoteGDB::HardBreakpoint::HardBreakpoint(RemoteGDB *_gdb, Addr pc) 712 : PCEvent(_gdb->getPcEventQueue(), "HardBreakpoint Event", pc), 713 gdb(_gdb), refcount(0) 714{ 715 DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc); 716 schedule(); 717} 718 719void 720RemoteGDB::HardBreakpoint::process(ExecContext *xc) 721{ 722 DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc()); 723 724 if (xc == gdb->context) 725 gdb->trap(ALPHA_KENTRY_INT); 726} 727 728bool 729RemoteGDB::insertSoftBreak(Addr addr, size_t len) 730{ 731 if (len != sizeof(MachInst)) 732 panic("invalid length\n"); 733 734 return insertHardBreak(addr, len); 735} 736 737bool 738RemoteGDB::removeSoftBreak(Addr addr, size_t len) 739{ 740 if (len != sizeof(MachInst)) 741 panic("invalid length\n"); 742 743 return removeHardBreak(addr, len); 744} 745 746bool 747RemoteGDB::insertHardBreak(Addr addr, size_t len) 748{ 749 if (len != sizeof(MachInst)) 750 panic("invalid length\n"); 751 752 DPRINTF(GDBMisc, "inserting hardware breakpoint at %#x\n", addr); 753 754 HardBreakpoint *&bkpt = hardBreakMap[addr]; 755 if (bkpt == 0) 756 bkpt = new HardBreakpoint(this, addr); 757 758 bkpt->refcount++; 759 760 return true; 761} 762 763bool 764RemoteGDB::removeHardBreak(Addr addr, size_t len) 765{ 766 if (len != sizeof(MachInst)) 767 panic("invalid length\n"); 768 769 DPRINTF(GDBMisc, "removing hardware breakpoint at %#x\n", addr); 770 771 break_iter_t i = hardBreakMap.find(addr); 772 if (i == hardBreakMap.end()) 773 return false; 774 775 HardBreakpoint *hbp = (*i).second; 776 if (--hbp->refcount == 0) { 777 delete hbp; 778 hardBreakMap.erase(i); 779 } 780 781 return true; 782} 783 784const char * 785break_type(char c) 786{ 787 switch(c) { 788 case '0': return "software breakpoint"; 789 case '1': return "hardware breakpoint"; 790 case '2': return "write watchpoint"; 791 case '3': return "read watchpoint"; 792 case '4': return "access watchpoint"; 793 default: return "unknown breakpoint/watchpoint"; 794 } 795} 796 797// This function does all command processing for interfacing to a 798// remote gdb. Note that the error codes are ignored by gdb at 799// present, but might eventually become meaningful. (XXX) It might 800// makes sense to use POSIX errno values, because that is what the 801// gdb/remote.c functions want to return. 802bool 803RemoteGDB::trap(int type) 804{ 805 uint64_t val; 806 size_t datalen, len; 807 char data[KGDB_BUFLEN + 1]; 808 char buffer[sizeof(gdbregs) * 2 + 256]; 809 char temp[KGDB_BUFLEN]; 810 const char *p; 811 char command, subcmd; 812 string var; 813 bool ret; 814 815 if (!attached) 816 return false; 817 818 DPRINTF(GDBMisc, "trap: PC=%#x NPC=%#x\n", 819 context->regs.pc, context->regs.npc); 820 821 clearSingleStep(); 822 823 /* 824 * The first entry to this function is normally through 825 * a breakpoint trap in kgdb_connect(), in which case we 826 * must advance past the breakpoint because gdb will not. 827 * 828 * On the first entry here, we expect that gdb is not yet 829 * listening to us, so just enter the interaction loop. 830 * After the debugger is "active" (connected) it will be 831 * waiting for a "signaled" message from us. 832 */ 833 if (!active) 834 active = true; 835 else 836 // Tell remote host that an exception has occurred. 837 sprintf((char *)buffer, "S%02x", signal(type)); 838 send(buffer); 839 840 // Stick frame regs into our reg cache. 841 getregs(); 842 843 for (;;) { 844 datalen = recv(data, sizeof(data)); 845 data[sizeof(data) - 1] = 0; // Sentinel 846 command = data[0]; 847 subcmd = 0; 848 p = data + 1; 849 switch (command) { 850 851 case KGDB_SIGNAL: 852 // if this command came from a running gdb, answer it -- 853 // the other guy has no way of knowing if we're in or out 854 // of this loop when he issues a "remote-signal". 855 sprintf((char *)buffer, "S%02x", signal(type)); 856 send(buffer); 857 continue; 858 859 case KGDB_REG_R: 860 if (2 * sizeof(gdbregs) > sizeof(buffer)) 861 panic("buffer too small"); 862 863 mem2hex(buffer, gdbregs, sizeof(gdbregs)); 864 send(buffer); 865 continue; 866 867 case KGDB_REG_W: 868 p = hex2mem(gdbregs, p, sizeof(gdbregs)); 869 if (p == NULL || *p != '\0') 870 send("E01"); 871 else { 872 setregs(); 873 send("OK"); 874 } 875 continue; 876 877#if 0 878 case KGDB_SET_REG: 879 val = hex2i(&p); 880 if (*p++ != '=') { 881 send("E01"); 882 continue; 883 } 884 if (val < 0 && val >= KGDB_NUMREGS) { 885 send("E01"); 886 continue; 887 } 888 889 gdbregs[val] = hex2i(&p); 890 setregs(); 891 send("OK"); 892 893 continue; 894#endif 895 896 case KGDB_MEM_R: 897 val = hex2i(&p); 898 if (*p++ != ',') { 899 send("E02"); 900 continue; 901 } 902 len = hex2i(&p); 903 if (*p != '\0') { 904 send("E03"); 905 continue; 906 } 907 if (len > sizeof(buffer)) { 908 send("E04"); 909 continue; 910 } 911 if (!acc(val, len)) { 912 send("E05"); 913 continue; 914 } 915 916 if (read(val, (size_t)len, (char *)buffer)) { 917 mem2hex(temp, buffer, len); 918 send(temp); 919 } else { 920 send("E05"); 921 } 922 continue; 923 924 case KGDB_MEM_W: 925 val = hex2i(&p); 926 if (*p++ != ',') { 927 send("E06"); 928 continue; 929 } 930 len = hex2i(&p); 931 if (*p++ != ':') { 932 send("E07"); 933 continue; 934 } 935 if (len > datalen - (p - data)) { 936 send("E08"); 937 continue; 938 } 939 p = hex2mem(buffer, p, sizeof(buffer)); 940 if (p == NULL) { 941 send("E09"); 942 continue; 943 } 944 if (!acc(val, len)) { 945 send("E0A"); 946 continue; 947 } 948 if (write(val, (size_t)len, (char *)buffer)) 949 send("OK"); 950 else 951 send("E0B"); 952 continue; 953 954 case KGDB_SET_THREAD: 955 subcmd = *p++; 956 val = hex2i(&p); 957 if (val == 0) 958 send("OK"); 959 else 960 send("E01"); 961 continue; 962 963 case KGDB_DETACH: 964 case KGDB_KILL: 965 active = false; 966 clearSingleStep(); 967 detach(); 968 goto out; 969 970 case KGDB_ASYNC_CONT: 971 subcmd = hex2i(&p); 972 if (*p++ == ';') { 973 val = hex2i(&p); 974 context->regs.pc = val; 975 context->regs.npc = val + sizeof(MachInst); 976 } 977 clearSingleStep(); 978 goto out; 979 980 case KGDB_CONT: 981 if (p - data < datalen) { 982 val = hex2i(&p); 983 context->regs.pc = val; 984 context->regs.npc = val + sizeof(MachInst); 985 } 986 clearSingleStep(); 987 goto out; 988 989 case KGDB_ASYNC_STEP: 990 subcmd = hex2i(&p); 991 if (*p++ == ';') { 992 val = hex2i(&p); 993 context->regs.pc = val; 994 context->regs.npc = val + sizeof(MachInst); 995 } 996 setSingleStep(); 997 goto out; 998 999 case KGDB_STEP: 1000 if (p - data < datalen) { 1001 val = hex2i(&p); 1002 context->regs.pc = val; 1003 context->regs.npc = val + sizeof(MachInst); 1004 } 1005 setSingleStep(); 1006 goto out; 1007 1008 case KGDB_CLR_HW_BKPT: 1009 subcmd = *p++; 1010 if (*p++ != ',') send("E0D"); 1011 val = hex2i(&p); 1012 if (*p++ != ',') send("E0D"); 1013 len = hex2i(&p); 1014 1015 DPRINTF(GDBMisc, "clear %s, addr=%#x, len=%d\n", 1016 break_type(subcmd), val, len); 1017 1018 ret = false; 1019 1020 switch (subcmd) { 1021 case '0': // software breakpoint 1022 ret = removeSoftBreak(val, len); 1023 break; 1024 1025 case '1': // hardware breakpoint 1026 ret = removeHardBreak(val, len); 1027 break; 1028 1029 case '2': // write watchpoint 1030 case '3': // read watchpoint 1031 case '4': // access watchpoint 1032 default: // unknown 1033 send(""); 1034 break; 1035 } 1036 1037 send(ret ? "OK" : "E0C"); 1038 continue; 1039 1040 case KGDB_SET_HW_BKPT: 1041 subcmd = *p++; 1042 if (*p++ != ',') send("E0D"); 1043 val = hex2i(&p); 1044 if (*p++ != ',') send("E0D"); 1045 len = hex2i(&p); 1046 1047 DPRINTF(GDBMisc, "set %s, addr=%#x, len=%d\n", 1048 break_type(subcmd), val, len); 1049 1050 ret = false; 1051 1052 switch (subcmd) { 1053 case '0': // software breakpoint 1054 ret = insertSoftBreak(val, len); 1055 break; 1056 1057 case '1': // hardware breakpoint 1058 ret = insertHardBreak(val, len); 1059 break; 1060 1061 case '2': // write watchpoint 1062 case '3': // read watchpoint 1063 case '4': // access watchpoint 1064 default: // unknown 1065 send(""); 1066 break; 1067 } 1068 1069 send(ret ? "OK" : "E0C"); 1070 continue; 1071 1072 case KGDB_QUERY_VAR: 1073 var = string(p, datalen - 1); 1074 if (var == "C") 1075 send("QC0"); 1076 else 1077 send(""); 1078 continue; 1079 1080 case KGDB_SET_BAUD: 1081 case KGDB_SET_BREAK: 1082 case KGDB_DEBUG: 1083 case KGDB_CYCLE_STEP: 1084 case KGDB_SIG_CYCLE_STEP: 1085 case KGDB_READ_REG: 1086 case KGDB_SET_VAR: 1087 case KGDB_RESET: 1088 case KGDB_THREAD_ALIVE: 1089 case KGDB_TARGET_EXIT: 1090 case KGDB_BINARY_DLOAD: 1091 // Unsupported command 1092 DPRINTF(GDBMisc, "Unsupported command: %s\n", 1093 gdb_command(command)); 1094 DDUMP(GDBMisc, (uint8_t *)data, datalen); 1095 send(""); 1096 continue; 1097 1098 default: 1099 // Unknown command. 1100 DPRINTF(GDBMisc, "Unknown command: %c(%#x)\n", 1101 command, command); 1102 send(""); 1103 continue; 1104 1105 1106 } 1107 } 1108 1109 out: 1110 return true; 1111} 1112 1113// Convert a hex digit into an integer. 1114// This returns -1 if the argument passed is no valid hex digit. 1115int 1116digit2i(char c) 1117{ 1118 if (c >= '0' && c <= '9') 1119 return (c - '0'); 1120 else if (c >= 'a' && c <= 'f') 1121 return (c - 'a' + 10); 1122 else if (c >= 'A' && c <= 'F') 1123 1124 return (c - 'A' + 10); 1125 else 1126 return (-1); 1127} 1128 1129// Convert the low 4 bits of an integer into an hex digit. 1130char 1131i2digit(int n) 1132{ 1133 return ("0123456789abcdef"[n & 0x0f]); 1134} 1135 1136// Convert a byte array into an hex string. 1137void 1138mem2hex(void *vdst, const void *vsrc, int len) 1139{ 1140 char *dst = (char *)vdst; 1141 const char *src = (const char *)vsrc; 1142 1143 while (len--) { 1144 *dst++ = i2digit(*src >> 4); 1145 *dst++ = i2digit(*src++); 1146 } 1147 *dst = '\0'; 1148} 1149 1150// Convert an hex string into a byte array. 1151// This returns a pointer to the character following the last valid 1152// hex digit. If the string ends in the middle of a byte, NULL is 1153// returned. 1154const char * 1155hex2mem(void *vdst, const char *src, int maxlen) 1156{ 1157 char *dst = (char *)vdst; 1158 int msb, lsb; 1159 1160 while (*src && maxlen--) { 1161 msb = digit2i(*src++); 1162 if (msb < 0) 1163 return (src - 1); 1164 lsb = digit2i(*src++); 1165 if (lsb < 0) 1166 return (NULL); 1167 *dst++ = (msb << 4) | lsb; 1168 } 1169 return (src); 1170} 1171 1172// Convert an hex string into an integer. 1173// This returns a pointer to the character following the last valid 1174// hex digit. 1175Addr 1176hex2i(const char **srcp) 1177{ 1178 const char *src = *srcp; 1179 Addr r = 0; 1180 int nibble; 1181 1182 while ((nibble = digit2i(*src)) >= 0) { 1183 r *= 16; 1184 r += nibble; 1185 src++; 1186 } 1187 *srcp = src; 1188 return (r); 1189} 1190 1191