diff options
Diffstat (limited to 'sim')
-rw-r--r-- | sim/system.cc | 64 | ||||
-rw-r--r-- | sim/system.hh | 51 |
2 files changed, 110 insertions, 5 deletions
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<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() { 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 <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; |