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
gdb(_gdb), refcount(0)
{
DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc);
- schedule();
}
void
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)
{
}
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"
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;
};
void dump() const;
};
-inline bool
-PCEvent::remove()
-{
- if (!queue)
- panic("cannot remove an uninitialized event;");
-
- return queue->remove(this);
-}
-inline bool
-PCEvent::schedule()
+inline
+PCEvent::PCEvent(PCEventQueue *q, const std::string &desc, Addr pc)
+ : description(desc), queue(q), evpc(pc)
{
- 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();
+ queue->schedule(this);
}
inline bool
-PCEvent::schedule(PCEventQueue *q, Addr pc)
+PCEvent::remove()
{
- if (queue)
- panic("cannot switch event queues");
-
- if (evpc != badpc)
- panic("cannot switch addresses");
-
- queue = q;
- evpc = pc & ~0x3;
+ if (!queue)
+ panic("cannot remove an uninitialized event;");
- return schedule();
+ return queue->remove(this);
}
class BreakPCEvent : public PCEvent
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);
};
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");
}
}
+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;
#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);
#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;
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));
- }
-
- 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");
+ 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;
+ }
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");
}
}
}
}
+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;
class ExecContext;
class BreakPCEvent;
-class DebugPrintkEvent;
-class BreakPCEvent;
-class LinuxSkipDelayLoopEvent;
-class SkipFuncEvent;
class IdleStartEvent;
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
* 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
}
-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)
{
}
#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; }
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);
};
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);
};
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);
};
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);
};
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);
};
}
#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
}
SkipFuncEvent *skipPowerStateEvent;
SkipFuncEvent *skipScavengeBootEvent;
PrintfEvent *printfEvent;
- DebugPrintfEvent *debugPrintfEvent;
- DebugPrintfEvent *debugPrintfrEvent;
+ DebugPrintfEvent *debugPrintfEvent;
+ DebugPrintfrEvent *debugPrintfrEvent;
DumpMbufEvent *dumpMbufEvent;
public:
Addr addr = 0;
#ifdef DEBUG
- consolePanicEvent = new BreakPCEvent(&pcEventQueue, "console panic");
- if (consoleSymtab->findAddress("panic", addr))
- consolePanicEvent->schedule(addr);
+ consolePanicEvent = addConsoleFuncEvent<BreakPCEvent>("panic");
#endif
/**
#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)
{
panic("could not find m5AlphaAccess\n");
}
+
bool
System::breakpoint()
{
#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"
class PhysicalMemory;
class Platform;
class RemoteGDB;
-class SymbolTable;
namespace Kernel { class Binning; }
class System : public SimObject
return numcpus;
}
- /** kernel Symbol table */
+ /** kernel symbol table */
SymbolTable *kernelSymtab;
/** console symbol table */
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;