diff --git a/SConscript b/SConscript index 2cbc96dda..4e2347431 100644 --- a/SConscript +++ b/SConscript @@ -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 diff --git a/base/remote_gdb.cc b/base/remote_gdb.cc index 17331fcd9..3af73179a 100644 --- a/base/remote_gdb.cc +++ b/base/remote_gdb.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 diff --git a/cpu/pc_event.cc b/cpu/pc_event.cc index c3bb3dbe6..83fbc3e2d 100644 --- a/cpu/pc_event.cc +++ b/cpu/pc_event.cc @@ -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" diff --git a/cpu/pc_event.hh b/cpu/pc_event.hh index 65ef0a088..7fa3902cc 100644 --- a/cpu/pc_event.hh +++ b/cpu/pc_event.hh @@ -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); }; diff --git a/kern/freebsd/freebsd_system.cc b/kern/freebsd/freebsd_system.cc index 5e0ce113b..283713d40 100644 --- a/kern/freebsd/freebsd_system.cc +++ b/kern/freebsd/freebsd_system.cc @@ -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("DELAY"); + skipCalibrateClocks = + addKernelFuncEvent("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 boot_cpu_frequency; diff --git a/kern/freebsd/freebsd_system.hh b/kern/freebsd/freebsd_system.hh index 6429b5690..ecb842ec6 100644 --- a/kern/freebsd/freebsd_system.hh +++ b/kern/freebsd/freebsd_system.hh @@ -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); diff --git a/kern/linux/linux_system.cc b/kern/linux/linux_system.cc index e3b9990c5..addce0389 100644 --- a/kern/linux/linux_system.cc +++ b/kern/linux/linux_system.cc @@ -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("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("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("ide_delay_50ms"); + skipDelayLoopEvent = + addKernelFuncEvent("calibrate_delay"); + skipCacheProbeEvent = + addKernelFuncEvent("determine_cpu_caches"); + debugPrintkEvent = addKernelFuncEvent("dprintk"); + idleStartEvent = addKernelFuncEvent("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("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("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("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("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 boot_cpu_frequency; diff --git a/kern/linux/linux_system.hh b/kern/linux/linux_system.hh index 2ddddbc1a..f883bef93 100644 --- a/kern/linux/linux_system.hh +++ b/kern/linux/linux_system.hh @@ -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 diff --git a/kern/system_events.cc b/kern/system_events.cc index d5c0d242a..ba3c9274a 100644 --- a/kern/system_events.cc +++ b/kern/system_events.cc @@ -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) { } diff --git a/kern/system_events.hh b/kern/system_events.hh index 94f6efeba..246140a09 100644 --- a/kern/system_events.hh +++ b/kern/system_events.hh @@ -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); }; diff --git a/kern/tru64/tru64_events.hh b/kern/tru64/tru64_events.hh index d3b6d6f8c..9b5bcfea2 100644 --- a/kern/tru64/tru64_events.hh +++ b/kern/tru64/tru64_events.hh @@ -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); }; diff --git a/kern/tru64/tru64_system.cc b/kern/tru64/tru64_system.cc index d4b056c62..f65293474 100644 --- a/kern/tru64/tru64_system.cc +++ b/kern/tru64/tru64_system.cc @@ -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("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("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("tl_v48_capture_power_state"); + skipScavengeBootEvent = + addKernelFuncEvent("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("printf"); + debugPrintfEvent = addKernelFuncEvent("m5printf"); + debugPrintfrEvent = addKernelFuncEvent("m5printfr"); + dumpMbufEvent = addKernelFuncEvent("m5_dump_mbuf"); #endif } diff --git a/kern/tru64/tru64_system.hh b/kern/tru64/tru64_system.hh index 290b44230..a9077e112 100644 --- a/kern/tru64/tru64_system.hh +++ b/kern/tru64/tru64_system.hh @@ -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: diff --git a/sim/system.cc b/sim/system.cc index 3da92c447..e67cae333 100644 --- a/sim/system.cc +++ b/sim/system.cc @@ -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("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() { diff --git a/sim/system.hh b/sim/system.hh index 870805e4c..c4ecc9458 100644 --- a/sim/system.hh +++ b/sim/system.hh @@ -33,6 +33,7 @@ #include #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 + 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 + T *System::addKernelFuncEvent(const char *lbl) + { + return addFuncEvent(kernelSymtab, lbl); + } + + /** Add a function-based event to PALcode. */ + template + T *System::addPalFuncEvent(const char *lbl) + { + return addFuncEvent(palSymtab, lbl); + } + + /** Add a function-based event to the console code. */ + template + T *System::addConsoleFuncEvent(const char *lbl) + { + return addFuncEvent(consoleSymtab, lbl); + } + public: std::vector remoteGDB; std::vector gdbListen;