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:
parent
b15a7aaf5e
commit
d60de7122d
15 changed files with 291 additions and 185 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue