diff options
author | Steve Reinhardt <stever@eecs.umich.edu> | 2007-07-29 13:25:14 -0700 |
---|---|---|
committer | Steve Reinhardt <stever@eecs.umich.edu> | 2007-07-29 13:25:14 -0700 |
commit | 08474ccf68e14f59b4517c6024a9bc6ecbd4a1d5 (patch) | |
tree | 5c1dc885b4fd33fc48d91a9ce489e24c88c9f3c2 | |
parent | 4a7d0c4b79450e05b87da4cfc48c2361758127c1 (diff) | |
parent | 362ff1bcebd78c0c247e435eac657c8a1134b1fb (diff) | |
download | gem5-08474ccf68e14f59b4517c6024a9bc6ecbd4a1d5.tar.xz |
Merge Gabe's changes from head.
--HG--
extra : convert_revision : d00b7b09c7f19bc0e37b385ef7c124f69c0e917f
36 files changed, 2268 insertions, 1051 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/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) 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" }; ''' 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) diff --git a/src/arch/x86/process.cc b/src/arch/x86/process.cc index 09962fdb6..6d30e53e3 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)0x7FFFFFFFF000ULL; // Set up region for mmaps. Tru64 seems to start just above 0 and // grow up from there. @@ -165,29 +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 + enum X86CpuFeature { + X86_OnboardFPU = 1 << 0, + X86_VirtualModeExtensions = 1 << 1, + X86_DebuggingExtensions = 1 << 2, + X86_PageSizeExtensions = 1 << 3, + + X86_TimeStampCounter = 1 << 4, + X86_ModelSpecificRegisters = 1 << 5, + X86_PhysicalAddressExtensions = 1 << 6, + X86_MachineCheckExtensions = 1 << 7, + + 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. @@ -195,36 +216,71 @@ X86LiveProcess::argsInit(int intSize, int pageSize) ElfObject * elfObject = dynamic_cast<ElfObject *>(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 - auxv.push_back(auxv_t(SPARC_AT_HWCAP, hwcap)); + //XXX Figure out what these should be + auxv.push_back(auxv_t(M5_AT_HWCAP, features)); //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(M5_AT_PAGESZ, X86ISA::VMPageSize)); //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())); + //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(M5_AT_BASE, 0)); + + //XXX Figure out what this should be. + 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)); + //The string "x86_64" with unknown meaning + auxv.push_back(auxv_t(M5_AT_PLATFORM, 0)); } //Figure out how big the initial stack needs to be @@ -234,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; @@ -270,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 + @@ -290,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; @@ -299,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); @@ -319,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++) { @@ -332,15 +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 - assert(NumArgumentRegs >= 2); - threadContexts[0]->setIntReg(ArgumentReg[0], argc); - threadContexts[0]->setIntReg(ArgumentReg[1], argv_array_base); + //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/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()); + } } }; 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 3b8d85c9c..ee409048b 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; @@ -188,6 +184,7 @@ BaseCPU::BaseCPU(Params *p) if (params->profile) profileEvent = new ProfileEvent(this, params->profile); #endif + tracer = params->tracer; } BaseCPU::Params::Params() @@ -196,6 +193,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<ThreadContext *> threadContexts; std::vector<TheISA::Predecoder *> 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 <errno.h> -#include <fstream> #include <iomanip> -#include <sys/ipc.h> -#include <sys/shm.h> -#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"}; - - 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 - } - if(!diff) { - } else if (IsOn(ExecIntel)) { - ccprintf(outs, "%7d ) ", when); - outs << "0x" << hex << PC << ":\t"; - if (staticInst->isLoad()) { - ccprintf(outs, "<RD %#x>", addr); - } else if (staticInst->isStore()) { - ccprintf(outs, "<WR %#x>", 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(ExecTicks)) + ccprintf(outs, "%7d: ", when); - if (IsOn(ExecOpClass)) { - outs << Enums::OpClassStrings[staticInst->opClass()] << " : "; - } + outs << thread->getCpuPtr()->name() << " "; - 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(ExecSpeculative)) + outs << (misspeculating ? "-" : "+") << " "; - if (IsOn(ExecEffAddr) && addr_valid) - outs << " A=0x" << hex << addr; + if (IsOn(ExecThread)) + outs << "T" << thread->getThreadNum() << " : "; - 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; + 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 << " : "; + } + 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(); - - // 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 & 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; + // + // Print decoded instruction + // - predecoder.setTC(thread); - predecoder.moreBytes(m5Pc, m5Pc, - shared_data->instruction); + outs << setw(26) << left; + outs << staticInst->disassemble(PC, debugSymbolTable); + outs << " : "; - assert(predecoder.extMachInstReady()); + if (IsOn(ExecOpClass)) { + outs << Enums::OpClassStrings[staticInst->opClass()] << " : "; + } - 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; + if (IsOn(ExecResult) && data_status != DataInvalid) { + ccprintf(outs, " D=%#018x", data.as_int); + } - 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; + if (IsOn(ExecEffAddr) && addr_valid) + outs << " A=0x" << hex << addr; - 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(); - } + if (IsOn(ExecFetchSeq) && fetch_seq_valid) + outs << " FetchSeq=" << dec << fetch_seq; - diffcount++; - if (diffcount > 3) - fatal("Differences found between Legion and M5\n"); - } else - diffcount = 0; + if (IsOn(ExecCPSeq) && cp_seq_valid) + outs << " CPSeq=" << dec << cp_seq; - compared = true; - shared_data->flags = OWN_LEGION; - } - } // while - } // if not microop - } -#endif + // + // 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 <cstring> -#include <fstream> -#include <vector> - #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 <iomanip> + +#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, "<RD %#x>", addr); + } else if (staticInst->isStore()) { + ccprintf(outs, "<WR %#x>", 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 <iomanip> +#include <sys/ipc.h> +#include <sys/shm.h> + +#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..90a0e1a62 --- /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 <errno.h> + +#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("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)); + 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 aa0c69ac4..ab411c7fe 100644 --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -1150,9 +1150,8 @@ DefaultFetch<Impl>::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 b830cbf3a..604c48086 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -570,6 +570,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 b1cb80949..a70ca7c75 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -725,6 +725,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__ 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;} diff --git a/util/statetrace/arch/tracechild_amd64.cc b/util/statetrace/arch/tracechild_amd64.cc new file mode 100644 index 000000000..088e547e4 --- /dev/null +++ b/util/statetrace/arch/tracechild_amd64.cc @@ -0,0 +1,322 @@ +/* + * 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 <iostream> +#include <iomanip> +#include <errno.h> +#include <sys/ptrace.h> +#include <stdint.h> + +#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 - 16, 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; +} + +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 new file mode 100644 index 000000000..e7457f677 --- /dev/null +++ b/util/statetrace/arch/tracechild_amd64.hh @@ -0,0 +1,110 @@ +/* + * 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 <sys/user.h> +#include <sys/types.h> +#include <sys/ptrace.h> +#include <assert.h> +#include <string> + +#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]; + + uint64_t findSyscall(); + + 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); + + bool step(); +}; + +#endif 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(","); 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 -- <command> <arguments>" << endl; + cout << execName << " -h | -r -- <command> <arguments>" << 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; + 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; } - if(printInitial) + else if(!strcmp(argv[x], "-i")) { - child->outputStartState(cout); + printInitial = true; } - if(printTrace) + else if(!strcmp(argv[x], "-nt")) { - // 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("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) + printTrace = false; + } + else if(!strcmp(argv[x], "--")) + { + x++; + if(x >= argc) { - cerr << "Couldn't connect to server! " << strerror(errno) << endl; + cerr << "Incorrect usage.\n" << endl; + printUsage(argv[0]); 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; + } + } + 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(); } - return 0; + } + if(!child->stopTracing()) + { + cerr << "Couldn't stop child" << endl; + return 1; + } + return 0; } 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__ || \ diff --git a/util/style.py b/util/style.py index 7238b9801..3d7336388 100644 --- a/util/style.py +++ b/util/style.py @@ -306,7 +306,7 @@ def check_whitespace(ui, repo, hooktype, node, parent1, parent2): lines = mdiff.splitnewlines(file_data) mod_lines = modified_lines(pctx[0].data(), file_data, len(lines)) if len(pctx) == 2: - m2 = modified_lines(pctx[1].data(), file_data) + m2 = modified_lines(pctx[1].data(), file_data, len(lines)) mod_lines = mod_lines & m2 # only the lines that are new in both fixonly = set() |