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:
Gabe Black 2006-11-06 18:29:58 -05:00
parent e39de58d21
commit 85a6079db7
13 changed files with 1368 additions and 373 deletions

View file

@ -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

View file

@ -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

View file

@ -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"

View 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;
}

View 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__ */

View file

@ -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"

View 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;
}

View 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__ */

View file

@ -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;

View file

@ -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();

View file

@ -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

View file

@ -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

View file

@ -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