Add functions to System object to set up function-based events,

including automatically fixing up addresses to deal with
optionally executed Alpha gp update prolog.

SConscript:
    Remove freebsd_events.cc and linux_events.cc.
base/remote_gdb.cc:
cpu/pc_event.cc:
kern/system_events.cc:
kern/system_events.hh:
    PCEvents now schedule themselves in constructor.
cpu/pc_event.hh:
    PCEvents now schedule themselves in the constructor.
    Get rid of constructor versions that don't take an address and
    all the schedule() methods that are now unnecessary.
kern/freebsd/freebsd_system.cc:
kern/freebsd/freebsd_system.hh:
    Use new System methods to schedule function-based events.
    Move FreeBSD-specific function event classes into FreebsdSystem.
kern/linux/linux_system.cc:
kern/linux/linux_system.hh:
    Use new System methods to schedule function-based events.
    Move Linux-specific function event classes into LinuxSystem.
kern/tru64/tru64_events.hh:
    PCEvents now schedule themselves in constructor.
    Add DebugPrintfrEvent to encapsulate raw setting as new type
    (to work better with new System function-event method.)
kern/tru64/tru64_system.cc:
    Use new System methods to schedule function-based events.
kern/tru64/tru64_system.hh:
    Add DebugPrintfrEvent to encapsulate raw setting as new type
    (to work better with new System function-event method.)
sim/system.cc:
sim/system.hh:
    Add functions to set up function-based events, including
    automatically fixing up addresses to deal with optionally
    executed Alpha gp update prolog.

--HG--
extra : convert_revision : c2cf09144297b6602afe755a34a0a2227023783f
This commit is contained in:
Steve Reinhardt 2005-09-24 14:20:29 -04:00
parent b15a7aaf5e
commit d60de7122d
15 changed files with 291 additions and 185 deletions

View file

@ -282,8 +282,6 @@ full_system_sources = Split('''
kern/kernel_stats.cc
kern/system_events.cc
kern/freebsd/freebsd_system.cc
kern/freebsd/freebsd_events.cc
kern/linux/linux_events.cc
kern/linux/linux_syscalls.cc
kern/linux/linux_system.cc
kern/linux/printk.cc

View file

@ -713,7 +713,6 @@ RemoteGDB::HardBreakpoint::HardBreakpoint(RemoteGDB *_gdb, Addr pc)
gdb(_gdb), refcount(0)
{
DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc);
schedule();
}
void

View file

@ -117,8 +117,9 @@ PCEventQueue::equal_range(Addr pc)
return std::equal_range(pc_map.begin(), pc_map.end(), pc, MapCompare());
}
BreakPCEvent::BreakPCEvent(PCEventQueue *q, const std::string &desc, bool del)
: PCEvent(q, desc), remove(del)
BreakPCEvent::BreakPCEvent(PCEventQueue *q, const std::string &desc, Addr addr,
bool del)
: PCEvent(q, desc, addr), remove(del)
{
}
@ -137,8 +138,7 @@ extern "C"
void
sched_break_pc_sys(System *sys, Addr addr)
{
PCEvent *event = new BreakPCEvent(&sys->pcEventQueue, "debug break", true);
event->schedule(addr);
new BreakPCEvent(&sys->pcEventQueue, "debug break", addr, true);
}
extern "C"

View file

@ -47,25 +47,17 @@ class PCEvent
Addr evpc;
public:
PCEvent() : queue(0), evpc(badpc) { }
PCEvent(const std::string &desc)
: description(desc), queue(0), evpc(badpc) { }
PCEvent(PCEventQueue *q, Addr pc = badpc) : queue(q), evpc(pc) { }
PCEvent(PCEventQueue *q, const std::string &desc, Addr pc = badpc)
: description(desc), queue(q), evpc(pc) { }
PCEvent(PCEventQueue *q, const std::string &desc, Addr pc);
virtual ~PCEvent() { if (queue) remove(); }
// for DPRINTF
virtual const std::string name() const { return description; }
std::string descr() const { return description; }
Addr pc() const { return evpc; }
bool remove();
bool schedule();
bool schedule(Addr pc);
bool schedule(PCEventQueue *q, Addr pc);
virtual void process(ExecContext *xc) = 0;
};
@ -120,6 +112,14 @@ class PCEventQueue
void dump() const;
};
inline
PCEvent::PCEvent(PCEventQueue *q, const std::string &desc, Addr pc)
: description(desc), queue(q), evpc(pc)
{
queue->schedule(this);
}
inline bool
PCEvent::remove()
{
@ -129,47 +129,14 @@ PCEvent::remove()
return queue->remove(this);
}
inline bool
PCEvent::schedule()
{
if (!queue || evpc == badpc)
panic("cannot schedule an uninitialized event;");
return queue->schedule(this);
}
inline bool
PCEvent::schedule(Addr pc)
{
if (evpc != badpc)
panic("cannot switch PC");
evpc = pc & ~0x3;
return schedule();
}
inline bool
PCEvent::schedule(PCEventQueue *q, Addr pc)
{
if (queue)
panic("cannot switch event queues");
if (evpc != badpc)
panic("cannot switch addresses");
queue = q;
evpc = pc & ~0x3;
return schedule();
}
class BreakPCEvent : public PCEvent
{
protected:
bool remove;
public:
BreakPCEvent(PCEventQueue *q, const std::string &desc, bool del = false);
BreakPCEvent(PCEventQueue *q, const std::string &desc, Addr addr,
bool del = false);
virtual void process(ExecContext *xc);
};

View file

@ -48,18 +48,13 @@ using namespace std;
FreebsdSystem::FreebsdSystem(Params *p)
: System(p)
{
Addr addr = 0;
/**
* Any time DELAY is called just skip the function.
* Shouldn't we actually emulate the delay?
*/
skipDelayEvent = new SkipFuncEvent(&pcEventQueue, "DELAY");
if (kernelSymtab->findAddress("DELAY", addr))
skipDelayEvent->schedule(addr+sizeof(MachInst));
skipCalibrateClocks = new FreebsdSkipCalibrateClocksEvent(&pcEventQueue, "calibrate_clocks");
if (kernelSymtab->findAddress("calibrate_clocks", addr))
skipCalibrateClocks->schedule(addr + sizeof(MachInst) * 2);
skipDelayEvent = addKernelFuncEvent<SkipFuncEvent>("DELAY");
skipCalibrateClocks =
addKernelFuncEvent<SkipCalibrateClocksEvent>("calibrate_clocks");
}
@ -92,6 +87,14 @@ FreebsdSystem::doCalibrateClocks(ExecContext *xc)
}
void
FreebsdSystem::SkipCalibrateClocksEvent::process(ExecContext *xc)
{
SkipFuncEvent::process(xc);
((FreebsdSystem *)xc->system)->doCalibrateClocks(xc);
}
BEGIN_DECLARE_SIM_OBJECT_PARAMS(FreebsdSystem)
Param<Tick> boot_cpu_frequency;

View file

@ -29,13 +29,22 @@
#ifndef __KERN_FREEBSD_FREEBSD_SYSTEM_HH__
#define __KERN_FREEBSD_FREEBSD_SYSTEM_HH__
#include "kern/freebsd/freebsd_events.hh"
#include "kern/system_events.hh"
class FreebsdSystem : public System
{
private:
class SkipCalibrateClocksEvent : public SkipFuncEvent
{
public:
SkipCalibrateClocksEvent(PCEventQueue *q, const std::string &desc,
Addr addr)
: SkipFuncEvent(q, desc, addr) {}
virtual void process(ExecContext *xc);
};
SkipFuncEvent *skipDelayEvent;
FreebsdSkipCalibrateClocksEvent *skipCalibrateClocks;
SkipCalibrateClocksEvent *skipCalibrateClocks;
public:
FreebsdSystem(Params *p);

View file

@ -38,12 +38,14 @@
#include "base/loader/symtab.hh"
#include "cpu/exec_context.hh"
#include "cpu/base.hh"
#include "kern/linux/linux_events.hh"
#include "kern/linux/linux_system.hh"
#include "kern/linux/linux_threadinfo.hh"
#include "kern/linux/printk.hh"
#include "mem/functional/memory_control.hh"
#include "mem/functional/physical.hh"
#include "sim/builder.hh"
#include "dev/platform.hh"
#include "targetarch/arguments.hh"
#include "targetarch/vtophys.hh"
using namespace std;
@ -106,80 +108,57 @@ LinuxSystem::LinuxSystem(Params *p)
panic("could not find dp264_mv\n");
#ifndef NDEBUG
kernelPanicEvent = new BreakPCEvent(&pcEventQueue, "kernel panic");
if (kernelSymtab->findAddress("panic", addr))
kernelPanicEvent->schedule(addr);
else
kernelPanicEvent = addKernelFuncEvent<BreakPCEvent>("panic");
if (!kernelPanicEvent)
panic("could not find kernel symbol \'panic\'");
#if 0
kernelDieEvent = new BreakPCEvent(&pcEventQueue, "die if kernel");
if (kernelSymtab->findAddress("die_if_kernel", addr))
kernelDieEvent->schedule(addr);
else
kernelDieEvent = addKernelFuncEvent<BreakPCEvent>("die_if_kernel");
if (!kernelDieEvent)
panic("could not find kernel symbol \'die_if_kernel\'");
#endif
#endif
/**
* Any time ide_delay_50ms, calibarte_delay or
v * Any time ide_delay_50ms, calibarte_delay or
* determine_cpu_caches is called just skip the
* function. Currently determine_cpu_caches only is used put
* information in proc, however if that changes in the future we
* will have to fill in the cache size variables appropriately.
*/
skipIdeDelay50msEvent = new SkipFuncEvent(&pcEventQueue, "ide_delay_50ms");
if (kernelSymtab->findAddress("ide_delay_50ms", addr))
skipIdeDelay50msEvent->schedule(addr+sizeof(MachInst));
skipDelayLoopEvent = new LinuxSkipDelayLoopEvent(&pcEventQueue,
"calibrate_delay");
if (kernelSymtab->findAddress("calibrate_delay", addr)) {
skipDelayLoopEvent->schedule(addr + 3 * sizeof(MachInst));
skipIdeDelay50msEvent =
addKernelFuncEvent<SkipFuncEvent>("ide_delay_50ms");
skipDelayLoopEvent =
addKernelFuncEvent<SkipDelayLoopEvent>("calibrate_delay");
skipCacheProbeEvent =
addKernelFuncEvent<SkipFuncEvent>("determine_cpu_caches");
debugPrintkEvent = addKernelFuncEvent<DebugPrintkEvent>("dprintk");
idleStartEvent = addKernelFuncEvent<IdleStartEvent>("cpu_idle");
if (kernelSymtab->findAddress("alpha_switch_to", addr) && DTRACE(Thread)) {
printThreadEvent = new PrintThreadInfo(&pcEventQueue, "threadinfo",
addr + sizeof(MachInst) * 6);
} else {
printThreadEvent = NULL;
}
skipCacheProbeEvent = new SkipFuncEvent(&pcEventQueue,
"determine_cpu_caches");
if (kernelSymtab->findAddress("determine_cpu_caches", addr))
skipCacheProbeEvent->schedule(addr+sizeof(MachInst));
debugPrintkEvent = new DebugPrintkEvent(&pcEventQueue, "dprintk");
if (kernelSymtab->findAddress("dprintk", addr))
debugPrintkEvent->schedule(addr+8);
idleStartEvent = new IdleStartEvent(&pcEventQueue, "cpu_idle", this);
if (kernelSymtab->findAddress("cpu_idle", addr))
idleStartEvent->schedule(addr);
printThreadEvent = new PrintThreadInfo(&pcEventQueue, "threadinfo");
if (kernelSymtab->findAddress("alpha_switch_to", addr) && DTRACE(Thread))
printThreadEvent->schedule(addr + sizeof(MachInst) * 6);
intStartEvent = new InterruptStartEvent(&pcEventQueue, "intStartEvent");
if (params->bin_int) {
if (palSymtab->findAddress("sys_int_21", addr))
intStartEvent->schedule(addr + sizeof(MachInst) * 2);
else
intStartEvent = addPalFuncEvent<InterruptStartEvent>("sys_int_21");
if (!intStartEvent)
panic("could not find symbol: sys_int_21\n");
intEndEvent = new InterruptEndEvent(&pcEventQueue, "intEndEvent");
if (palSymtab->findAddress("rti_to_kern", addr))
intEndEvent->schedule(addr) ;
else
intEndEvent = addPalFuncEvent<InterruptEndEvent>("rti_to_kern");
if (!intEndEvent)
panic("could not find symbol: rti_to_kern\n");
intEndEvent2 = new InterruptEndEvent(&pcEventQueue, "intEndEvent2");
if (palSymtab->findAddress("rti_to_user", addr))
intEndEvent2->schedule(addr);
else
intEndEvent2 = addPalFuncEvent<InterruptEndEvent>("rti_to_user");
if (!intEndEvent2)
panic("could not find symbol: rti_to_user\n");
intEndEvent3 = new InterruptEndEvent(&pcEventQueue, "intEndEvent3");
if (kernelSymtab->findAddress("do_softirq", addr))
intEndEvent3->schedule(addr + sizeof(MachInst) * 2);
else
intEndEvent3 = addKernelFuncEvent<InterruptEndEvent>("do_softirq");
if (!intEndEvent3)
panic("could not find symbol: do_softirq\n");
}
}
@ -218,6 +197,39 @@ LinuxSystem::setDelayLoop(ExecContext *xc)
}
}
void
LinuxSystem::SkipDelayLoopEvent::process(ExecContext *xc)
{
SkipFuncEvent::process(xc);
// calculate and set loops_per_jiffy
((LinuxSystem *)xc->system)->setDelayLoop(xc);
}
void
LinuxSystem::DebugPrintkEvent::process(ExecContext *xc)
{
if (DTRACE(DebugPrintf)) {
if (!raw) {
StringWrap name(xc->system->name() + ".dprintk");
DPRINTFN("");
}
AlphaArguments args(xc);
Printk(args);
SkipFuncEvent::process(xc);
}
}
void
LinuxSystem::PrintThreadInfo::process(ExecContext *xc)
{
Linux::ThreadInfo ti(xc);
DPRINTF(Thread, "Currently Executing Thread %s, pid %d, started at: %d\n",
ti.curTaskName(), ti.curTaskPID(), ti.curTaskStart());
}
BEGIN_DECLARE_SIM_OBJECT_PARAMS(LinuxSystem)
Param<Tick> boot_cpu_frequency;

View file

@ -32,10 +32,6 @@
class ExecContext;
class BreakPCEvent;
class DebugPrintkEvent;
class BreakPCEvent;
class LinuxSkipDelayLoopEvent;
class SkipFuncEvent;
class IdleStartEvent;
class PrintThreadInfo;
@ -47,6 +43,34 @@ class PrintThreadInfo;
class LinuxSystem : public System
{
private:
class SkipDelayLoopEvent : public SkipFuncEvent
{
public:
SkipDelayLoopEvent(PCEventQueue *q, const std::string &desc, Addr addr)
: SkipFuncEvent(q, desc, addr) {}
virtual void process(ExecContext *xc);
};
class DebugPrintkEvent : public SkipFuncEvent
{
private:
bool raw;
public:
DebugPrintkEvent(PCEventQueue *q, const std::string &desc, Addr addr,
bool r = false)
: SkipFuncEvent(q, desc, addr), raw(r) {}
virtual void process(ExecContext *xc);
};
class PrintThreadInfo : public PCEvent
{
public:
PrintThreadInfo(PCEventQueue *q, const std::string &desc, Addr addr)
: PCEvent(q, desc, addr) {}
virtual void process(ExecContext *xc);
};
/**
* Addresses defining where the kernel bootloader places various
* elements. Details found in include/asm-alpha/system.h
@ -94,7 +118,7 @@ class LinuxSystem : public System
* Skip calculate_delay_loop() rather than waiting for this to be
* calculated
*/
LinuxSkipDelayLoopEvent *skipDelayLoopEvent;
SkipDelayLoopEvent *skipDelayLoopEvent;
/**
* Event to print information about thread switches if the trace flag

View file

@ -47,8 +47,9 @@ SkipFuncEvent::process(ExecContext *xc)
}
FnEvent::FnEvent(PCEventQueue *q, const std::string &desc, Stats::MainBin *bin)
: PCEvent(q, desc), _name(desc), mybin(bin)
FnEvent::FnEvent(PCEventQueue *q, const std::string &desc, Addr addr,
Stats::MainBin *bin)
: PCEvent(q, desc, addr), _name(desc), mybin(bin)
{
}

View file

@ -29,20 +29,24 @@
#ifndef __SYSTEM_EVENTS_HH__
#define __SYSTEM_EVENTS_HH__
#include "cpu/pc_event.hh"
class System;
class SkipFuncEvent : public PCEvent
{
public:
SkipFuncEvent(PCEventQueue *q, const std::string &desc)
: PCEvent(q, desc) {}
SkipFuncEvent(PCEventQueue *q, const std::string &desc, Addr addr)
: PCEvent(q, desc, addr)
{}
virtual void process(ExecContext *xc);
};
class FnEvent : public PCEvent
{
public:
FnEvent(PCEventQueue *q, const std::string &desc, Stats::MainBin *bin);
FnEvent(PCEventQueue *q, const std::string &desc, Addr addr,
Stats::MainBin *bin);
virtual void process(ExecContext *xc);
std::string myname() const { return _name; }
@ -53,12 +57,9 @@ class FnEvent : public PCEvent
class IdleStartEvent : public PCEvent
{
private:
System *system;
public:
IdleStartEvent(PCEventQueue *q, const std::string &desc, System *sys)
: PCEvent(q, desc), system(sys)
IdleStartEvent(PCEventQueue *q, const std::string &desc, Addr addr)
: PCEvent(q, desc, addr)
{}
virtual void process(ExecContext *xc);
};
@ -66,8 +67,8 @@ class IdleStartEvent : public PCEvent
class InterruptStartEvent : public PCEvent
{
public:
InterruptStartEvent(PCEventQueue *q, const std::string &desc)
: PCEvent(q, desc)
InterruptStartEvent(PCEventQueue *q, const std::string &desc, Addr addr)
: PCEvent(q, desc, addr)
{}
virtual void process(ExecContext *xc);
};
@ -75,8 +76,8 @@ class InterruptStartEvent : public PCEvent
class InterruptEndEvent : public PCEvent
{
public:
InterruptEndEvent(PCEventQueue *q, const std::string &desc)
: PCEvent(q, desc)
InterruptEndEvent(PCEventQueue *q, const std::string &desc, Addr addr)
: PCEvent(q, desc, addr)
{}
virtual void process(ExecContext *xc);
};

View file

@ -39,16 +39,16 @@ class ExecContext;
class BadAddrEvent : public SkipFuncEvent
{
public:
BadAddrEvent(PCEventQueue *q, const std::string &desc)
: SkipFuncEvent(q, desc) {}
BadAddrEvent(PCEventQueue *q, const std::string &desc, Addr addr)
: SkipFuncEvent(q, desc, addr) {}
virtual void process(ExecContext *xc);
};
class PrintfEvent : public PCEvent
{
public:
PrintfEvent(PCEventQueue *q, const std::string &desc)
: PCEvent(q, desc) {}
PrintfEvent(PCEventQueue *q, const std::string &desc, Addr addr)
: PCEvent(q, desc, addr) {}
virtual void process(ExecContext *xc);
};
@ -58,16 +58,25 @@ class DebugPrintfEvent : public PCEvent
bool raw;
public:
DebugPrintfEvent(PCEventQueue *q, const std::string &desc, bool r = false)
: PCEvent(q, desc), raw(r) {}
DebugPrintfEvent(PCEventQueue *q, const std::string &desc, Addr addr,
bool r = false)
: PCEvent(q, desc, addr), raw(r) {}
virtual void process(ExecContext *xc);
};
class DebugPrintfrEvent : public DebugPrintfEvent
{
public:
DebugPrintfrEvent(PCEventQueue *q, const std::string &desc, Addr addr)
: DebugPrintfEvent(q, desc, addr, true)
{}
};
class DumpMbufEvent : public PCEvent
{
public:
DumpMbufEvent(PCEventQueue *q, const std::string &desc)
: PCEvent(q, desc) {}
DumpMbufEvent(PCEventQueue *q, const std::string &desc, Addr addr)
: PCEvent(q, desc, addr) {}
virtual void process(ExecContext *xc);
};

View file

@ -55,47 +55,25 @@ Tru64System::Tru64System(Tru64System::Params *p)
}
#ifdef DEBUG
kernelPanicEvent = new BreakPCEvent(&pcEventQueue, "kernel panic");
if (kernelSymtab->findAddress("panic", addr))
kernelPanicEvent->schedule(addr);
else
kernelPanicEvent = addKernelFuncEvent<BreakPCEvent>("panic");
if (!kernelPanicEvent)
panic("could not find kernel symbol \'panic\'");
#endif
badaddrEvent = new BadAddrEvent(&pcEventQueue, "badaddr");
if (kernelSymtab->findAddress("badaddr", addr))
badaddrEvent->schedule(addr);
else
badaddrEvent = addKernelFuncEvent<BadAddrEvent>("badaddr");
if (!badaddrEvent)
panic("could not find kernel symbol \'badaddr\'");
skipPowerStateEvent = new SkipFuncEvent(&pcEventQueue,
"tl_v48_capture_power_state");
if (kernelSymtab->findAddress("tl_v48_capture_power_state", addr))
skipPowerStateEvent->schedule(addr);
skipScavengeBootEvent = new SkipFuncEvent(&pcEventQueue,
"pmap_scavenge_boot");
if (kernelSymtab->findAddress("pmap_scavenge_boot", addr))
skipScavengeBootEvent->schedule(addr);
skipPowerStateEvent =
addKernelFuncEvent<SkipFuncEvent>("tl_v48_capture_power_state");
skipScavengeBootEvent =
addKernelFuncEvent<SkipFuncEvent>("pmap_scavenge_boot");
#if TRACING_ON
printfEvent = new PrintfEvent(&pcEventQueue, "printf");
if (kernelSymtab->findAddress("printf", addr))
printfEvent->schedule(addr);
debugPrintfEvent = new DebugPrintfEvent(&pcEventQueue, "debug_printf",
false);
if (kernelSymtab->findAddress("m5printf", addr))
debugPrintfEvent->schedule(addr);
debugPrintfrEvent = new DebugPrintfEvent(&pcEventQueue, "debug_printfr",
true);
if (kernelSymtab->findAddress("m5printfr", addr))
debugPrintfrEvent->schedule(addr);
dumpMbufEvent = new DumpMbufEvent(&pcEventQueue, "dump_mbuf");
if (kernelSymtab->findAddress("m5_dump_mbuf", addr))
dumpMbufEvent->schedule(addr);
printfEvent = addKernelFuncEvent<PrintfEvent>("printf");
debugPrintfEvent = addKernelFuncEvent<DebugPrintfEvent>("m5printf");
debugPrintfrEvent = addKernelFuncEvent<DebugPrintfrEvent>("m5printfr");
dumpMbufEvent = addKernelFuncEvent<DumpMbufEvent>("m5_dump_mbuf");
#endif
}

View file

@ -54,8 +54,8 @@ class Tru64System : public System
SkipFuncEvent *skipPowerStateEvent;
SkipFuncEvent *skipScavengeBootEvent;
PrintfEvent *printfEvent;
DebugPrintfEvent *debugPrintfEvent;
DebugPrintfEvent *debugPrintfrEvent;
DebugPrintfEvent *debugPrintfEvent;
DebugPrintfrEvent *debugPrintfrEvent;
DumpMbufEvent *dumpMbufEvent;
public:

View file

@ -124,9 +124,7 @@ System::System(Params *p)
Addr addr = 0;
#ifdef DEBUG
consolePanicEvent = new BreakPCEvent(&pcEventQueue, "console panic");
if (consoleSymtab->findAddress("panic", addr))
consolePanicEvent->schedule(addr);
consolePanicEvent = addConsoleFuncEvent<BreakPCEvent>("panic");
#endif
/**
@ -180,6 +178,65 @@ System::~System()
#endif
}
/**
* This function fixes up addresses that are used to match PCs for
* hooking simulator events on to target function executions.
*
* Alpha binaries may have multiple global offset table (GOT)
* sections. A function that uses the GOT starts with a
* two-instruction prolog which sets the global pointer (gp == r29) to
* the appropriate GOT section. The proper gp value is calculated
* based on the function address, which must be passed by the caller
* in the procedure value register (pv aka t12 == r27). This sequence
* looks like the following:
*
* opcode Ra Rb offset
* ldah gp,X(pv) 09 29 27 X
* lda gp,Y(gp) 08 29 29 Y
*
* for some constant offsets X and Y. The catch is that the linker
* (or maybe even the compiler, I'm not sure) may recognize that the
* caller and callee are using the same GOT section, making this
* prolog redundant, and modify the call target to skip these
* instructions. If we check for execution of the first instruction
* of a function (the one the symbol points to) to detect when to skip
* it, we'll miss all these modified calls. It might work to
* unconditionally check for the third instruction, but not all
* functions have this prolog, and there's some chance that those
* first two instructions could have undesired consequences. So we do
* the Right Thing and pattern-match the first two instructions of the
* function to decide where to patch.
*
* Eventually this code should be moved into an ISA-specific file.
*/
Addr
System::fixFuncEventAddr(Addr addr)
{
// mask for just the opcode, Ra, and Rb fields (not the offset)
const uint32_t inst_mask = 0xffff0000;
// ldah gp,X(pv): opcode 9, Ra = 29, Rb = 27
const uint32_t gp_ldah_pattern = (9 << 26) | (29 << 21) | (27 << 16);
// lda gp,Y(gp): opcode 8, Ra = 29, rb = 29
const uint32_t gp_lda_pattern = (8 << 26) | (29 << 21) | (29 << 16);
// instruction size
const int sz = sizeof(uint32_t);
Addr paddr = vtophys(physmem, addr);
uint32_t i1 = *(uint32_t *)physmem->dma_addr(paddr, sz);
uint32_t i2 = *(uint32_t *)physmem->dma_addr(paddr+sz, sz);
if ((i1 & inst_mask) == gp_ldah_pattern &&
(i2 & inst_mask) == gp_lda_pattern) {
Addr new_addr = addr + 2*sz;
DPRINTF(Loader, "fixFuncEventAddr: %p -> %p", addr, new_addr);
return new_addr;
} else {
return addr;
}
}
void
System::setAlphaAccess(Addr access)
{
@ -197,6 +254,7 @@ System::setAlphaAccess(Addr access)
panic("could not find m5AlphaAccess\n");
}
bool
System::breakpoint()
{

View file

@ -33,6 +33,7 @@
#include <vector>
#include "base/statistics.hh"
#include "base/loader/symtab.hh"
#include "cpu/pc_event.hh"
#include "kern/system_events.hh"
#include "sim/sim_object.hh"
@ -45,7 +46,6 @@ class ObjectFile;
class PhysicalMemory;
class Platform;
class RemoteGDB;
class SymbolTable;
namespace Kernel { class Binning; }
class System : public SimObject
@ -68,7 +68,7 @@ class System : public SimObject
return numcpus;
}
/** kernel Symbol table */
/** kernel symbol table */
SymbolTable *kernelSymtab;
/** console symbol table */
@ -102,6 +102,53 @@ class System : public SimObject
BreakPCEvent *consolePanicEvent;
#endif
protected:
/**
* Fix up an address used to match PCs for hooking simulator
* events on to target function executions. See comment in
* system.cc for details.
*/
Addr fixFuncEventAddr(Addr addr);
/**
* Add a function-based event to the given function, to be looked
* up in the specified symbol table.
*/
template <class T>
T *System::addFuncEvent(SymbolTable *symtab, const char *lbl)
{
Addr addr;
if (symtab->findAddress(lbl, addr)) {
T *ev = new T(&pcEventQueue, lbl, fixFuncEventAddr(addr));
return ev;
}
return NULL;
}
/** Add a function-based event to kernel code. */
template <class T>
T *System::addKernelFuncEvent(const char *lbl)
{
return addFuncEvent<T>(kernelSymtab, lbl);
}
/** Add a function-based event to PALcode. */
template <class T>
T *System::addPalFuncEvent(const char *lbl)
{
return addFuncEvent<T>(palSymtab, lbl);
}
/** Add a function-based event to the console code. */
template <class T>
T *System::addConsoleFuncEvent(const char *lbl)
{
return addFuncEvent<T>(consoleSymtab, lbl);
}
public:
std::vector<RemoteGDB *> remoteGDB;
std::vector<GDBListener *> gdbListen;