From 8dd7700482b8ad7fa5e96469b23f0c917f5e3599 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sat, 28 Jul 2007 20:30:43 -0700 Subject: [PATCH 01/15] Turn the instruction tracing code into pluggable sim objects. These need to be refined a little still and given parameters. --HG-- extra : convert_revision : 9a8f5a7bd9dacbebbbd2c235cd890c49a81040d7 --- src/cpu/BaseCPU.py | 6 + src/cpu/ExeTracer.py | 36 ++ src/cpu/IntelTrace.py | 36 ++ src/cpu/LegionTrace.py | 36 ++ src/cpu/NativeTrace.py | 36 ++ src/cpu/SConscript | 11 + src/cpu/base.cc | 2 + src/cpu/base.hh | 8 + src/cpu/exetrace.cc | 802 +++------------------------------------ src/cpu/exetrace.hh | 135 ++----- src/cpu/inteltrace.cc | 70 ++++ src/cpu/inteltrace.hh | 84 ++++ src/cpu/legiontrace.cc | 600 +++++++++++++++++++++++++++++ src/cpu/legiontrace.hh | 77 ++++ src/cpu/nativetrace.cc | 188 +++++++++ src/cpu/nativetrace.hh | 96 +++++ src/cpu/o3/fetch_impl.hh | 5 +- src/cpu/simple/atomic.cc | 1 + src/cpu/simple/base.cc | 2 +- src/cpu/simple/timing.cc | 1 + src/sim/InstTracer.py | 35 ++ src/sim/SConscript | 1 + src/sim/insttracer.hh | 146 +++++++ 23 files changed, 1556 insertions(+), 858 deletions(-) create mode 100644 src/cpu/ExeTracer.py create mode 100644 src/cpu/IntelTrace.py create mode 100644 src/cpu/LegionTrace.py create mode 100644 src/cpu/NativeTrace.py create mode 100644 src/cpu/inteltrace.cc create mode 100644 src/cpu/inteltrace.hh create mode 100644 src/cpu/legiontrace.cc create mode 100644 src/cpu/legiontrace.hh create mode 100644 src/cpu/nativetrace.cc create mode 100644 src/cpu/nativetrace.hh create mode 100644 src/sim/InstTracer.py create mode 100644 src/sim/insttracer.hh diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py index 6c2aace51..8be84392d 100644 --- a/src/cpu/BaseCPU.py +++ b/src/cpu/BaseCPU.py @@ -31,8 +31,12 @@ from m5.params import * from m5.proxy import * from m5 import build_env from Bus import Bus +from InstTracer import InstTracer +from ExeTracer import ExeTracer import sys +default_tracer = ExeTracer() + if build_env['FULL_SYSTEM']: if build_env['TARGET_ISA'] == 'alpha': from AlphaTLB import AlphaDTB, AlphaITB @@ -83,6 +87,8 @@ class BaseCPU(SimObject): clock = Param.Clock('1t', "clock speed") phase = Param.Latency('0ns', "clock phase") + tracer = Param.InstTracer(default_tracer, "Instruction tracer") + _mem_ports = [] def connectMemPorts(self, bus): diff --git a/src/cpu/ExeTracer.py b/src/cpu/ExeTracer.py new file mode 100644 index 000000000..e904f9e7d --- /dev/null +++ b/src/cpu/ExeTracer.py @@ -0,0 +1,36 @@ +# Copyright (c) 2007 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.SimObject import SimObject +from m5.params import * +from InstTracer import InstTracer + +class ExeTracer(InstTracer): + type = 'ExeTracer' + cxx_namespace = 'Trace' + cxx_class = 'ExeTracer' diff --git a/src/cpu/IntelTrace.py b/src/cpu/IntelTrace.py new file mode 100644 index 000000000..6e8f567b3 --- /dev/null +++ b/src/cpu/IntelTrace.py @@ -0,0 +1,36 @@ +# Copyright (c) 2007 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.SimObject import SimObject +from m5.params import * +from InstTracer import InstTracer + +class IntelTrace(InstTracer): + type = 'IntelTrace' + cxx_namespace = 'Trace' + cxx_class = 'IntelTrace' diff --git a/src/cpu/LegionTrace.py b/src/cpu/LegionTrace.py new file mode 100644 index 000000000..f9b6470a6 --- /dev/null +++ b/src/cpu/LegionTrace.py @@ -0,0 +1,36 @@ +# Copyright (c) 2007 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.SimObject import SimObject +from m5.params import * +from InstTracer import InstTracer + +class LegionTrace(InstTracer): + type = 'LegionTrace' + cxx_namespace = 'Trace' + cxx_class = 'LegionTrace' diff --git a/src/cpu/NativeTrace.py b/src/cpu/NativeTrace.py new file mode 100644 index 000000000..96b4e991b --- /dev/null +++ b/src/cpu/NativeTrace.py @@ -0,0 +1,36 @@ +# Copyright (c) 2007 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.SimObject import SimObject +from m5.params import * +from InstTracer import InstTracer + +class NativeTrace(InstTracer): + type = 'NativeTrace' + cxx_namespace = 'Trace' + cxx_class = 'NativeTrace' diff --git a/src/cpu/SConscript b/src/cpu/SConscript index adf47fa4d..b686c0d95 100644 --- a/src/cpu/SConscript +++ b/src/cpu/SConscript @@ -105,12 +105,15 @@ CheckerSupportedCPUList = ['O3CPU', 'OzoneCPU'] SimObject('BaseCPU.py') SimObject('FuncUnit.py') +SimObject('ExeTracer.py') +SimObject('IntelTrace.py') Source('activity.cc') Source('base.cc') Source('cpuevent.cc') Source('exetrace.cc') Source('func_unit.cc') +Source('inteltrace.cc') Source('pc_event.cc') Source('quiesce_event.cc') Source('static_inst.cc') @@ -123,6 +126,14 @@ if env['FULL_SYSTEM']: Source('intr_control.cc') Source('profile.cc') + if env['TARGET_ISA'] == 'sparc': + SimObject('LegionTrace.py') + Source('legiontrace.cc') + +if env['TARGET_ISA'] == 'x86': + SimObject('NativeTrace.py') + Source('nativetrace.cc') + if env['USE_CHECKER']: Source('checker/cpu.cc') checker_supports = False diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 17c04907a..0fc3b4cea 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -188,6 +188,7 @@ BaseCPU::BaseCPU(Params *p) if (params->profile) profileEvent = new ProfileEvent(this, params->profile); #endif + tracer = params->tracer; } BaseCPU::Params::Params() @@ -196,6 +197,7 @@ BaseCPU::Params::Params() profile = false; #endif checker = NULL; + tracer = NULL; } void diff --git a/src/cpu/base.hh b/src/cpu/base.hh index 4d8300186..76f6e4684 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -38,6 +38,7 @@ #include "base/statistics.hh" #include "config/full_system.hh" #include "sim/eventq.hh" +#include "sim/insttracer.hh" #include "mem/mem_object.hh" #if FULL_SYSTEM @@ -132,8 +133,13 @@ class BaseCPU : public MemObject std::vector threadContexts; std::vector predecoders; + Trace::InstTracer * tracer; + public: + /// Provide access to the tracer pointer + Trace::InstTracer * getTracer() { return tracer; } + /// Notify the CPU that the indicated context is now active. The /// delay parameter indicates the number of ticks to wait before /// executing (typically 0 or 1). @@ -169,6 +175,8 @@ class BaseCPU : public MemObject Tick functionTraceStart; System *system; int cpu_id; + Trace::InstTracer * tracer; + Tick phase; #if FULL_SYSTEM Tick profile; diff --git a/src/cpu/exetrace.cc b/src/cpu/exetrace.cc index 25d41811e..38c22da94 100644 --- a/src/cpu/exetrace.cc +++ b/src/cpu/exetrace.cc @@ -31,772 +31,90 @@ * Steve Raasch */ -#include -#include #include -#include -#include -#include "arch/predecoder.hh" -#include "arch/regfile.hh" -#include "arch/utility.hh" #include "base/loader/symtab.hh" -#include "base/socket.hh" -#include "config/full_system.hh" #include "cpu/base.hh" #include "cpu/exetrace.hh" #include "cpu/static_inst.hh" +#include "cpu/thread_context.hh" #include "enums/OpClass.hh" -#include "sim/system.hh" - -#if FULL_SYSTEM -#include "arch/tlb.hh" -#endif - -//XXX This is temporary -#include "arch/isa_specific.hh" -#include "cpu/m5legion_interface.h" +#include "params/ExeTracer.hh" using namespace std; using namespace TheISA; -#if THE_ISA == SPARC_ISA && FULL_SYSTEM -static int diffcount = 0; -static bool wasMicro = false; -#endif - namespace Trace { -SharedData *shared_data = NULL; -ListenSocket *cosim_listener = NULL; void -setupSharedData() -{ - int shmfd = shmget('M' << 24 | getuid(), sizeof(SharedData), 0777); - if (shmfd < 0) - fatal("Couldn't get shared memory fd. Is Legion running?"); - - shared_data = (SharedData*)shmat(shmfd, NULL, SHM_RND); - if (shared_data == (SharedData*)-1) - fatal("Couldn't allocate shared memory"); - - if (shared_data->flags != OWN_M5) - fatal("Shared memory has invalid owner"); - - if (shared_data->version != VERSION) - fatal("Shared Data is wrong version! M5: %d Legion: %d", VERSION, - shared_data->version); - - // step legion forward one cycle so we can get register values - shared_data->flags = OWN_LEGION; -} - -//////////////////////////////////////////////////////////////////////// -// -// Methods for the InstRecord object -// - -#if THE_ISA == SPARC_ISA - -inline char * genCenteredLabel(int length, char * buffer, char * label) -{ - int labelLength = strlen(label); - assert(labelLength <= length); - int leftPad = (length - labelLength) / 2; - int rightPad = length - leftPad - labelLength; - char format[64]; - sprintf(format, "%%%ds%%s%%%ds", leftPad, rightPad); - sprintf(buffer, format, "", label, ""); - return buffer; -} - -inline void printRegPair(ostream & os, char const * title, uint64_t a, uint64_t b) -{ - ccprintf(os, " %16s | %#018x %s %#-018x \n", - title, a, (a == b) ? "|" : "X", b); -} - -inline void printColumnLabels(ostream & os) -{ - static char * regLabel = genCenteredLabel(16, new char[17], "Register"); - static char * m5Label = genCenteredLabel(18, new char[18], "M5"); - static char * legionLabel = genCenteredLabel(18, new char[18], "Legion"); - ccprintf(os, " %s | %s | %s \n", regLabel, m5Label, legionLabel); - ccprintf(os, "--------------------+-----------------------+-----------------------\n"); -} - -inline void printSectionHeader(ostream & os, char * name) -{ - char sectionString[70]; - genCenteredLabel(69, sectionString, name); - ccprintf(os, "====================================================================\n"); - ccprintf(os, "%69s\n", sectionString); - ccprintf(os, "====================================================================\n"); -} - -inline void printLevelHeader(ostream & os, int level) -{ - char sectionString[70]; - char levelName[70]; - sprintf(levelName, "Trap stack level %d", level); - genCenteredLabel(69, sectionString, levelName); - ccprintf(os, "====================================================================\n"); - ccprintf(os, "%69s\n", sectionString); - ccprintf(os, "====================================================================\n"); -} - -#endif - -void -Trace::InstRecord::dump() +Trace::ExeTracerRecord::dump() { ostream &outs = Trace::output(); - DPRINTF(Sparc, "Instruction: %#X\n", staticInst->machInst); - bool diff = true; - if (IsOn(ExecRegDelta)) - { - diff = false; -#ifndef NDEBUG -#if THE_ISA == SPARC_ISA - static int fd = 0; - //Don't print what happens for each micro-op, just print out - //once at the last op, and for regular instructions. - if(!staticInst->isMicroop() || staticInst->isLastMicroop()) - { - if(!cosim_listener) - { - int port = 8000; - cosim_listener = new ListenSocket(); - while(!cosim_listener->listen(port, true)) - { - DPRINTF(GDBMisc, "Can't bind port %d\n", port); - port++; - } - ccprintf(cerr, "Listening for cosimulator on port %d\n", port); - fd = cosim_listener->accept(); - } - char prefix[] = "goli"; - for(int p = 0; p < 4; p++) - { - for(int i = 0; i < 8; i++) - { - uint64_t regVal; - int res = read(fd, ®Val, sizeof(regVal)); - if(res < 0) - panic("First read call failed! %s\n", strerror(errno)); - regVal = TheISA::gtoh(regVal); - uint64_t realRegVal = thread->readIntReg(p * 8 + i); - if((regVal & 0xffffffffULL) != (realRegVal & 0xffffffffULL)) - { - DPRINTF(ExecRegDelta, "Register %s%d should be %#x but is %#x.\n", prefix[p], i, regVal, realRegVal); - diff = true; - } - //ccprintf(outs, "%s%d m5 = %#x statetrace = %#x\n", prefix[p], i, realRegVal, regVal); - } - } - /*for(int f = 0; f <= 62; f+=2) - { - uint64_t regVal; - int res = read(fd, ®Val, sizeof(regVal)); - if(res < 0) - panic("First read call failed! %s\n", strerror(errno)); - regVal = TheISA::gtoh(regVal); - uint64_t realRegVal = thread->readFloatRegBits(f, 64); - if(regVal != realRegVal) - { - DPRINTF(ExecRegDelta, "Register f%d should be %#x but is %#x.\n", f, regVal, realRegVal); - } - }*/ - uint64_t regVal; - int res = read(fd, ®Val, sizeof(regVal)); - if(res < 0) - panic("First read call failed! %s\n", strerror(errno)); - regVal = TheISA::gtoh(regVal); - uint64_t realRegVal = thread->readNextPC(); - if(regVal != realRegVal) - { - DPRINTF(ExecRegDelta, "Register pc should be %#x but is %#x.\n", regVal, realRegVal); - diff = true; - } - res = read(fd, ®Val, sizeof(regVal)); - if(res < 0) - panic("First read call failed! %s\n", strerror(errno)); - regVal = TheISA::gtoh(regVal); - realRegVal = thread->readNextNPC(); - if(regVal != realRegVal) - { - DPRINTF(ExecRegDelta, "Register npc should be %#x but is %#x.\n", regVal, realRegVal); - diff = true; - } - res = read(fd, ®Val, sizeof(regVal)); - if(res < 0) - panic("First read call failed! %s\n", strerror(errno)); - regVal = TheISA::gtoh(regVal); - realRegVal = thread->readIntReg(SparcISA::NumIntArchRegs + 2); - if((regVal & 0xF) != (realRegVal & 0xF)) - { - DPRINTF(ExecRegDelta, "Register ccr should be %#x but is %#x.\n", regVal, realRegVal); - diff = true; - } - } -#endif -#endif -#if 0 //THE_ISA == SPARC_ISA - //Don't print what happens for each micro-op, just print out - //once at the last op, and for regular instructions. - if(!staticInst->isMicroop() || staticInst->isLastMicroop()) - { - static uint64_t regs[32] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0}; - static uint64_t ccr = 0; - static uint64_t y = 0; - static uint64_t floats[32]; - uint64_t newVal; - static const char * prefixes[4] = {"G", "O", "L", "I"}; + if (IsOn(ExecTicks)) + ccprintf(outs, "%7d: ", when); - outs << hex; - outs << "PC = " << thread->readNextPC(); - outs << " NPC = " << thread->readNextNPC(); - newVal = thread->readIntReg(SparcISA::NumIntArchRegs + 2); - //newVal = thread->readMiscRegNoEffect(SparcISA::MISCREG_CCR); - if(newVal != ccr) - { - outs << " CCR = " << newVal; - ccr = newVal; - } - newVal = thread->readIntReg(SparcISA::NumIntArchRegs + 1); - //newVal = thread->readMiscRegNoEffect(SparcISA::MISCREG_Y); - if(newVal != y) - { - outs << " Y = " << newVal; - y = newVal; - } - for(int y = 0; y < 4; y++) - { - for(int x = 0; x < 8; x++) - { - int index = x + 8 * y; - newVal = thread->readIntReg(index); - if(regs[index] != newVal) - { - outs << " " << prefixes[y] << dec << x << " = " << hex << newVal; - regs[index] = newVal; - } - } - } - for(int y = 0; y < 32; y++) - { - newVal = thread->readFloatRegBits(2 * y, 64); - if(floats[y] != newVal) - { - outs << " F" << dec << (2 * y) << " = " << hex << newVal; - floats[y] = newVal; - } - } - outs << dec << endl; - } -#endif + outs << thread->getCpuPtr()->name() << " "; + + if (IsOn(ExecSpeculative)) + outs << (misspeculating ? "-" : "+") << " "; + + if (IsOn(ExecThread)) + outs << "T" << thread->getThreadNum() << " : "; + + + std::string sym_str; + Addr sym_addr; + if (debugSymbolTable + && IsOn(ExecSymbol) + && debugSymbolTable->findNearestSymbol(PC, sym_str, sym_addr)) { + if (PC != sym_addr) + sym_str += csprintf("+%d", PC - sym_addr); + outs << "@" << sym_str << " : "; } - if(!diff) { - } else if (IsOn(ExecIntel)) { - ccprintf(outs, "%7d ) ", when); - outs << "0x" << hex << PC << ":\t"; - if (staticInst->isLoad()) { - ccprintf(outs, "", addr); - } else if (staticInst->isStore()) { - ccprintf(outs, "", addr); - } - outs << endl; - } else { - if (IsOn(ExecTicks)) - ccprintf(outs, "%7d: ", when); - - outs << thread->getCpuPtr()->name() << " "; - - if (IsOn(ExecSpeculative)) - outs << (misspeculating ? "-" : "+") << " "; - - if (IsOn(ExecThread)) - outs << "T" << thread->getThreadNum() << " : "; - - - std::string sym_str; - Addr sym_addr; - if (debugSymbolTable - && debugSymbolTable->findNearestSymbol(PC, sym_str, sym_addr) - && IsOn(ExecSymbol)) { - if (PC != sym_addr) - sym_str += csprintf("+%d", PC - sym_addr); - outs << "@" << sym_str << " : "; - } - else { - outs << "0x" << hex << PC << " : "; - } - - // - // Print decoded instruction - // - -#if defined(__GNUC__) && (__GNUC__ < 3) - // There's a bug in gcc 2.x library that prevents setw() - // from working properly on strings - string mc(staticInst->disassemble(PC, debugSymbolTable)); - while (mc.length() < 26) - mc += " "; - outs << mc; -#else - outs << setw(26) << left << staticInst->disassemble(PC, debugSymbolTable); -#endif - - outs << " : "; - - if (IsOn(ExecOpClass)) { - outs << Enums::OpClassStrings[staticInst->opClass()] << " : "; - } - - if (IsOn(ExecResult) && data_status != DataInvalid) { - outs << " D="; -#if 0 - if (data_status == DataDouble) - ccprintf(outs, "%f", data.as_double); - else - ccprintf(outs, "%#018x", data.as_int); -#else - ccprintf(outs, "%#018x", data.as_int); -#endif - } - - if (IsOn(ExecEffAddr) && addr_valid) - outs << " A=0x" << hex << addr; - - if (IsOn(ExecIntRegs) && regs_valid) { - for (int i = 0; i < TheISA::NumIntRegs;) - for (int j = i + 1; i <= j; i++) - ccprintf(outs, "r%02d = %#018x%s", i, - iregs->regs.readReg(i), - ((i == j) ? "\n" : " ")); - outs << "\n"; - } - - if (IsOn(ExecFetchSeq) && fetch_seq_valid) - outs << " FetchSeq=" << dec << fetch_seq; - - if (IsOn(ExecCPSeq) && cp_seq_valid) - outs << " CPSeq=" << dec << cp_seq; - - // - // End of line... - // - outs << endl; + else { + outs << "0x" << hex << PC << " : "; } -#if THE_ISA == SPARC_ISA && FULL_SYSTEM - static TheISA::Predecoder predecoder(NULL); - // Compare - if (IsOn(ExecLegion)) - { - bool compared = false; - bool diffPC = false; - bool diffCC = false; - bool diffInst = false; - bool diffIntRegs = false; - bool diffFpRegs = false; - bool diffTpc = false; - bool diffTnpc = false; - bool diffTstate = false; - bool diffTt = false; - bool diffTba = false; - bool diffHpstate = false; - bool diffHtstate = false; - bool diffHtba = false; - bool diffPstate = false; - bool diffY = false; - bool diffFsr = false; - bool diffCcr = false; - bool diffTl = false; - bool diffGl = false; - bool diffAsi = false; - bool diffPil = false; - bool diffCwp = false; - bool diffCansave = false; - bool diffCanrestore = false; - bool diffOtherwin = false; - bool diffCleanwin = false; - bool diffTlb = false; - Addr m5Pc, lgnPc; - if (!shared_data) - setupSharedData(); + // + // Print decoded instruction + // - // We took a trap on a micro-op... - if (wasMicro && !staticInst->isMicroop()) - { - // let's skip comparing this tick - while (!compared) - if (shared_data->flags == OWN_M5) { - shared_data->flags = OWN_LEGION; - compared = true; - } - compared = false; - wasMicro = false; - } + outs << setw(26) << left; + outs << staticInst->disassemble(PC, debugSymbolTable); + outs << " : "; - if (staticInst->isLastMicroop()) - wasMicro = false; - else if (staticInst->isMicroop()) - wasMicro = true; - - - if(!staticInst->isMicroop() || staticInst->isLastMicroop()) { - while (!compared) { - if (shared_data->flags == OWN_M5) { - m5Pc = PC & TheISA::PAddrImplMask; - if (bits(shared_data->pstate,3,3)) { - m5Pc &= mask(32); - } - lgnPc = shared_data->pc & TheISA::PAddrImplMask; - if (lgnPc != m5Pc) - diffPC = true; - - if (shared_data->cycle_count != - thread->getCpuPtr()->instCount()) - diffCC = true; - - if (shared_data->instruction != - (SparcISA::MachInst)staticInst->machInst) { - diffInst = true; - } - // assume we have %g0 working correctly - for (int i = 1; i < TheISA::NumIntArchRegs; i++) { - if (thread->readIntReg(i) != shared_data->intregs[i]) { - diffIntRegs = true; - } - } - for (int i = 0; i < TheISA::NumFloatRegs/2; i++) { - if (thread->readFloatRegBits(i*2,FloatRegFile::DoubleWidth) != shared_data->fpregs[i]) { - diffFpRegs = true; - } - } - uint64_t oldTl = thread->readMiscRegNoEffect(MISCREG_TL); - if (oldTl != shared_data->tl) - diffTl = true; - for (int i = 1; i <= MaxTL; i++) { - thread->setMiscRegNoEffect(MISCREG_TL, i); - if (thread->readMiscRegNoEffect(MISCREG_TPC) != - shared_data->tpc[i-1]) - diffTpc = true; - if (thread->readMiscRegNoEffect(MISCREG_TNPC) != - shared_data->tnpc[i-1]) - diffTnpc = true; - if (thread->readMiscRegNoEffect(MISCREG_TSTATE) != - shared_data->tstate[i-1]) - diffTstate = true; - if (thread->readMiscRegNoEffect(MISCREG_TT) != - shared_data->tt[i-1]) - diffTt = true; - if (thread->readMiscRegNoEffect(MISCREG_HTSTATE) != - shared_data->htstate[i-1]) - diffHtstate = true; - } - thread->setMiscRegNoEffect(MISCREG_TL, oldTl); - - if(shared_data->tba != thread->readMiscRegNoEffect(MISCREG_TBA)) - diffTba = true; - //When the hpstate register is read by an instruction, - //legion has bit 11 set. When it's in storage, it doesn't. - //Since we don't directly support seperate interpretations - //of the registers like that, the bit is always set to 1 and - //we just don't compare it. It's not supposed to matter - //anyway. - if((shared_data->hpstate | (1 << 11)) != thread->readMiscRegNoEffect(MISCREG_HPSTATE)) - diffHpstate = true; - if(shared_data->htba != thread->readMiscRegNoEffect(MISCREG_HTBA)) - diffHtba = true; - if(shared_data->pstate != thread->readMiscRegNoEffect(MISCREG_PSTATE)) - diffPstate = true; - //if(shared_data->y != thread->readMiscRegNoEffect(MISCREG_Y)) - if(shared_data->y != - thread->readIntReg(NumIntArchRegs + 1)) - diffY = true; - if(shared_data->fsr != thread->readMiscRegNoEffect(MISCREG_FSR)) { - diffFsr = true; - if (mbits(shared_data->fsr, 63,10) == - mbits(thread->readMiscRegNoEffect(MISCREG_FSR), 63,10)) { - thread->setMiscRegNoEffect(MISCREG_FSR, shared_data->fsr); - diffFsr = false; - } - } - //if(shared_data->ccr != thread->readMiscRegNoEffect(MISCREG_CCR)) - if(shared_data->ccr != - thread->readIntReg(NumIntArchRegs + 2)) - diffCcr = true; - if(shared_data->gl != thread->readMiscRegNoEffect(MISCREG_GL)) - diffGl = true; - if(shared_data->asi != thread->readMiscRegNoEffect(MISCREG_ASI)) - diffAsi = true; - if(shared_data->pil != thread->readMiscRegNoEffect(MISCREG_PIL)) - diffPil = true; - if(shared_data->cwp != thread->readMiscRegNoEffect(MISCREG_CWP)) - diffCwp = true; - //if(shared_data->cansave != thread->readMiscRegNoEffect(MISCREG_CANSAVE)) - if(shared_data->cansave != - thread->readIntReg(NumIntArchRegs + 3)) - diffCansave = true; - //if(shared_data->canrestore != - // thread->readMiscRegNoEffect(MISCREG_CANRESTORE)) - if(shared_data->canrestore != - thread->readIntReg(NumIntArchRegs + 4)) - diffCanrestore = true; - //if(shared_data->otherwin != thread->readMiscRegNoEffect(MISCREG_OTHERWIN)) - if(shared_data->otherwin != - thread->readIntReg(NumIntArchRegs + 6)) - diffOtherwin = true; - //if(shared_data->cleanwin != thread->readMiscRegNoEffect(MISCREG_CLEANWIN)) - if(shared_data->cleanwin != - thread->readIntReg(NumIntArchRegs + 5)) - diffCleanwin = true; - - for (int i = 0; i < 64; i++) { - if (shared_data->itb[i] != thread->getITBPtr()->TteRead(i)) - diffTlb = true; - if (shared_data->dtb[i] != thread->getDTBPtr()->TteRead(i)) - diffTlb = true; - } - - if (diffPC || diffCC || diffInst || diffIntRegs || - diffFpRegs || diffTpc || diffTnpc || diffTstate || - diffTt || diffHpstate || diffHtstate || diffHtba || - diffPstate || diffY || diffCcr || diffTl || diffFsr || - diffGl || diffAsi || diffPil || diffCwp || diffCansave || - diffCanrestore || diffOtherwin || diffCleanwin || diffTlb) - { - - outs << "Differences found between M5 and Legion:"; - if (diffPC) - outs << " [PC]"; - if (diffCC) - outs << " [CC]"; - if (diffInst) - outs << " [Instruction]"; - if (diffIntRegs) - outs << " [IntRegs]"; - if (diffFpRegs) - outs << " [FpRegs]"; - if (diffTpc) - outs << " [Tpc]"; - if (diffTnpc) - outs << " [Tnpc]"; - if (diffTstate) - outs << " [Tstate]"; - if (diffTt) - outs << " [Tt]"; - if (diffHpstate) - outs << " [Hpstate]"; - if (diffHtstate) - outs << " [Htstate]"; - if (diffHtba) - outs << " [Htba]"; - if (diffPstate) - outs << " [Pstate]"; - if (diffY) - outs << " [Y]"; - if (diffFsr) - outs << " [FSR]"; - if (diffCcr) - outs << " [Ccr]"; - if (diffTl) - outs << " [Tl]"; - if (diffGl) - outs << " [Gl]"; - if (diffAsi) - outs << " [Asi]"; - if (diffPil) - outs << " [Pil]"; - if (diffCwp) - outs << " [Cwp]"; - if (diffCansave) - outs << " [Cansave]"; - if (diffCanrestore) - outs << " [Canrestore]"; - if (diffOtherwin) - outs << " [Otherwin]"; - if (diffCleanwin) - outs << " [Cleanwin]"; - if (diffTlb) - outs << " [Tlb]"; - outs << endl << endl; - - outs << right << setfill(' ') << setw(15) - << "M5 PC: " << "0x"<< setw(16) << setfill('0') - << hex << m5Pc << endl; - outs << setfill(' ') << setw(15) - << "Legion PC: " << "0x"<< setw(16) << setfill('0') << hex - << lgnPc << endl << endl; - - outs << right << setfill(' ') << setw(15) - << "M5 CC: " << "0x"<< setw(16) << setfill('0') - << hex << thread->getCpuPtr()->instCount() << endl; - outs << setfill(' ') << setw(15) - << "Legion CC: " << "0x"<< setw(16) << setfill('0') << hex - << shared_data->cycle_count << endl << endl; - - outs << setfill(' ') << setw(15) - << "M5 Inst: " << "0x"<< setw(8) - << setfill('0') << hex << staticInst->machInst - << staticInst->disassemble(m5Pc, debugSymbolTable) - << endl; - - predecoder.setTC(thread); - predecoder.moreBytes(m5Pc, m5Pc, - shared_data->instruction); - - assert(predecoder.extMachInstReady()); - - StaticInstPtr legionInst = - StaticInst::decode(predecoder.getExtMachInst(), lgnPc); - outs << setfill(' ') << setw(15) - << " Legion Inst: " - << "0x" << setw(8) << setfill('0') << hex - << shared_data->instruction - << legionInst->disassemble(lgnPc, debugSymbolTable) - << endl << endl; - - printSectionHeader(outs, "General State"); - printColumnLabels(outs); - printRegPair(outs, "HPstate", - thread->readMiscRegNoEffect(MISCREG_HPSTATE), - shared_data->hpstate | (1 << 11)); - printRegPair(outs, "Htba", - thread->readMiscRegNoEffect(MISCREG_HTBA), - shared_data->htba); - printRegPair(outs, "Pstate", - thread->readMiscRegNoEffect(MISCREG_PSTATE), - shared_data->pstate); - printRegPair(outs, "Y", - //thread->readMiscRegNoEffect(MISCREG_Y), - thread->readIntReg(NumIntArchRegs + 1), - shared_data->y); - printRegPair(outs, "FSR", - thread->readMiscRegNoEffect(MISCREG_FSR), - shared_data->fsr); - printRegPair(outs, "Ccr", - //thread->readMiscRegNoEffect(MISCREG_CCR), - thread->readIntReg(NumIntArchRegs + 2), - shared_data->ccr); - printRegPair(outs, "Tl", - thread->readMiscRegNoEffect(MISCREG_TL), - shared_data->tl); - printRegPair(outs, "Gl", - thread->readMiscRegNoEffect(MISCREG_GL), - shared_data->gl); - printRegPair(outs, "Asi", - thread->readMiscRegNoEffect(MISCREG_ASI), - shared_data->asi); - printRegPair(outs, "Pil", - thread->readMiscRegNoEffect(MISCREG_PIL), - shared_data->pil); - printRegPair(outs, "Cwp", - thread->readMiscRegNoEffect(MISCREG_CWP), - shared_data->cwp); - printRegPair(outs, "Cansave", - //thread->readMiscRegNoEffect(MISCREG_CANSAVE), - thread->readIntReg(NumIntArchRegs + 3), - shared_data->cansave); - printRegPair(outs, "Canrestore", - //thread->readMiscRegNoEffect(MISCREG_CANRESTORE), - thread->readIntReg(NumIntArchRegs + 4), - shared_data->canrestore); - printRegPair(outs, "Otherwin", - //thread->readMiscRegNoEffect(MISCREG_OTHERWIN), - thread->readIntReg(NumIntArchRegs + 6), - shared_data->otherwin); - printRegPair(outs, "Cleanwin", - //thread->readMiscRegNoEffect(MISCREG_CLEANWIN), - thread->readIntReg(NumIntArchRegs + 5), - shared_data->cleanwin); - outs << endl; - for (int i = 1; i <= MaxTL; i++) { - printLevelHeader(outs, i); - printColumnLabels(outs); - thread->setMiscRegNoEffect(MISCREG_TL, i); - printRegPair(outs, "Tpc", - thread->readMiscRegNoEffect(MISCREG_TPC), - shared_data->tpc[i-1]); - printRegPair(outs, "Tnpc", - thread->readMiscRegNoEffect(MISCREG_TNPC), - shared_data->tnpc[i-1]); - printRegPair(outs, "Tstate", - thread->readMiscRegNoEffect(MISCREG_TSTATE), - shared_data->tstate[i-1]); - printRegPair(outs, "Tt", - thread->readMiscRegNoEffect(MISCREG_TT), - shared_data->tt[i-1]); - printRegPair(outs, "Htstate", - thread->readMiscRegNoEffect(MISCREG_HTSTATE), - shared_data->htstate[i-1]); - } - thread->setMiscRegNoEffect(MISCREG_TL, oldTl); - outs << endl; - - printSectionHeader(outs, "General Purpose Registers"); - static const char * regtypes[4] = {"%g", "%o", "%l", "%i"}; - for(int y = 0; y < 4; y++) { - for(int x = 0; x < 8; x++) { - char label[8]; - sprintf(label, "%s%d", regtypes[y], x); - printRegPair(outs, label, - thread->readIntReg(y*8+x), - shared_data->intregs[y*8+x]); - } - } - if (diffFpRegs) { - for (int x = 0; x < 32; x++) { - char label[8]; - sprintf(label, "%%f%d", x); - printRegPair(outs, label, - thread->readFloatRegBits(x*2,FloatRegFile::DoubleWidth), - shared_data->fpregs[x]); - } - } - if (diffTlb) { - printColumnLabels(outs); - char label[8]; - for (int x = 0; x < 64; x++) { - if (shared_data->itb[x] != ULL(0xFFFFFFFFFFFFFFFF) || - thread->getITBPtr()->TteRead(x) != ULL(0xFFFFFFFFFFFFFFFF)) { - sprintf(label, "I-TLB:%02d", x); - printRegPair(outs, label, thread->getITBPtr()->TteRead(x), - shared_data->itb[x]); - } - } - for (int x = 0; x < 64; x++) { - if (shared_data->dtb[x] != ULL(0xFFFFFFFFFFFFFFFF) || - thread->getDTBPtr()->TteRead(x) != ULL(0xFFFFFFFFFFFFFFFF)) { - sprintf(label, "D-TLB:%02d", x); - printRegPair(outs, label, thread->getDTBPtr()->TteRead(x), - shared_data->dtb[x]); - } - } - thread->getITBPtr()->dumpAll(); - thread->getDTBPtr()->dumpAll(); - } - - diffcount++; - if (diffcount > 3) - fatal("Differences found between Legion and M5\n"); - } else - diffcount = 0; - - compared = true; - shared_data->flags = OWN_LEGION; - } - } // while - } // if not microop + if (IsOn(ExecOpClass)) { + outs << Enums::OpClassStrings[staticInst->opClass()] << " : "; } -#endif + + if (IsOn(ExecResult) && data_status != DataInvalid) { + ccprintf(outs, " D=%#018x", data.as_int); + } + + if (IsOn(ExecEffAddr) && addr_valid) + outs << " A=0x" << hex << addr; + + if (IsOn(ExecFetchSeq) && fetch_seq_valid) + outs << " FetchSeq=" << dec << fetch_seq; + + if (IsOn(ExecCPSeq) && cp_seq_valid) + outs << " CPSeq=" << dec << cp_seq; + + // + // End of line... + // + outs << endl; } /* namespace Trace */ } + +//////////////////////////////////////////////////////////////////////// +// +// ExeTracer Simulation Object +// +Trace::ExeTracer * +ExeTracerParams::create() +{ + return new Trace::ExeTracer(name); +}; diff --git a/src/cpu/exetrace.hh b/src/cpu/exetrace.hh index 8c0fa22cb..76907d955 100644 --- a/src/cpu/exetrace.hh +++ b/src/cpu/exetrace.hh @@ -32,141 +32,52 @@ #ifndef __EXETRACE_HH__ #define __EXETRACE_HH__ -#include -#include -#include - #include "base/trace.hh" -#include "cpu/inst_seq.hh" // for InstSeqNum #include "cpu/static_inst.hh" -#include "cpu/thread_context.hh" #include "sim/host.hh" +#include "sim/insttracer.hh" class ThreadContext; namespace Trace { -class InstRecord +class ExeTracerRecord : public InstRecord { - protected: - typedef TheISA::IntRegFile IntRegFile; - - Tick when; - - // The following fields are initialized by the constructor and - // thus guaranteed to be valid. - ThreadContext *thread; - // need to make this ref-counted so it doesn't go away before we - // dump the record - StaticInstPtr staticInst; - Addr PC; - bool misspeculating; - - // The remaining fields are only valid for particular instruction - // types (e.g, addresses for memory ops) or when particular - // options are enabled (e.g., tracing full register contents). - // Each data field has an associated valid flag to indicate - // whether the data field is valid. - Addr addr; - bool addr_valid; - - union { - uint64_t as_int; - double as_double; - } data; - enum { - DataInvalid = 0, - DataInt8 = 1, // set to equal number of bytes - DataInt16 = 2, - DataInt32 = 4, - DataInt64 = 8, - DataDouble = 3 - } data_status; - - InstSeqNum fetch_seq; - bool fetch_seq_valid; - - InstSeqNum cp_seq; - bool cp_seq_valid; - - struct iRegFile { - IntRegFile regs; - }; - iRegFile *iregs; - bool regs_valid; - public: - InstRecord(Tick _when, ThreadContext *_thread, - const StaticInstPtr &_staticInst, - Addr _pc, bool spec) - : when(_when), thread(_thread), - staticInst(_staticInst), PC(_pc), - misspeculating(spec) + ExeTracerRecord(Tick _when, ThreadContext *_thread, + const StaticInstPtr &_staticInst, Addr _pc, bool spec) + : InstRecord(_when, _thread, _staticInst, _pc, spec) { - data_status = DataInvalid; - addr_valid = false; - regs_valid = false; - - fetch_seq_valid = false; - cp_seq_valid = false; } - ~InstRecord() { } - - void setAddr(Addr a) { addr = a; addr_valid = true; } - - void setData(Twin64_t d) { data.as_int = d.a; data_status = DataInt64; } - void setData(Twin32_t d) { data.as_int = d.a; data_status = DataInt32; } - void setData(uint64_t d) { data.as_int = d; data_status = DataInt64; } - void setData(uint32_t d) { data.as_int = d; data_status = DataInt32; } - void setData(uint16_t d) { data.as_int = d; data_status = DataInt16; } - void setData(uint8_t d) { data.as_int = d; data_status = DataInt8; } - - void setData(int64_t d) { setData((uint64_t)d); } - void setData(int32_t d) { setData((uint32_t)d); } - void setData(int16_t d) { setData((uint16_t)d); } - void setData(int8_t d) { setData((uint8_t)d); } - - void setData(double d) { data.as_double = d; data_status = DataDouble; } - - void setFetchSeq(InstSeqNum seq) - { fetch_seq = seq; fetch_seq_valid = true; } - - void setCPSeq(InstSeqNum seq) - { cp_seq = seq; cp_seq_valid = true; } - - void setRegs(const IntRegFile ®s); - void dump(); }; - -inline void -InstRecord::setRegs(const IntRegFile ®s) +class ExeTracer : public InstTracer { - if (!iregs) - iregs = new iRegFile; + public: - std::memcpy(&iregs->regs, ®s, sizeof(IntRegFile)); - regs_valid = true; -} + ExeTracer(const std::string & name) : InstTracer(name) + {} -inline InstRecord * -getInstRecord(Tick when, ThreadContext *tc, const StaticInstPtr staticInst, - Addr pc) -{ - if (!IsOn(ExecEnable)) - return NULL; + InstRecord * + getInstRecord(Tick when, ThreadContext *tc, + const StaticInstPtr staticInst, Addr pc) + { + if (!IsOn(ExecEnable)) + return NULL; - if (!Trace::enabled) - return NULL; + if (!Trace::enabled) + return NULL; - if (!IsOn(ExecSpeculative) && tc->misspeculating()) - return NULL; + if (!IsOn(ExecSpeculative) && tc->misspeculating()) + return NULL; - return new InstRecord(when, tc, staticInst, pc, tc->misspeculating()); -} + return new ExeTracerRecord(when, tc, + staticInst, pc, tc->misspeculating()); + } +}; /* namespace Trace */ } diff --git a/src/cpu/inteltrace.cc b/src/cpu/inteltrace.cc new file mode 100644 index 000000000..afa51b517 --- /dev/null +++ b/src/cpu/inteltrace.cc @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Steve Reinhardt + * Lisa Hsu + * Nathan Binkert + * Steve Raasch + */ + +#include + +#include "cpu/exetrace.hh" +#include "cpu/inteltrace.hh" +#include "cpu/static_inst.hh" +#include "params/IntelTrace.hh" + +using namespace std; +using namespace TheISA; + +namespace Trace { + +void +Trace::IntelTraceRecord::dump() +{ + ostream &outs = Trace::output(); + ccprintf(outs, "%7d ) ", when); + outs << "0x" << hex << PC << ":\t"; + if (staticInst->isLoad()) { + ccprintf(outs, "", addr); + } else if (staticInst->isStore()) { + ccprintf(outs, "", addr); + } + outs << endl; +} + +/* namespace Trace */ } + +//////////////////////////////////////////////////////////////////////// +// +// ExeTracer Simulation Object +// +Trace::IntelTrace * +IntelTraceParams::create() +{ + return new Trace::IntelTrace(name); +}; diff --git a/src/cpu/inteltrace.hh b/src/cpu/inteltrace.hh new file mode 100644 index 000000000..21afe0fc0 --- /dev/null +++ b/src/cpu/inteltrace.hh @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Steve Reinhardt + * Nathan Binkert + */ + +#ifndef __INTELTRACE_HH__ +#define __INTELTRACE_HH__ + +#include "base/trace.hh" +#include "cpu/static_inst.hh" +#include "sim/host.hh" +#include "sim/insttracer.hh" + +class ThreadContext; + + +namespace Trace { + +class IntelTraceRecord : public InstRecord +{ + public: + IntelTraceRecord(Tick _when, ThreadContext *_thread, + const StaticInstPtr &_staticInst, Addr _pc, bool spec) + : InstRecord(_when, _thread, _staticInst, _pc, spec) + { + } + + void dump(); +}; + +class IntelTrace : public InstTracer +{ + public: + + IntelTrace(const std::string & name) : InstTracer(name) + {} + + IntelTraceRecord * + getInstRecord(Tick when, ThreadContext *tc, + const StaticInstPtr staticInst, Addr pc) + { + if (!IsOn(ExecEnable)) + return NULL; + + if (!Trace::enabled) + return NULL; + + if (!IsOn(ExecSpeculative) && tc->misspeculating()) + return NULL; + + return new IntelTraceRecord(when, tc, + staticInst, pc, tc->misspeculating()); + } +}; + +/* namespace Trace */ } + +#endif // __EXETRACE_HH__ diff --git a/src/cpu/legiontrace.cc b/src/cpu/legiontrace.cc new file mode 100644 index 000000000..58181cb88 --- /dev/null +++ b/src/cpu/legiontrace.cc @@ -0,0 +1,600 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Steve Reinhardt + * Lisa Hsu + * Nathan Binkert + * Steve Raasch + */ + +#include "arch/isa_specific.hh" +#if THE_ISA != SPARC_ISA + #error Legion tracing only works with SPARC simulations! +#endif + +#include "config/full_system.hh" +#if !FULL_SYSTEM + #error Legion tracing only works in full system! +#endif + +#include +#include +#include + +#include "arch/sparc/predecoder.hh" +#include "arch/sparc/regfile.hh" +#include "arch/sparc/utility.hh" +#include "base/socket.hh" +#include "cpu/base.hh" +#include "cpu/legiontrace.hh" +#include "cpu/static_inst.hh" +#include "cpu/thread_context.hh" +#include "params/LegionTrace.hh" +#include "sim/system.hh" + +#if FULL_SYSTEM +#include "arch/tlb.hh" +#endif + +//XXX This is temporary +#include "cpu/m5legion_interface.h" + +using namespace std; +using namespace TheISA; + +#if FULL_SYSTEM +static int diffcount = 0; +static bool wasMicro = false; +#endif + +namespace Trace { +SharedData *shared_data = NULL; + +void +setupSharedData() +{ + int shmfd = shmget('M' << 24 | getuid(), sizeof(SharedData), 0777); + if (shmfd < 0) + fatal("Couldn't get shared memory fd. Is Legion running?"); + + shared_data = (SharedData*)shmat(shmfd, NULL, SHM_RND); + if (shared_data == (SharedData*)-1) + fatal("Couldn't allocate shared memory"); + + if (shared_data->flags != OWN_M5) + fatal("Shared memory has invalid owner"); + + if (shared_data->version != VERSION) + fatal("Shared Data is wrong version! M5: %d Legion: %d", VERSION, + shared_data->version); + + // step legion forward one cycle so we can get register values + shared_data->flags = OWN_LEGION; +} + +//////////////////////////////////////////////////////////////////////// +// +// Utility methods for pretty printing a report about a difference +// + +inline char * genCenteredLabel(int length, char * buffer, char * label) +{ + int labelLength = strlen(label); + assert(labelLength <= length); + int leftPad = (length - labelLength) / 2; + int rightPad = length - leftPad - labelLength; + char format[64]; + sprintf(format, "%%%ds%%s%%%ds", leftPad, rightPad); + sprintf(buffer, format, "", label, ""); + return buffer; +} + +inline void printRegPair(ostream & os, char const * title, uint64_t a, uint64_t b) +{ + ccprintf(os, " %16s | %#018x %s %#-018x \n", + title, a, (a == b) ? "|" : "X", b); +} + +inline void printColumnLabels(ostream & os) +{ + static char * regLabel = genCenteredLabel(16, new char[17], "Register"); + static char * m5Label = genCenteredLabel(18, new char[18], "M5"); + static char * legionLabel = genCenteredLabel(18, new char[18], "Legion"); + ccprintf(os, " %s | %s | %s \n", regLabel, m5Label, legionLabel); + ccprintf(os, "--------------------+-----------------------+-----------------------\n"); +} + +inline void printSectionHeader(ostream & os, char * name) +{ + char sectionString[70]; + genCenteredLabel(69, sectionString, name); + ccprintf(os, "====================================================================\n"); + ccprintf(os, "%69s\n", sectionString); + ccprintf(os, "====================================================================\n"); +} + +inline void printLevelHeader(ostream & os, int level) +{ + char sectionString[70]; + char levelName[70]; + sprintf(levelName, "Trap stack level %d", level); + genCenteredLabel(69, sectionString, levelName); + ccprintf(os, "====================================================================\n"); + ccprintf(os, "%69s\n", sectionString); + ccprintf(os, "====================================================================\n"); +} + +void +Trace::LegionTraceRecord::dump() +{ + ostream &outs = Trace::output(); + + static TheISA::Predecoder predecoder(NULL); + // Compare + bool compared = false; + bool diffPC = false; + bool diffCC = false; + bool diffInst = false; + bool diffIntRegs = false; + bool diffFpRegs = false; + bool diffTpc = false; + bool diffTnpc = false; + bool diffTstate = false; + bool diffTt = false; + bool diffTba = false; + bool diffHpstate = false; + bool diffHtstate = false; + bool diffHtba = false; + bool diffPstate = false; + bool diffY = false; + bool diffFsr = false; + bool diffCcr = false; + bool diffTl = false; + bool diffGl = false; + bool diffAsi = false; + bool diffPil = false; + bool diffCwp = false; + bool diffCansave = false; + bool diffCanrestore = false; + bool diffOtherwin = false; + bool diffCleanwin = false; + bool diffTlb = false; + Addr m5Pc, lgnPc; + + if (!shared_data) + setupSharedData(); + + // We took a trap on a micro-op... + if (wasMicro && !staticInst->isMicroop()) + { + // let's skip comparing this tick + while (!compared) + if (shared_data->flags == OWN_M5) { + shared_data->flags = OWN_LEGION; + compared = true; + } + compared = false; + wasMicro = false; + } + + if (staticInst->isLastMicroop()) + wasMicro = false; + else if (staticInst->isMicroop()) + wasMicro = true; + + + if(!staticInst->isMicroop() || staticInst->isLastMicroop()) { + while (!compared) { + if (shared_data->flags == OWN_M5) { + m5Pc = PC & SparcISA::PAddrImplMask; + if (bits(shared_data->pstate,3,3)) { + m5Pc &= mask(32); + } + lgnPc = shared_data->pc & SparcISA::PAddrImplMask; + if (lgnPc != m5Pc) + diffPC = true; + + if (shared_data->cycle_count != + thread->getCpuPtr()->instCount()) + diffCC = true; + + if (shared_data->instruction != + (SparcISA::MachInst)staticInst->machInst) { + diffInst = true; + } + // assume we have %g0 working correctly + for (int i = 1; i < TheISA::NumIntArchRegs; i++) { + if (thread->readIntReg(i) != shared_data->intregs[i]) { + diffIntRegs = true; + } + } + for (int i = 0; i < TheISA::NumFloatRegs/2; i++) { + if (thread->readFloatRegBits(i*2, + FloatRegFile::DoubleWidth) != + shared_data->fpregs[i]) { + diffFpRegs = true; + } + } + uint64_t oldTl = + thread->readMiscRegNoEffect(MISCREG_TL); + if (oldTl != shared_data->tl) + diffTl = true; + for (int i = 1; i <= MaxTL; i++) { + thread->setMiscRegNoEffect(MISCREG_TL, i); + if (thread->readMiscRegNoEffect(MISCREG_TPC) != + shared_data->tpc[i-1]) + diffTpc = true; + if (thread->readMiscRegNoEffect(MISCREG_TNPC) != + shared_data->tnpc[i-1]) + diffTnpc = true; + if (thread->readMiscRegNoEffect(MISCREG_TSTATE) != + shared_data->tstate[i-1]) + diffTstate = true; + if (thread->readMiscRegNoEffect(MISCREG_TT) != + shared_data->tt[i-1]) + diffTt = true; + if (thread->readMiscRegNoEffect(MISCREG_HTSTATE) != + shared_data->htstate[i-1]) + diffHtstate = true; + } + thread->setMiscRegNoEffect(MISCREG_TL, oldTl); + + if(shared_data->tba != thread->readMiscRegNoEffect(MISCREG_TBA)) + diffTba = true; + //When the hpstate register is read by an instruction, + //legion has bit 11 set. When it's in storage, it doesn't. + //Since we don't directly support seperate interpretations + //of the registers like that, the bit is always set to 1 and + //we just don't compare it. It's not supposed to matter + //anyway. + if((shared_data->hpstate | (1 << 11)) != + thread->readMiscRegNoEffect(MISCREG_HPSTATE)) + diffHpstate = true; + if(shared_data->htba != + thread->readMiscRegNoEffect(MISCREG_HTBA)) + diffHtba = true; + if(shared_data->pstate != + thread->readMiscRegNoEffect(MISCREG_PSTATE)) + diffPstate = true; + //if(shared_data->y != + // thread->readMiscRegNoEffect(MISCREG_Y)) + if(shared_data->y != + thread->readIntReg(NumIntArchRegs + 1)) + diffY = true; + if(shared_data->fsr != + thread->readMiscRegNoEffect(MISCREG_FSR)) { + diffFsr = true; + if (mbits(shared_data->fsr, 63,10) == + mbits(thread->readMiscRegNoEffect(MISCREG_FSR), + 63,10)) { + thread->setMiscRegNoEffect(MISCREG_FSR, + shared_data->fsr); + diffFsr = false; + } + } + //if(shared_data->ccr != + // thread->readMiscRegNoEffect(MISCREG_CCR)) + if(shared_data->ccr != + thread->readIntReg(NumIntArchRegs + 2)) + diffCcr = true; + if(shared_data->gl != + thread->readMiscRegNoEffect(MISCREG_GL)) + diffGl = true; + if(shared_data->asi != + thread->readMiscRegNoEffect(MISCREG_ASI)) + diffAsi = true; + if(shared_data->pil != + thread->readMiscRegNoEffect(MISCREG_PIL)) + diffPil = true; + if(shared_data->cwp != + thread->readMiscRegNoEffect(MISCREG_CWP)) + diffCwp = true; + //if(shared_data->cansave != + // thread->readMiscRegNoEffect(MISCREG_CANSAVE)) + if(shared_data->cansave != + thread->readIntReg(NumIntArchRegs + 3)) + diffCansave = true; + //if(shared_data->canrestore != + // thread->readMiscRegNoEffect(MISCREG_CANRESTORE)) + if(shared_data->canrestore != + thread->readIntReg(NumIntArchRegs + 4)) + diffCanrestore = true; + //if(shared_data->otherwin != + // thread->readMiscRegNoEffect(MISCREG_OTHERWIN)) + if(shared_data->otherwin != + thread->readIntReg(NumIntArchRegs + 6)) + diffOtherwin = true; + //if(shared_data->cleanwin != + // thread->readMiscRegNoEffect(MISCREG_CLEANWIN)) + if(shared_data->cleanwin != + thread->readIntReg(NumIntArchRegs + 5)) + diffCleanwin = true; + + for (int i = 0; i < 64; i++) { + if (shared_data->itb[i] != + thread->getITBPtr()->TteRead(i)) + diffTlb = true; + if (shared_data->dtb[i] != + thread->getDTBPtr()->TteRead(i)) + diffTlb = true; + } + + if (diffPC || diffCC || diffInst || + diffIntRegs || diffFpRegs || + diffTpc || diffTnpc || diffTstate || diffTt || + diffHpstate || diffHtstate || diffHtba || + diffPstate || diffY || diffCcr || diffTl || diffFsr || + diffGl || diffAsi || diffPil || diffCwp || + diffCansave || diffCanrestore || + diffOtherwin || diffCleanwin || diffTlb) { + + outs << "Differences found between M5 and Legion:"; + if (diffPC) + outs << " [PC]"; + if (diffCC) + outs << " [CC]"; + if (diffInst) + outs << " [Instruction]"; + if (diffIntRegs) + outs << " [IntRegs]"; + if (diffFpRegs) + outs << " [FpRegs]"; + if (diffTpc) + outs << " [Tpc]"; + if (diffTnpc) + outs << " [Tnpc]"; + if (diffTstate) + outs << " [Tstate]"; + if (diffTt) + outs << " [Tt]"; + if (diffHpstate) + outs << " [Hpstate]"; + if (diffHtstate) + outs << " [Htstate]"; + if (diffHtba) + outs << " [Htba]"; + if (diffPstate) + outs << " [Pstate]"; + if (diffY) + outs << " [Y]"; + if (diffFsr) + outs << " [FSR]"; + if (diffCcr) + outs << " [Ccr]"; + if (diffTl) + outs << " [Tl]"; + if (diffGl) + outs << " [Gl]"; + if (diffAsi) + outs << " [Asi]"; + if (diffPil) + outs << " [Pil]"; + if (diffCwp) + outs << " [Cwp]"; + if (diffCansave) + outs << " [Cansave]"; + if (diffCanrestore) + outs << " [Canrestore]"; + if (diffOtherwin) + outs << " [Otherwin]"; + if (diffCleanwin) + outs << " [Cleanwin]"; + if (diffTlb) + outs << " [Tlb]"; + outs << endl << endl; + + outs << right << setfill(' ') << setw(15) + << "M5 PC: " << "0x"<< setw(16) << setfill('0') + << hex << m5Pc << endl; + outs << setfill(' ') << setw(15) + << "Legion PC: " << "0x" + << setw(16) << setfill('0') << hex + << lgnPc << endl << endl; + + outs << right << setfill(' ') << setw(15) + << "M5 CC: " << "0x" + << setw(16) << setfill('0') << hex + << thread->getCpuPtr()->instCount() << endl; + outs << setfill(' ') << setw(15) + << "Legion CC: " << "0x" + << setw(16) << setfill('0') << hex + << shared_data->cycle_count << endl << endl; + + outs << setfill(' ') << setw(15) + << "M5 Inst: " << "0x" + << setw(8) << setfill('0') << hex + << staticInst->machInst + << staticInst->disassemble(m5Pc, debugSymbolTable) + << endl; + + predecoder.setTC(thread); + predecoder.moreBytes(m5Pc, m5Pc, + shared_data->instruction); + + assert(predecoder.extMachInstReady()); + + StaticInstPtr legionInst = + StaticInst::decode(predecoder.getExtMachInst(), lgnPc); + outs << setfill(' ') << setw(15) + << " Legion Inst: " + << "0x" << setw(8) << setfill('0') << hex + << shared_data->instruction + << legionInst->disassemble(lgnPc, debugSymbolTable) + << endl << endl; + + printSectionHeader(outs, "General State"); + printColumnLabels(outs); + printRegPair(outs, "HPstate", + thread->readMiscRegNoEffect(MISCREG_HPSTATE), + shared_data->hpstate | (1 << 11)); + printRegPair(outs, "Htba", + thread->readMiscRegNoEffect(MISCREG_HTBA), + shared_data->htba); + printRegPair(outs, "Pstate", + thread->readMiscRegNoEffect(MISCREG_PSTATE), + shared_data->pstate); + printRegPair(outs, "Y", + //thread->readMiscRegNoEffect(MISCREG_Y), + thread->readIntReg(NumIntArchRegs + 1), + shared_data->y); + printRegPair(outs, "FSR", + thread->readMiscRegNoEffect(MISCREG_FSR), + shared_data->fsr); + printRegPair(outs, "Ccr", + //thread->readMiscRegNoEffect(MISCREG_CCR), + thread->readIntReg(NumIntArchRegs + 2), + shared_data->ccr); + printRegPair(outs, "Tl", + thread->readMiscRegNoEffect(MISCREG_TL), + shared_data->tl); + printRegPair(outs, "Gl", + thread->readMiscRegNoEffect(MISCREG_GL), + shared_data->gl); + printRegPair(outs, "Asi", + thread->readMiscRegNoEffect(MISCREG_ASI), + shared_data->asi); + printRegPair(outs, "Pil", + thread->readMiscRegNoEffect(MISCREG_PIL), + shared_data->pil); + printRegPair(outs, "Cwp", + thread->readMiscRegNoEffect(MISCREG_CWP), + shared_data->cwp); + printRegPair(outs, "Cansave", + //thread->readMiscRegNoEffect(MISCREG_CANSAVE), + thread->readIntReg(NumIntArchRegs + 3), + shared_data->cansave); + printRegPair(outs, "Canrestore", + //thread->readMiscRegNoEffect(MISCREG_CANRESTORE), + thread->readIntReg(NumIntArchRegs + 4), + shared_data->canrestore); + printRegPair(outs, "Otherwin", + //thread->readMiscRegNoEffect(MISCREG_OTHERWIN), + thread->readIntReg(NumIntArchRegs + 6), + shared_data->otherwin); + printRegPair(outs, "Cleanwin", + //thread->readMiscRegNoEffect(MISCREG_CLEANWIN), + thread->readIntReg(NumIntArchRegs + 5), + shared_data->cleanwin); + outs << endl; + for (int i = 1; i <= MaxTL; i++) { + printLevelHeader(outs, i); + printColumnLabels(outs); + thread->setMiscRegNoEffect(MISCREG_TL, i); + printRegPair(outs, "Tpc", + thread->readMiscRegNoEffect(MISCREG_TPC), + shared_data->tpc[i-1]); + printRegPair(outs, "Tnpc", + thread->readMiscRegNoEffect(MISCREG_TNPC), + shared_data->tnpc[i-1]); + printRegPair(outs, "Tstate", + thread->readMiscRegNoEffect(MISCREG_TSTATE), + shared_data->tstate[i-1]); + printRegPair(outs, "Tt", + thread->readMiscRegNoEffect(MISCREG_TT), + shared_data->tt[i-1]); + printRegPair(outs, "Htstate", + thread->readMiscRegNoEffect(MISCREG_HTSTATE), + shared_data->htstate[i-1]); + } + thread->setMiscRegNoEffect(MISCREG_TL, oldTl); + outs << endl; + + printSectionHeader(outs, "General Purpose Registers"); + static const char * regtypes[4] = + {"%g", "%o", "%l", "%i"}; + for(int y = 0; y < 4; y++) { + for(int x = 0; x < 8; x++) { + char label[8]; + sprintf(label, "%s%d", regtypes[y], x); + printRegPair(outs, label, + thread->readIntReg(y*8+x), + shared_data->intregs[y*8+x]); + } + } + if (diffFpRegs) { + for (int x = 0; x < 32; x++) { + char label[8]; + sprintf(label, "%%f%d", x); + printRegPair(outs, label, + thread->readFloatRegBits(x*2, + FloatRegFile::DoubleWidth), + shared_data->fpregs[x]); + } + } + if (diffTlb) { + printColumnLabels(outs); + char label[8]; + for (int x = 0; x < 64; x++) { + if (shared_data->itb[x] != + ULL(0xFFFFFFFFFFFFFFFF) || + thread->getITBPtr()->TteRead(x) != + ULL(0xFFFFFFFFFFFFFFFF)) { + sprintf(label, "I-TLB:%02d", x); + printRegPair(outs, label, + thread->getITBPtr()->TteRead(x), + shared_data->itb[x]); + } + } + for (int x = 0; x < 64; x++) { + if (shared_data->dtb[x] != + ULL(0xFFFFFFFFFFFFFFFF) || + thread->getDTBPtr()->TteRead(x) != + ULL(0xFFFFFFFFFFFFFFFF)) { + sprintf(label, "D-TLB:%02d", x); + printRegPair(outs, label, + thread->getDTBPtr()->TteRead(x), + shared_data->dtb[x]); + } + } + thread->getITBPtr()->dumpAll(); + thread->getDTBPtr()->dumpAll(); + } + + diffcount++; + if (diffcount > 3) + fatal("Differences found between Legion and M5\n"); + } else + diffcount = 0; + + compared = true; + shared_data->flags = OWN_LEGION; + } + } // while + } // if not microop +} + +/* namespace Trace */ } + +//////////////////////////////////////////////////////////////////////// +// +// ExeTracer Simulation Object +// +Trace::LegionTrace * +LegionTraceParams::create() +{ + return new Trace::LegionTrace(name); +}; diff --git a/src/cpu/legiontrace.hh b/src/cpu/legiontrace.hh new file mode 100644 index 000000000..55c05e7ae --- /dev/null +++ b/src/cpu/legiontrace.hh @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Steve Reinhardt + * Nathan Binkert + */ + +#ifndef __LEGIONTRACE_HH__ +#define __LEGIONTRACE_HH__ + +#include "base/trace.hh" +#include "cpu/static_inst.hh" +#include "sim/host.hh" +#include "sim/insttracer.hh" + +class ThreadContext; + +namespace Trace { + +class LegionTraceRecord : public InstRecord +{ + public: + LegionTraceRecord(Tick _when, ThreadContext *_thread, + const StaticInstPtr &_staticInst, Addr _pc, bool spec) + : InstRecord(_when, _thread, _staticInst, _pc, spec) + { + } + + void dump(); +}; + +class LegionTrace : public InstTracer +{ + public: + + LegionTrace(const std::string & name) : InstTracer(name) + {} + + LegionTraceRecord * + getInstRecord(Tick when, ThreadContext *tc, + const StaticInstPtr staticInst, Addr pc) + { + if (tc->misspeculating()) + return NULL; + + return new LegionTraceRecord(when, tc, + staticInst, pc, tc->misspeculating()); + } +}; + +/* namespace Trace */ } + +#endif // __LEGIONTRACE_HH__ diff --git a/src/cpu/nativetrace.cc b/src/cpu/nativetrace.cc new file mode 100644 index 000000000..57304c79b --- /dev/null +++ b/src/cpu/nativetrace.cc @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Steve Reinhardt + * Lisa Hsu + * Nathan Binkert + * Steve Raasch + */ + +#include + +#include "arch/regfile.hh" +#include "arch/utility.hh" +#include "base/loader/symtab.hh" +#include "base/socket.hh" +#include "cpu/nativetrace.hh" +#include "cpu/static_inst.hh" +#include "cpu/thread_context.hh" +#include "params/NativeTrace.hh" + +//XXX This is temporary +#include "arch/isa_specific.hh" + +using namespace std; +using namespace TheISA; + +namespace Trace { + +NativeTrace::NativeTrace(const std::string & _name) : InstTracer(_name) +{ + int port = 8000; + while(!native_listener.listen(port, true)) + { + DPRINTF(GDBMisc, "Can't bind port %d\n", port); + port++; + } + ccprintf(cerr, "Listening for native process on port %d\n", port); + fd = native_listener.accept(); +} + +bool +NativeTraceRecord::checkIntReg(const char * regName, int index, int size) +{ + uint64_t regVal; + int res = read(parent->fd, ®Val, size); + if(res < 0) + panic("Read call failed! %s\n", strerror(errno)); + regVal = TheISA::gtoh(regVal); + uint64_t realRegVal = thread->readIntReg(index); + if(regVal != realRegVal) + { + DPRINTFN("Register %s should be %#x but is %#x.\n", + regName, regVal, realRegVal); + return false; + } + return true; +} + +bool NativeTraceRecord::checkPC(const char * regName, int size) +{ + uint64_t regVal; + int res = read(parent->fd, ®Val, size); + if(res < 0) + panic("Read call failed! %s\n", strerror(errno)); + regVal = TheISA::gtoh(regVal); + uint64_t realRegVal = thread->readNextPC(); + if(regVal != realRegVal) + { + DPRINTFN("%s should be %#x but is %#x.\n", + regName, regVal, realRegVal); + return false; + } + return true; +} + +void +Trace::NativeTraceRecord::dump() +{ +// ostream &outs = Trace::output(); + + //Don't print what happens for each micro-op, just print out + //once at the last op, and for regular instructions. + if(!staticInst->isMicroop() || staticInst->isLastMicroop()) + { + checkIntReg("rax", INTREG_RAX, sizeof(uint64_t)); + checkIntReg("rbx", INTREG_RBX, sizeof(uint64_t)); + checkIntReg("rcx", INTREG_RCX, sizeof(uint64_t)); + checkIntReg("rdx", INTREG_RDX, sizeof(uint64_t)); + checkIntReg("rsp", INTREG_RSP, sizeof(uint64_t)); + checkIntReg("rbp", INTREG_RBP, sizeof(uint64_t)); + checkIntReg("rsi", INTREG_RSI, sizeof(uint64_t)); + checkIntReg("rdi", INTREG_RDI, sizeof(uint64_t)); + checkIntReg("r8", INTREG_R8, sizeof(uint64_t)); + checkIntReg("r9", INTREG_R9, sizeof(uint64_t)); + checkIntReg("r10", INTREG_R10, sizeof(uint64_t)); + checkIntReg("r11", INTREG_R11, sizeof(uint64_t)); + checkIntReg("r12", INTREG_R12, sizeof(uint64_t)); + checkIntReg("r13", INTREG_R13, sizeof(uint64_t)); + checkIntReg("r14", INTREG_R14, sizeof(uint64_t)); + checkIntReg("r15", INTREG_R15, sizeof(uint64_t)); + checkPC("rip", sizeof(uint64_t)); +#if THE_ISA == SPARC_ISA + /*for(int f = 0; f <= 62; f+=2) + { + uint64_t regVal; + int res = read(fd, ®Val, sizeof(regVal)); + if(res < 0) + panic("First read call failed! %s\n", strerror(errno)); + regVal = TheISA::gtoh(regVal); + uint64_t realRegVal = thread->readFloatRegBits(f, 64); + if(regVal != realRegVal) + { + DPRINTF(ExecRegDelta, "Register f%d should be %#x but is %#x.\n", f, regVal, realRegVal); + } + }*/ + uint64_t regVal; + int res = read(fd, ®Val, sizeof(regVal)); + if(res < 0) + panic("First read call failed! %s\n", strerror(errno)); + regVal = TheISA::gtoh(regVal); + uint64_t realRegVal = thread->readNextPC(); + if(regVal != realRegVal) + { + DPRINTF(ExecRegDelta, + "Register pc should be %#x but is %#x.\n", + regVal, realRegVal); + } + res = read(fd, ®Val, sizeof(regVal)); + if(res < 0) + panic("First read call failed! %s\n", strerror(errno)); + regVal = TheISA::gtoh(regVal); + realRegVal = thread->readNextNPC(); + if(regVal != realRegVal) + { + DPRINTF(ExecRegDelta, + "Register npc should be %#x but is %#x.\n", + regVal, realRegVal); + } + res = read(fd, ®Val, sizeof(regVal)); + if(res < 0) + panic("First read call failed! %s\n", strerror(errno)); + regVal = TheISA::gtoh(regVal); + realRegVal = thread->readIntReg(SparcISA::NumIntArchRegs + 2); + if((regVal & 0xF) != (realRegVal & 0xF)) + { + DPRINTF(ExecRegDelta, + "Register ccr should be %#x but is %#x.\n", + regVal, realRegVal); + } +#endif + } +} + +/* namespace Trace */ } + +//////////////////////////////////////////////////////////////////////// +// +// ExeTracer Simulation Object +// +Trace::NativeTrace * +NativeTraceParams::create() +{ + return new Trace::NativeTrace(name); +}; diff --git a/src/cpu/nativetrace.hh b/src/cpu/nativetrace.hh new file mode 100644 index 000000000..48395792d --- /dev/null +++ b/src/cpu/nativetrace.hh @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Steve Reinhardt + * Nathan Binkert + */ + +#ifndef __NATIVETRACE_HH__ +#define __NATIVETRACE_HH__ + +#include "base/trace.hh" +#include "cpu/static_inst.hh" +#include "sim/host.hh" +#include "sim/insttracer.hh" + +class ThreadContext; + + +namespace Trace { + +class NativeTrace; + +class NativeTraceRecord : public InstRecord +{ + protected: + NativeTrace * parent; + + bool + checkIntReg(const char * regName, int index, int size); + + bool + checkPC(const char * regName, int size); + + public: + NativeTraceRecord(NativeTrace * _parent, + Tick _when, ThreadContext *_thread, + const StaticInstPtr &_staticInst, Addr _pc, bool spec) + : InstRecord(_when, _thread, _staticInst, _pc, spec), parent(_parent) + { + } + + void dump(); +}; + +class NativeTrace : public InstTracer +{ + protected: + int fd; + + ListenSocket native_listener; + + public: + + NativeTrace(const std::string & name); + + NativeTraceRecord * + getInstRecord(Tick when, ThreadContext *tc, + const StaticInstPtr staticInst, Addr pc) + { + if (tc->misspeculating()) + return NULL; + + return new NativeTraceRecord(this, when, tc, + staticInst, pc, tc->misspeculating()); + } + + friend class NativeTraceRecord; +}; + +/* namespace Trace */ } + +#endif // __EXETRACE_HH__ diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh index 01e9b5b31..d1c660258 100644 --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -1156,9 +1156,8 @@ DefaultFetch::fetch(bool &status_change) #if TRACING_ON instruction->traceData = - Trace::getInstRecord(curTick, cpu->tcBase(tid), - instruction->staticInst, - instruction->readPC()); + cpu->getTracer()->getInstRecord(curTick, cpu->tcBase(tid), + instruction->staticInst, instruction->readPC()); #else instruction->traceData = NULL; #endif diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index b2c24daad..888ef4960 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -590,6 +590,7 @@ AtomicSimpleCPUParams::create() params->simulate_stalls = simulate_stalls; params->system = system; params->cpu_id = cpu_id; + params->tracer = tracer; #if FULL_SYSTEM params->itb = itb; diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index 4359ebebf..d2dd52b64 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -417,7 +417,7 @@ BaseSimpleCPU::preExecute() if(curStaticInst) { #if TRACING_ON - traceData = Trace::getInstRecord(curTick, tc, curStaticInst, + traceData = tracer->getInstRecord(curTick, tc, curStaticInst, thread->readPC()); DPRINTF(Decode,"Decode: Decoded %s instruction: 0x%x\n", diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index 754bd8c5f..855aaab59 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -719,6 +719,7 @@ TimingSimpleCPUParams::create() params->functionTraceStart = function_trace_start; params->system = system; params->cpu_id = cpu_id; + params->tracer = tracer; #if FULL_SYSTEM params->itb = itb; diff --git a/src/sim/InstTracer.py b/src/sim/InstTracer.py new file mode 100644 index 000000000..f7500f1e8 --- /dev/null +++ b/src/sim/InstTracer.py @@ -0,0 +1,35 @@ +# Copyright (c) 2007 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.SimObject import SimObject +from m5.params import * + +class InstTracer(SimObject): + type = 'InstTracer' + cxx_namespace = 'Trace' + abstract = True diff --git a/src/sim/SConscript b/src/sim/SConscript index 455e5678a..6bd53e205 100644 --- a/src/sim/SConscript +++ b/src/sim/SConscript @@ -32,6 +32,7 @@ Import('*') SimObject('Root.py') SimObject('System.py') +SimObject('InstTracer.py') Source('async.cc') Source('core.cc') diff --git a/src/sim/insttracer.hh b/src/sim/insttracer.hh new file mode 100644 index 000000000..ebeae1fe9 --- /dev/null +++ b/src/sim/insttracer.hh @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Steve Reinhardt + * Nathan Binkert + */ + +#ifndef __INSTRECORD_HH__ +#define __INSTRECORD_HH__ + +#include "base/trace.hh" +#include "cpu/inst_seq.hh" // for InstSeqNum +#include "cpu/static_inst.hh" +#include "sim/host.hh" +#include "sim/sim_object.hh" + +class ThreadContext; + +namespace Trace { + +class InstRecord +{ + protected: + Tick when; + + // The following fields are initialized by the constructor and + // thus guaranteed to be valid. + ThreadContext *thread; + // need to make this ref-counted so it doesn't go away before we + // dump the record + StaticInstPtr staticInst; + Addr PC; + bool misspeculating; + + // The remaining fields are only valid for particular instruction + // types (e.g, addresses for memory ops) or when particular + // options are enabled (e.g., tracing full register contents). + // Each data field has an associated valid flag to indicate + // whether the data field is valid. + Addr addr; + bool addr_valid; + + union { + uint64_t as_int; + double as_double; + } data; + enum { + DataInvalid = 0, + DataInt8 = 1, // set to equal number of bytes + DataInt16 = 2, + DataInt32 = 4, + DataInt64 = 8, + DataDouble = 3 + } data_status; + + InstSeqNum fetch_seq; + bool fetch_seq_valid; + + InstSeqNum cp_seq; + bool cp_seq_valid; + + public: + InstRecord(Tick _when, ThreadContext *_thread, + const StaticInstPtr &_staticInst, + Addr _pc, bool spec) + : when(_when), thread(_thread), + staticInst(_staticInst), PC(_pc), + misspeculating(spec) + { + data_status = DataInvalid; + addr_valid = false; + + fetch_seq_valid = false; + cp_seq_valid = false; + } + + virtual ~InstRecord() { } + + void setAddr(Addr a) { addr = a; addr_valid = true; } + + void setData(Twin64_t d) { data.as_int = d.a; data_status = DataInt64; } + void setData(Twin32_t d) { data.as_int = d.a; data_status = DataInt32; } + void setData(uint64_t d) { data.as_int = d; data_status = DataInt64; } + void setData(uint32_t d) { data.as_int = d; data_status = DataInt32; } + void setData(uint16_t d) { data.as_int = d; data_status = DataInt16; } + void setData(uint8_t d) { data.as_int = d; data_status = DataInt8; } + + void setData(int64_t d) { setData((uint64_t)d); } + void setData(int32_t d) { setData((uint32_t)d); } + void setData(int16_t d) { setData((uint16_t)d); } + void setData(int8_t d) { setData((uint8_t)d); } + + void setData(double d) { data.as_double = d; data_status = DataDouble; } + + void setFetchSeq(InstSeqNum seq) + { fetch_seq = seq; fetch_seq_valid = true; } + + void setCPSeq(InstSeqNum seq) + { cp_seq = seq; cp_seq_valid = true; } + + virtual void dump() = 0; +}; + +class InstTracer : public SimObject +{ + public: + InstTracer(const std::string & name) : SimObject(name) + {} + + virtual ~InstTracer() + {}; + + virtual InstRecord * + getInstRecord(Tick when, ThreadContext *tc, + const StaticInstPtr staticInst, Addr pc) = 0; +}; + + + +}; // namespace Trace + +#endif // __INSTRECORD_HH__ From e996ff74978c09eda4903dc491ed5261b5def789 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sat, 28 Jul 2007 20:33:42 -0700 Subject: [PATCH 02/15] X86: Fix up auxiliary vectors. The type constants should go into an architecture independent spot since they are universal to all Linux elf binaries. The right value for some of the vectors needs to be determined. Also, x86 does not store argc or argv_array_base in registers like some other architectures. --HG-- extra : convert_revision : 8d3f6a3e028d881d3c41e8ddf4f29d25738b529c --- src/arch/x86/process.cc | 49 +++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/src/arch/x86/process.cc b/src/arch/x86/process.cc index 09962fdb6..713e5d0a2 100644 --- a/src/arch/x86/process.cc +++ b/src/arch/x86/process.cc @@ -187,7 +187,14 @@ X86LiveProcess::argsInit(int intSize, int pageSize) X86_AT_UID = 11, X86_AT_EUID = 12, X86_AT_GID = 13, - X86_AT_EGID = 14 + X86_AT_EGID = 14, + X86_AT_PLATFORM = 15, + X86_AT_HWCAP = 16, + X86_AT_CLKTCK = 17, + + X86_AT_SECURE = 13, + + X86_AT_VECTOR_SIZE = 44 }; //Setup the auxilliary vectors. These will already have endian conversion. @@ -195,36 +202,39 @@ X86LiveProcess::argsInit(int intSize, int pageSize) ElfObject * elfObject = dynamic_cast(objFile); if(elfObject) { - /* //Bits which describe the system hardware capabilities - auxv.push_back(auxv_t(SPARC_AT_HWCAP, hwcap)); + //XXX Figure out what these should be + auxv.push_back(auxv_t(X86_AT_HWCAP, 0)); //The system page size - auxv.push_back(auxv_t(SPARC_AT_PAGESZ, SparcISA::VMPageSize)); - //Defined to be 100 in the kernel source. + auxv.push_back(auxv_t(X86_AT_PAGESZ, X86ISA::VMPageSize)); //Frequency at which times() increments - auxv.push_back(auxv_t(SPARC_AT_CLKTCK, 100)); + auxv.push_back(auxv_t(X86_AT_CLKTCK, 100)); // For statically linked executables, this is the virtual address of the // program header tables if they appear in the executable image - auxv.push_back(auxv_t(SPARC_AT_PHDR, elfObject->programHeaderTable())); + auxv.push_back(auxv_t(X86_AT_PHDR, elfObject->programHeaderTable())); // This is the size of a program header entry from the elf file. - auxv.push_back(auxv_t(SPARC_AT_PHENT, elfObject->programHeaderSize())); + auxv.push_back(auxv_t(X86_AT_PHENT, elfObject->programHeaderSize())); // This is the number of program headers from the original elf file. - auxv.push_back(auxv_t(SPARC_AT_PHNUM, elfObject->programHeaderCount())); + auxv.push_back(auxv_t(X86_AT_PHNUM, elfObject->programHeaderCount())); + //Defined to be 100 in the kernel source. //This is the address of the elf "interpreter", It should be set //to 0 for regular executables. It should be something else //(not sure what) for dynamic libraries. - auxv.push_back(auxv_t(SPARC_AT_BASE, 0)); - //This is hardwired to 0 in the elf loading code in the kernel - auxv.push_back(auxv_t(SPARC_AT_FLAGS, 0)); + auxv.push_back(auxv_t(X86_AT_BASE, 0)); + + //XXX Figure out what this should be. + auxv.push_back(auxv_t(X86_AT_FLAGS, 0)); //The entry point to the program - auxv.push_back(auxv_t(SPARC_AT_ENTRY, objFile->entryPoint())); + auxv.push_back(auxv_t(X86_AT_ENTRY, objFile->entryPoint())); //Different user and group IDs - auxv.push_back(auxv_t(SPARC_AT_UID, uid())); - auxv.push_back(auxv_t(SPARC_AT_EUID, euid())); - auxv.push_back(auxv_t(SPARC_AT_GID, gid())); - auxv.push_back(auxv_t(SPARC_AT_EGID, egid())); + auxv.push_back(auxv_t(X86_AT_UID, uid())); + auxv.push_back(auxv_t(X86_AT_EUID, euid())); + auxv.push_back(auxv_t(X86_AT_GID, gid())); + auxv.push_back(auxv_t(X86_AT_EGID, egid())); //Whether to enable "secure mode" in the executable - auxv.push_back(auxv_t(SPARC_AT_SECURE, 0));*/ + auxv.push_back(auxv_t(X86_AT_SECURE, 0)); + //The string "x86_64" with unknown meaning + auxv.push_back(auxv_t(X86_AT_PLATFORM, 0)); } //Figure out how big the initial stack needs to be @@ -338,9 +348,6 @@ X86LiveProcess::argsInit(int intSize, int pageSize) initVirtMem->writeBlob(argc_base, (uint8_t*)&guestArgc, intSize); //Set up the thread context to start running the process - assert(NumArgumentRegs >= 2); - threadContexts[0]->setIntReg(ArgumentReg[0], argc); - threadContexts[0]->setIntReg(ArgumentReg[1], argv_array_base); threadContexts[0]->setIntReg(StackPointerReg, stack_min); Addr prog_entry = objFile->entryPoint(); From 77f712cdb66ce5682824cbb3cd40607c01f8a495 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sat, 28 Jul 2007 20:34:17 -0700 Subject: [PATCH 03/15] Statetrace: Fix compilation problem. --HG-- extra : convert_revision : 7f501de99e5389dc3a4172654d7cbe32ed811259 --- util/statetrace/printer.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/util/statetrace/printer.cc b/util/statetrace/printer.cc index b14671f2c..178972ea8 100644 --- a/util/statetrace/printer.cc +++ b/util/statetrace/printer.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 The Regents of The University of Michigan + * Copyright (c) 2006-2007 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -181,7 +181,10 @@ bool NestingPrinter::configure(string config) lastEndPos = endPos; constStrings.push_back(prefix); string subConfig, subString; - int commaPos, lastCommaPos, childSwitchVar; + long int commaPos, lastCommaPos, childSwitchVar; + //Set up the register printer + RegPrinter * regPrinter = new RegPrinter(child); + NestingPrinter * nestingPrinter = new NestingPrinter(child); switch(type) { //If we found a plain register printer @@ -189,8 +192,6 @@ bool NestingPrinter::configure(string config) numPrinters++; //Get the register name subConfig = config.substr(startPos + 2, endPos - startPos - 2); - //Set up the register printer - RegPrinter * regPrinter = new RegPrinter(child); if(!regPrinter->configure(subConfig)) { delete regPrinter; @@ -203,7 +204,6 @@ bool NestingPrinter::configure(string config) case PRINTER_NESTING: numPrinters++; //Punt on reading in all the parameters of the nesting printer - NestingPrinter * nestingPrinter = new NestingPrinter(child); subConfig = config.substr(startPos + 2, endPos - startPos - 2); lastCommaPos = string::npos; commaPos = subConfig.find(","); From fa968da296410a9a6036bdffb17f80be18d99128 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sat, 28 Jul 2007 20:35:33 -0700 Subject: [PATCH 04/15] Statetrace: Fix indendation. Set the default hostname to "localhost" instead of my machine at UM. --HG-- extra : convert_revision : f268c04e39fd384e0ac17253faae2233b58e9373 --- util/statetrace/statetrace.cc | 192 +++++++++++++++++----------------- 1 file changed, 96 insertions(+), 96 deletions(-) diff --git a/util/statetrace/statetrace.cc b/util/statetrace/statetrace.cc index 4fe47dc02..5f7224b25 100644 --- a/util/statetrace/statetrace.cc +++ b/util/statetrace/statetrace.cc @@ -49,115 +49,115 @@ using namespace std; void printUsage(const char * execName) { - cout << execName << " -h | -r -- " << endl; + cout << execName << " -h | -r -- " << endl; } int main(int argc, char * argv[], char * envp[]) { - TraceChild * child = genTraceChild(); - string args; - int startProgramArgs; + TraceChild * child = genTraceChild(); + string args; + int startProgramArgs; - //Parse the command line arguments - bool printInitial = false; - bool printTrace = true; - for(int x = 1; x < argc; x++) + //Parse the command line arguments + bool printInitial = false; + bool printTrace = true; + for(int x = 1; x < argc; x++) + { + if(!strcmp(argv[x], "-h")) { - if(!strcmp(argv[x], "-h")) - { - printUsage(argv[0]); - return 0; - } - else if(!strcmp(argv[x], "-r")) - { - cout << "Legal register names:" << endl; - int numRegs = child->getNumRegs(); - for(unsigned int x = 0; x < numRegs; x++) - { - cout << "\t" << child->getRegName(x) << endl; - } - return 0; - } - else if(!strcmp(argv[x], "-i")) - { - printInitial = true; - } - else if(!strcmp(argv[x], "-nt")) - { - printTrace = false; - } - else if(!strcmp(argv[x], "--")) - { - x++; - if(x >= argc) - { - cerr << "Incorrect usage.\n" << endl; - printUsage(argv[0]); - return 1; - } - startProgramArgs = x; - break; - } - else - { - cerr << "Incorrect usage.\n" << endl; - printUsage(argv[0]); - return 1; - } + printUsage(argv[0]); + return 0; } - if(!child->startTracing(argv[startProgramArgs], - argv + startProgramArgs)) + else if(!strcmp(argv[x], "-r")) { - cerr << "Couldn't start target program" << endl; - return 1; - } - if(printInitial) - { - child->outputStartState(cout); - } - if(printTrace) - { - // Connect to m5 - bool portSet = false; - int port; - int sock = socket(AF_INET, SOCK_STREAM, 0); - if(sock < 0) + cout << "Legal register names:" << endl; + int numRegs = child->getNumRegs(); + for(unsigned int x = 0; x < numRegs; x++) { - cerr << "Error opening socket! " << strerror(errno) << endl; + cout << "\t" << child->getRegName(x) << endl; + } + return 0; + } + else if(!strcmp(argv[x], "-i")) + { + printInitial = true; + } + else if(!strcmp(argv[x], "-nt")) + { + printTrace = false; + } + else if(!strcmp(argv[x], "--")) + { + x++; + if(x >= argc) + { + cerr << "Incorrect usage.\n" << endl; + printUsage(argv[0]); return 1; } - struct hostent *server; - server = gethostbyname("zower.eecs.umich.edu"); - if(!server) - { - cerr << "Couldn't get host ip! " << strerror(errno) << endl; - return 1; - } - struct sockaddr_in serv_addr; - bzero((char *)&serv_addr, sizeof(serv_addr)); - serv_addr.sin_family = AF_INET; - bcopy((char *)server->h_addr, - (char *)&serv_addr.sin_addr.s_addr, - server->h_length); - serv_addr.sin_port = htons(8000); - if(connect(sock, (sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) - { - cerr << "Couldn't connect to server! " << strerror(errno) << endl; - return 1; - } - child->step(); - while(child->isTracing()) - { - if(!child->sendState(sock)) - break; - child->step(); - } + startProgramArgs = x; + break; } - if(!child->stopTracing()) + else { - cerr << "Couldn't stop child" << endl; - return 1; + cerr << "Incorrect usage.\n" << endl; + printUsage(argv[0]); + return 1; } - return 0; + } + if(!child->startTracing(argv[startProgramArgs], + argv + startProgramArgs)) + { + cerr << "Couldn't start target program" << endl; + return 1; + } + if(printInitial) + { + child->outputStartState(cout); + } + if(printTrace) + { + // Connect to m5 + bool portSet = false; + int port; + int sock = socket(AF_INET, SOCK_STREAM, 0); + if(sock < 0) + { + cerr << "Error opening socket! " << strerror(errno) << endl; + return 1; + } + struct hostent *server; + server = gethostbyname("localhost"); + if(!server) + { + cerr << "Couldn't get host ip! " << strerror(errno) << endl; + return 1; + } + struct sockaddr_in serv_addr; + bzero((char *)&serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + bcopy((char *)server->h_addr, + (char *)&serv_addr.sin_addr.s_addr, + server->h_length); + serv_addr.sin_port = htons(8000); + if(connect(sock, (sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) + { + cerr << "Couldn't connect to server! " << strerror(errno) << endl; + return 1; + } + child->step(); + while(child->isTracing()) + { + if(!child->sendState(sock)) + break; + child->step(); + } + } + if(!child->stopTracing()) + { + cerr << "Couldn't stop child" << endl; + return 1; + } + return 0; } From 4903b549e77f30abec6fee211adb1f203e14239b Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sat, 28 Jul 2007 20:36:35 -0700 Subject: [PATCH 05/15] Statetrace: Implement the AMD64 version of TraceChild. --HG-- extra : convert_revision : cde33fefe46dc05e9b4ea785a4df6b78ac57ccd5 --- util/statetrace/arch/tracechild_amd64.cc | 239 +++++++++++++++++++++++ util/statetrace/arch/tracechild_amd64.hh | 106 ++++++++++ util/statetrace/tracechild_arch.cc | 5 +- 3 files changed, 348 insertions(+), 2 deletions(-) create mode 100644 util/statetrace/arch/tracechild_amd64.cc create mode 100644 util/statetrace/arch/tracechild_amd64.hh diff --git a/util/statetrace/arch/tracechild_amd64.cc b/util/statetrace/arch/tracechild_amd64.cc new file mode 100644 index 000000000..505745575 --- /dev/null +++ b/util/statetrace/arch/tracechild_amd64.cc @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2007 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include +#include +#include +#include + +#include "tracechild_amd64.hh" + +using namespace std; + +char * AMD64TraceChild::regNames[numregs] = { + //GPRs + "rax", "rbx", "rcx", "rdx", + //Index registers + "rsi", "rdi", + //Base pointer and stack pointer + "rbp", "rsp", + //New 64 bit mode registers + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + //Segmentation registers + "cs", "ds", "es", "fs", "gs", "ss", "fs_base", "gs_base", + //PC + "rip", + //Flags + "eflags"}; + +bool AMD64TraceChild::sendState(int socket) +{ + uint64_t regVal = 0; + for(int x = 0; x <= R15; x++) + { + regVal = getRegVal(x); + if(write(socket, ®Val, sizeof(regVal)) == -1) + { + cerr << "Write failed! " << strerror(errno) << endl; + tracing = false; + return false; + } + } + regVal = getRegVal(RIP); + if(write(socket, ®Val, sizeof(regVal)) == -1) + { + cerr << "Write failed! " << strerror(errno) << endl; + tracing = false; + return false; + } + return true; +} + +int64_t AMD64TraceChild::getRegs(user_regs_struct & myregs, int num) +{ + assert(num < numregs && num >= 0); + switch(num) + { + //GPRs + case RAX: return myregs.rax; + case RBX: return myregs.rbx; + case RCX: return myregs.rcx; + case RDX: return myregs.rdx; + //Index registers + case RSI: return myregs.rsi; + case RDI: return myregs.rdi; + //Base pointer and stack pointer + case RBP: return myregs.rbp; + case RSP: return myregs.rsp; + //New 64 bit mode registers + case R8: return myregs.r8; + case R9: return myregs.r9; + case R10: return myregs.r10; + case R11: return myregs.r11; + case R12: return myregs.r12; + case R13: return myregs.r13; + case R14: return myregs.r14; + case R15: return myregs.r15; + //Segmentation registers + case CS: return myregs.cs; + case DS: return myregs.ds; + case ES: return myregs.es; + case FS: return myregs.fs; + case GS: return myregs.gs; + case SS: return myregs.ss; + case FS_BASE: return myregs.fs_base; + case GS_BASE: return myregs.gs_base; + //PC + case RIP: return myregs.rip; + //Flags + case EFLAGS: return myregs.eflags; + default: + assert(0); + return 0; + } +} + +bool AMD64TraceChild::update(int pid) +{ + oldregs = regs; + if(ptrace(PTRACE_GETREGS, pid, 0, ®s) != 0) + { + cerr << "update: " << strerror(errno) << endl; + return false; + } + for(unsigned int x = 0; x < numregs; x++) + regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x)); + return true; +} + +AMD64TraceChild::AMD64TraceChild() +{ + for(unsigned int x = 0; x < numregs; x++) + regDiffSinceUpdate[x] = false; +} + +int64_t AMD64TraceChild::getRegVal(int num) +{ + return getRegs(regs, num); +} + +int64_t AMD64TraceChild::getOldRegVal(int num) +{ + return getRegs(oldregs, num); +} + +char * AMD64TraceChild::printReg(int num) +{ + sprintf(printBuffer, "0x%08X", getRegVal(num)); + return printBuffer; +} + +ostream & AMD64TraceChild::outputStartState(ostream & os) +{ + uint64_t sp = getSP(); + uint64_t pc = getPC(); + char obuf[1024]; + sprintf(obuf, "Initial stack pointer = 0x%016llx\n", sp); + os << obuf; + sprintf(obuf, "Initial program counter = 0x%016llx\n", pc); + os << obuf; + + //Output the argument count + uint64_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0); + sprintf(obuf, "0x%016llx: Argc = 0x%016llx\n", sp, cargc); + os << obuf; + sp += 8; + + //Output argv pointers + int argCount = 0; + uint64_t cargv; + do + { + cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0); + sprintf(obuf, "0x%016llx: argv[%d] = 0x%016llx\n", + sp, argCount++, cargv); + os << obuf; + sp += 8; + } while(cargv); + + //Output the envp pointers + int envCount = 0; + uint64_t cenvp; + do + { + cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0); + sprintf(obuf, "0x%016llx: envp[%d] = 0x%016llx\n", + sp, envCount++, cenvp); + os << obuf; + sp += 8; + } while(cenvp); + uint64_t auxType, auxVal; + do + { + auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0); + sp += 8; + auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0); + sp += 8; + sprintf(obuf, "0x%016llx: Auxiliary vector = {0x%016llx, 0x%016llx}\n", + sp - 8, auxType, auxVal); + os << obuf; + } while(auxType != 0 || auxVal != 0); + //Print out the argument strings, environment strings, and file name. + string current; + uint64_t buf; + uint64_t currentStart = sp; + bool clearedInitialPadding = false; + do + { + buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0); + char * cbuf = (char *)&buf; + for(int x = 0; x < sizeof(uint64_t); x++) + { + if(cbuf[x]) + current += cbuf[x]; + else + { + sprintf(obuf, "0x%016llx: \"%s\"\n", + currentStart, current.c_str()); + os << obuf; + current = ""; + currentStart = sp + x + 1; + } + } + sp += 8; + clearedInitialPadding = clearedInitialPadding || buf != 0; + } while(!clearedInitialPadding || buf != 0); + return os; +} + +TraceChild * genTraceChild() +{ + return new AMD64TraceChild; +} diff --git a/util/statetrace/arch/tracechild_amd64.hh b/util/statetrace/arch/tracechild_amd64.hh new file mode 100644 index 000000000..36974e56d --- /dev/null +++ b/util/statetrace/arch/tracechild_amd64.hh @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2007 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef REGSTATE_AMD64_HH +#define REGSTATE_AMD64_HH + +#include +#include +#include +#include +#include + +#include "tracechild.hh" + +class AMD64TraceChild : public TraceChild +{ + public: + enum RegNum + { + //GPRs + RAX, RCX, RDX, RBX, + //Base pointer and stack pointer + RSP, RBP, + //Index registers + RSI, RDI, + //New 64 bit mode registers + R8, R9, R10, R11, R12, R13, R14, R15, + //Segmentation registers + CS, DS, ES, FS, GS, SS, FS_BASE, GS_BASE, + //PC + RIP, + //Flags + EFLAGS, + numregs + }; + private: + char printBuffer [256]; + static char * regNames[numregs]; + int64_t getRegs(user_regs_struct & myregs, int num); + user_regs_struct regs; + user_regs_struct oldregs; + bool regDiffSinceUpdate[numregs]; + + protected: + bool update(int pid); + + public: + + AMD64TraceChild(); + + bool sendState(int socket); + + int getNumRegs() + { + return numregs; + } + + bool diffSinceUpdate(int num) + { + assert(num < numregs && num >= 0); + return regDiffSinceUpdate[num]; + } + + std::string getRegName(int num) + { + assert(num < numregs && num >= 0); + return regNames[num]; + } + + int64_t getRegVal(int num); + int64_t getOldRegVal(int num); + uint64_t getPC() {return getRegVal(RIP);} + uint64_t getSP() {return getRegVal(RSP);} + std::ostream & outputStartState(std::ostream & output); + + char * printReg(int num); +}; + +#endif diff --git a/util/statetrace/tracechild_arch.cc b/util/statetrace/tracechild_arch.cc index 603ccb12c..570a12b54 100644 --- a/util/statetrace/tracechild_arch.cc +++ b/util/statetrace/tracechild_arch.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 The Regents of The University of Michigan + * Copyright (c) 2006-2007 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,7 +31,8 @@ #if defined __alpha__ #error "Alpha architecture not implemented" #elif defined __amd64__ - #error "AMD64 architecture not implemented" +// #error "AMD64 architecture not implemented" + #include "arch/tracechild_amd64.cc" #elif defined __hppa__ #error "Hppa architecture not implemented" #elif defined __i386__ || defined __i486__ || \ From dc86f3229c2d3278bf5f32fb9b0b4bf039c0735e Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sat, 28 Jul 2007 21:18:53 -0700 Subject: [PATCH 06/15] X86: Fix a comment and adjust the stack base address. The stack base on my development machine starts one page below where it needs to. I don't know why it does, but I've duplicated it in m5. --HG-- extra : convert_revision : c4783ba885b90f17e843f61e07af0bc3330a74bc --- src/arch/x86/process.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/arch/x86/process.cc b/src/arch/x86/process.cc index 713e5d0a2..ff23be339 100644 --- a/src/arch/x86/process.cc +++ b/src/arch/x86/process.cc @@ -122,9 +122,10 @@ X86LiveProcess::X86LiveProcess(const std::string &nm, ObjectFile *objFile, // Set pointer for next thread stack. Reserve 8M for main stack. next_thread_stack_base = stack_base - (8 * 1024 * 1024); - // Set up stack. On SPARC Linux, stack goes from the top of memory - // downward, less the hole for the kernel address space. - stack_base = (Addr)0x80000000000ULL; + // Set up stack. On X86_64 Linux, stack goes from the top of memory + // downward, less the hole for the kernel address space plus one page + // for undertermined purposes. + stack_base = (Addr)0x7FFFFFFF000ULL; // Set up region for mmaps. Tru64 seems to start just above 0 and // grow up from there. From 3dcd848ec340e96f374ee9859bf4f8906fb577cc Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 29 Jul 2007 01:24:57 -0700 Subject: [PATCH 07/15] X86: Fix a bug with merge Merge was returning the value to merge in, not the actual result of the merge. --HG-- extra : convert_revision : 230b4b5064037d099ae7859edabdf5be84603849 --- src/arch/x86/insts/static_inst.hh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/arch/x86/insts/static_inst.hh b/src/arch/x86/insts/static_inst.hh index c39c2956e..f42e6693d 100644 --- a/src/arch/x86/insts/static_inst.hh +++ b/src/arch/x86/insts/static_inst.hh @@ -58,6 +58,7 @@ #ifndef __ARCH_X86_INSTS_STATICINST_HH__ #define __ARCH_X86_INSTS_STATICINST_HH__ +#include "base/trace.hh" #include "cpu/static_inst.hh" namespace X86ISA @@ -113,7 +114,7 @@ namespace X86ISA default: panic("Tried to merge with unrecognized size %d.\n", size); } - return val; + return reg; } inline uint64_t pick(uint64_t from, int size) From d99557534217dc59e33ca70591b52d9d9e8322a8 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 29 Jul 2007 01:26:47 -0700 Subject: [PATCH 08/15] X86: Fix popa and push with the stack pointer. POPA used st instead of ld, and it didn't skip rsp. push rsp needs to store the -original- value of the stack pointer. --HG-- extra : convert_revision : 376370c99b6ab60fb2bc4cd4f0a6dce71153ad06 --- .../insts/data_transfer/stack_operations.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/arch/x86/isa/insts/data_transfer/stack_operations.py b/src/arch/x86/isa/insts/data_transfer/stack_operations.py index 889e7b88b..1c13b44b4 100644 --- a/src/arch/x86/isa/insts/data_transfer/stack_operations.py +++ b/src/arch/x86/isa/insts/data_transfer/stack_operations.py @@ -85,8 +85,10 @@ def macroop PUSH_R { # Make the default data size of pops 64 bits in 64 bit mode .adjust_env oszIn64Override + # This needs to work slightly differently from the other versions of push + # because the -original- version of the stack pointer is what gets pushed + st reg, ss, [0, t0, rsp], "-env.dataSize" subi rsp, rsp, dsz - st reg, ss, [0, t0, rsp] }; def macroop PUSH_I { @@ -130,14 +132,13 @@ def macroop PUSHA { }; def macroop POPA { - st rdi, ss, [0, t0, rsp], "0 * env.dataSize" - st rsi, ss, [0, t0, rsp], "1 * env.dataSize" - st rbp, ss, [0, t0, rsp], "2 * env.dataSize" - st rsp, ss, [0, t0, rsp], "3 * env.dataSize" - st rbx, ss, [0, t0, rsp], "4 * env.dataSize" - st rdx, ss, [0, t0, rsp], "5 * env.dataSize" - st rcx, ss, [0, t0, rsp], "6 * env.dataSize" - st rax, ss, [0, t0, rsp], "7 * env.dataSize" + ld rdi, ss, [0, t0, rsp], "0 * env.dataSize" + ld rsi, ss, [0, t0, rsp], "1 * env.dataSize" + ld rbp, ss, [0, t0, rsp], "2 * env.dataSize" + ld rbx, ss, [0, t0, rsp], "4 * env.dataSize" + ld rdx, ss, [0, t0, rsp], "5 * env.dataSize" + ld rcx, ss, [0, t0, rsp], "6 * env.dataSize" + ld rax, ss, [0, t0, rsp], "7 * env.dataSize" addi rsp, rsp, "8 * env.dataSize" }; ''' From 33847f8c83f8ac3c85c1388b5b69aacbc5163564 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 29 Jul 2007 01:27:34 -0700 Subject: [PATCH 09/15] X86: return -return_value.value() on failure. --HG-- extra : convert_revision : d8e1486ff075b2917be62a0008f83fd6c9e4c09a --- src/arch/x86/syscallreturn.hh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/arch/x86/syscallreturn.hh b/src/arch/x86/syscallreturn.hh index 6a7fdba58..be9715d21 100644 --- a/src/arch/x86/syscallreturn.hh +++ b/src/arch/x86/syscallreturn.hh @@ -67,7 +67,11 @@ namespace X86ISA static inline void setSyscallReturn(SyscallReturn return_value, ThreadContext * tc) { - tc->setIntReg(INTREG_RAX, return_value.value()); + if (return_value.successful()) { + tc->setIntReg(INTREG_RAX, return_value.value()); + } else { + tc->setIntReg(INTREG_RAX, -return_value.value()); + } } }; From b6395da4cea2d12f27ae52517675dfdf507d4a92 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 29 Jul 2007 01:28:36 -0700 Subject: [PATCH 10/15] X86: Fix register ordering. The correct order is unintuitively rax, rcx, rdx, rbx, etc, not rax, rbx, rcx, rdx. --HG-- extra : convert_revision : 3abe6a723a6e30becfe34f8da707ea2ff5d4df77 --- src/cpu/nativetrace.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpu/nativetrace.cc b/src/cpu/nativetrace.cc index 57304c79b..90a0e1a62 100644 --- a/src/cpu/nativetrace.cc +++ b/src/cpu/nativetrace.cc @@ -107,9 +107,9 @@ Trace::NativeTraceRecord::dump() if(!staticInst->isMicroop() || staticInst->isLastMicroop()) { checkIntReg("rax", INTREG_RAX, sizeof(uint64_t)); - checkIntReg("rbx", INTREG_RBX, sizeof(uint64_t)); checkIntReg("rcx", INTREG_RCX, sizeof(uint64_t)); checkIntReg("rdx", INTREG_RDX, sizeof(uint64_t)); + checkIntReg("rbx", INTREG_RBX, sizeof(uint64_t)); checkIntReg("rsp", INTREG_RSP, sizeof(uint64_t)); checkIntReg("rbp", INTREG_RBP, sizeof(uint64_t)); checkIntReg("rsi", INTREG_RSI, sizeof(uint64_t)); From c52e28a4d9ddfcfb3e3610b88c1470d3147375a5 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 29 Jul 2007 01:29:53 -0700 Subject: [PATCH 11/15] Statetrace: Print the correct address of auxiliary vectors. The address of the stackpointer proceeding the vector minus 8 should be minus 16. --HG-- extra : convert_revision : 648f01e9753e28391fc8d282bd9fe2bd47a0193f --- util/statetrace/arch/tracechild_amd64.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/statetrace/arch/tracechild_amd64.cc b/util/statetrace/arch/tracechild_amd64.cc index 505745575..d408598e1 100644 --- a/util/statetrace/arch/tracechild_amd64.cc +++ b/util/statetrace/arch/tracechild_amd64.cc @@ -202,7 +202,7 @@ ostream & AMD64TraceChild::outputStartState(ostream & os) auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0); sp += 8; sprintf(obuf, "0x%016llx: Auxiliary vector = {0x%016llx, 0x%016llx}\n", - sp - 8, auxType, auxVal); + sp - 16, auxType, auxVal); os << obuf; } while(auxType != 0 || auxVal != 0); //Print out the argument strings, environment strings, and file name. From e5f58903651299d8cbba793423d953e750eb16f4 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 29 Jul 2007 01:30:28 -0700 Subject: [PATCH 12/15] X86: Make limm use merge and allow overriding the data size. --HG-- extra : convert_revision : c6057226b8ff8f272612a9d3bf7d1d9ba90c819b --- src/arch/x86/isa/microops/limmop.isa | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/arch/x86/isa/microops/limmop.isa b/src/arch/x86/isa/microops/limmop.isa index 37180d7fa..ec68c36dc 100644 --- a/src/arch/x86/isa/microops/limmop.isa +++ b/src/arch/x86/isa/microops/limmop.isa @@ -142,12 +142,12 @@ def template MicroLimmOpConstructor {{ let {{ class LimmOp(X86Microop): - def __init__(self, dest, imm): + def __init__(self, dest, imm, dataSize="env.dataSize"): self.className = "Limm" self.mnemonic = "limm" self.dest = dest self.imm = imm - self.dataSize = "env.dataSize" + self.dataSize = dataSize def getAllocator(self, *microFlags): allocator = '''new %(class_name)s(machInst, mnemonic @@ -165,7 +165,7 @@ let {{ let {{ # Build up the all register version of this micro op iop = InstObjParams("limm", "Limm", 'X86MicroopBase', - {"code" : "DestReg = imm;"}) + {"code" : "DestReg = merge(DestReg, imm, dataSize);"}) header_output += MicroLimmOpDeclare.subst(iop) decoder_output += MicroLimmOpConstructor.subst(iop) decoder_output += MicroLimmOpDisassembly.subst(iop) From 5e34c62b3b3f54c826730841029a875607824c42 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 29 Jul 2007 01:33:06 -0700 Subject: [PATCH 13/15] X86: Initial stack frame fixes and constant shuffling. The initial stack frame for x86 is now substantially more correct. The fixes made here can be back ported to SPARC and possible the other ISAs as well. The auxiliary vector types were moved to the LiveProcess base class because they are independent of ISA. Some of the types may only apply to Linux, though, so they may have to be moved. --HG-- extra : convert_revision : 89ace35fcc8eb9586d2fee8eeccbc3686499ef24 --- src/arch/sparc/process.cc | 47 ++++------- src/arch/x86/process.cc | 163 +++++++++++++++++++++++++++----------- src/sim/process.hh | 26 ++++++ 3 files changed, 156 insertions(+), 80 deletions(-) diff --git a/src/arch/sparc/process.cc b/src/arch/sparc/process.cc index bc950301a..41a1c2136 100644 --- a/src/arch/sparc/process.cc +++ b/src/arch/sparc/process.cc @@ -194,25 +194,6 @@ Sparc64LiveProcess::argsInit(int intSize, int pageSize) // load object file into target memory objFile->loadSections(initVirtMem); - //These are the auxilliary vector types - enum auxTypes - { - SPARC_AT_HWCAP = 16, - SPARC_AT_PAGESZ = 6, - SPARC_AT_CLKTCK = 17, - SPARC_AT_PHDR = 3, - SPARC_AT_PHENT = 4, - SPARC_AT_PHNUM = 5, - SPARC_AT_BASE = 7, - SPARC_AT_FLAGS = 8, - SPARC_AT_ENTRY = 9, - SPARC_AT_UID = 11, - SPARC_AT_EUID = 12, - SPARC_AT_GID = 13, - SPARC_AT_EGID = 14, - SPARC_AT_SECURE = 23 - }; - enum hardwareCaps { M5_HWCAP_SPARC_FLUSH = 1, @@ -241,34 +222,34 @@ Sparc64LiveProcess::argsInit(int intSize, int pageSize) if(elfObject) { //Bits which describe the system hardware capabilities - auxv.push_back(auxv_t(SPARC_AT_HWCAP, hwcap)); + auxv.push_back(auxv_t(M5_AT_HWCAP, hwcap)); //The system page size - auxv.push_back(auxv_t(SPARC_AT_PAGESZ, SparcISA::VMPageSize)); + auxv.push_back(auxv_t(M5_AT_PAGESZ, SparcISA::VMPageSize)); //Defined to be 100 in the kernel source. //Frequency at which times() increments - auxv.push_back(auxv_t(SPARC_AT_CLKTCK, 100)); + auxv.push_back(auxv_t(M5_AT_CLKTCK, 100)); // For statically linked executables, this is the virtual address of the // program header tables if they appear in the executable image - auxv.push_back(auxv_t(SPARC_AT_PHDR, elfObject->programHeaderTable())); + auxv.push_back(auxv_t(M5_AT_PHDR, elfObject->programHeaderTable())); // This is the size of a program header entry from the elf file. - auxv.push_back(auxv_t(SPARC_AT_PHENT, elfObject->programHeaderSize())); + auxv.push_back(auxv_t(M5_AT_PHENT, elfObject->programHeaderSize())); // This is the number of program headers from the original elf file. - auxv.push_back(auxv_t(SPARC_AT_PHNUM, elfObject->programHeaderCount())); + auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount())); //This is the address of the elf "interpreter", It should be set //to 0 for regular executables. It should be something else //(not sure what) for dynamic libraries. - auxv.push_back(auxv_t(SPARC_AT_BASE, 0)); + auxv.push_back(auxv_t(M5_AT_BASE, 0)); //This is hardwired to 0 in the elf loading code in the kernel - auxv.push_back(auxv_t(SPARC_AT_FLAGS, 0)); + auxv.push_back(auxv_t(M5_AT_FLAGS, 0)); //The entry point to the program - auxv.push_back(auxv_t(SPARC_AT_ENTRY, objFile->entryPoint())); + auxv.push_back(auxv_t(M5_AT_ENTRY, objFile->entryPoint())); //Different user and group IDs - auxv.push_back(auxv_t(SPARC_AT_UID, uid())); - auxv.push_back(auxv_t(SPARC_AT_EUID, euid())); - auxv.push_back(auxv_t(SPARC_AT_GID, gid())); - auxv.push_back(auxv_t(SPARC_AT_EGID, egid())); + auxv.push_back(auxv_t(M5_AT_UID, uid())); + auxv.push_back(auxv_t(M5_AT_EUID, euid())); + auxv.push_back(auxv_t(M5_AT_GID, gid())); + auxv.push_back(auxv_t(M5_AT_EGID, egid())); //Whether to enable "secure mode" in the executable - auxv.push_back(auxv_t(SPARC_AT_SECURE, 0)); + auxv.push_back(auxv_t(M5_AT_SECURE, 0)); } //Figure out how big the initial stack needs to be diff --git a/src/arch/x86/process.cc b/src/arch/x86/process.cc index ff23be339..6d30e53e3 100644 --- a/src/arch/x86/process.cc +++ b/src/arch/x86/process.cc @@ -125,7 +125,7 @@ X86LiveProcess::X86LiveProcess(const std::string &nm, ObjectFile *objFile, // Set up stack. On X86_64 Linux, stack goes from the top of memory // downward, less the hole for the kernel address space plus one page // for undertermined purposes. - stack_base = (Addr)0x7FFFFFFF000ULL; + stack_base = (Addr)0x7FFFFFFFF000ULL; // Set up region for mmaps. Tru64 seems to start just above 0 and // grow up from there. @@ -166,36 +166,49 @@ X86LiveProcess::argsInit(int intSize, int pageSize) else filename = argv[0]; - Addr alignmentMask = ~(intSize - 1); + //We want 16 byte alignment + Addr alignmentMask = ~mask(4); // load object file into target memory objFile->loadSections(initVirtMem); - //These are the auxilliary vector types - enum auxTypes - { - X86_AT_NULL = 0, - X86_AT_IGNORE = 1, - X86_AT_EXECFD = 2, - X86_AT_PHDR = 3, - X86_AT_PHENT = 4, - X86_AT_PHNUM = 5, - X86_AT_PAGESZ = 6, - X86_AT_BASE = 7, - X86_AT_FLAGS = 8, - X86_AT_ENTRY = 9, - X86_AT_NOTELF = 10, - X86_AT_UID = 11, - X86_AT_EUID = 12, - X86_AT_GID = 13, - X86_AT_EGID = 14, - X86_AT_PLATFORM = 15, - X86_AT_HWCAP = 16, - X86_AT_CLKTCK = 17, + enum X86CpuFeature { + X86_OnboardFPU = 1 << 0, + X86_VirtualModeExtensions = 1 << 1, + X86_DebuggingExtensions = 1 << 2, + X86_PageSizeExtensions = 1 << 3, - X86_AT_SECURE = 13, + X86_TimeStampCounter = 1 << 4, + X86_ModelSpecificRegisters = 1 << 5, + X86_PhysicalAddressExtensions = 1 << 6, + X86_MachineCheckExtensions = 1 << 7, - X86_AT_VECTOR_SIZE = 44 + X86_CMPXCHG8Instruction = 1 << 8, + X86_OnboardAPIC = 1 << 9, + X86_SYSENTER_SYSEXIT = 1 << 11, + + X86_MemoryTypeRangeRegisters = 1 << 12, + X86_PageGlobalEnable = 1 << 13, + X86_MachineCheckArchitecture = 1 << 14, + X86_CMOVInstruction = 1 << 15, + + X86_PageAttributeTable = 1 << 16, + X86_36BitPSEs = 1 << 17, + X86_ProcessorSerialNumber = 1 << 18, + X86_CLFLUSHInstruction = 1 << 19, + + X86_DebugTraceStore = 1 << 21, + X86_ACPIViaMSR = 1 << 22, + X86_MultimediaExtensions = 1 << 23, + + X86_FXSAVE_FXRSTOR = 1 << 24, + X86_StreamingSIMDExtensions = 1 << 25, + X86_StreamingSIMDExtensions2 = 1 << 26, + X86_CPUSelfSnoop = 1 << 27, + + X86_HyperThreading = 1 << 28, + X86_AutomaticClockControl = 1 << 29, + X86_IA64Processor = 1 << 30 }; //Setup the auxilliary vectors. These will already have endian conversion. @@ -203,39 +216,71 @@ X86LiveProcess::argsInit(int intSize, int pageSize) ElfObject * elfObject = dynamic_cast(objFile); if(elfObject) { + uint64_t features = + X86_OnboardFPU | + X86_VirtualModeExtensions | + X86_DebuggingExtensions | + X86_PageSizeExtensions | + X86_TimeStampCounter | + X86_ModelSpecificRegisters | + X86_PhysicalAddressExtensions | + X86_MachineCheckExtensions | + X86_CMPXCHG8Instruction | + X86_OnboardAPIC | + X86_SYSENTER_SYSEXIT | + X86_MemoryTypeRangeRegisters | + X86_PageGlobalEnable | + X86_MachineCheckArchitecture | + X86_CMOVInstruction | + X86_PageAttributeTable | + X86_36BitPSEs | +// X86_ProcessorSerialNumber | + X86_CLFLUSHInstruction | +// X86_DebugTraceStore | +// X86_ACPIViaMSR | + X86_MultimediaExtensions | + X86_FXSAVE_FXRSTOR | + X86_StreamingSIMDExtensions | + X86_StreamingSIMDExtensions2 | +// X86_CPUSelfSnoop | +// X86_HyperThreading | +// X86_AutomaticClockControl | +// X86_IA64Processor | + 0; + //Bits which describe the system hardware capabilities //XXX Figure out what these should be - auxv.push_back(auxv_t(X86_AT_HWCAP, 0)); + auxv.push_back(auxv_t(M5_AT_HWCAP, features)); //The system page size - auxv.push_back(auxv_t(X86_AT_PAGESZ, X86ISA::VMPageSize)); + auxv.push_back(auxv_t(M5_AT_PAGESZ, X86ISA::VMPageSize)); //Frequency at which times() increments - auxv.push_back(auxv_t(X86_AT_CLKTCK, 100)); + auxv.push_back(auxv_t(M5_AT_CLKTCK, 100)); // For statically linked executables, this is the virtual address of the // program header tables if they appear in the executable image - auxv.push_back(auxv_t(X86_AT_PHDR, elfObject->programHeaderTable())); + auxv.push_back(auxv_t(M5_AT_PHDR, elfObject->programHeaderTable())); // This is the size of a program header entry from the elf file. - auxv.push_back(auxv_t(X86_AT_PHENT, elfObject->programHeaderSize())); + auxv.push_back(auxv_t(M5_AT_PHENT, elfObject->programHeaderSize())); // This is the number of program headers from the original elf file. - auxv.push_back(auxv_t(X86_AT_PHNUM, elfObject->programHeaderCount())); + auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount())); //Defined to be 100 in the kernel source. //This is the address of the elf "interpreter", It should be set //to 0 for regular executables. It should be something else //(not sure what) for dynamic libraries. - auxv.push_back(auxv_t(X86_AT_BASE, 0)); + auxv.push_back(auxv_t(M5_AT_BASE, 0)); //XXX Figure out what this should be. - auxv.push_back(auxv_t(X86_AT_FLAGS, 0)); + auxv.push_back(auxv_t(M5_AT_FLAGS, 0)); //The entry point to the program - auxv.push_back(auxv_t(X86_AT_ENTRY, objFile->entryPoint())); + auxv.push_back(auxv_t(M5_AT_ENTRY, objFile->entryPoint())); //Different user and group IDs - auxv.push_back(auxv_t(X86_AT_UID, uid())); - auxv.push_back(auxv_t(X86_AT_EUID, euid())); - auxv.push_back(auxv_t(X86_AT_GID, gid())); - auxv.push_back(auxv_t(X86_AT_EGID, egid())); + auxv.push_back(auxv_t(M5_AT_UID, uid())); + auxv.push_back(auxv_t(M5_AT_EUID, euid())); + auxv.push_back(auxv_t(M5_AT_GID, gid())); + auxv.push_back(auxv_t(M5_AT_EGID, egid())); //Whether to enable "secure mode" in the executable - auxv.push_back(auxv_t(X86_AT_SECURE, 0)); + auxv.push_back(auxv_t(M5_AT_SECURE, 0)); //The string "x86_64" with unknown meaning - auxv.push_back(auxv_t(X86_AT_PLATFORM, 0)); + auxv.push_back(auxv_t(M5_AT_PLATFORM, 0)); } //Figure out how big the initial stack needs to be @@ -245,29 +290,39 @@ X86LiveProcess::argsInit(int intSize, int pageSize) //This is the name of the file which is present on the initial stack //It's purpose is to let the user space linker examine the original file. - int file_name_size = filename.size() + 1; + int file_name_size = filename.size(); + + string platform = "x86_64"; + int aux_data_size = platform.size() + 1; int env_data_size = 0; for (int i = 0; i < envp.size(); ++i) { - env_data_size += envp[i].size() + 1; + env_data_size += envp[i].size(); } int arg_data_size = 0; for (int i = 0; i < argv.size(); ++i) { - arg_data_size += argv[i].size() + 1; + arg_data_size += argv[i].size(); } + //The auxiliary vector data needs to be padded so it's size is a multiple + //of the alignment mask. + int aux_padding = + ((aux_data_size + ~alignmentMask) & alignmentMask) - aux_data_size; + //The info_block needs to be padded so it's size is a multiple of the //alignment mask. Also, it appears that there needs to be at least some //padding, so if the size is already a multiple, we need to increase it //anyway. int info_block_size = - (file_name_size + + (mysterious_size + + file_name_size + env_data_size + arg_data_size + - intSize) & alignmentMask; + ~alignmentMask) & alignmentMask; int info_block_padding = info_block_size - + mysterious_size - file_name_size - env_data_size - arg_data_size; @@ -281,8 +336,9 @@ X86LiveProcess::argsInit(int intSize, int pageSize) int argc_size = intSize; int space_needed = - mysterious_size + info_block_size + + aux_data_size + + aux_padding + aux_array_size + envp_array_size + argv_array_size + @@ -301,7 +357,8 @@ X86LiveProcess::argsInit(int intSize, int pageSize) Addr file_name_base = mysterious_base - file_name_size; Addr env_data_base = file_name_base - env_data_size; Addr arg_data_base = env_data_base - arg_data_size; - Addr auxv_array_base = arg_data_base - aux_array_size - info_block_padding; + Addr aux_data_base = arg_data_base - aux_data_size - info_block_padding; + Addr auxv_array_base = aux_data_base - aux_array_size - aux_padding; Addr envp_array_base = auxv_array_base - envp_array_size; Addr argv_array_base = envp_array_base - argv_array_size; Addr argc_base = argv_array_base - argc_size; @@ -310,6 +367,7 @@ X86LiveProcess::argsInit(int intSize, int pageSize) DPRINTF(X86, "0x%x - file name\n", file_name_base); DPRINTF(X86, "0x%x - env data\n", env_data_base); DPRINTF(X86, "0x%x - arg data\n", arg_data_base); + DPRINTF(X86, "0x%x - aux data\n", aux_data_base); DPRINTF(X86, "0x%x - auxv array\n", auxv_array_base); DPRINTF(X86, "0x%x - envp array\n", envp_array_base); DPRINTF(X86, "0x%x - argv array\n", argv_array_base); @@ -330,6 +388,10 @@ X86LiveProcess::argsInit(int intSize, int pageSize) //Write the file name initVirtMem->writeString(file_name_base, filename.c_str()); + //Fix up the aux vector which points to the "platform" string + assert(auxv[auxv.size() - 1].a_type = M5_AT_PLATFORM); + auxv[auxv.size() - 1].a_val = aux_data_base; + //Copy the aux stuff for(int x = 0; x < auxv.size(); x++) { @@ -343,12 +405,19 @@ X86LiveProcess::argsInit(int intSize, int pageSize) initVirtMem->writeBlob(auxv_array_base + 2 * intSize * auxv.size(), (uint8_t*)&zero, 2 * intSize); + initVirtMem->writeString(aux_data_base, platform.c_str()); + copyStringArray(envp, envp_array_base, env_data_base, initVirtMem); copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem); initVirtMem->writeBlob(argc_base, (uint8_t*)&guestArgc, intSize); //Set up the thread context to start running the process + //Because of the peculiarities of how syscall works, I believe + //a process starts with r11 containing the value of eflags or maybe r11 + //from before the call to execve. Empirically this value is 0x200. + threadContexts[0]->setIntReg(INTREG_R11, 0x200); + //Set the stack pointer register threadContexts[0]->setIntReg(StackPointerReg, stack_min); Addr prog_entry = objFile->entryPoint(); diff --git a/src/sim/process.hh b/src/sim/process.hh index fa46b9c95..8c702da60 100644 --- a/src/sim/process.hh +++ b/src/sim/process.hh @@ -214,6 +214,32 @@ class LiveProcess : public Process public: + enum AuxiliaryVectorType { + M5_AT_NULL = 0, + M5_AT_IGNORE = 1, + M5_AT_EXECFD = 2, + M5_AT_PHDR = 3, + M5_AT_PHENT = 4, + M5_AT_PHNUM = 5, + M5_AT_PAGESZ = 6, + M5_AT_BASE = 7, + M5_AT_FLAGS = 8, + M5_AT_ENTRY = 9, + M5_AT_NOTELF = 10, + M5_AT_UID = 11, + M5_AT_EUID = 12, + M5_AT_GID = 13, + M5_AT_EGID = 14, + // The following may be specific to Linux + M5_AT_PLATFORM = 15, + M5_AT_HWCAP = 16, + M5_AT_CLKTCK = 17, + + M5_AT_SECURE = 23, + + M5_AT_VECTOR_SIZE = 44 + }; + inline uint64_t uid() {return __uid;} inline uint64_t euid() {return __euid;} inline uint64_t gid() {return __gid;} From b4087e0e44bba5c4ddbfdb541d50c6c55abed338 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 29 Jul 2007 12:37:35 -0700 Subject: [PATCH 14/15] Statetrace: Make statetrace patch amd64 executables for true single stepping after system calls. Because of peculiarities in how system calls are returned from, single stepping executes some system calls and the instruction following them in a single step. Statetrace now patches the executable image when it detects a system call to force "correct" behavior, aka the appearance of stepping one instruction every single time. --HG-- extra : convert_revision : ac6243a2e00ff98f827b005efd27b4dc5be4f774 --- util/statetrace/arch/tracechild_amd64.cc | 83 ++++++++++++++++++++++++ util/statetrace/arch/tracechild_amd64.hh | 4 ++ 2 files changed, 87 insertions(+) diff --git a/util/statetrace/arch/tracechild_amd64.cc b/util/statetrace/arch/tracechild_amd64.cc index d408598e1..088e547e4 100644 --- a/util/statetrace/arch/tracechild_amd64.cc +++ b/util/statetrace/arch/tracechild_amd64.cc @@ -29,6 +29,7 @@ */ #include +#include #include #include #include @@ -233,6 +234,88 @@ ostream & AMD64TraceChild::outputStartState(ostream & os) return os; } +uint64_t AMD64TraceChild::findSyscall() +{ + uint64_t rip = getPC(); + bool foundOpcode = false; + bool twoByteOpcode = false; + for(;;) + { + uint64_t buf = ptrace(PTRACE_PEEKDATA, pid, rip, 0); + for(int i = 0; i < sizeof(uint64_t); i++) + { + unsigned char byte = buf & 0xFF; + if(!foundOpcode) + { + if(!(byte == 0x66 || //operand override + byte == 0x67 || //address override + byte == 0x2E || //cs + byte == 0x3E || //ds + byte == 0x26 || //es + byte == 0x64 || //fs + byte == 0x65 || //gs + byte == 0x36 || //ss + byte == 0xF0 || //lock + byte == 0xF2 || //repe + byte == 0xF3 || //repne + (byte >= 0x40 && byte <= 0x4F) // REX + )) + { + foundOpcode = true; + } + } + if(foundOpcode) + { + if(twoByteOpcode) + { + //SYSCALL or SYSENTER + if(byte == 0x05 || byte == 0x34) + return rip + 1; + else + return 0; + } + if(!twoByteOpcode) + { + if(byte == 0xCC) // INT3 + return rip + 1; + else if(byte == 0xCD) // INT with byte immediate + return rip + 2; + else if(byte == 0x0F) // two byte opcode prefix + twoByteOpcode = true; + else + return 0; + } + } + buf >>= 8; + rip++; + } + } +} + +bool AMD64TraceChild::step() +{ + uint64_t ripAfterSyscall = findSyscall(); + if(ripAfterSyscall) + { + //Get the original contents of memory + uint64_t buf = ptrace(PTRACE_PEEKDATA, pid, ripAfterSyscall, 0); + //Patch the first two bytes of the memory immediately after this with + //jmp -2. Either single stepping will take over before this + //instruction, leaving the rip where it should be, or it will take + //over after this instruction, -still- leaving the rip where it should + //be. + uint64_t newBuf = (buf & ~0xFFFF) | 0xFEEB; + //Write the patched memory to the processes address space + ptrace(PTRACE_POKEDATA, pid, ripAfterSyscall, newBuf); + //Step and hit it + ptraceSingleStep(); + //Put things back to the way they started + ptrace(PTRACE_POKEDATA, pid, ripAfterSyscall, buf); + } + else + ptraceSingleStep(); +} + TraceChild * genTraceChild() { return new AMD64TraceChild; diff --git a/util/statetrace/arch/tracechild_amd64.hh b/util/statetrace/arch/tracechild_amd64.hh index 36974e56d..e7457f677 100644 --- a/util/statetrace/arch/tracechild_amd64.hh +++ b/util/statetrace/arch/tracechild_amd64.hh @@ -68,6 +68,8 @@ class AMD64TraceChild : public TraceChild user_regs_struct oldregs; bool regDiffSinceUpdate[numregs]; + uint64_t findSyscall(); + protected: bool update(int pid); @@ -101,6 +103,8 @@ class AMD64TraceChild : public TraceChild std::ostream & outputStartState(std::ostream & output); char * printReg(int num); + + bool step(); }; #endif From 362ff1bcebd78c0c247e435eac657c8a1134b1fb Mon Sep 17 00:00:00 2001 From: Steve Reinhardt Date: Sun, 29 Jul 2007 13:22:44 -0700 Subject: [PATCH 15/15] BsaeCPU: Get rid of some bad DPRINTFs. People should never put pointers in DPRINTFs; it messes up tracediffs. Plus these used the FullCPU trace flag, which is not right. --HG-- extra : convert_revision : 82ed56757da0ad947c165ba205b5f752c85c6667 --- src/cpu/base.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 0fc3b4cea..6c8bf65fa 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -106,14 +106,10 @@ BaseCPU::BaseCPU(Params *p) #endif { // currentTick = curTick; - DPRINTF(FullCPU, "BaseCPU: Creating object, mem address %#x.\n", this); // add self to global list of CPUs cpuList.push_back(this); - DPRINTF(FullCPU, "BaseCPU: CPU added to cpuList, mem address %#x.\n", - this); - if (number_of_threads > maxThreadsPerCPU) maxThreadsPerCPU = number_of_threads;