From: Gabe Black Date: Sun, 17 Sep 2006 07:46:30 +0000 (-0400) Subject: Adding what was tracedump but is now statetrace to the tree. Let me know if statetrac... X-Git-Tag: m5_2.0_beta2~114 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b7d03951268d352254b918fbe1464954828ee8fd;p=gem5.git Adding what was tracedump but is now statetrace to the tree. Let me know if statetrace is also already taken. util/statetrace/Makefile: Makefile to build statetrace. Targets are: statetrace: alias to build using the "native" compiler statetrace-native: use the native compiler statetrace-sparc: use the sparc cross compiler I'll make this a little more fancy and capable later. util/statetrace/arch/tracechild_i386.cc: Implementation of i386 support util/statetrace/arch/tracechild_i386.hh: Declaration of i386 support util/statetrace/arch/tracechild_sparc.cc: implementation of SPARC support util/statetrace/arch/tracechild_sparc.hh: declaration of SPARC support util/statetrace/printer.cc: Implementation of the "Printer" objects which parse and output the state of the process after each instruction. There are currently two types of printers, nested ones and register ones. These are called NestingPrinter and RegPrinter respectively. util/statetrace/printer.hh: Declaration of "Printer" objects util/statetrace/refcnt.hh: This is copied from m5. I should use the one already in the tree, but I'll do that later. util/statetrace/regstate.hh: Interface for accessing registers. util/statetrace/statetrace.cc: Main file with argument parsing and the "main" function which contains the tracing loop. util/statetrace/tracechild.cc: Implementation of the base tracechild class. util/statetrace/tracechild.hh: Declaration of the base tracechild class. util/statetrace/tracechild_arch.cc: This file hooks in support for the appropriate architecture. Just the implementation is brought in, since the main program should ideally not have to know anything at all about an architecture other than it's interface. util/statetrace/x86.format: An example output template for x86. A few example SPARC templates will be added later. --HG-- extra : convert_revision : 7c8bf8230907aba42ed1e707b9ca2d6da0d4e6d4 --- diff --git a/util/statetrace/Makefile b/util/statetrace/Makefile new file mode 100644 index 000000000..c59748163 --- /dev/null +++ b/util/statetrace/Makefile @@ -0,0 +1,37 @@ +# Copyright (c) 2006 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 + +.PHONY: statetrace + +statetrace: statetrace-native + +statetrace-native: statetrace.cc tracechild.cc tracechild_arch.cc printer.cc printer.hh refcnt.hh regstate.hh tracechild.hh + g++ statetrace.cc tracechild.cc tracechild_arch.cc printer.cc -I ./ -I ./arch/ -O3 --static -o statetrace + +statetrace-sparc: statetrace.cc tracechild.cc tracechild_arch.cc printer.cc printer.hh refcnt.hh regstate.hh tracechild.hh + sparc64-unknown-linux-gnu-g++ statetrace.cc tracechild.cc tracechild_arch.cc printer.cc -I ./ -I ./arch/ -O3 --static -o statetrace diff --git a/util/statetrace/arch/tracechild_i386.cc b/util/statetrace/arch/tracechild_i386.cc new file mode 100644 index 000000000..14c22c7f0 --- /dev/null +++ b/util/statetrace/arch/tracechild_i386.cc @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include +#include +#include +#include + +#include "tracechild_i386.hh" + +using namespace std; + +char * I386TraceChild::regNames[numregs] = { + //GPRs + "eax", "ebx", "ecx", "edx", + //Index registers + "esi", "edi", + //Base pointer and stack pointer + "ebp", "esp", + //Segmentation registers + "cs", "ds", "es", "fs", "gs", "ss", + //PC + "eip"}; + +int64_t I386TraceChild::getRegs(user_regs_struct & myregs, int num) +{ + assert(num < numregs && num >= 0); + switch(num) + { + //GPRs + case EAX: return myregs.eax; + case EBX: return myregs.ebx; + case ECX: return myregs.ecx; + case EDX: return myregs.edx; + //Index registers + case ESI: return myregs.esi; + case EDI: return myregs.edi; + //Base pointer and stack pointer + case EBP: return myregs.ebp; + case ESP: return myregs.esp; + //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; + //PC + case EIP: return myregs.eip; + default: + assert(0); + return 0; + } +} + +bool I386TraceChild::update(int pid) +{ + oldregs = regs; + if(ptrace(PTRACE_GETREGS, pid, 0, ®s) != 0) + return false; + for(unsigned int x = 0; x < numregs; x++) + { + regDiffSinceUpdate[x] = + (getRegVal(x) != getOldRegVal(x)); + } +} + +I386TraceChild::I386TraceChild() +{ + for(unsigned int x = 0; x < numregs; x++) + regDiffSinceUpdate[x] = false; +} + +int64_t I386TraceChild::getRegVal(int num) +{ + return getRegs(regs, num); +} + +int64_t I386TraceChild::getOldRegVal(int num) +{ + return getRegs(oldregs, num); +} + +char * I386TraceChild::printReg(int num) +{ + sprintf(printBuffer, "0x%08X", getRegVal(num)); + return printBuffer; +} + +TraceChild * genTraceChild() +{ + return new I386TraceChild; +} diff --git a/util/statetrace/arch/tracechild_i386.hh b/util/statetrace/arch/tracechild_i386.hh new file mode 100644 index 000000000..f8c68c770 --- /dev/null +++ b/util/statetrace/arch/tracechild_i386.hh @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2006 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_I386_HH +#define REGSTATE_I386_HH + +#include +#include +#include +#include +#include + +#include "tracechild.hh" + +class I386TraceChild : public TraceChild +{ +public: + enum RegNum + { + //GPRs + EAX, EBX, ECX, EDX, + //Index registers + ESI, EDI, + //Base pointer and stack pointer + EBP, ESP, + //Segmentation registers + CS, DS, ES, FS, GS, SS, + //PC + EIP, + numregs + }; +private: + char printBuffer [256]; + static char * regNames[numregs]; + int64_t getRegs(user_regs_struct & myregs, int num); + user_regs_struct regs; + user_regs_struct oldregs; + bool regDiffSinceUpdate[numregs]; + +protected: + bool update(int pid); + +public: + + I386TraceChild(); + + 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(EIP);} + uint64_t getSP() {return getRegVal(ESP);} + std::ostream & outputStartState(std::ostream & output) + { + output << "Printing i386 initial state not yet implemented" + << std::endl; + return output; + } + + char * printReg(int num); +}; + +#endif diff --git a/util/statetrace/arch/tracechild_sparc.cc b/util/statetrace/arch/tracechild_sparc.cc new file mode 100644 index 000000000..378de0865 --- /dev/null +++ b/util/statetrace/arch/tracechild_sparc.cc @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include +#include +#include +#include + +#include "tracechild_sparc.hh" + +using namespace std; + +string SparcTraceChild::regNames[numregs] = { + //Global registers + "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", + //Output registers + "o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7", + //Local registers + "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", + //Input registers + "i0", "i1", "i2", "i3", "i4", "i5", "i6", "i7", + //Floating point + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", + //Miscelaneous + "fsr", "fprs", "pc", "npc", "y", "cwp", "pstate", "asi", "ccr"}; + +int64_t getRegs(regs & myregs, fpu & myfpu, + int64_t * locals, int64_t * inputs, int num) +{ + assert(num < SparcTraceChild::numregs && num >= 0); + switch(num) + { + //Global registers + case SparcTraceChild::G0: return 0; + case SparcTraceChild::G1: return myregs.r_g1; + case SparcTraceChild::G2: return myregs.r_g2; + case SparcTraceChild::G3: return myregs.r_g3; + case SparcTraceChild::G4: return myregs.r_g4; + case SparcTraceChild::G5: return myregs.r_g5; + case SparcTraceChild::G6: return myregs.r_g6; + case SparcTraceChild::G7: return myregs.r_g7; + //Output registers + case SparcTraceChild::O0: return myregs.r_o0; + case SparcTraceChild::O1: return myregs.r_o1; + case SparcTraceChild::O2: return myregs.r_o2; + case SparcTraceChild::O3: return myregs.r_o3; + case SparcTraceChild::O4: return myregs.r_o4; + case SparcTraceChild::O5: return myregs.r_o5; + case SparcTraceChild::O6: return myregs.r_o6; + case SparcTraceChild::O7: return myregs.r_o7; + //Local registers + case SparcTraceChild::L0: return locals[0]; + case SparcTraceChild::L1: return locals[1]; + case SparcTraceChild::L2: return locals[2]; + case SparcTraceChild::L3: return locals[3]; + case SparcTraceChild::L4: return locals[4]; + case SparcTraceChild::L5: return locals[5]; + case SparcTraceChild::L6: return locals[6]; + case SparcTraceChild::L7: return locals[7]; + //Input registers + case SparcTraceChild::I0: return inputs[0]; + case SparcTraceChild::I1: return inputs[1]; + case SparcTraceChild::I2: return inputs[2]; + case SparcTraceChild::I3: return inputs[3]; + case SparcTraceChild::I4: return inputs[4]; + case SparcTraceChild::I5: return inputs[5]; + case SparcTraceChild::I6: return inputs[6]; + case SparcTraceChild::I7: return inputs[7]; + //Floating point + case SparcTraceChild::F0: return myfpu.f_fpstatus.fpu_fr[0]; + case SparcTraceChild::F1: return myfpu.f_fpstatus.fpu_fr[1]; + case SparcTraceChild::F2: return myfpu.f_fpstatus.fpu_fr[2]; + case SparcTraceChild::F3: return myfpu.f_fpstatus.fpu_fr[3]; + case SparcTraceChild::F4: return myfpu.f_fpstatus.fpu_fr[4]; + case SparcTraceChild::F5: return myfpu.f_fpstatus.fpu_fr[5]; + case SparcTraceChild::F6: return myfpu.f_fpstatus.fpu_fr[6]; + case SparcTraceChild::F7: return myfpu.f_fpstatus.fpu_fr[7]; + case SparcTraceChild::F8: return myfpu.f_fpstatus.fpu_fr[8]; + case SparcTraceChild::F9: return myfpu.f_fpstatus.fpu_fr[9]; + case SparcTraceChild::F10: return myfpu.f_fpstatus.fpu_fr[10]; + case SparcTraceChild::F11: return myfpu.f_fpstatus.fpu_fr[11]; + case SparcTraceChild::F12: return myfpu.f_fpstatus.fpu_fr[12]; + case SparcTraceChild::F13: return myfpu.f_fpstatus.fpu_fr[13]; + case SparcTraceChild::F14: return myfpu.f_fpstatus.fpu_fr[14]; + case SparcTraceChild::F15: return myfpu.f_fpstatus.fpu_fr[15]; + case SparcTraceChild::F16: return myfpu.f_fpstatus.fpu_fr[16]; + case SparcTraceChild::F17: return myfpu.f_fpstatus.fpu_fr[17]; + case SparcTraceChild::F18: return myfpu.f_fpstatus.fpu_fr[18]; + case SparcTraceChild::F19: return myfpu.f_fpstatus.fpu_fr[19]; + case SparcTraceChild::F20: return myfpu.f_fpstatus.fpu_fr[20]; + case SparcTraceChild::F21: return myfpu.f_fpstatus.fpu_fr[21]; + case SparcTraceChild::F22: return myfpu.f_fpstatus.fpu_fr[22]; + case SparcTraceChild::F23: return myfpu.f_fpstatus.fpu_fr[23]; + case SparcTraceChild::F24: return myfpu.f_fpstatus.fpu_fr[24]; + case SparcTraceChild::F25: return myfpu.f_fpstatus.fpu_fr[25]; + case SparcTraceChild::F26: return myfpu.f_fpstatus.fpu_fr[26]; + case SparcTraceChild::F27: return myfpu.f_fpstatus.fpu_fr[27]; + case SparcTraceChild::F28: return myfpu.f_fpstatus.fpu_fr[28]; + case SparcTraceChild::F29: return myfpu.f_fpstatus.fpu_fr[29]; + case SparcTraceChild::F30: return myfpu.f_fpstatus.fpu_fr[30]; + case SparcTraceChild::F31: return myfpu.f_fpstatus.fpu_fr[31]; + //Miscelaneous + case SparcTraceChild::FSR: return myfpu.f_fpstatus.Fpu_fsr; + case SparcTraceChild::FPRS: return myregs.r_fprs; + case SparcTraceChild::PC: return myregs.r_tpc; + case SparcTraceChild::NPC: return myregs.r_tnpc; + case SparcTraceChild::Y: return myregs.r_y; + case SparcTraceChild::CWP: + return (myregs.r_tstate >> 0) & ((1 << 5) - 1); + case SparcTraceChild::PSTATE: + return (myregs.r_tstate >> 8) & ((1 << 13) - 1); + case SparcTraceChild::ASI: + return (myregs.r_tstate >> 24) & ((1 << 8) - 1); + case SparcTraceChild::CCR: + return (myregs.r_tstate >> 32) & ((1 << 8) - 1); + default: + assert(0); + return 0; + } +} + +bool SparcTraceChild::update(int pid) +{ + static const int stackBias = 2047; + memcpy(&oldregs, &theregs, sizeof(regs)); + memcpy(&oldfpregs, &thefpregs, sizeof(fpu)); + memcpy(oldLocals, locals, 8 * sizeof(uint64_t)); + memcpy(oldInputs, inputs, 8 * sizeof(uint64_t)); + if(ptrace(PTRACE_GETREGS, pid, &theregs, 0) != 0) + { + cerr << "Update failed" << endl; + return false; + } + uint64_t StackPointer = getRegVal(O6); + for(unsigned int x = 0; x < 8; x++) + { + locals[x] = ptrace(PTRACE_PEEKTEXT, pid, + StackPointer + stackBias + x * 8, 0); + inputs[x] = ptrace(PTRACE_PEEKTEXT, pid, + StackPointer + stackBias + x * 8 + (8 * 8), 0); + } + if(ptrace(PTRACE_GETFPREGS, pid, &thefpregs, 0) != 0) + return false; + for(unsigned int x = 0; x < numregs; x++) + regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x)); + return true; +} + +SparcTraceChild::SparcTraceChild() +{ + for(unsigned int x = 0; x < numregs; x++) + regDiffSinceUpdate[x] = false; +} + +bool SparcTraceChild::step() +{ + //Two important considerations are that the address of the instruction + //being breakpointed should be word (64bit) aligned, and that both the + //next instruction and the instruction after that need to be breakpointed + //so that annulled branches will still stop as well. + const static uint64_t breakInst = 0x91d02001; + const static uint64_t breakWord = breakInst | (breakInst << 32); + const static uint64_t lowMask = (uint64_t)(0xFFFFFFFF); + const static uint64_t highMask = lowMask << 32; + uint64_t originalInst, originalAnnulInst; + uint64_t nextPC = getRegVal(NPC); + bool unaligned = nextPC & 7; + uint64_t alignedPC = nextPC & (~7); + originalInst = ptrace(PTRACE_PEEKTEXT, pid, alignedPC, 0); + if(unaligned) + { + originalAnnulInst = ptrace(PTRACE_PEEKTEXT, pid, alignedPC+8, 0); + } + uint64_t newInst; + if(unaligned) + { + newInst = (originalInst & highMask) | (breakInst << 0); + if(ptrace(PTRACE_POKETEXT, pid, alignedPC, newInst) != 0) + cerr << "Poke failed" << endl; + newInst = (originalAnnulInst & lowMask) | (breakInst << 32); + if(ptrace(PTRACE_POKETEXT, pid, alignedPC+8, newInst) != 0) + cerr << "Poke failed" << endl; + } + else + { + if(ptrace(PTRACE_POKETEXT, pid, alignedPC, breakWord) != 0) + cerr << "Poke failed" << endl; + } + //Note that the "addr" parameter is supposed to be ignored, but in at + //least one version of the kernel, it must be 1 or it will set what + //pc to continue from + if(ptrace(PTRACE_CONT, pid, /*nextPC - 4*/ 1, 0) != 0) + cerr << "Cont failed" << endl; + doWait(); + update(pid); + if(ptrace(PTRACE_POKETEXT, pid, alignedPC, originalInst) != 0) + cerr << "Repoke failed" << endl; + if(unaligned) + { + if(ptrace(PTRACE_POKETEXT, pid, alignedPC+8, originalAnnulInst) != 0) + cerr << "Repoke failed" << endl; + } + return true; +} + +int64_t SparcTraceChild::getRegVal(int num) +{ + return getRegs(theregs, thefpregs, locals, inputs, num); +} + +int64_t SparcTraceChild::getOldRegVal(int num) +{ + return getRegs(oldregs, oldfpregs, oldLocals, oldInputs, num); +} + +char * SparcTraceChild::printReg(int num) +{ + sprintf(printBuffer, "0x%016llx", getRegVal(num)); + return printBuffer; +} + +ostream & SparcTraceChild::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; + //Take out the stack bias + sp += 2047; + //Output the window save area + for(unsigned int x = 0; x < 16; x++) + { + uint64_t regspot = ptrace(PTRACE_PEEKDATA, pid, sp, 0); + sprintf(obuf, "0x%016llx: Window save %d = 0x%016llx\n", + sp, x+1, regspot); + os << obuf; + sp += 8; + } + //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; +} + +TraceChild * genTraceChild() +{ + return new SparcTraceChild; +} + diff --git a/util/statetrace/arch/tracechild_sparc.hh b/util/statetrace/arch/tracechild_sparc.hh new file mode 100644 index 000000000..d177d5941 --- /dev/null +++ b/util/statetrace/arch/tracechild_sparc.hh @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2006 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 TRACECHILD_SPARC_HH +#define TRACECHILD_SPARC_HH + +#include +#include +#include +#include +#include +#include +#include + +#include "tracechild.hh" + +struct regs; + +class SparcTraceChild : public TraceChild +{ +public: + enum RegNum + { + //Global registers + G0, G1, G2, G3, G4, G5, G6, G7, + //Output registers + O0, O1, O2, O3, O4, O5, O6, O7, + //Local registers + L0, L1, L2, L3, L4, L5, L6, L7, + //Input registers + I0, I1, I2, I3, I4, I5, I6, I7, + //Floating point + F0, F1, F2, F3, F4, F5, F6, F7, + F8, F9, F10, F11, F12, F13, F14, F15, + F16, F17, F18, F19, F20, F21, F22, F23, + F24, F25, F26, F27, F28, F29, F30, F31, + //Miscelaneous + FSR, FPRS, PC, NPC, Y, CWP, PSTATE, ASI, CCR, + numregs + }; +private: + char printBuffer[256]; + static std::string regNames[numregs]; + regs theregs; + regs oldregs; + fpu thefpregs; + fpu oldfpregs; + int64_t locals[8]; + int64_t oldLocals[8]; + int64_t inputs[8]; + int64_t oldInputs[8]; + bool regDiffSinceUpdate[numregs]; + +protected: + bool update(int pid); + +public: + SparcTraceChild(); + + 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); + + bool step(); + + uint64_t getPC() + { + return getRegVal(PC); + } + + uint64_t getSP() + { + return getRegVal(O6); + } + + char * printReg(int num); + + std::ostream & outputStartState(std::ostream & os); +}; + +#endif diff --git a/util/statetrace/printer.cc b/util/statetrace/printer.cc new file mode 100644 index 000000000..b14671f2c --- /dev/null +++ b/util/statetrace/printer.cc @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2006 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 "tracechild.hh" +#include "printer.hh" + +using namespace std; + +//Types of printers. If none is found, or there is an error in the input, +//there are psuedo types to return. +enum PrinterType {PRINTER_NONE, PRINTER_ERROR, PRINTER_NESTING, PRINTER_REG}; + +int findEndOfRegPrinter(string, int); +int findEndOfNestingPrinter(string, int); +PrinterType findSub(string, int &, int &); + +//This is pretty easy. Just find the closing parenthesis. +int findEndOfRegPrinter(string config, int startPos) +{ + int pos = config.find(")", startPos); + if(pos == string::npos) + { + cerr << "Couldn't find the closing parenthesis for a reg printer" << endl; + return 0; + } + return pos; +} + +//This is a little harder. We need to make sure we don't +//grab an ending parenthesis that belongs to the nesting printer. +int findEndOfNestingPrinter(string config, int startPos) +{ + int length = config.length(); + int pos = startPos; + int endPos = length; + int parenPos = config.find(")", pos); + //If we didn't find an ending parenthesis at all, we're in trouble + if(parenPos == string::npos) + { + cerr << "Couldn't find the closing parenthesis for a nesting printer on the first try" << endl; + return 0; + } + //Keep pulling out embedded stuff until we can't any more + //we need to make sure we aren't skipping over the parenthesis + //that ends -this- printer. + PrinterType type = findSub(config, pos, endPos); + if(type == PRINTER_ERROR) + return 0; + while(type != PRINTER_NONE && endPos >= parenPos) + { + //Find the next closest ending parenthesis since we passed + //up the last one + parenPos = config.find(")", endPos + 1); + //If we didn't find one, we're in trouble + if(parenPos == string::npos) + { + cerr << "Couldn't find the closing parenthesis for a nested printer on later tries" << endl; + return 0; + } + //Start looking for the end of this printer and embedded + //stuff past the one we just found + pos = endPos + 1; + //Reset endPos so we search to the end of config + endPos = length; + type = findSub(config, pos, endPos); + if(type == PRINTER_ERROR) + return 0; + } + //We ran out of embedded items, and we didn't pass up our last + //closing paren. This must be the end of this printer. + return parenPos; +} + +//Find a sub printer. This looks for things which have a type defining +//character and then an opening parenthesis. The type is returned, and +//startPos and endPos are set to the beginning and end of the sub printer +//On entry, the search starts at index startPos and ends at either index +//endPos or a closing parenthesis, whichever comes first +PrinterType findSub(string config, int & startPos, int & endPos) +{ + int length = config.length(); + //Figure out where the different types of sub printers may start + int regPos = config.find("%(", startPos); + int nestingPos = config.find("~(", startPos); + //If a type of printer wasn't found, say it was found too far away. + //This simplifies things later + if(regPos == string::npos) + regPos = endPos; + if(nestingPos == string::npos) + nestingPos = endPos; + //If we find a closing paren, that marks the + //end of the region we're searching. + int closingPos = config.find(")", startPos); + if(closingPos != string::npos && + closingPos < regPos && + closingPos < nestingPos) + return PRINTER_NONE; + //If we didn't find anything close enough, say so. + if(regPos >= endPos && nestingPos >= endPos) + return PRINTER_NONE; + //At this point, we know that one of the options starts legally + //We need to find which one is first and return that + if(regPos < nestingPos) + { + int regEnd = findEndOfRegPrinter(config, regPos + 2); + //If we couldn't find the end... + if(!regEnd) + { + cerr << "Couldn't find the end of the reg printer" << endl; + return PRINTER_ERROR; + } + //Report the sub printer's vitals. + startPos = regPos; + endPos = regEnd; + return PRINTER_REG; + } + else + { + int nestingEnd = findEndOfNestingPrinter(config, nestingPos + 2); + //If we couldn't find the end... + if(!nestingEnd) + { + cerr << "Couldn't find the end of the nesting printer" << endl; + return PRINTER_ERROR; + } + //Report the sub printer's vitals. + startPos = nestingPos; + endPos = nestingEnd; + return PRINTER_NESTING; + } + return PRINTER_NONE; +} + +//Set up a nesting printer. This printer can contain sub printers +bool NestingPrinter::configure(string config) +{ + //Clear out any old stuff + constStrings.clear(); + numPrinters = 0; + printers.clear(); + int length = config.length(); + int startPos = 0, endPos = length; + int lastEndPos = -1; + //Try to find a sub printer + PrinterType type = findSub(config, startPos, endPos); + if(type == PRINTER_ERROR) + { + cerr << "Problem finding first sub printer" << endl; + return false; + } + while(type != PRINTER_NONE) + { + string prefix = config.substr(lastEndPos + 1, startPos - lastEndPos - 1); + lastEndPos = endPos; + constStrings.push_back(prefix); + string subConfig, subString; + int commaPos, lastCommaPos, childSwitchVar; + switch(type) + { + //If we found a plain register printer + case PRINTER_REG: + 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; + cerr << "Error configuring reg printer" << endl; + return false; + } + printers.push_back(regPrinter); + break; + //If we found an embedded nesting printer + 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(","); + if(commaPos == string::npos) + return false; + childSwitchVar = child->getRegNum(subConfig.substr(0, commaPos)); + if(childSwitchVar == -1) + { + cerr << "Couldn't configure switching variable!" << endl; + return false; + } + //Eat up remaining arguments + while(commaPos != string::npos) + { + lastCommaPos = commaPos; + commaPos = subConfig.find(",", commaPos + 1); + } + if(lastCommaPos != string::npos) + { + subConfig = subConfig.substr(lastCommaPos + 1, subConfig.length() - lastCommaPos - 1); + } + if(!nestingPrinter->configure(subConfig)) + { + delete nestingPrinter; + cerr << "Error configuring nesting printer" << endl; + return false; + } + nestingPrinter->switchVar = childSwitchVar; + printers.push_back(nestingPrinter); + break; + default: + cerr << "Unrecognized printer type" << endl; + return false; + } + //Move down past what we just parsed + startPos = endPos + 1; + endPos = length; + type = findSub(config, startPos, endPos); + if(type == PRINTER_ERROR) + { + cerr << "Unable to find subprinters on later tries" << endl; + return false; + } + } + //Put in the trailing stuff + string trailer = config.substr(startPos, length - startPos); + constStrings.push_back(trailer); + return true; +} + +bool RegPrinter::configure(string config) +{ + //Figure out what our register number is based on the name we're given + int num = child->getRegNum(config); + if(num == -1) + { + cerr << "Couldn't find register " << config << endl; + return false; + } + regNum(num); + return true; +} + +ostream & NestingPrinter::writeOut(ostream & os) +{ + if(switchVar == -1 || child->diffSinceUpdate(switchVar)) + { + int x; + for(x = 0; x < numPrinters; x++) + { + os << constStrings[x]; + os << printers[x]; + } + os << constStrings[x]; + } + return os; +} + +ostream & RegPrinter::writeOut(ostream & os) +{ + os << child->printReg(intRegNum); + return os; +} + diff --git a/util/statetrace/printer.hh b/util/statetrace/printer.hh new file mode 100644 index 000000000..db3b8c1b8 --- /dev/null +++ b/util/statetrace/printer.hh @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2006 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 PRINTER_HH +#define PRINTER_HH + +#include +#include +#include + +#include "refcnt.hh" + +class TraceChild; +class PrinterObject; + +typedef RefCountingPtr PrinterPointer; + +class PrinterObject : public RefCounted +{ + protected: + TraceChild * child; + public: + PrinterObject(TraceChild * newChild) : child(newChild) + {;} + virtual std::ostream & writeOut(std::ostream & os) = 0; + virtual bool configure(std::string) = 0; +}; + +class NestingPrinter : public PrinterObject +{ + private: + std::vector constStrings; + std::vector printers; + int switchVar; + int numPrinters; + public: + NestingPrinter(TraceChild * newChild) : + PrinterObject(newChild), numPrinters(0), switchVar(-1) + {;} + + bool configure(std::string); + + std::ostream & writeOut(std::ostream & os); +}; + +class RegPrinter : public PrinterObject +{ + private: + int intRegNum; + public: + RegPrinter(TraceChild * newChild, int num = 0) : + PrinterObject(newChild), intRegNum(num) + {;} + + void regNum(int num) + { + intRegNum = num; + } + + int regNum() + { + return intRegNum; + } + + bool configure(std::string); + + std::ostream & writeOut(std::ostream & os); +}; + +static inline std::ostream & operator << (std::ostream & os, + PrinterObject & printer) +{ + return printer.writeOut(os); +} + +static inline std::ostream & operator << (std::ostream & os, + PrinterPointer & printer) +{ + return printer->writeOut(os); +} + +#endif diff --git a/util/statetrace/refcnt.hh b/util/statetrace/refcnt.hh new file mode 100644 index 000000000..6672d4a5f --- /dev/null +++ b/util/statetrace/refcnt.hh @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2002-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: Nathan Binkert + */ + +#ifndef __REFCNT_HH__ +#define __REFCNT_HH__ + +#include //For the NULL macro definition + +class RefCounted +{ + private: + int count; + + private: + RefCounted(const RefCounted &); + + public: + RefCounted() : count(0) {} + virtual ~RefCounted() {} + + void incref() { ++count; } + void decref() { if (--count <= 0) delete this; } +}; + +template +class RefCountingPtr +{ + protected: + T *data; + + void copy(T *d) + { + data = d; + if (data) + data->incref(); + } + void del() + { + if (data) + data->decref(); + } + void set(T *d) + { + if (data == d) + return; + + del(); + copy(d); + } + + + public: + RefCountingPtr() : data(NULL) {} + RefCountingPtr(T *data) { copy(data); } + RefCountingPtr(const RefCountingPtr &r) { copy(r.data); } + ~RefCountingPtr() { del(); } + + T *operator->() { return data; } + T &operator*() { return *data; } + T *get() { return data; } + + const T *operator->() const { return data; } + const T &operator*() const { return *data; } + const T *get() const { return data; } + + RefCountingPtr &operator=(T *p) { set(p); return *this; } + RefCountingPtr &operator=(const RefCountingPtr &r) + { return operator=(r.data); } + + bool operator!() const { return data == 0; } + operator bool() const { return data != 0; } +}; + +template +bool operator==(const RefCountingPtr &l, const RefCountingPtr &r) +{ return l.get() == r.get(); } + +template +bool operator==(const RefCountingPtr &l, const T *r) +{ return l.get() == r; } + +template +bool operator==(const T &l, const RefCountingPtr &r) +{ return l == r.get(); } + +template +bool operator!=(const RefCountingPtr &l, const RefCountingPtr &r) +{ return l.get() != r.get(); } + +template +bool operator!=(const RefCountingPtr &l, const T *r) +{ return l.get() != r; } + +template +bool operator!=(const T &l, const RefCountingPtr &r) +{ return l != r.get(); } + +#endif // __REFCNT_HH__ diff --git a/util/statetrace/regstate.hh b/util/statetrace/regstate.hh new file mode 100644 index 000000000..e97d535a3 --- /dev/null +++ b/util/statetrace/regstate.hh @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2006 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_H +#define REGSTATE_H + +#include +#include + +class RegState +{ +protected: + virtual bool update(int pid) = 0; +public: + virtual int getNumRegs() = 0; + virtual bool diffSinceUpdate(int num) = 0; + virtual std::string getRegName(int num) = 0; + virtual int getRegNum(std::string name) + { + int numregs = getNumRegs(); + for(unsigned int x = 0; x < numregs; x++) + if(getRegName(x) == name) + return x; + return -1; + } + virtual int64_t getRegVal(int num) = 0; + virtual int64_t getOldRegVal(int num) = 0; + virtual char * printReg(int num) = 0; +}; + +#endif diff --git a/util/statetrace/statetrace.cc b/util/statetrace/statetrace.cc new file mode 100644 index 000000000..78fdf9393 --- /dev/null +++ b/util/statetrace/statetrace.cc @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "tracechild.hh" +#include "printer.hh" + +using namespace std; + +void printUsage(const char * execName) +{ + cout << execName << " -f | -h | -r -- " << endl; +} + +int main(int argc, char * argv[], char * envp[]) +{ + TraceChild * child = genTraceChild(); + NestingPrinter printer(child); + string args; + int startProgramArgs; + + //Parse the command line arguments + bool formatStringSet = false; + bool printInitial = false; + bool printTrace = true; + string format; + for(int x = 1; x < argc; x++) + { + if(!strcmp(argv[x], "-f")) + { + if(formatStringSet) + { + cerr << "Attempted to set format twice!" + << endl; + printUsage(argv[0]); + return 1; + } + formatStringSet = true; + x++; + if(x >= argc) + { + cerr << "Incorrect usage.\n" << endl; + printUsage(argv[0]); + return 1; + } + ifstream formatFile(argv[x]); + if(!formatFile) + { + cerr << "Problem opening file " + << argv[x] << "." << endl; + return 1; + } + format = ""; + while(formatFile) + { + string line; + getline(formatFile, line); + if(formatFile.eof()) + { + format += line; + break; + } + if(!formatFile) + { + cerr << "Problem reading from file " + << argv[x] << "." << endl; + return 1; + } + format += line + '\n'; + } + } + else 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; + } + } + for(unsigned int x = startProgramArgs; x < argc; x++) + args += argv[x]; + if(!child->startTracing(argv[startProgramArgs], args.c_str())) + { + cerr << "Couldn't start target program" << endl; + return 1; + } + if(printInitial) + { + child->outputStartState(cout); + } + if(printTrace) + { + if(!formatStringSet) + { + cerr << "No output format set!" << endl; + child->stopTracing(); + printUsage(argv[0]); + return 1; + } + if(!printer.configure(format)) + { + cerr << "Problem in the output format" << endl; + child->stopTracing(); + return 1; + } + child->step(); + while(child->isTracing()) + { + cout << printer; + child->step(); + } + cout << printer; + } + if(!child->stopTracing()) + { + cerr << "Couldn't stop child" << endl; + return 1; + } + return 0; +} + diff --git a/util/statetrace/tracechild.cc b/util/statetrace/tracechild.cc new file mode 100644 index 000000000..292c45658 --- /dev/null +++ b/util/statetrace/tracechild.cc @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2006 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 "tracechild.hh" +#include +#include +#include +#include + +using namespace std; + +bool TraceChild::startTracing(const char * pathToFile, const char * arg) +{ + pid = fork(); + if(pid == -1) + { + cout << "fork failed" << endl; + return false; + } + else if(pid == 0) + { + //We're the child. Get things ready and then exec the + //program to trace. + + //Let our parent trace us + ptrace(PTRACE_TRACEME, 0, 0, 0); + + //Start the program to trace + execl(pathToFile, arg); + + //We should never get here, so this is an error! + return false; + } + + //From this point forward, we know we're in the parent process. + if(!doWait()) + { + cout << "Didn't wait successfully" << endl; + return false; + } + tracing = true; + if(!update(pid)) + { + cout << "Didn't update successfully!" << endl; + return false; + } + return true; +} + +bool TraceChild::stopTracing() +{ + if(ptrace(PTRACE_KILL, pid, 0, 0) != 0) + return false; + tracing = false; + return true; +} + +bool TraceChild::step() +{ + ptraceSingleStep(); +} + +bool TraceChild::ptraceSingleStep() +{ + if(!tracing) + { + cout << "Not tracing!" << endl; + return false; + } + if(ptrace(PTRACE_SINGLESTEP, pid, 0, 0) != 0) + { + switch(errno) + { + case EBUSY: cout << "EBUSY" << endl; break; + case EFAULT: cout << "EFAULT" << endl; break; + case EIO: cout << "EIO" << endl; break; + case EPERM: cout << "EPERM" << endl; break; + case ESRCH: cout << "ESRCH" << endl; break; + default: cout << "Unknown error" << endl; break; + } + cout << "Not able to single step!" << endl; + tracing == false; + return false; + } + doWait(); + update(pid); +} + +bool TraceChild::doWait() +{ + int wait_val; + wait(&wait_val); + if(WIFEXITED(wait_val)) + { + cerr << "Program exited! Exit status is " + << WEXITSTATUS(wait_val) << endl; + tracing = false; + return false; + } + if(WIFSIGNALED(wait_val)) + { + if(WTERMSIG(wait_val)) + cerr << "Program terminated by signal " + << WTERMSIG(wait_val) << endl; + if(WCOREDUMP(wait_val)) + cerr << "Program core dumped!" << endl; + tracing = false; + return false; + } + if(WIFSTOPPED(wait_val) && WSTOPSIG(wait_val) != SIGTRAP) + { + cerr << "Program stopped by signal " + << WSTOPSIG(wait_val) << endl; + tracing = false; + return false; + } + return true; +} diff --git a/util/statetrace/tracechild.hh b/util/statetrace/tracechild.hh new file mode 100644 index 000000000..f9c23b781 --- /dev/null +++ b/util/statetrace/tracechild.hh @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2006 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 TRACECHILD_HH +#define TRACECHILD_HH + +#include "regstate.hh" + +class TraceChild : public RegState +{ +protected: + int pid; + bool tracing; +public: + TraceChild() : tracing(false) + {;} + virtual bool startTracing(const char * pathToFile, const char * arg); + virtual bool stopTracing(); + virtual bool step(); + virtual uint64_t getPC() = 0; + virtual uint64_t getSP() = 0; + virtual std::ostream & outputStartState(std::ostream & os) = 0; + int getPid() + { + return pid; + } + bool isTracing() + { + return tracing; + } +protected: + bool ptraceSingleStep(); + bool doWait(); +}; + +TraceChild * genTraceChild(); + +#endif diff --git a/util/statetrace/tracechild_arch.cc b/util/statetrace/tracechild_arch.cc new file mode 100644 index 000000000..603ccb12c --- /dev/null +++ b/util/statetrace/tracechild_arch.cc @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2006 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 + */ + +#if defined __alpha__ + #error "Alpha architecture not implemented" +#elif defined __amd64__ + #error "AMD64 architecture not implemented" +#elif defined __hppa__ + #error "Hppa architecture not implemented" +#elif defined __i386__ || defined __i486__ || \ + defined __i586__ || defined __i686 + #include "arch/tracechild_i386.cc" +#elif defined __ia64__ + #error "IA64 architecture not implemented" +#elif defined __mips__ + #error "Mips architecture not implemented" +#elif defined __powerpc__ + #error "PowerPC architecture not implemented" +#elif defined __sparc__ + #include "arch/tracechild_sparc.cc" +#elif defined __sh__ + #include "SuperH architecture not implemented" +#elif defined __s390__ + #include "System/390 architecture not implemented" +#else + #error "Couldn't determine architecture" +#endif diff --git a/util/statetrace/x86.format b/util/statetrace/x86.format new file mode 100644 index 000000000..03035ee29 --- /dev/null +++ b/util/statetrace/x86.format @@ -0,0 +1,6 @@ +###################### +EIP = %(eip) +EAX = %(eax), EBX = %(ebx), ECX = %(ecx), EDX = %(edx) +EDI = %(edi), ESI = %(esi) +EBP = %(ebp), ESP = %(esp) +CS = %(cs), DS = %(ds), ES = %(es), FS = %(fs), GS = %(gs), SS = %(ss)