Remote GDB support has been changed to use inheritance. Alpha should work, but isn't tested. Other architectures will not.
--HG-- extra : convert_revision : fc7e1e73e2f3b1a4ab9905a1eb98c5f07c6c8707
This commit is contained in:
parent
e39de58d21
commit
85a6079db7
13 changed files with 1368 additions and 373 deletions
|
@ -54,6 +54,7 @@ isa_switch_hdrs = Split('''
|
||||||
locked_mem.hh
|
locked_mem.hh
|
||||||
process.hh
|
process.hh
|
||||||
regfile.hh
|
regfile.hh
|
||||||
|
remote_gdb.hh
|
||||||
stacktrace.hh
|
stacktrace.hh
|
||||||
syscallreturn.hh
|
syscallreturn.hh
|
||||||
tlb.hh
|
tlb.hh
|
||||||
|
|
|
@ -60,6 +60,7 @@ full_system_sources = Split('''
|
||||||
osfpal.cc
|
osfpal.cc
|
||||||
stacktrace.cc
|
stacktrace.cc
|
||||||
vtophys.cc
|
vtophys.cc
|
||||||
|
remote_gdb.cc
|
||||||
system.cc
|
system.cc
|
||||||
freebsd/system.cc
|
freebsd/system.cc
|
||||||
linux/system.cc
|
linux/system.cc
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
#include "arch/alpha/isa_traits.hh"
|
#include "arch/alpha/isa_traits.hh"
|
||||||
#include "arch/alpha/osfpal.hh"
|
#include "arch/alpha/osfpal.hh"
|
||||||
#include "arch/alpha/tlb.hh"
|
#include "arch/alpha/tlb.hh"
|
||||||
#include "base/kgdb.h"
|
#include "arch/alpha/kgdb.h"
|
||||||
#include "base/remote_gdb.hh"
|
#include "base/remote_gdb.hh"
|
||||||
#include "base/stats/events.hh"
|
#include "base/stats/events.hh"
|
||||||
#include "config/full_system.hh"
|
#include "config/full_system.hh"
|
||||||
|
|
424
src/arch/alpha/remote_gdb.cc
Normal file
424
src/arch/alpha/remote_gdb.cc
Normal file
|
@ -0,0 +1,424 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2002-2005 The Regents of The University of Michigan
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met: redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer;
|
||||||
|
* redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution;
|
||||||
|
* neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* Authors: Nathan Binkert
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1990, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* This software was developed by the Computer Systems Engineering group
|
||||||
|
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
|
||||||
|
* contributed to Berkeley.
|
||||||
|
*
|
||||||
|
* All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the University of
|
||||||
|
* California, Lawrence Berkeley Laboratories.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the University of
|
||||||
|
* California, Berkeley and its contributors.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 2001 The NetBSD Foundation, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This code is derived from software contributed to The NetBSD Foundation
|
||||||
|
* by Jason R. Thorpe.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the NetBSD
|
||||||
|
* Foundation, Inc. and its contributors.
|
||||||
|
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||||
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* $NetBSD: kgdb_stub.c,v 1.8 2001/07/07 22:58:00 wdk Exp $
|
||||||
|
*
|
||||||
|
* Taken from NetBSD
|
||||||
|
*
|
||||||
|
* "Stub" to allow remote cpu to debug over a serial line using gdb.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/signal.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "arch/vtophys.hh"
|
||||||
|
#include "arch/alpha/remote_gdb.hh"
|
||||||
|
#include "base/intmath.hh"
|
||||||
|
#include "base/remote_gdb.hh"
|
||||||
|
#include "base/socket.hh"
|
||||||
|
#include "base/trace.hh"
|
||||||
|
#include "config/full_system.hh"
|
||||||
|
#include "cpu/thread_context.hh"
|
||||||
|
#include "cpu/static_inst.hh"
|
||||||
|
#include "mem/physical.hh"
|
||||||
|
#include "mem/port.hh"
|
||||||
|
#include "sim/system.hh"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace AlphaISA;
|
||||||
|
|
||||||
|
RemoteGDB::Event::Event(RemoteGDB *g, int fd, int e)
|
||||||
|
: PollEvent(fd, e), gdb(g)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void
|
||||||
|
RemoteGDB::Event::process(int revent)
|
||||||
|
{
|
||||||
|
if (revent & POLLIN)
|
||||||
|
gdb->trap(ALPHA_KENTRY_IF);
|
||||||
|
else if (revent & POLLNVAL)
|
||||||
|
gdb->detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteGDB::RemoteGDB(System *_system, ThreadContext *c)
|
||||||
|
: BaseRemoteGDB(_system, c, KGDB_NUMREGS),
|
||||||
|
event(NULL)
|
||||||
|
{}
|
||||||
|
|
||||||
|
RemoteGDB::~RemoteGDB()
|
||||||
|
{
|
||||||
|
if (event)
|
||||||
|
delete event;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////
|
||||||
|
// RemoteGDB::acc
|
||||||
|
//
|
||||||
|
// Determine if the mapping at va..(va+len) is valid.
|
||||||
|
//
|
||||||
|
bool
|
||||||
|
RemoteGDB::acc(Addr va, size_t len)
|
||||||
|
{
|
||||||
|
Addr last_va;
|
||||||
|
|
||||||
|
va = TheISA::TruncPage(va);
|
||||||
|
last_va = TheISA::RoundPage(va + len);
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (TheISA::IsK0Seg(va)) {
|
||||||
|
if (va < (TheISA::K0SegBase + pmem->size())) {
|
||||||
|
DPRINTF(GDBAcc, "acc: Mapping is valid K0SEG <= "
|
||||||
|
"%#x < K0SEG + size\n", va);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
DPRINTF(GDBAcc, "acc: Mapping invalid %#x > K0SEG + size\n",
|
||||||
|
va);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This code says that all accesses to palcode (instruction and data)
|
||||||
|
* are valid since there isn't a va->pa mapping because palcode is
|
||||||
|
* accessed physically. At some point this should probably be cleaned up
|
||||||
|
* but there is no easy way to do it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (AlphaISA::PcPAL(va) || va < 0x10000)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
Addr ptbr = context->readMiscReg(AlphaISA::IPR_PALtemp20);
|
||||||
|
TheISA::PageTableEntry pte = TheISA::kernel_pte_lookup(context->getPhysPort(), ptbr, va);
|
||||||
|
if (!pte.valid()) {
|
||||||
|
DPRINTF(GDBAcc, "acc: %#x pte is invalid\n", va);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
va += TheISA::PageBytes;
|
||||||
|
} while (va < last_va);
|
||||||
|
|
||||||
|
DPRINTF(GDBAcc, "acc: %#x mapping is valid\n", va);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////
|
||||||
|
// RemoteGDB::getregs
|
||||||
|
//
|
||||||
|
// Translate the kernel debugger register format into
|
||||||
|
// the GDB register format.
|
||||||
|
void
|
||||||
|
RemoteGDB::getregs()
|
||||||
|
{
|
||||||
|
memset(gdbregs.regs, 0, gdbregs.size);
|
||||||
|
|
||||||
|
gdbregs.regs[KGDB_REG_PC] = context->readPC();
|
||||||
|
|
||||||
|
// @todo: Currently this is very Alpha specific.
|
||||||
|
if (AlphaISA::PcPAL(gdbregs.regs[KGDB_REG_PC])) {
|
||||||
|
for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
|
||||||
|
gdbregs.regs[i] = context->readIntReg(AlphaISA::reg_redir[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
|
||||||
|
gdbregs.regs[i] = context->readIntReg(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef KGDB_FP_REGS
|
||||||
|
for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) {
|
||||||
|
gdbregs.regs[i + KGDB_REG_F0] = context->readFloatRegBits(i);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////
|
||||||
|
// RemoteGDB::setregs
|
||||||
|
//
|
||||||
|
// Translate the GDB register format into the kernel
|
||||||
|
// debugger register format.
|
||||||
|
//
|
||||||
|
void
|
||||||
|
RemoteGDB::setregs()
|
||||||
|
{
|
||||||
|
// @todo: Currently this is very Alpha specific.
|
||||||
|
if (AlphaISA::PcPAL(gdbregs.regs[KGDB_REG_PC])) {
|
||||||
|
for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
|
||||||
|
context->setIntReg(AlphaISA::reg_redir[i], gdbregs.regs[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
|
||||||
|
context->setIntReg(i, gdbregs.regs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef KGDB_FP_REGS
|
||||||
|
for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) {
|
||||||
|
context->setFloatRegBits(i, gdbregs.regs[i + KGDB_REG_F0]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
context->setPC(gdbregs.regs[KGDB_REG_PC]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RemoteGDB::setTempBreakpoint(TempBreakpoint &bkpt, Addr addr)
|
||||||
|
{
|
||||||
|
DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", addr);
|
||||||
|
|
||||||
|
bkpt.address = addr;
|
||||||
|
insertHardBreak(addr, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RemoteGDB::clearTempBreakpoint(TempBreakpoint &bkpt)
|
||||||
|
{
|
||||||
|
DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n",
|
||||||
|
bkpt.address);
|
||||||
|
|
||||||
|
|
||||||
|
removeHardBreak(bkpt.address, 4);
|
||||||
|
bkpt.address = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RemoteGDB::clearSingleStep()
|
||||||
|
{
|
||||||
|
DPRINTF(GDBMisc, "clearSingleStep bt_addr=%#x nt_addr=%#x\n",
|
||||||
|
takenBkpt.address, notTakenBkpt.address);
|
||||||
|
|
||||||
|
if (takenBkpt.address != 0)
|
||||||
|
clearTempBreakpoint(takenBkpt);
|
||||||
|
|
||||||
|
if (notTakenBkpt.address != 0)
|
||||||
|
clearTempBreakpoint(notTakenBkpt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RemoteGDB::setSingleStep()
|
||||||
|
{
|
||||||
|
Addr pc = context->readPC();
|
||||||
|
Addr npc, bpc;
|
||||||
|
bool set_bt = false;
|
||||||
|
|
||||||
|
npc = pc + sizeof(MachInst);
|
||||||
|
|
||||||
|
// User was stopped at pc, e.g. the instruction at pc was not
|
||||||
|
// executed.
|
||||||
|
MachInst inst = read<MachInst>(pc);
|
||||||
|
StaticInstPtr si(inst);
|
||||||
|
if (si->hasBranchTarget(pc, context, bpc)) {
|
||||||
|
// Don't bother setting a breakpoint on the taken branch if it
|
||||||
|
// is the same as the next pc
|
||||||
|
if (bpc != npc)
|
||||||
|
set_bt = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINTF(GDBMisc, "setSingleStep bt_addr=%#x nt_addr=%#x\n",
|
||||||
|
takenBkpt.address, notTakenBkpt.address);
|
||||||
|
|
||||||
|
setTempBreakpoint(notTakenBkpt, npc);
|
||||||
|
|
||||||
|
if (set_bt)
|
||||||
|
setTempBreakpoint(takenBkpt, bpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write bytes to kernel address space for debugger.
|
||||||
|
bool
|
||||||
|
RemoteGDB::write(Addr vaddr, size_t size, const char *data)
|
||||||
|
{
|
||||||
|
if (BaseRemoteGDB::write(vaddr, size, data)) {
|
||||||
|
#ifdef IMB
|
||||||
|
alpha_pal_imb();
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PCEventQueue *RemoteGDB::getPcEventQueue()
|
||||||
|
{
|
||||||
|
return &system->pcEventQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RemoteGDB::HardBreakpoint::HardBreakpoint(RemoteGDB *_gdb, Addr pc)
|
||||||
|
: PCEvent(_gdb->getPcEventQueue(), "HardBreakpoint Event", pc),
|
||||||
|
gdb(_gdb), refcount(0)
|
||||||
|
{
|
||||||
|
DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RemoteGDB::HardBreakpoint::process(ThreadContext *tc)
|
||||||
|
{
|
||||||
|
DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc());
|
||||||
|
|
||||||
|
if (tc == gdb->context)
|
||||||
|
gdb->trap(ALPHA_KENTRY_INT);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
RemoteGDB::insertSoftBreak(Addr addr, size_t len)
|
||||||
|
{
|
||||||
|
if (len != sizeof(MachInst))
|
||||||
|
panic("invalid length\n");
|
||||||
|
|
||||||
|
return insertHardBreak(addr, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
RemoteGDB::removeSoftBreak(Addr addr, size_t len)
|
||||||
|
{
|
||||||
|
if (len != sizeof(MachInst))
|
||||||
|
panic("invalid length\n");
|
||||||
|
|
||||||
|
return removeHardBreak(addr, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
RemoteGDB::insertHardBreak(Addr addr, size_t len)
|
||||||
|
{
|
||||||
|
if (len != sizeof(MachInst))
|
||||||
|
panic("invalid length\n");
|
||||||
|
|
||||||
|
DPRINTF(GDBMisc, "inserting hardware breakpoint at %#x\n", addr);
|
||||||
|
|
||||||
|
HardBreakpoint *&bkpt = hardBreakMap[addr];
|
||||||
|
if (bkpt == 0)
|
||||||
|
bkpt = new HardBreakpoint(this, addr);
|
||||||
|
|
||||||
|
bkpt->refcount++;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
RemoteGDB::removeHardBreak(Addr addr, size_t len)
|
||||||
|
{
|
||||||
|
if (len != sizeof(MachInst))
|
||||||
|
panic("invalid length\n");
|
||||||
|
|
||||||
|
DPRINTF(GDBMisc, "removing hardware breakpoint at %#x\n", addr);
|
||||||
|
|
||||||
|
break_iter_t i = hardBreakMap.find(addr);
|
||||||
|
if (i == hardBreakMap.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
HardBreakpoint *hbp = (*i).second;
|
||||||
|
if (--hbp->refcount == 0) {
|
||||||
|
delete hbp;
|
||||||
|
hardBreakMap.erase(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
130
src/arch/alpha/remote_gdb.hh
Normal file
130
src/arch/alpha/remote_gdb.hh
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2002-2005 The Regents of The University of Michigan
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met: redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer;
|
||||||
|
* redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution;
|
||||||
|
* neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* Authors: Nathan Binkert
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ARCH_ALPHA_REMOTE_GDB_HH__
|
||||||
|
#define __ARCH_ALPHA_REMOTE_GDB_HH__
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "arch/alpha/types.hh"
|
||||||
|
#include "arch/alpha/kgdb.h"
|
||||||
|
#include "base/remote_gdb.hh"
|
||||||
|
#include "cpu/pc_event.hh"
|
||||||
|
#include "base/pollevent.hh"
|
||||||
|
#include "base/socket.hh"
|
||||||
|
|
||||||
|
class System;
|
||||||
|
class ThreadContext;
|
||||||
|
class PhysicalMemory;
|
||||||
|
|
||||||
|
namespace AlphaISA
|
||||||
|
{
|
||||||
|
class RemoteGDB : public BaseRemoteGDB
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
friend void debugger();
|
||||||
|
friend class GDBListener;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
class Event : public PollEvent
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
RemoteGDB *gdb;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Event(RemoteGDB *g, int fd, int e);
|
||||||
|
void process(int revent);
|
||||||
|
};
|
||||||
|
|
||||||
|
friend class Event;
|
||||||
|
Event *event;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Machine memory
|
||||||
|
bool write(Addr addr, size_t size, const char *data);
|
||||||
|
|
||||||
|
public:
|
||||||
|
RemoteGDB(System *system, ThreadContext *context);
|
||||||
|
~RemoteGDB();
|
||||||
|
|
||||||
|
bool acc(Addr addr, size_t len);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void getregs();
|
||||||
|
void setregs();
|
||||||
|
|
||||||
|
void clearSingleStep();
|
||||||
|
void setSingleStep();
|
||||||
|
|
||||||
|
PCEventQueue *getPcEventQueue();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
class HardBreakpoint : public PCEvent
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
RemoteGDB *gdb;
|
||||||
|
|
||||||
|
public:
|
||||||
|
int refcount;
|
||||||
|
|
||||||
|
public:
|
||||||
|
HardBreakpoint(RemoteGDB *_gdb, Addr addr);
|
||||||
|
std::string name() { return gdb->name() + ".hwbkpt"; }
|
||||||
|
|
||||||
|
virtual void process(ThreadContext *tc);
|
||||||
|
};
|
||||||
|
friend class HardBreakpoint;
|
||||||
|
|
||||||
|
typedef std::map<Addr, HardBreakpoint *> break_map_t;
|
||||||
|
typedef break_map_t::iterator break_iter_t;
|
||||||
|
break_map_t hardBreakMap;
|
||||||
|
|
||||||
|
bool insertSoftBreak(Addr addr, size_t len);
|
||||||
|
bool removeSoftBreak(Addr addr, size_t len);
|
||||||
|
bool insertHardBreak(Addr addr, size_t len);
|
||||||
|
bool removeHardBreak(Addr addr, size_t len);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
struct TempBreakpoint {
|
||||||
|
Addr address; // set here
|
||||||
|
MachInst bkpt_inst; // saved instruction at bkpt
|
||||||
|
int init_count; // number of times to skip bkpt
|
||||||
|
int count; // current count
|
||||||
|
};
|
||||||
|
|
||||||
|
TempBreakpoint notTakenBkpt;
|
||||||
|
TempBreakpoint takenBkpt;
|
||||||
|
|
||||||
|
void clearTempBreakpoint(TempBreakpoint &bkpt);
|
||||||
|
void setTempBreakpoint(TempBreakpoint &bkpt, Addr addr);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __ARCH_ALPHA_REMOTE_GDB_H__ */
|
|
@ -31,8 +31,8 @@
|
||||||
|
|
||||||
#include "arch/alpha/ev5.hh"
|
#include "arch/alpha/ev5.hh"
|
||||||
#include "arch/alpha/system.hh"
|
#include "arch/alpha/system.hh"
|
||||||
|
#include "arch/alpha/remote_gdb.hh"
|
||||||
#include "arch/vtophys.hh"
|
#include "arch/vtophys.hh"
|
||||||
#include "base/remote_gdb.hh"
|
|
||||||
#include "base/loader/object_file.hh"
|
#include "base/loader/object_file.hh"
|
||||||
#include "base/loader/symtab.hh"
|
#include "base/loader/symtab.hh"
|
||||||
#include "base/trace.hh"
|
#include "base/trace.hh"
|
||||||
|
|
456
src/arch/sparc/remote_gdb.cc
Normal file
456
src/arch/sparc/remote_gdb.cc
Normal file
|
@ -0,0 +1,456 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2002-2005 The Regents of The University of Michigan
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met: redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer;
|
||||||
|
* redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution;
|
||||||
|
* neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* Authors: Nathan Binkert
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1990, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* This software was developed by the Computer Systems Engineering group
|
||||||
|
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
|
||||||
|
* contributed to Berkeley.
|
||||||
|
*
|
||||||
|
* All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the University of
|
||||||
|
* California, Lawrence Berkeley Laboratories.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the University of
|
||||||
|
* California, Berkeley and its contributors.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 2001 The NetBSD Foundation, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This code is derived from software contributed to The NetBSD Foundation
|
||||||
|
* by Jason R. Thorpe.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the NetBSD
|
||||||
|
* Foundation, Inc. and its contributors.
|
||||||
|
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||||
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* $NetBSD: kgdb_stub.c,v 1.8 2001/07/07 22:58:00 wdk Exp $
|
||||||
|
*
|
||||||
|
* Taken from NetBSD
|
||||||
|
*
|
||||||
|
* "Stub" to allow remote cpu to debug over a serial line using gdb.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/signal.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "arch/vtophys.hh"
|
||||||
|
#include "arch/sparc/remote_gdb.hh"
|
||||||
|
#include "base/intmath.hh"
|
||||||
|
#include "base/kgdb.h"
|
||||||
|
#include "base/remote_gdb.hh"
|
||||||
|
#include "base/socket.hh"
|
||||||
|
#include "base/trace.hh"
|
||||||
|
#include "config/full_system.hh"
|
||||||
|
#include "cpu/thread_context.hh"
|
||||||
|
#include "cpu/static_inst.hh"
|
||||||
|
#include "mem/physical.hh"
|
||||||
|
#include "mem/port.hh"
|
||||||
|
#include "sim/system.hh"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace TheISA;
|
||||||
|
|
||||||
|
RemoteGDB::Event::Event(RemoteGDB *g, int fd, int e)
|
||||||
|
: PollEvent(fd, e), gdb(g)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void
|
||||||
|
RemoteGDB::Event::process(int revent)
|
||||||
|
{
|
||||||
|
if (revent & POLLIN)
|
||||||
|
gdb->trap(ALPHA_KENTRY_IF);
|
||||||
|
else if (revent & POLLNVAL)
|
||||||
|
gdb->detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteGDB::RemoteGDB(System *_system, ThreadContext *c)
|
||||||
|
: BaseRemoteGDB(_system, c, KGDB_NUMREGS),
|
||||||
|
event(NULL)
|
||||||
|
{}
|
||||||
|
|
||||||
|
RemoteGDB::~RemoteGDB()
|
||||||
|
{
|
||||||
|
if (event)
|
||||||
|
delete event;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////
|
||||||
|
// RemoteGDB::acc
|
||||||
|
//
|
||||||
|
// Determine if the mapping at va..(va+len) is valid.
|
||||||
|
//
|
||||||
|
bool
|
||||||
|
RemoteGDB::acc(Addr va, size_t len)
|
||||||
|
{
|
||||||
|
Addr last_va;
|
||||||
|
|
||||||
|
va = TheISA::TruncPage(va);
|
||||||
|
last_va = TheISA::RoundPage(va + len);
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (TheISA::IsK0Seg(va)) {
|
||||||
|
if (va < (TheISA::K0SegBase + pmem->size())) {
|
||||||
|
DPRINTF(GDBAcc, "acc: Mapping is valid K0SEG <= "
|
||||||
|
"%#x < K0SEG + size\n", va);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
DPRINTF(GDBAcc, "acc: Mapping invalid %#x > K0SEG + size\n",
|
||||||
|
va);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This code says that all accesses to palcode (instruction and data)
|
||||||
|
* are valid since there isn't a va->pa mapping because palcode is
|
||||||
|
* accessed physically. At some point this should probably be cleaned up
|
||||||
|
* but there is no easy way to do it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (AlphaISA::PcPAL(va) || va < 0x10000)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
Addr ptbr = context->readMiscReg(AlphaISA::IPR_PALtemp20);
|
||||||
|
TheISA::PageTableEntry pte = TheISA::kernel_pte_lookup(context->getPhysPort(), ptbr, va);
|
||||||
|
if (!pte.valid()) {
|
||||||
|
DPRINTF(GDBAcc, "acc: %#x pte is invalid\n", va);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
va += TheISA::PageBytes;
|
||||||
|
} while (va < last_va);
|
||||||
|
|
||||||
|
DPRINTF(GDBAcc, "acc: %#x mapping is valid\n", va);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////
|
||||||
|
// RemoteGDB::signal
|
||||||
|
//
|
||||||
|
// Translate a trap number into a Unix-compatible signal number.
|
||||||
|
// (GDB only understands Unix signal numbers.)
|
||||||
|
//
|
||||||
|
int
|
||||||
|
RemoteGDB::signal(int type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case ALPHA_KENTRY_INT:
|
||||||
|
return (SIGTRAP);
|
||||||
|
|
||||||
|
case ALPHA_KENTRY_UNA:
|
||||||
|
return (SIGBUS);
|
||||||
|
|
||||||
|
case ALPHA_KENTRY_ARITH:
|
||||||
|
return (SIGFPE);
|
||||||
|
|
||||||
|
case ALPHA_KENTRY_IF:
|
||||||
|
return (SIGILL);
|
||||||
|
|
||||||
|
case ALPHA_KENTRY_MM:
|
||||||
|
return (SIGSEGV);
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic("unknown signal type");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////
|
||||||
|
// RemoteGDB::getregs
|
||||||
|
//
|
||||||
|
// Translate the kernel debugger register format into
|
||||||
|
// the GDB register format.
|
||||||
|
void
|
||||||
|
RemoteGDB::getregs()
|
||||||
|
{
|
||||||
|
memset(gdbregs.regs, 0, gdbregs.size);
|
||||||
|
|
||||||
|
gdbregs.regs[KGDB_REG_PC] = context->readPC();
|
||||||
|
|
||||||
|
// @todo: Currently this is very Alpha specific.
|
||||||
|
if (AlphaISA::PcPAL(gdbregs.regs[KGDB_REG_PC])) {
|
||||||
|
for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
|
||||||
|
gdbregs.regs[i] = context->readIntReg(AlphaISA::reg_redir[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
|
||||||
|
gdbregs.regs[i] = context->readIntReg(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef KGDB_FP_REGS
|
||||||
|
for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) {
|
||||||
|
gdbregs.regs[i + KGDB_REG_F0] = context->readFloatRegBits(i);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////
|
||||||
|
// RemoteGDB::setregs
|
||||||
|
//
|
||||||
|
// Translate the GDB register format into the kernel
|
||||||
|
// debugger register format.
|
||||||
|
//
|
||||||
|
void
|
||||||
|
RemoteGDB::setregs()
|
||||||
|
{
|
||||||
|
// @todo: Currently this is very Alpha specific.
|
||||||
|
if (AlphaISA::PcPAL(gdbregs.regs[KGDB_REG_PC])) {
|
||||||
|
for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
|
||||||
|
context->setIntReg(AlphaISA::reg_redir[i], gdbregs.regs[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
|
||||||
|
context->setIntReg(i, gdbregs.regs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef KGDB_FP_REGS
|
||||||
|
for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) {
|
||||||
|
context->setFloatRegBits(i, gdbregs.regs[i + KGDB_REG_F0]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
context->setPC(gdbregs.regs[KGDB_REG_PC]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RemoteGDB::setTempBreakpoint(TempBreakpoint &bkpt, Addr addr)
|
||||||
|
{
|
||||||
|
DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", addr);
|
||||||
|
|
||||||
|
bkpt.address = addr;
|
||||||
|
insertHardBreak(addr, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RemoteGDB::clearTempBreakpoint(TempBreakpoint &bkpt)
|
||||||
|
{
|
||||||
|
DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n",
|
||||||
|
bkpt.address);
|
||||||
|
|
||||||
|
|
||||||
|
removeHardBreak(bkpt.address, 4);
|
||||||
|
bkpt.address = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RemoteGDB::clearSingleStep()
|
||||||
|
{
|
||||||
|
DPRINTF(GDBMisc, "clearSingleStep bt_addr=%#x nt_addr=%#x\n",
|
||||||
|
takenBkpt.address, notTakenBkpt.address);
|
||||||
|
|
||||||
|
if (takenBkpt.address != 0)
|
||||||
|
clearTempBreakpoint(takenBkpt);
|
||||||
|
|
||||||
|
if (notTakenBkpt.address != 0)
|
||||||
|
clearTempBreakpoint(notTakenBkpt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RemoteGDB::setSingleStep()
|
||||||
|
{
|
||||||
|
Addr pc = context->readPC();
|
||||||
|
Addr npc, bpc;
|
||||||
|
bool set_bt = false;
|
||||||
|
|
||||||
|
npc = pc + sizeof(MachInst);
|
||||||
|
|
||||||
|
// User was stopped at pc, e.g. the instruction at pc was not
|
||||||
|
// executed.
|
||||||
|
MachInst inst = read<MachInst>(pc);
|
||||||
|
StaticInstPtr si(inst);
|
||||||
|
if (si->hasBranchTarget(pc, context, bpc)) {
|
||||||
|
// Don't bother setting a breakpoint on the taken branch if it
|
||||||
|
// is the same as the next pc
|
||||||
|
if (bpc != npc)
|
||||||
|
set_bt = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINTF(GDBMisc, "setSingleStep bt_addr=%#x nt_addr=%#x\n",
|
||||||
|
takenBkpt.address, notTakenBkpt.address);
|
||||||
|
|
||||||
|
setTempBreakpoint(notTakenBkpt, npc);
|
||||||
|
|
||||||
|
if (set_bt)
|
||||||
|
setTempBreakpoint(takenBkpt, bpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write bytes to kernel address space for debugger.
|
||||||
|
bool
|
||||||
|
RemoteGDB::write(Addr vaddr, size_t size, const char *data)
|
||||||
|
{
|
||||||
|
if (BaseRemoteGDB::write(vaddr, size, data)) {
|
||||||
|
#ifdef IMB
|
||||||
|
alpha_pal_imb();
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PCEventQueue *RemoteGDB::getPcEventQueue()
|
||||||
|
{
|
||||||
|
return &system->pcEventQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RemoteGDB::HardBreakpoint::HardBreakpoint(RemoteGDB *_gdb, Addr pc)
|
||||||
|
: PCEvent(_gdb->getPcEventQueue(), "HardBreakpoint Event", pc),
|
||||||
|
gdb(_gdb), refcount(0)
|
||||||
|
{
|
||||||
|
DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RemoteGDB::HardBreakpoint::process(ThreadContext *tc)
|
||||||
|
{
|
||||||
|
DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc());
|
||||||
|
|
||||||
|
if (tc == gdb->context)
|
||||||
|
gdb->trap(ALPHA_KENTRY_INT);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
RemoteGDB::insertSoftBreak(Addr addr, size_t len)
|
||||||
|
{
|
||||||
|
if (len != sizeof(MachInst))
|
||||||
|
panic("invalid length\n");
|
||||||
|
|
||||||
|
return insertHardBreak(addr, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
RemoteGDB::removeSoftBreak(Addr addr, size_t len)
|
||||||
|
{
|
||||||
|
if (len != sizeof(MachInst))
|
||||||
|
panic("invalid length\n");
|
||||||
|
|
||||||
|
return removeHardBreak(addr, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
RemoteGDB::insertHardBreak(Addr addr, size_t len)
|
||||||
|
{
|
||||||
|
if (len != sizeof(MachInst))
|
||||||
|
panic("invalid length\n");
|
||||||
|
|
||||||
|
DPRINTF(GDBMisc, "inserting hardware breakpoint at %#x\n", addr);
|
||||||
|
|
||||||
|
HardBreakpoint *&bkpt = hardBreakMap[addr];
|
||||||
|
if (bkpt == 0)
|
||||||
|
bkpt = new HardBreakpoint(this, addr);
|
||||||
|
|
||||||
|
bkpt->refcount++;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
RemoteGDB::removeHardBreak(Addr addr, size_t len)
|
||||||
|
{
|
||||||
|
if (len != sizeof(MachInst))
|
||||||
|
panic("invalid length\n");
|
||||||
|
|
||||||
|
DPRINTF(GDBMisc, "removing hardware breakpoint at %#x\n", addr);
|
||||||
|
|
||||||
|
break_iter_t i = hardBreakMap.find(addr);
|
||||||
|
if (i == hardBreakMap.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
HardBreakpoint *hbp = (*i).second;
|
||||||
|
if (--hbp->refcount == 0) {
|
||||||
|
delete hbp;
|
||||||
|
hardBreakMap.erase(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
129
src/arch/sparc/remote_gdb.hh
Normal file
129
src/arch/sparc/remote_gdb.hh
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2002-2005 The Regents of The University of Michigan
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met: redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer;
|
||||||
|
* redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution;
|
||||||
|
* neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* Authors: Nathan Binkert
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ARCH_ALPHA_REMOTE_GDB_HH__
|
||||||
|
#define __ARCH_ALPHA_REMOTE_GDB_HH__
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "arch/types.hh"
|
||||||
|
#include "base/remote_gdb.hh"
|
||||||
|
#include "cpu/pc_event.hh"
|
||||||
|
#include "base/pollevent.hh"
|
||||||
|
|
||||||
|
class System;
|
||||||
|
class ThreadContext;
|
||||||
|
class PhysicalMemory;
|
||||||
|
|
||||||
|
namespace SparcISA
|
||||||
|
{
|
||||||
|
class RemoteGDB : public BaseRemoteGDB
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
friend void debugger();
|
||||||
|
friend class GDBListener;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
class Event : public PollEvent
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
RemoteGDB *gdb;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Event(RemoteGDB *g, int fd, int e);
|
||||||
|
void process(int revent);
|
||||||
|
};
|
||||||
|
|
||||||
|
friend class Event;
|
||||||
|
Event *event;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Machine memory
|
||||||
|
bool write(Addr addr, size_t size, const char *data);
|
||||||
|
|
||||||
|
public:
|
||||||
|
RemoteGDB(System *system, ThreadContext *context);
|
||||||
|
~RemoteGDB();
|
||||||
|
|
||||||
|
bool acc(Addr addr, size_t len);
|
||||||
|
int signal(int type);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void getregs();
|
||||||
|
void setregs();
|
||||||
|
|
||||||
|
void clearSingleStep();
|
||||||
|
void setSingleStep();
|
||||||
|
|
||||||
|
PCEventQueue *getPcEventQueue();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
class HardBreakpoint : public PCEvent
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
RemoteGDB *gdb;
|
||||||
|
|
||||||
|
public:
|
||||||
|
int refcount;
|
||||||
|
|
||||||
|
public:
|
||||||
|
HardBreakpoint(RemoteGDB *_gdb, Addr addr);
|
||||||
|
std::string name() { return gdb->name() + ".hwbkpt"; }
|
||||||
|
|
||||||
|
virtual void process(ThreadContext *tc);
|
||||||
|
};
|
||||||
|
friend class HardBreakpoint;
|
||||||
|
|
||||||
|
typedef std::map<Addr, HardBreakpoint *> break_map_t;
|
||||||
|
typedef break_map_t::iterator break_iter_t;
|
||||||
|
break_map_t hardBreakMap;
|
||||||
|
|
||||||
|
bool insertSoftBreak(Addr addr, size_t len);
|
||||||
|
bool removeSoftBreak(Addr addr, size_t len);
|
||||||
|
bool insertHardBreak(Addr addr, size_t len);
|
||||||
|
bool removeHardBreak(Addr addr, size_t len);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
struct TempBreakpoint {
|
||||||
|
Addr address; // set here
|
||||||
|
MachInst bkpt_inst; // saved instruction at bkpt
|
||||||
|
int init_count; // number of times to skip bkpt
|
||||||
|
int count; // current count
|
||||||
|
};
|
||||||
|
|
||||||
|
TempBreakpoint notTakenBkpt;
|
||||||
|
TempBreakpoint takenBkpt;
|
||||||
|
|
||||||
|
void clearTempBreakpoint(TempBreakpoint &bkpt);
|
||||||
|
void setTempBreakpoint(TempBreakpoint &bkpt, Addr addr);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __ARCH_ALPHA_REMOTE_GDB_H__ */
|
|
@ -123,7 +123,6 @@
|
||||||
|
|
||||||
#include "arch/vtophys.hh"
|
#include "arch/vtophys.hh"
|
||||||
#include "base/intmath.hh"
|
#include "base/intmath.hh"
|
||||||
#include "base/kgdb.h"
|
|
||||||
#include "base/remote_gdb.hh"
|
#include "base/remote_gdb.hh"
|
||||||
#include "base/socket.hh"
|
#include "base/socket.hh"
|
||||||
#include "base/trace.hh"
|
#include "base/trace.hh"
|
||||||
|
@ -138,18 +137,18 @@ using namespace std;
|
||||||
using namespace TheISA;
|
using namespace TheISA;
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
vector<RemoteGDB *> debuggers;
|
vector<BaseRemoteGDB *> debuggers;
|
||||||
int current_debugger = -1;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
debugger()
|
debugger()
|
||||||
{
|
{
|
||||||
|
static int current_debugger = -1;
|
||||||
if (current_debugger >= 0 && current_debugger < debuggers.size()) {
|
if (current_debugger >= 0 && current_debugger < debuggers.size()) {
|
||||||
RemoteGDB *gdb = debuggers[current_debugger];
|
BaseRemoteGDB *gdb = debuggers[current_debugger];
|
||||||
if (!gdb->isattached())
|
if (!gdb->isattached())
|
||||||
gdb->listener->accept();
|
gdb->listener->accept();
|
||||||
if (gdb->isattached())
|
if (gdb->isattached())
|
||||||
gdb->trap(ALPHA_KENTRY_IF);
|
gdb->trap(SIGILL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -169,7 +168,7 @@ GDBListener::Event::process(int revent)
|
||||||
listener->accept();
|
listener->accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
GDBListener::GDBListener(RemoteGDB *g, int p)
|
GDBListener::GDBListener(BaseRemoteGDB *g, int p)
|
||||||
: event(NULL), gdb(g), port(p)
|
: event(NULL), gdb(g), port(p)
|
||||||
{
|
{
|
||||||
assert(!gdb->listener);
|
assert(!gdb->listener);
|
||||||
|
@ -229,55 +228,46 @@ GDBListener::accept()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////
|
BaseRemoteGDB::Event::Event(BaseRemoteGDB *g, int fd, int e)
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
int digit2i(char);
|
|
||||||
char i2digit(int);
|
|
||||||
void mem2hex(void *, const void *, int);
|
|
||||||
const char *hex2mem(void *, const char *, int);
|
|
||||||
Addr hex2i(const char **);
|
|
||||||
|
|
||||||
RemoteGDB::Event::Event(RemoteGDB *g, int fd, int e)
|
|
||||||
: PollEvent(fd, e), gdb(g)
|
: PollEvent(fd, e), gdb(g)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void
|
void
|
||||||
RemoteGDB::Event::process(int revent)
|
BaseRemoteGDB::Event::process(int revent)
|
||||||
{
|
{
|
||||||
if (revent & POLLIN)
|
if (revent & POLLIN)
|
||||||
gdb->trap(ALPHA_KENTRY_IF);
|
gdb->trap(SIGILL);
|
||||||
else if (revent & POLLNVAL)
|
else if (revent & POLLNVAL)
|
||||||
gdb->detach();
|
gdb->detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoteGDB::RemoteGDB(System *_system, ThreadContext *c)
|
BaseRemoteGDB::BaseRemoteGDB(System *_system, ThreadContext *c, size_t cacheSize)
|
||||||
: event(NULL), listener(NULL), number(-1), fd(-1),
|
: event(NULL), listener(NULL), number(-1), fd(-1),
|
||||||
active(false), attached(false),
|
active(false), attached(false),
|
||||||
system(_system), pmem(_system->physmem), context(c)
|
system(_system), pmem(_system->physmem), context(c),
|
||||||
|
gdbregs(cacheSize)
|
||||||
{
|
{
|
||||||
memset(gdbregs, 0, sizeof(gdbregs));
|
memset(gdbregs.regs, 0, gdbregs.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoteGDB::~RemoteGDB()
|
BaseRemoteGDB::~BaseRemoteGDB()
|
||||||
{
|
{
|
||||||
if (event)
|
if (event)
|
||||||
delete event;
|
delete event;
|
||||||
}
|
}
|
||||||
|
|
||||||
string
|
string
|
||||||
RemoteGDB::name()
|
BaseRemoteGDB::name()
|
||||||
{
|
{
|
||||||
return system->name() + ".remote_gdb";
|
return system->name() + ".remote_gdb";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
RemoteGDB::isattached()
|
BaseRemoteGDB::isattached()
|
||||||
{ return attached; }
|
{ return attached; }
|
||||||
|
|
||||||
void
|
void
|
||||||
RemoteGDB::attach(int f)
|
BaseRemoteGDB::attach(int f)
|
||||||
{
|
{
|
||||||
fd = f;
|
fd = f;
|
||||||
|
|
||||||
|
@ -289,7 +279,7 @@ RemoteGDB::attach(int f)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RemoteGDB::detach()
|
BaseRemoteGDB::detach()
|
||||||
{
|
{
|
||||||
attached = false;
|
attached = false;
|
||||||
close(fd);
|
close(fd);
|
||||||
|
@ -300,250 +290,50 @@ RemoteGDB::detach()
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
gdb_command(char cmd)
|
BaseRemoteGDB::gdb_command(char cmd)
|
||||||
{
|
{
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case KGDB_SIGNAL: return "KGDB_SIGNAL";
|
case GDBSignal: return "KGDB_SIGNAL";
|
||||||
case KGDB_SET_BAUD: return "KGDB_SET_BAUD";
|
case GDBSetBaud: return "KGDB_SET_BAUD";
|
||||||
case KGDB_SET_BREAK: return "KGDB_SET_BREAK";
|
case GDBSetBreak: return "KGDB_SET_BREAK";
|
||||||
case KGDB_CONT: return "KGDB_CONT";
|
case GDBCont: return "KGDB_CONT";
|
||||||
case KGDB_ASYNC_CONT: return "KGDB_ASYNC_CONT";
|
case GDBAsyncCont: return "KGDB_ASYNC_CONT";
|
||||||
case KGDB_DEBUG: return "KGDB_DEBUG";
|
case GDBDebug: return "KGDB_DEBUG";
|
||||||
case KGDB_DETACH: return "KGDB_DETACH";
|
case GDBDetach: return "KGDB_DETACH";
|
||||||
case KGDB_REG_R: return "KGDB_REG_R";
|
case GDBRegR: return "KGDB_REG_R";
|
||||||
case KGDB_REG_W: return "KGDB_REG_W";
|
case GDBRegW: return "KGDB_REG_W";
|
||||||
case KGDB_SET_THREAD: return "KGDB_SET_THREAD";
|
case GDBSetThread: return "KGDB_SET_THREAD";
|
||||||
case KGDB_CYCLE_STEP: return "KGDB_CYCLE_STEP";
|
case GDBCycleStep: return "KGDB_CYCLE_STEP";
|
||||||
case KGDB_SIG_CYCLE_STEP: return "KGDB_SIG_CYCLE_STEP";
|
case GDBSigCycleStep: return "KGDB_SIG_CYCLE_STEP";
|
||||||
case KGDB_KILL: return "KGDB_KILL";
|
case GDBKill: return "KGDB_KILL";
|
||||||
case KGDB_MEM_W: return "KGDB_MEM_W";
|
case GDBMemW: return "KGDB_MEM_W";
|
||||||
case KGDB_MEM_R: return "KGDB_MEM_R";
|
case GDBMemR: return "KGDB_MEM_R";
|
||||||
case KGDB_SET_REG: return "KGDB_SET_REG";
|
case GDBSetReg: return "KGDB_SET_REG";
|
||||||
case KGDB_READ_REG: return "KGDB_READ_REG";
|
case GDBReadReg: return "KGDB_READ_REG";
|
||||||
case KGDB_QUERY_VAR: return "KGDB_QUERY_VAR";
|
case GDBQueryVar: return "KGDB_QUERY_VAR";
|
||||||
case KGDB_SET_VAR: return "KGDB_SET_VAR";
|
case GDBSetVar: return "KGDB_SET_VAR";
|
||||||
case KGDB_RESET: return "KGDB_RESET";
|
case GDBReset: return "KGDB_RESET";
|
||||||
case KGDB_STEP: return "KGDB_STEP";
|
case GDBStep: return "KGDB_STEP";
|
||||||
case KGDB_ASYNC_STEP: return "KGDB_ASYNC_STEP";
|
case GDBAsyncStep: return "KGDB_ASYNC_STEP";
|
||||||
case KGDB_THREAD_ALIVE: return "KGDB_THREAD_ALIVE";
|
case GDBThreadAlive: return "KGDB_THREAD_ALIVE";
|
||||||
case KGDB_TARGET_EXIT: return "KGDB_TARGET_EXIT";
|
case GDBTargetExit: return "KGDB_TARGET_EXIT";
|
||||||
case KGDB_BINARY_DLOAD: return "KGDB_BINARY_DLOAD";
|
case GDBBinaryDload: return "KGDB_BINARY_DLOAD";
|
||||||
case KGDB_CLR_HW_BKPT: return "KGDB_CLR_HW_BKPT";
|
case GDBClrHwBkpt: return "KGDB_CLR_HW_BKPT";
|
||||||
case KGDB_SET_HW_BKPT: return "KGDB_SET_HW_BKPT";
|
case GDBSetHwBkpt: return "KGDB_SET_HW_BKPT";
|
||||||
case KGDB_START: return "KGDB_START";
|
case GDBStart: return "KGDB_START";
|
||||||
case KGDB_END: return "KGDB_END";
|
case GDBEnd: return "KGDB_END";
|
||||||
case KGDB_GOODP: return "KGDB_GOODP";
|
case GDBGoodP: return "KGDB_GOODP";
|
||||||
case KGDB_BADP: return "KGDB_BADP";
|
case GDBBadP: return "KGDB_BADP";
|
||||||
default: return "KGDB_UNKNOWN";
|
default: return "KGDB_UNKNOWN";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////
|
|
||||||
// RemoteGDB::acc
|
|
||||||
//
|
|
||||||
// Determine if the mapping at va..(va+len) is valid.
|
|
||||||
//
|
|
||||||
bool
|
|
||||||
RemoteGDB::acc(Addr va, size_t len)
|
|
||||||
{
|
|
||||||
Addr last_va;
|
|
||||||
|
|
||||||
va = TheISA::TruncPage(va);
|
|
||||||
last_va = TheISA::RoundPage(va + len);
|
|
||||||
|
|
||||||
do {
|
|
||||||
if (TheISA::IsK0Seg(va)) {
|
|
||||||
if (va < (TheISA::K0SegBase + pmem->size())) {
|
|
||||||
DPRINTF(GDBAcc, "acc: Mapping is valid K0SEG <= "
|
|
||||||
"%#x < K0SEG + size\n", va);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
DPRINTF(GDBAcc, "acc: Mapping invalid %#x > K0SEG + size\n",
|
|
||||||
va);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This code says that all accesses to palcode (instruction and data)
|
|
||||||
* are valid since there isn't a va->pa mapping because palcode is
|
|
||||||
* accessed physically. At some point this should probably be cleaned up
|
|
||||||
* but there is no easy way to do it.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (AlphaISA::PcPAL(va) || va < 0x10000)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
Addr ptbr = context->readMiscReg(AlphaISA::IPR_PALtemp20);
|
|
||||||
TheISA::PageTableEntry pte = TheISA::kernel_pte_lookup(context->getPhysPort(), ptbr, va);
|
|
||||||
if (!pte.valid()) {
|
|
||||||
DPRINTF(GDBAcc, "acc: %#x pte is invalid\n", va);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
va += TheISA::PageBytes;
|
|
||||||
} while (va < last_va);
|
|
||||||
|
|
||||||
DPRINTF(GDBAcc, "acc: %#x mapping is valid\n", va);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////
|
|
||||||
// RemoteGDB::signal
|
|
||||||
//
|
|
||||||
// Translate a trap number into a Unix-compatible signal number.
|
|
||||||
// (GDB only understands Unix signal numbers.)
|
|
||||||
//
|
|
||||||
int
|
|
||||||
RemoteGDB::signal(int type)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case ALPHA_KENTRY_INT:
|
|
||||||
return (SIGTRAP);
|
|
||||||
|
|
||||||
case ALPHA_KENTRY_UNA:
|
|
||||||
return (SIGBUS);
|
|
||||||
|
|
||||||
case ALPHA_KENTRY_ARITH:
|
|
||||||
return (SIGFPE);
|
|
||||||
|
|
||||||
case ALPHA_KENTRY_IF:
|
|
||||||
return (SIGILL);
|
|
||||||
|
|
||||||
case ALPHA_KENTRY_MM:
|
|
||||||
return (SIGSEGV);
|
|
||||||
|
|
||||||
default:
|
|
||||||
panic("unknown signal type");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////
|
|
||||||
// RemoteGDB::getregs
|
|
||||||
//
|
|
||||||
// Translate the kernel debugger register format into
|
|
||||||
// the GDB register format.
|
|
||||||
void
|
|
||||||
RemoteGDB::getregs()
|
|
||||||
{
|
|
||||||
memset(gdbregs, 0, sizeof(gdbregs));
|
|
||||||
|
|
||||||
gdbregs[KGDB_REG_PC] = context->readPC();
|
|
||||||
|
|
||||||
// @todo: Currently this is very Alpha specific.
|
|
||||||
if (AlphaISA::PcPAL(gdbregs[KGDB_REG_PC])) {
|
|
||||||
for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
|
|
||||||
gdbregs[i] = context->readIntReg(AlphaISA::reg_redir[i]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
|
|
||||||
gdbregs[i] = context->readIntReg(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef KGDB_FP_REGS
|
|
||||||
for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) {
|
|
||||||
gdbregs[i + KGDB_REG_F0] = context->readFloatRegBits(i);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////
|
|
||||||
// RemoteGDB::setregs
|
|
||||||
//
|
|
||||||
// Translate the GDB register format into the kernel
|
|
||||||
// debugger register format.
|
|
||||||
//
|
|
||||||
void
|
|
||||||
RemoteGDB::setregs()
|
|
||||||
{
|
|
||||||
// @todo: Currently this is very Alpha specific.
|
|
||||||
if (AlphaISA::PcPAL(gdbregs[KGDB_REG_PC])) {
|
|
||||||
for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
|
|
||||||
context->setIntReg(AlphaISA::reg_redir[i], gdbregs[i]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
|
|
||||||
context->setIntReg(i, gdbregs[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef KGDB_FP_REGS
|
|
||||||
for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) {
|
|
||||||
context->setFloatRegBits(i, gdbregs[i + KGDB_REG_F0]);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
context->setPC(gdbregs[KGDB_REG_PC]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
RemoteGDB::setTempBreakpoint(TempBreakpoint &bkpt, Addr addr)
|
|
||||||
{
|
|
||||||
DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", addr);
|
|
||||||
|
|
||||||
bkpt.address = addr;
|
|
||||||
insertHardBreak(addr, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
RemoteGDB::clearTempBreakpoint(TempBreakpoint &bkpt)
|
|
||||||
{
|
|
||||||
DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n",
|
|
||||||
bkpt.address);
|
|
||||||
|
|
||||||
|
|
||||||
removeHardBreak(bkpt.address, 4);
|
|
||||||
bkpt.address = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
RemoteGDB::clearSingleStep()
|
|
||||||
{
|
|
||||||
DPRINTF(GDBMisc, "clearSingleStep bt_addr=%#x nt_addr=%#x\n",
|
|
||||||
takenBkpt.address, notTakenBkpt.address);
|
|
||||||
|
|
||||||
if (takenBkpt.address != 0)
|
|
||||||
clearTempBreakpoint(takenBkpt);
|
|
||||||
|
|
||||||
if (notTakenBkpt.address != 0)
|
|
||||||
clearTempBreakpoint(notTakenBkpt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
RemoteGDB::setSingleStep()
|
|
||||||
{
|
|
||||||
Addr pc = context->readPC();
|
|
||||||
Addr npc, bpc;
|
|
||||||
bool set_bt = false;
|
|
||||||
|
|
||||||
npc = pc + sizeof(MachInst);
|
|
||||||
|
|
||||||
// User was stopped at pc, e.g. the instruction at pc was not
|
|
||||||
// executed.
|
|
||||||
MachInst inst = read<MachInst>(pc);
|
|
||||||
StaticInstPtr si(inst);
|
|
||||||
if (si->hasBranchTarget(pc, context, bpc)) {
|
|
||||||
// Don't bother setting a breakpoint on the taken branch if it
|
|
||||||
// is the same as the next pc
|
|
||||||
if (bpc != npc)
|
|
||||||
set_bt = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
DPRINTF(GDBMisc, "setSingleStep bt_addr=%#x nt_addr=%#x\n",
|
|
||||||
takenBkpt.address, notTakenBkpt.address);
|
|
||||||
|
|
||||||
setTempBreakpoint(notTakenBkpt, npc);
|
|
||||||
|
|
||||||
if (set_bt)
|
|
||||||
setTempBreakpoint(takenBkpt, bpc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////
|
/////////////////////////
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
|
||||||
uint8_t
|
uint8_t
|
||||||
RemoteGDB::getbyte()
|
BaseRemoteGDB::getbyte()
|
||||||
{
|
{
|
||||||
uint8_t b;
|
uint8_t b;
|
||||||
::read(fd, &b, 1);
|
::read(fd, &b, 1);
|
||||||
|
@ -551,14 +341,14 @@ RemoteGDB::getbyte()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RemoteGDB::putbyte(uint8_t b)
|
BaseRemoteGDB::putbyte(uint8_t b)
|
||||||
{
|
{
|
||||||
::write(fd, &b, 1);
|
::write(fd, &b, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a packet to gdb
|
// Send a packet to gdb
|
||||||
void
|
void
|
||||||
RemoteGDB::send(const char *bp)
|
BaseRemoteGDB::send(const char *bp)
|
||||||
{
|
{
|
||||||
const char *p;
|
const char *p;
|
||||||
uint8_t csum, c;
|
uint8_t csum, c;
|
||||||
|
@ -567,20 +357,26 @@ RemoteGDB::send(const char *bp)
|
||||||
|
|
||||||
do {
|
do {
|
||||||
p = bp;
|
p = bp;
|
||||||
putbyte(KGDB_START);
|
//Start sending a packet
|
||||||
|
putbyte(GDBStart);
|
||||||
|
//Send the contents, and also keep a check sum.
|
||||||
for (csum = 0; (c = *p); p++) {
|
for (csum = 0; (c = *p); p++) {
|
||||||
putbyte(c);
|
putbyte(c);
|
||||||
csum += c;
|
csum += c;
|
||||||
}
|
}
|
||||||
putbyte(KGDB_END);
|
//Send the ending character.
|
||||||
|
putbyte(GDBEnd);
|
||||||
|
//Sent the checksum.
|
||||||
putbyte(i2digit(csum >> 4));
|
putbyte(i2digit(csum >> 4));
|
||||||
putbyte(i2digit(csum));
|
putbyte(i2digit(csum));
|
||||||
} while ((c = getbyte() & 0x7f) == KGDB_BADP);
|
//Try transmitting over and over again until the other end doesn't send an
|
||||||
|
//error back.
|
||||||
|
} while ((c = getbyte() & 0x7f) == GDBBadP);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Receive a packet from gdb
|
// Receive a packet from gdb
|
||||||
int
|
int
|
||||||
RemoteGDB::recv(char *bp, int maxlen)
|
BaseRemoteGDB::recv(char *bp, int maxlen)
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
int c, csum;
|
int c, csum;
|
||||||
|
@ -589,28 +385,37 @@ RemoteGDB::recv(char *bp, int maxlen)
|
||||||
do {
|
do {
|
||||||
p = bp;
|
p = bp;
|
||||||
csum = len = 0;
|
csum = len = 0;
|
||||||
while ((c = getbyte()) != KGDB_START)
|
//Find the beginning of a packet
|
||||||
|
while ((c = getbyte()) != GDBStart)
|
||||||
;
|
;
|
||||||
|
|
||||||
while ((c = getbyte()) != KGDB_END && len < maxlen) {
|
//Read until you find the end of the data in the packet, and keep
|
||||||
|
//track of the check sum.
|
||||||
|
while ((c = getbyte()) != GDBEnd && len < maxlen) {
|
||||||
c &= 0x7f;
|
c &= 0x7f;
|
||||||
csum += c;
|
csum += c;
|
||||||
*p++ = c;
|
*p++ = c;
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Mask the check sum, and terminate the command string.
|
||||||
csum &= 0xff;
|
csum &= 0xff;
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
|
|
||||||
|
//If the command was too long, report an error.
|
||||||
if (len >= maxlen) {
|
if (len >= maxlen) {
|
||||||
putbyte(KGDB_BADP);
|
putbyte(GDBBadP);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Bring in the checksum. If the check sum matches, csum will be 0.
|
||||||
csum -= digit2i(getbyte()) * 16;
|
csum -= digit2i(getbyte()) * 16;
|
||||||
csum -= digit2i(getbyte());
|
csum -= digit2i(getbyte());
|
||||||
|
|
||||||
|
//If the check sum was correct
|
||||||
if (csum == 0) {
|
if (csum == 0) {
|
||||||
putbyte(KGDB_GOODP);
|
//Report that the packet was received correctly
|
||||||
|
putbyte(GDBGoodP);
|
||||||
// Sequence present?
|
// Sequence present?
|
||||||
if (bp[2] == ':') {
|
if (bp[2] == ':') {
|
||||||
putbyte(bp[0]);
|
putbyte(bp[0]);
|
||||||
|
@ -620,7 +425,8 @@ RemoteGDB::recv(char *bp, int maxlen)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
putbyte(KGDB_BADP);
|
//Otherwise, report that there was a mistake.
|
||||||
|
putbyte(GDBBadP);
|
||||||
} while (1);
|
} while (1);
|
||||||
|
|
||||||
DPRINTF(GDBRecv, "recv: %s: %s\n", gdb_command(*bp), bp);
|
DPRINTF(GDBRecv, "recv: %s: %s\n", gdb_command(*bp), bp);
|
||||||
|
@ -630,7 +436,7 @@ RemoteGDB::recv(char *bp, int maxlen)
|
||||||
|
|
||||||
// Read bytes from kernel address space for debugger.
|
// Read bytes from kernel address space for debugger.
|
||||||
bool
|
bool
|
||||||
RemoteGDB::read(Addr vaddr, size_t size, char *data)
|
BaseRemoteGDB::read(Addr vaddr, size_t size, char *data)
|
||||||
{
|
{
|
||||||
static Addr lastaddr = 0;
|
static Addr lastaddr = 0;
|
||||||
static size_t lastsize = 0;
|
static size_t lastsize = 0;
|
||||||
|
@ -662,7 +468,7 @@ RemoteGDB::read(Addr vaddr, size_t size, char *data)
|
||||||
|
|
||||||
// Write bytes to kernel address space for debugger.
|
// Write bytes to kernel address space for debugger.
|
||||||
bool
|
bool
|
||||||
RemoteGDB::write(Addr vaddr, size_t size, const char *data)
|
BaseRemoteGDB::write(Addr vaddr, size_t size, const char *data)
|
||||||
{
|
{
|
||||||
static Addr lastaddr = 0;
|
static Addr lastaddr = 0;
|
||||||
static size_t lastsize = 0;
|
static size_t lastsize = 0;
|
||||||
|
@ -685,21 +491,15 @@ RemoteGDB::write(Addr vaddr, size_t size, const char *data)
|
||||||
vp->writeBlob(vaddr, (uint8_t*)data, size);
|
vp->writeBlob(vaddr, (uint8_t*)data, size);
|
||||||
context->delVirtPort(vp);
|
context->delVirtPort(vp);
|
||||||
|
|
||||||
#ifdef IMB
|
|
||||||
alpha_pal_imb();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PCEventQueue *BaseRemoteGDB::getPcEventQueue()
|
||||||
PCEventQueue *RemoteGDB::getPcEventQueue()
|
|
||||||
{
|
{
|
||||||
return &system->pcEventQueue;
|
return &system->pcEventQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BaseRemoteGDB::HardBreakpoint::HardBreakpoint(BaseRemoteGDB *_gdb, Addr pc)
|
||||||
RemoteGDB::HardBreakpoint::HardBreakpoint(RemoteGDB *_gdb, Addr pc)
|
|
||||||
: PCEvent(_gdb->getPcEventQueue(), "HardBreakpoint Event", pc),
|
: PCEvent(_gdb->getPcEventQueue(), "HardBreakpoint Event", pc),
|
||||||
gdb(_gdb), refcount(0)
|
gdb(_gdb), refcount(0)
|
||||||
{
|
{
|
||||||
|
@ -707,25 +507,25 @@ RemoteGDB::HardBreakpoint::HardBreakpoint(RemoteGDB *_gdb, Addr pc)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RemoteGDB::HardBreakpoint::process(ThreadContext *tc)
|
BaseRemoteGDB::HardBreakpoint::process(ThreadContext *tc)
|
||||||
{
|
{
|
||||||
DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc());
|
DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc());
|
||||||
|
|
||||||
if (tc == gdb->context)
|
if (tc == gdb->context)
|
||||||
gdb->trap(ALPHA_KENTRY_INT);
|
gdb->trap(SIGTRAP);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
RemoteGDB::insertSoftBreak(Addr addr, size_t len)
|
BaseRemoteGDB::insertSoftBreak(Addr addr, size_t len)
|
||||||
{
|
{
|
||||||
if (len != sizeof(MachInst))
|
if (len != sizeof(TheISA::MachInst))
|
||||||
panic("invalid length\n");
|
panic("invalid length\n");
|
||||||
|
|
||||||
return insertHardBreak(addr, len);
|
return insertHardBreak(addr, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
RemoteGDB::removeSoftBreak(Addr addr, size_t len)
|
BaseRemoteGDB::removeSoftBreak(Addr addr, size_t len)
|
||||||
{
|
{
|
||||||
if (len != sizeof(MachInst))
|
if (len != sizeof(MachInst))
|
||||||
panic("invalid length\n");
|
panic("invalid length\n");
|
||||||
|
@ -734,7 +534,7 @@ RemoteGDB::removeSoftBreak(Addr addr, size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
RemoteGDB::insertHardBreak(Addr addr, size_t len)
|
BaseRemoteGDB::insertHardBreak(Addr addr, size_t len)
|
||||||
{
|
{
|
||||||
if (len != sizeof(MachInst))
|
if (len != sizeof(MachInst))
|
||||||
panic("invalid length\n");
|
panic("invalid length\n");
|
||||||
|
@ -751,7 +551,7 @@ RemoteGDB::insertHardBreak(Addr addr, size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
RemoteGDB::removeHardBreak(Addr addr, size_t len)
|
BaseRemoteGDB::removeHardBreak(Addr addr, size_t len)
|
||||||
{
|
{
|
||||||
if (len != sizeof(MachInst))
|
if (len != sizeof(MachInst))
|
||||||
panic("invalid length\n");
|
panic("invalid length\n");
|
||||||
|
@ -772,7 +572,7 @@ RemoteGDB::removeHardBreak(Addr addr, size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
break_type(char c)
|
BaseRemoteGDB::break_type(char c)
|
||||||
{
|
{
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case '0': return "software breakpoint";
|
case '0': return "software breakpoint";
|
||||||
|
@ -790,12 +590,12 @@ break_type(char c)
|
||||||
// makes sense to use POSIX errno values, because that is what the
|
// makes sense to use POSIX errno values, because that is what the
|
||||||
// gdb/remote.c functions want to return.
|
// gdb/remote.c functions want to return.
|
||||||
bool
|
bool
|
||||||
RemoteGDB::trap(int type)
|
BaseRemoteGDB::trap(int type)
|
||||||
{
|
{
|
||||||
uint64_t val;
|
uint64_t val;
|
||||||
size_t datalen, len;
|
size_t datalen, len;
|
||||||
char data[KGDB_BUFLEN + 1];
|
char data[GDBPacketBufLen + 1];
|
||||||
char buffer[sizeof(gdbregs) * 2 + 256];
|
char buffer[gdbregs.size * 2 + 256];
|
||||||
const char *p;
|
const char *p;
|
||||||
char command, subcmd;
|
char command, subcmd;
|
||||||
string var;
|
string var;
|
||||||
|
@ -823,7 +623,7 @@ RemoteGDB::trap(int type)
|
||||||
active = true;
|
active = true;
|
||||||
else
|
else
|
||||||
// Tell remote host that an exception has occurred.
|
// Tell remote host that an exception has occurred.
|
||||||
snprintf((char *)buffer, sizeof(buffer), "S%02x", signal(type));
|
snprintf((char *)buffer, sizeof(buffer), "S%02x", type);
|
||||||
send(buffer);
|
send(buffer);
|
||||||
|
|
||||||
// Stick frame regs into our reg cache.
|
// Stick frame regs into our reg cache.
|
||||||
|
@ -837,24 +637,25 @@ RemoteGDB::trap(int type)
|
||||||
p = data + 1;
|
p = data + 1;
|
||||||
switch (command) {
|
switch (command) {
|
||||||
|
|
||||||
case KGDB_SIGNAL:
|
case GDBSignal:
|
||||||
// if this command came from a running gdb, answer it --
|
// if this command came from a running gdb, answer it --
|
||||||
// the other guy has no way of knowing if we're in or out
|
// the other guy has no way of knowing if we're in or out
|
||||||
// of this loop when he issues a "remote-signal".
|
// of this loop when he issues a "remote-signal".
|
||||||
snprintf((char *)buffer, sizeof(buffer), "S%02x", signal(type));
|
snprintf((char *)buffer, sizeof(buffer),
|
||||||
|
"S%02x", type);
|
||||||
send(buffer);
|
send(buffer);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case KGDB_REG_R:
|
case GDBRegR:
|
||||||
if (2 * sizeof(gdbregs) > sizeof(buffer))
|
if (2 * gdbregs.size > sizeof(buffer))
|
||||||
panic("buffer too small");
|
panic("buffer too small");
|
||||||
|
|
||||||
mem2hex(buffer, gdbregs, sizeof(gdbregs));
|
mem2hex(buffer, gdbregs.regs, gdbregs.size);
|
||||||
send(buffer);
|
send(buffer);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case KGDB_REG_W:
|
case GDBRegW:
|
||||||
p = hex2mem(gdbregs, p, sizeof(gdbregs));
|
p = hex2mem(gdbregs.regs, p, gdbregs.size);
|
||||||
if (p == NULL || *p != '\0')
|
if (p == NULL || *p != '\0')
|
||||||
send("E01");
|
send("E01");
|
||||||
else {
|
else {
|
||||||
|
@ -864,7 +665,7 @@ RemoteGDB::trap(int type)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
case KGDB_SET_REG:
|
case GDBSetReg:
|
||||||
val = hex2i(&p);
|
val = hex2i(&p);
|
||||||
if (*p++ != '=') {
|
if (*p++ != '=') {
|
||||||
send("E01");
|
send("E01");
|
||||||
|
@ -875,14 +676,14 @@ RemoteGDB::trap(int type)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
gdbregs[val] = hex2i(&p);
|
gdbregs.regs[val] = hex2i(&p);
|
||||||
setregs();
|
setregs();
|
||||||
send("OK");
|
send("OK");
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case KGDB_MEM_R:
|
case GDBMemR:
|
||||||
val = hex2i(&p);
|
val = hex2i(&p);
|
||||||
if (*p++ != ',') {
|
if (*p++ != ',') {
|
||||||
send("E02");
|
send("E02");
|
||||||
|
@ -914,7 +715,7 @@ RemoteGDB::trap(int type)
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case KGDB_MEM_W:
|
case GDBMemW:
|
||||||
val = hex2i(&p);
|
val = hex2i(&p);
|
||||||
if (*p++ != ',') {
|
if (*p++ != ',') {
|
||||||
send("E06");
|
send("E06");
|
||||||
|
@ -944,7 +745,7 @@ RemoteGDB::trap(int type)
|
||||||
send("E0B");
|
send("E0B");
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case KGDB_SET_THREAD:
|
case GDBSetThread:
|
||||||
subcmd = *p++;
|
subcmd = *p++;
|
||||||
val = hex2i(&p);
|
val = hex2i(&p);
|
||||||
if (val == 0)
|
if (val == 0)
|
||||||
|
@ -953,14 +754,14 @@ RemoteGDB::trap(int type)
|
||||||
send("E01");
|
send("E01");
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case KGDB_DETACH:
|
case GDBDetach:
|
||||||
case KGDB_KILL:
|
case GDBKill:
|
||||||
active = false;
|
active = false;
|
||||||
clearSingleStep();
|
clearSingleStep();
|
||||||
detach();
|
detach();
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
case KGDB_ASYNC_CONT:
|
case GDBAsyncCont:
|
||||||
subcmd = hex2i(&p);
|
subcmd = hex2i(&p);
|
||||||
if (*p++ == ';') {
|
if (*p++ == ';') {
|
||||||
val = hex2i(&p);
|
val = hex2i(&p);
|
||||||
|
@ -970,7 +771,7 @@ RemoteGDB::trap(int type)
|
||||||
clearSingleStep();
|
clearSingleStep();
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
case KGDB_CONT:
|
case GDBCont:
|
||||||
if (p - data < datalen) {
|
if (p - data < datalen) {
|
||||||
val = hex2i(&p);
|
val = hex2i(&p);
|
||||||
context->setPC(val);
|
context->setPC(val);
|
||||||
|
@ -979,7 +780,7 @@ RemoteGDB::trap(int type)
|
||||||
clearSingleStep();
|
clearSingleStep();
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
case KGDB_ASYNC_STEP:
|
case GDBAsyncStep:
|
||||||
subcmd = hex2i(&p);
|
subcmd = hex2i(&p);
|
||||||
if (*p++ == ';') {
|
if (*p++ == ';') {
|
||||||
val = hex2i(&p);
|
val = hex2i(&p);
|
||||||
|
@ -989,7 +790,7 @@ RemoteGDB::trap(int type)
|
||||||
setSingleStep();
|
setSingleStep();
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
case KGDB_STEP:
|
case GDBStep:
|
||||||
if (p - data < datalen) {
|
if (p - data < datalen) {
|
||||||
val = hex2i(&p);
|
val = hex2i(&p);
|
||||||
context->setPC(val);
|
context->setPC(val);
|
||||||
|
@ -998,7 +799,7 @@ RemoteGDB::trap(int type)
|
||||||
setSingleStep();
|
setSingleStep();
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
case KGDB_CLR_HW_BKPT:
|
case GDBClrHwBkpt:
|
||||||
subcmd = *p++;
|
subcmd = *p++;
|
||||||
if (*p++ != ',') send("E0D");
|
if (*p++ != ',') send("E0D");
|
||||||
val = hex2i(&p);
|
val = hex2i(&p);
|
||||||
|
@ -1030,7 +831,7 @@ RemoteGDB::trap(int type)
|
||||||
send(ret ? "OK" : "E0C");
|
send(ret ? "OK" : "E0C");
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case KGDB_SET_HW_BKPT:
|
case GDBSetHwBkpt:
|
||||||
subcmd = *p++;
|
subcmd = *p++;
|
||||||
if (*p++ != ',') send("E0D");
|
if (*p++ != ',') send("E0D");
|
||||||
val = hex2i(&p);
|
val = hex2i(&p);
|
||||||
|
@ -1062,7 +863,7 @@ RemoteGDB::trap(int type)
|
||||||
send(ret ? "OK" : "E0C");
|
send(ret ? "OK" : "E0C");
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case KGDB_QUERY_VAR:
|
case GDBQueryVar:
|
||||||
var = string(p, datalen - 1);
|
var = string(p, datalen - 1);
|
||||||
if (var == "C")
|
if (var == "C")
|
||||||
send("QC0");
|
send("QC0");
|
||||||
|
@ -1070,17 +871,17 @@ RemoteGDB::trap(int type)
|
||||||
send("");
|
send("");
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case KGDB_SET_BAUD:
|
case GDBSetBaud:
|
||||||
case KGDB_SET_BREAK:
|
case GDBSetBreak:
|
||||||
case KGDB_DEBUG:
|
case GDBDebug:
|
||||||
case KGDB_CYCLE_STEP:
|
case GDBCycleStep:
|
||||||
case KGDB_SIG_CYCLE_STEP:
|
case GDBSigCycleStep:
|
||||||
case KGDB_READ_REG:
|
case GDBReadReg:
|
||||||
case KGDB_SET_VAR:
|
case GDBSetVar:
|
||||||
case KGDB_RESET:
|
case GDBReset:
|
||||||
case KGDB_THREAD_ALIVE:
|
case GDBThreadAlive:
|
||||||
case KGDB_TARGET_EXIT:
|
case GDBTargetExit:
|
||||||
case KGDB_BINARY_DLOAD:
|
case GDBBinaryDload:
|
||||||
// Unsupported command
|
// Unsupported command
|
||||||
DPRINTF(GDBMisc, "Unsupported command: %s\n",
|
DPRINTF(GDBMisc, "Unsupported command: %s\n",
|
||||||
gdb_command(command));
|
gdb_command(command));
|
||||||
|
@ -1106,7 +907,7 @@ RemoteGDB::trap(int type)
|
||||||
// Convert a hex digit into an integer.
|
// Convert a hex digit into an integer.
|
||||||
// This returns -1 if the argument passed is no valid hex digit.
|
// This returns -1 if the argument passed is no valid hex digit.
|
||||||
int
|
int
|
||||||
digit2i(char c)
|
BaseRemoteGDB::digit2i(char c)
|
||||||
{
|
{
|
||||||
if (c >= '0' && c <= '9')
|
if (c >= '0' && c <= '9')
|
||||||
return (c - '0');
|
return (c - '0');
|
||||||
|
@ -1121,14 +922,14 @@ digit2i(char c)
|
||||||
|
|
||||||
// Convert the low 4 bits of an integer into an hex digit.
|
// Convert the low 4 bits of an integer into an hex digit.
|
||||||
char
|
char
|
||||||
i2digit(int n)
|
BaseRemoteGDB::i2digit(int n)
|
||||||
{
|
{
|
||||||
return ("0123456789abcdef"[n & 0x0f]);
|
return ("0123456789abcdef"[n & 0x0f]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert a byte array into an hex string.
|
// Convert a byte array into an hex string.
|
||||||
void
|
void
|
||||||
mem2hex(void *vdst, const void *vsrc, int len)
|
BaseRemoteGDB::mem2hex(void *vdst, const void *vsrc, int len)
|
||||||
{
|
{
|
||||||
char *dst = (char *)vdst;
|
char *dst = (char *)vdst;
|
||||||
const char *src = (const char *)vsrc;
|
const char *src = (const char *)vsrc;
|
||||||
|
@ -1145,7 +946,7 @@ mem2hex(void *vdst, const void *vsrc, int len)
|
||||||
// hex digit. If the string ends in the middle of a byte, NULL is
|
// hex digit. If the string ends in the middle of a byte, NULL is
|
||||||
// returned.
|
// returned.
|
||||||
const char *
|
const char *
|
||||||
hex2mem(void *vdst, const char *src, int maxlen)
|
BaseRemoteGDB::hex2mem(void *vdst, const char *src, int maxlen)
|
||||||
{
|
{
|
||||||
char *dst = (char *)vdst;
|
char *dst = (char *)vdst;
|
||||||
int msb, lsb;
|
int msb, lsb;
|
||||||
|
@ -1166,7 +967,7 @@ hex2mem(void *vdst, const char *src, int maxlen)
|
||||||
// This returns a pointer to the character following the last valid
|
// This returns a pointer to the character following the last valid
|
||||||
// hex digit.
|
// hex digit.
|
||||||
Addr
|
Addr
|
||||||
hex2i(const char **srcp)
|
BaseRemoteGDB::hex2i(const char **srcp)
|
||||||
{
|
{
|
||||||
const char *src = *srcp;
|
const char *src = *srcp;
|
||||||
Addr r = 0;
|
Addr r = 0;
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "arch/types.hh"
|
#include "arch/types.hh"
|
||||||
#include "base/kgdb.h"
|
|
||||||
#include "cpu/pc_event.hh"
|
#include "cpu/pc_event.hh"
|
||||||
#include "base/pollevent.hh"
|
#include "base/pollevent.hh"
|
||||||
#include "base/socket.hh"
|
#include "base/socket.hh"
|
||||||
|
@ -44,22 +43,72 @@ class ThreadContext;
|
||||||
class PhysicalMemory;
|
class PhysicalMemory;
|
||||||
|
|
||||||
class GDBListener;
|
class GDBListener;
|
||||||
class RemoteGDB
|
|
||||||
|
enum GDBCommands
|
||||||
|
{
|
||||||
|
GDBSignal = '?', // last signal
|
||||||
|
GDBSetBaud = 'b', // set baud (depracated)
|
||||||
|
GDBSetBreak = 'B', // set breakpoint (depracated)
|
||||||
|
GDBCont = 'c', // resume
|
||||||
|
GDBAsyncCont = 'C', // continue with signal
|
||||||
|
GDBDebug = 'd', // toggle debug flags (deprecated)
|
||||||
|
GDBDetach = 'D', // detach remote gdb
|
||||||
|
GDBRegR = 'g', // read general registers
|
||||||
|
GDBRegW = 'G', // write general registers
|
||||||
|
GDBSetThread = 'H', // set thread
|
||||||
|
GDBCycleStep = 'i', // step a single cycle
|
||||||
|
GDBSigCycleStep = 'I', // signal then cycle step
|
||||||
|
GDBKill = 'k', // kill program
|
||||||
|
GDBMemR = 'm', // read memory
|
||||||
|
GDBMemW = 'M', // write memory
|
||||||
|
GDBReadReg = 'p', // read register
|
||||||
|
GDBSetReg = 'P', // write register
|
||||||
|
GDBQueryVar = 'q', // query variable
|
||||||
|
GDBSetVar = 'Q', // set variable
|
||||||
|
GDBReset = 'r', // reset system. (Deprecated)
|
||||||
|
GDBStep = 's', // step
|
||||||
|
GDBAsyncStep = 'S', // signal and step
|
||||||
|
GDBThreadAlive = 'T', // find out if the thread is alive
|
||||||
|
GDBTargetExit = 'W', // target exited
|
||||||
|
GDBBinaryDload = 'X', // write memory
|
||||||
|
GDBClrHwBkpt = 'z', // remove breakpoint or watchpoint
|
||||||
|
GDBSetHwBkpt = 'Z' // insert breakpoint or watchpoint
|
||||||
|
};
|
||||||
|
|
||||||
|
const char GDBStart = '$';
|
||||||
|
const char GDBEnd = '#';
|
||||||
|
const char GDBGoodP = '+';
|
||||||
|
const char GDBBadP = '-';
|
||||||
|
|
||||||
|
const int GDBPacketBufLen = 1024;
|
||||||
|
|
||||||
|
class BaseRemoteGDB
|
||||||
{
|
{
|
||||||
protected:
|
|
||||||
typedef TheISA::MachInst MachInst;
|
|
||||||
private:
|
private:
|
||||||
friend void debugger();
|
friend void debugger();
|
||||||
friend class GDBListener;
|
friend class GDBListener;
|
||||||
|
|
||||||
|
//Helper functions
|
||||||
|
protected:
|
||||||
|
int digit2i(char);
|
||||||
|
char i2digit(int);
|
||||||
|
Addr hex2i(const char **);
|
||||||
|
//Address formats, break types, and gdb commands may change
|
||||||
|
//between architectures, so they're defined as virtual
|
||||||
|
//functions.
|
||||||
|
virtual void mem2hex(void *, const void *, int);
|
||||||
|
virtual const char * hex2mem(void *, const char *, int);
|
||||||
|
virtual const char * break_type(char c);
|
||||||
|
virtual const char * gdb_command(char cmd);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
class Event : public PollEvent
|
class Event : public PollEvent
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
RemoteGDB *gdb;
|
BaseRemoteGDB *gdb;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Event(RemoteGDB *g, int fd, int e);
|
Event(BaseRemoteGDB *g, int fd, int e);
|
||||||
void process(int revent);
|
void process(int revent);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -69,8 +118,8 @@ class RemoteGDB
|
||||||
int number;
|
int number;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
//The socket commands come in through
|
||||||
int fd;
|
int fd;
|
||||||
uint64_t gdbregs[KGDB_NUMREGS];
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
#ifdef notyet
|
#ifdef notyet
|
||||||
|
@ -83,6 +132,23 @@ class RemoteGDB
|
||||||
PhysicalMemory *pmem;
|
PhysicalMemory *pmem;
|
||||||
ThreadContext *context;
|
ThreadContext *context;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
class GdbRegCache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GdbRegCache(size_t newSize) : regs(new uint64_t[newSize]), size(newSize)
|
||||||
|
{}
|
||||||
|
~GdbRegCache()
|
||||||
|
{
|
||||||
|
delete [] regs;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t * regs;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
GdbRegCache gdbregs;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint8_t getbyte();
|
uint8_t getbyte();
|
||||||
void putbyte(uint8_t b);
|
void putbyte(uint8_t b);
|
||||||
|
@ -92,15 +158,15 @@ class RemoteGDB
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Machine memory
|
// Machine memory
|
||||||
bool read(Addr addr, size_t size, char *data);
|
virtual bool read(Addr addr, size_t size, char *data);
|
||||||
bool write(Addr addr, size_t size, const char *data);
|
virtual bool write(Addr addr, size_t size, const char *data);
|
||||||
|
|
||||||
template <class T> T read(Addr addr);
|
template <class T> T read(Addr addr);
|
||||||
template <class T> void write(Addr addr, T data);
|
template <class T> void write(Addr addr, T data);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RemoteGDB(System *system, ThreadContext *context);
|
BaseRemoteGDB(System *system, ThreadContext *context, size_t cacheSize);
|
||||||
~RemoteGDB();
|
virtual ~BaseRemoteGDB();
|
||||||
|
|
||||||
void replaceThreadContext(ThreadContext *tc) { context = tc; }
|
void replaceThreadContext(ThreadContext *tc) { context = tc; }
|
||||||
|
|
||||||
|
@ -108,16 +174,15 @@ class RemoteGDB
|
||||||
void detach();
|
void detach();
|
||||||
bool isattached();
|
bool isattached();
|
||||||
|
|
||||||
bool acc(Addr addr, size_t len);
|
virtual bool acc(Addr addr, size_t len) = 0;
|
||||||
static int signal(int type);
|
|
||||||
bool trap(int type);
|
bool trap(int type);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void getregs();
|
virtual void getregs() = 0;
|
||||||
void setregs();
|
virtual void setregs() = 0;
|
||||||
|
|
||||||
void clearSingleStep();
|
virtual void clearSingleStep() = 0;
|
||||||
void setSingleStep();
|
virtual void setSingleStep() = 0;
|
||||||
|
|
||||||
PCEventQueue *getPcEventQueue();
|
PCEventQueue *getPcEventQueue();
|
||||||
|
|
||||||
|
@ -125,13 +190,13 @@ class RemoteGDB
|
||||||
class HardBreakpoint : public PCEvent
|
class HardBreakpoint : public PCEvent
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
RemoteGDB *gdb;
|
BaseRemoteGDB *gdb;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int refcount;
|
int refcount;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HardBreakpoint(RemoteGDB *_gdb, Addr addr);
|
HardBreakpoint(BaseRemoteGDB *_gdb, Addr addr);
|
||||||
std::string name() { return gdb->name() + ".hwbkpt"; }
|
std::string name() { return gdb->name() + ".hwbkpt"; }
|
||||||
|
|
||||||
virtual void process(ThreadContext *tc);
|
virtual void process(ThreadContext *tc);
|
||||||
|
@ -147,27 +212,13 @@ class RemoteGDB
|
||||||
bool insertHardBreak(Addr addr, size_t len);
|
bool insertHardBreak(Addr addr, size_t len);
|
||||||
bool removeHardBreak(Addr addr, size_t len);
|
bool removeHardBreak(Addr addr, size_t len);
|
||||||
|
|
||||||
protected:
|
|
||||||
struct TempBreakpoint {
|
|
||||||
Addr address; // set here
|
|
||||||
MachInst bkpt_inst; // saved instruction at bkpt
|
|
||||||
int init_count; // number of times to skip bkpt
|
|
||||||
int count; // current count
|
|
||||||
};
|
|
||||||
|
|
||||||
TempBreakpoint notTakenBkpt;
|
|
||||||
TempBreakpoint takenBkpt;
|
|
||||||
|
|
||||||
void clearTempBreakpoint(TempBreakpoint &bkpt);
|
|
||||||
void setTempBreakpoint(TempBreakpoint &bkpt, Addr addr);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::string name();
|
std::string name();
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
inline T
|
inline T
|
||||||
RemoteGDB::read(Addr addr)
|
BaseRemoteGDB::read(Addr addr)
|
||||||
{
|
{
|
||||||
T temp;
|
T temp;
|
||||||
read(addr, sizeof(T), (char *)&temp);
|
read(addr, sizeof(T), (char *)&temp);
|
||||||
|
@ -176,7 +227,7 @@ RemoteGDB::read(Addr addr)
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
inline void
|
inline void
|
||||||
RemoteGDB::write(Addr addr, T data)
|
BaseRemoteGDB::write(Addr addr, T data)
|
||||||
{ write(addr, sizeof(T), (const char *)&data); }
|
{ write(addr, sizeof(T), (const char *)&data); }
|
||||||
|
|
||||||
class GDBListener
|
class GDBListener
|
||||||
|
@ -197,11 +248,11 @@ class GDBListener
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ListenSocket listener;
|
ListenSocket listener;
|
||||||
RemoteGDB *gdb;
|
BaseRemoteGDB *gdb;
|
||||||
int port;
|
int port;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GDBListener(RemoteGDB *g, int p);
|
GDBListener(BaseRemoteGDB *g, int p);
|
||||||
~GDBListener();
|
~GDBListener();
|
||||||
|
|
||||||
void accept();
|
void accept();
|
||||||
|
|
|
@ -45,7 +45,6 @@
|
||||||
#if FULL_SYSTEM
|
#if FULL_SYSTEM
|
||||||
#include "arch/tlb.hh"
|
#include "arch/tlb.hh"
|
||||||
#include "arch/vtophys.hh"
|
#include "arch/vtophys.hh"
|
||||||
#include "base/remote_gdb.hh"
|
|
||||||
#include "sim/system.hh"
|
#include "sim/system.hh"
|
||||||
#endif // FULL_SYSTEM
|
#endif // FULL_SYSTEM
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
#include "sim/system.hh"
|
#include "sim/system.hh"
|
||||||
#if FULL_SYSTEM
|
#if FULL_SYSTEM
|
||||||
#include "arch/vtophys.hh"
|
#include "arch/vtophys.hh"
|
||||||
#include "base/remote_gdb.hh"
|
#include "arch/remote_gdb.hh"
|
||||||
#include "kern/kernel_stats.hh"
|
#include "kern/kernel_stats.hh"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,10 @@ class PhysicalMemory;
|
||||||
#if FULL_SYSTEM
|
#if FULL_SYSTEM
|
||||||
class Platform;
|
class Platform;
|
||||||
class GDBListener;
|
class GDBListener;
|
||||||
class RemoteGDB;
|
namespace TheISA
|
||||||
|
{
|
||||||
|
class RemoteGDB;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class System : public SimObject
|
class System : public SimObject
|
||||||
|
@ -157,7 +160,7 @@ class System : public SimObject
|
||||||
#endif
|
#endif
|
||||||
public:
|
public:
|
||||||
#if FULL_SYSTEM
|
#if FULL_SYSTEM
|
||||||
std::vector<RemoteGDB *> remoteGDB;
|
std::vector<TheISA::RemoteGDB *> remoteGDB;
|
||||||
std::vector<GDBListener *> gdbListen;
|
std::vector<GDBListener *> gdbListen;
|
||||||
virtual bool breakpoint() = 0;
|
virtual bool breakpoint() = 0;
|
||||||
#endif // FULL_SYSTEM
|
#endif // FULL_SYSTEM
|
||||||
|
|
Loading…
Reference in a new issue