diff options
Diffstat (limited to 'util')
35 files changed, 1927 insertions, 252 deletions
diff --git a/util/ccdrv/devtime.c b/util/ccdrv/devtime.c index 62b0e2592..d8be97bb4 100644 --- a/util/ccdrv/devtime.c +++ b/util/ccdrv/devtime.c @@ -24,6 +24,8 @@ * 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: Ali Saidi */ #include <linux/module.h> diff --git a/util/cscope-find.py b/util/cscope-find.py new file mode 100755 index 000000000..1775f1864 --- /dev/null +++ b/util/cscope-find.py @@ -0,0 +1,38 @@ +#! /usr/bin/python + +# Generate list of files to index with cscope. + +# From the m5 directory, run: +# util/cscope-find.py > cscope.files +# cscope -b + +import os + +# absolute paths to skip +skipdirs = [ 'src/unittest', 'src/doxygen' ] + +# suffixes of files to index +suffixes = [ '.cc', '.hh', '.c', '.h' ] + +def oksuffix(f): + for s in suffixes: + if f.endswith(s): + return True + return False + +for dirpath,subdirs,files in os.walk('src'): + # filter out undesirable subdirectories + for i,dir in enumerate(subdirs): + if dir == 'SCCS': + del subdirs[i] + break + + # filter out undesriable absolute paths + if dirpath in skipdirs: + del subdirs[:] + continue + + # find C/C++ sources + okfiles = [f for f in files if oksuffix(f)] + if okfiles: + print '\n'.join([os.path.join(dirpath, f) for f in okfiles]) diff --git a/util/m5/Makefile b/util/m5/Makefile index 518542322..a98092e47 100644 --- a/util/m5/Makefile +++ b/util/m5/Makefile @@ -23,6 +23,9 @@ # 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 +# Ali Saidi ### If we are not compiling on an alpha, we must use cross tools ### ifneq ($(shell uname -m), alpha) diff --git a/util/m5/m5.c b/util/m5/m5.c index fa9be96e8..23401aea5 100644 --- a/util/m5/m5.c +++ b/util/m5/m5.c @@ -24,6 +24,8 @@ * 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 */ #include <inttypes.h> @@ -48,6 +50,7 @@ usage() " m5 dumpstats [delay [period]]\n" " m5 dumpresetstats [delay [period]]\n" " m5 checkpoint [delay [period]]\n" + " m5 readfile\n" "\n" "All times in nanoseconds!\n"); exit(1); @@ -202,6 +205,20 @@ main(int argc, char *argv[]) if (COMPARE("loadsymbol")) { m5_loadsymbol(arg1); return 0; + if (COMPARE("readfile")) { + char buf[256*1024]; + int offset = 0; + int len; + + if (argc != 2) + usage(); + + while ((len = m5_readfile(buf, sizeof(buf), offset)) > 0) { + write(STDOUT_FILENO, buf, len); + offset += len; + } + + return 0; } usage(); diff --git a/util/m5/m5op.S b/util/m5/m5op.S index 97eb9238d..a19113e62 100644 --- a/util/m5/m5op.S +++ b/util/m5/m5op.S @@ -24,6 +24,9 @@ * 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 + * Ali Saidi */ #define m5_op 0x01 @@ -48,6 +51,8 @@ #define switchcpu_func 0x52 #define addsymbol_func 0x53 #define panic_func 0x54 +#define anbegin_func 0x55 +#define anwait_func 0x56 #define INST(op, ra, rb, func) \ .long (((op) << 26) | ((ra) << 21) | ((rb) << 16) | (func)) @@ -83,6 +88,8 @@ func: #define SWITCHCPU INST(m5_op, 0, 0, switchcpu_func) #define ADDSYMBOL(r1,r2) INST(m5_op, r1, r2, addsymbol_func) #define PANIC INST(m5_op, 0, 0, panic_func) +#define AN_BEGIN(r1) INST(m5_op, r1, 0, anbegin_func) +#define AN_WAIT(r1,r2) INST(m5_op, r1, r2, anwait_func) .set noreorder @@ -202,3 +209,17 @@ LEAF(m5_panic) END(m5_panic) + .align 4 +LEAF(m5_anbegin) + AN_BEGIN(16) + RET +END(m5_anbegin) + + + .align 4 +LEAF(m5_anwait) + AN_WAIT(16,17) + RET +END(m5_anwait) + + diff --git a/util/m5/m5op.h b/util/m5/m5op.h index 34ac7760d..eab4e7fd5 100644 --- a/util/m5/m5op.h +++ b/util/m5/m5op.h @@ -24,6 +24,9 @@ * 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 + * Ali Saidi */ #ifndef __M5OP_H__ @@ -50,5 +53,7 @@ void m5_debugbreak(void); void m5_switchcpu(void); void m5_addsymbol(uint64_t addr, char *symbol); void m5_panic(void); +void m5_anbegin(uint64_t s); +void m5_anwait(uint64_t s, uint64_t w); #endif // __M5OP_H__ diff --git a/util/oprofile-top.py b/util/oprofile-top.py index c6e35344c..aea9dfadd 100755 --- a/util/oprofile-top.py +++ b/util/oprofile-top.py @@ -25,6 +25,9 @@ # 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: Ali Saidi +# Nathan Binkert # Parse sampled function profile output (quick hack). @@ -25,6 +25,8 @@ # 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 import sys import os @@ -179,10 +181,10 @@ try: if output_dir: secs_waited = 0 - while not shell.dir_exists(output_dir) and secs_waited < 45: + while not shell.dir_exists(output_dir) and secs_waited < 90: time.sleep(5) secs_waited += 5 - if secs_waited > 10: + if secs_waited > 30: print "waited", secs_waited, "seconds for", output_dir # run command diff --git a/util/regress b/util/regress index 067f9f092..8e60b6fee 100755 --- a/util/regress +++ b/util/regress @@ -1,5 +1,5 @@ #! /usr/bin/env python -# Copyright (c) 2005 The Regents of The University of Michigan +# Copyright (c) 2005-2006 The Regents of The University of Michigan # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,39 +32,22 @@ import os import optparse import datetime -# -# Regression invocation: -# -# regress \ -# --workdir poolfs \ -# --scons-opts 'BATCH=yes USE_MYSQL=no -j 30 -Q' \ -# --recurse - progname = os.path.basename(sys.argv[0]) optparser = optparse.OptionParser() optparser.add_option('-v', '--verbose', dest='verbose', action='store_true', default=False, help='echo commands before executing') -optparser.add_option('--scratch', dest='scratch', action='store_true', - default=False, - help='rebuld from scratch') optparser.add_option('--builds', dest='builds', - default='ALPHA_SE,ALPHA_FS,ALPHA_FS_TL', - help='comma-separated list of builds to test') + default='ALPHA_SE,ALPHA_FS,MIPS_SE,SPARC_SE', + help='comma-separated list of build targets to test ' + " (default: '%default')" ) optparser.add_option('--variants', dest='variants', default='opt', - help='comma-separated list of build variants to test') -optparser.add_option('--workdir', dest='workdir', - help='directory for checked-out source trees') + help='comma-separated list of build variants to test ' + " (default: '%default')" ) optparser.add_option('--scons-opts', dest='scons_opts', default='', - help='scons options') -optparser.add_option('--no-pull', dest='pull', action='store_false', - default=True, - help="don't pull changes from repository") -optparser.add_option('--recurse', dest='recurse', action='store_true', - default=False, - help='call recursively to get summary up front') + help='scons options', metavar='OPTS') (options, tests) = optparser.parse_args() @@ -73,9 +56,6 @@ optparser.add_option('--recurse', dest='recurse', action='store_true', builds = options.builds.split(',') variants = options.variants.split(',') -# Repositories to clone/update -repos = ['m5', 'm5-test', 'ext'] - # Call os.system() and raise exception if return status is non-zero def system(cmd): if options.verbose: @@ -93,58 +73,20 @@ def shellquote(s): s = "'%s'" % s return s -# The '--recurse' option invokes scons once to perform any necessary -# rebuilds/test runs with the (possibly verbose) output placed in a -# log file, then (if the buld was successful) returns scons to print a -# summary of the results. -if options.recurse: - sys.argv.remove('--recurse') # avoid infinite recursion... - timestr = datetime.datetime.now().isoformat('-')[:19] - logfile = '%s-%s' % (progname, timestr) - # quote args for shell - qargs = [shellquote(a) for a in sys.argv] - # always run the sub-job in verbose mode - qargs.append('-v') - cmd = '%s > %s 2>&1' % (' '.join(qargs), logfile) - try: - system(cmd) - except OSError, exc: - print "Error: recursive invocation failed, aborting." - print exc - print "=======================" - os.system('cat %s' % logfile) - sys.exit(1) - # recursive call succeeded... re-run to generate summary - # don't *re*-build from scratch now - options.scratch = False - # no need to re-pull since the recursive call shoudl have done that - options.pull = False - print "Recursive invocation successful, see %s for output." % logfile - try: - if options.workdir: - if options.verbose: - print 'cd', options.workdir - os.chdir(options.workdir) - - if options.scratch: - for dir in repos: - system('rm -rf %s' % dir) - system('bk clone /bk/%s' % dir) - elif options.pull: - for dir in repos: - system('cd %s; bk pull' % dir) - if not tests: print "No tests specified." sys.exit(1) - if options.verbose: - print 'cd m5/build' - os.chdir('m5/build') - - targets = ['%s/test/%s/%s' % (build, variant, test) - for build in builds for variant in variants for test in tests] + if 'all' in tests: + targets = ['build/%s/tests/%s' % (build, variant) + for build in builds + for variant in variants] + else: + targets = ['build/%s/tests/%s/%s' % (build, variant, test) + for build in builds + for variant in variants + for test in tests] system('scons %s %s' % (options.scons_opts, ' '.join(targets))) diff --git a/util/rundiff b/util/rundiff index 9376e4b9e..c34bb53a3 100755 --- a/util/rundiff +++ b/util/rundiff @@ -25,6 +25,9 @@ # 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 +# Steve Reinhardt # Diff two streams. # @@ -36,7 +39,7 @@ # "filename" is a pipe (|). Thus to compare the instruction traces # from two versions of m5 (m5a and m5b), you can do this: # -# rundiff 'm5a --trace:flags=InstExec |' 'm5b --trace:flags=InstExec |' +# rundiff 'm5a --traceflags=InstExec |' 'm5b --traceflags=InstExec |' # use strict; 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 <iostream> +#include <errno.h> +#include <sys/ptrace.h> +#include <stdint.h> + +#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 <linux/user.h> +#include <sys/types.h> +#include <sys/ptrace.h> +#include <assert.h> +#include <string> + +#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 <iostream> +#include <errno.h> +#include <sys/ptrace.h> +#include <stdint.h> + +#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 <asm-sparc64/reg.h> +#include <assert.h> +#include <ostream> +#include <stdint.h> +#include <string> +#include <sys/ptrace.h> +#include <sys/types.h> + +#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 <iostream> +#include <string> +#include <vector> + +#include "refcnt.hh" + +class TraceChild; +class PrinterObject; + +typedef RefCountingPtr<PrinterObject> 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<std::string> constStrings; + std::vector<PrinterPointer> 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 <stddef.h> //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 T> +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<class T> +bool operator==(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r) +{ return l.get() == r.get(); } + +template<class T> +bool operator==(const RefCountingPtr<T> &l, const T *r) +{ return l.get() == r; } + +template<class T> +bool operator==(const T &l, const RefCountingPtr<T> &r) +{ return l == r.get(); } + +template<class T> +bool operator!=(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r) +{ return l.get() != r.get(); } + +template<class T> +bool operator!=(const RefCountingPtr<T> &l, const T *r) +{ return l.get() != r; } + +template<class T> +bool operator!=(const T &l, const RefCountingPtr<T> &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 <string> +#include <stdint.h> + +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 <iostream> +#include <fstream> +#include <string> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/ptrace.h> +#include <unistd.h> + +#include "tracechild.hh" +#include "printer.hh" + +using namespace std; + +void printUsage(const char * execName) +{ + cout << execName << " -f <output format file> | -h | -r -- <command> <arguments>" << 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 <sys/wait.h> +#include <sys/ptrace.h> +#include <iostream> +#include <errno.h> + +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) diff --git a/util/stats/db.py b/util/stats/db.py index c0e7796eb..e1198d438 100644 --- a/util/stats/db.py +++ b/util/stats/db.py @@ -23,6 +23,8 @@ # 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 import MySQLdb, re, string @@ -135,10 +137,6 @@ class Database(object): self.allRunIds = {} self.allRunNames = {} - self.allBins = [] - self.allBinIds = {} - self.allBinNames = {} - self.allFormulas = {} self.stattop = {} @@ -147,7 +145,6 @@ class Database(object): self.mode = 'sum'; self.runs = None - self.bins = None self.ticks = None self.method = 'sum' self._method = type(self).sum @@ -218,11 +215,6 @@ class Database(object): self.allRunIds[run.run] = run self.allRunNames[run.name] = run - self.query('select * from bins') - for id,name in self.cursor.fetchall(): - self.allBinIds[int(id)] = name - self.allBinNames[name] = int(id) - self.query('select sd_stat,sd_x,sd_y,sd_name,sd_descr from subdata') for result in self.cursor.fetchall(): subdata = SubData(result) @@ -245,18 +237,6 @@ class Database(object): self.allStatIds[stat.stat] = stat self.allStatNames[stat.name] = stat - # Name: listbins - # Desc: Prints all bins matching regex argument, if no argument - # is given all bins are returned - def listBins(self, regex='.*'): - print '%-50s %-10s' % ('bin name', 'id') - print '-' * 61 - names = self.allBinNames.keys() - names.sort() - for name in names: - id = self.allBinNames[name] - print '%-50s %-10d' % (name, id) - # Name: listruns # Desc: Prints all runs matching a given user, if no argument # is given all runs are returned @@ -360,39 +340,10 @@ class Database(object): ret.append(stat) return ret - def getBin(self, bins): - if type(bins) is not list: - bins = [ bins ] - - ret = [] - for bin in bins: - if type(bin) is int: - ret.append(bin) - elif type(bin) is str: - ret.append(self.allBinNames[bin]) - else: - for name,id in self.allBinNames.items(): - if bin.match(name): - ret.append(id) - - return ret - - def getNotBin(self, bin): - map = {} - for bin in getBin(bin): - map[bin] = 1 - - ret = [] - for bin in self.allBinIds.keys(): - if not map.has_key(bin): - ret.append(bin) - - return ret - ######################################### # get the data # - def inner(self, op, stat, bins, ticks, group=False): + def query(self, op, stat, ticks, group=False): sql = 'select ' sql += 'dt_stat as stat, ' sql += 'dt_run as run, ' @@ -414,10 +365,6 @@ class Database(object): val = ' or '.join([ 'dt_run=%d' % r for r in self.runs ]) sql += ' and (%s)' % val - if bins != None and len(bins): - val = ' or '.join([ 'dt_bin=%d' % b for b in bins ]) - sql += ' and (%s)' % val - if ticks != None and len(ticks): val = ' or '.join([ 'dt_tick=%d' % s for s in ticks ]) sql += ' and (%s)' % val @@ -427,35 +374,21 @@ class Database(object): sql += ',dt_tick' return sql - def outer(self, op_out, op_in, stat, bins, ticks): - sql = self.inner(op_in, stat, bins, ticks, True) - sql = 'select stat,run,x,y,%s(data) from (%s) as tb ' % (op_out, sql) - sql += 'group by stat,run,x,y' - return sql - # Name: sum - # Desc: given a run, a stat and an array of samples and bins, - # sum all the bins and then get the standard deviation of the - # samples for non-binned runs. This will just return the average - # of samples, however a bin array still must be passed - def sum(self, stat, bins, ticks): - return self.inner('sum', stat, bins, ticks) + # Desc: given a run, a stat and an array of samples, total the samples + def sum(self, *args, **kwargs): + return self.query('sum', *args, **kwargs) # Name: avg - # Desc: given a run, a stat and an array of samples and bins, - # sum all the bins and then average the samples for non-binned - # runs this will just return the average of samples, however - # a bin array still must be passed - def avg(self, stat, bins, ticks): - return self.outer('avg', 'sum', stat, bins, ticks) + # Desc: given a run, a stat and an array of samples, average the samples + def avg(self, stat, ticks): + return self.query('avg', *args, **kwargs) # Name: stdev - # Desc: given a run, a stat and an array of samples and bins, - # sum all the bins and then get the standard deviation of the - # samples for non-binned runs. This will just return the average - # of samples, however a bin array still must be passed - def stdev(self, stat, bins, ticks): - return self.outer('stddev', 'sum', stat, bins, ticks) + # Desc: given a run, a stat and an array of samples, get the standard + # deviation + def stdev(self, stat, ticks): + return self.query('stddev', *args, **kwargs) def __setattr__(self, attr, value): super(Database, self).__setattr__(attr, value) @@ -471,12 +404,10 @@ class Database(object): else: raise AttributeError, "can only set get to: sum | avg | stdev" - def data(self, stat, bins=None, ticks=None): - if bins is None: - bins = self.bins + def data(self, stat, ticks=None): if ticks is None: ticks = self.ticks - sql = self._method(self, stat, bins, ticks) + sql = self._method(self, stat, ticks) self.query(sql) runs = {} diff --git a/util/stats/dbinit.py b/util/stats/dbinit.py index ffae88cdb..036941675 100644 --- a/util/stats/dbinit.py +++ b/util/stats/dbinit.py @@ -23,6 +23,8 @@ # 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 import MySQLdb @@ -98,28 +100,6 @@ class MyDB(object): ) TYPE=InnoDB''') # - # We keep the bin names separate so that the data table doesn't get - # huge since bin names are frequently repeated. - # - # COLUMNS: - # 'id' is the unique bin identifer. - # 'name' is the string name for the bin. - # - # INDEXES: - # 'bin' is indexed to get the name of a bin when data is retrieved - # via the data table. - # 'name' is indexed to get the bin id for a named bin when you want - # to search the data table based on a specific bin. - # - self.query(''' - CREATE TABLE bins( - bn_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, - bn_name VARCHAR(255) NOT NULL, - PRIMARY KEY(bn_id), - UNIQUE (bn_name) - ) TYPE=InnoDB''') - - # # The stat table gives us all of the data for a particular stat. # # COLUMNS: @@ -220,14 +200,12 @@ class MyDB(object): # 'run' is the run that the data was generated from. Details up in # the run table # 'tick' is a timestamp generated by the simulator. - # 'bin' is the name of the bin that the data was generated in, if - # any. # 'data' is the actual stat value. # # INDEXES: # 'stat' is indexed so that a user can find all of the data for a # particular stat. It is not unique, because that specific stat - # can be found in many runs, bins, and samples, in addition to + # can be found in many runs and samples, in addition to # having entries for the mulidimensional cases. # 'run' is indexed to allow a user to remove all of the data for a # particular execution run. It can also be used to allow the @@ -240,11 +218,10 @@ class MyDB(object): dt_y SMALLINT NOT NULL, dt_run SMALLINT UNSIGNED NOT NULL, dt_tick BIGINT UNSIGNED NOT NULL, - dt_bin SMALLINT UNSIGNED NOT NULL, dt_data DOUBLE NOT NULL, INDEX (dt_stat), INDEX (dt_run), - UNIQUE (dt_stat,dt_x,dt_y,dt_run,dt_tick,dt_bin) + UNIQUE (dt_stat,dt_x,dt_y,dt_run,dt_tick) ) TYPE=InnoDB;''') # @@ -396,12 +373,6 @@ class MyDB(object): WHERE dt_stat IS NULL''') self.query(''' - DELETE bins - FROM bins - LEFT JOIN data ON bn_id=dt_bin - WHERE dt_bin IS NULL''') - - self.query(''' DELETE events FROM events LEFT JOIN runs ON ev_run=rn_id diff --git a/util/stats/display.py b/util/stats/display.py index fbcff5c70..cb825f493 100644 --- a/util/stats/display.py +++ b/util/stats/display.py @@ -23,6 +23,8 @@ # 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 class Value: def __init__(self, value, precision, percent = False): diff --git a/util/stats/info.py b/util/stats/info.py index 4cb55f564..193159b4c 100644 --- a/util/stats/info.py +++ b/util/stats/info.py @@ -23,6 +23,8 @@ # 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 from __future__ import division import operator, re, types @@ -174,7 +176,7 @@ def WrapValue(value): class Statistic(object): def __getattr__(self, attr): if attr in ('data', 'x', 'y'): - result = self.source.data(self, self.bins, self.ticks) + result = self.source.data(self, self.ticks) self.data = result.data self.x = result.x self.y = result.y @@ -183,7 +185,7 @@ class Statistic(object): def __setattr__(self, attr, value): if attr == 'stat': raise AttributeError, '%s is read only' % stat - if attr in ('source', 'bins', 'ticks'): + if attr in ('source', 'ticks'): if getattr(self, attr) != value: if hasattr(self, 'data'): delattr(self, 'data') @@ -759,7 +761,6 @@ def NewStat(source, data): stat = Formula() stat.__dict__['source'] = source - stat.__dict__['bins'] = None stat.__dict__['ticks'] = None stat.__dict__.update(data.__dict__) diff --git a/util/stats/orderdict.py b/util/stats/orderdict.py index 816355ae2..3f755d299 100644 --- a/util/stats/orderdict.py +++ b/util/stats/orderdict.py @@ -23,6 +23,8 @@ # 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 __all__ = [ 'orderdict' ] diff --git a/util/stats/output.py b/util/stats/output.py index abfb8d901..03c100edc 100644 --- a/util/stats/output.py +++ b/util/stats/output.py @@ -29,24 +29,16 @@ from chart import ChartOptions class StatOutput(ChartOptions): - def __init__(self, jobfile, info, stat=None, binstats=None): + def __init__(self, jobfile, info, stat=None): super(StatOutput, self).__init__() self.jobfile = jobfile self.stat = stat - self.binstats = None self.invert = False self.info = info - def printdata(self, name, bin = None, printmode = 'G'): + def display(self, name, printmode = 'G'): import info - if bin: - print '%s %s stats' % (name, bin) - - if self.binstats: - for stat in self.binstats: - stat.bins = bin - if printmode == 'G': valformat = '%g' elif printmode != 'F' and value > 1e6: @@ -70,16 +62,6 @@ class StatOutput(ChartOptions): valstring = ', '.join([ valformat % val for val in value ]) print '%-50s %s' % (job.name + ':', valstring) - def display(self, name, binned = False, printmode = 'G'): - if binned and self.binstats: - self.printdata(name, 'kernel', printmode) - self.printdata(name, 'idle', printmode) - self.printdata(name, 'user', printmode) - self.printdata(name, 'interrupt', printmode) - - print '%s total stats' % name - self.printdata(name, printmode=printmode) - def graph(self, name, graphdir, proxy=None): from os.path import expanduser, isdir, join as joinpath from barchart import BarChart diff --git a/util/stats/print.py b/util/stats/print.py index 2572fd4e7..1c83fa87d 100644 --- a/util/stats/print.py +++ b/util/stats/print.py @@ -23,6 +23,8 @@ # 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 all = False descriptions = False diff --git a/util/stats/profile.py b/util/stats/profile.py index f28c5867c..6959e0e34 100644 --- a/util/stats/profile.py +++ b/util/stats/profile.py @@ -23,6 +23,8 @@ # 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 from orderdict import orderdict import output diff --git a/util/stats/stats.py b/util/stats/stats.py index 08281287f..2aa0d4e0b 100755 --- a/util/stats/stats.py +++ b/util/stats/stats.py @@ -25,6 +25,8 @@ # 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 from __future__ import division import re, sys, math @@ -37,7 +39,6 @@ Usage: %s [-E] [-F] [ -G <get> ] [-d <db> ] [-g <graphdir> ] [-h <host>] [-p] commands extra parameters description ----------- ------------------ --------------------------------------- - bins [regex] List bins (only matching regex) formula <formula> Evaluated formula specified formulas [regex] List formulas (only matching regex) runs none List all runs in database @@ -140,16 +141,6 @@ def commands(options, command, args): return - if command == 'bins': - if len(args) == 0: - source.listBins() - elif len(args) == 1: - source.listBins(args[0]) - else: - raise CommandException - - return - if command == 'formulas': if len(args) == 0: source.listFormulas() @@ -279,7 +270,7 @@ def commands(options, command, args): if options.graph: output.graph(stat.name, options.graphdir) else: - output.display(stat.name, options.binned, options.printmode) + output.display(stat.name, options.printmode) return @@ -299,22 +290,10 @@ def commands(options, command, args): if options.graph: output.graph(command, options.graphdir, proxy) else: - output.display(command, options.binned, options.printmode) - - if command == 'usertime': - import copy - user = copy.copy(system.run0.numCycles) - user.bins = 'user' - - output.stat = user / system.run0.numCycles - output.ylabel = 'User Fraction' - - display() - return + output.display(command, options.printmode) if command == 'ticks': output.stat = system.run0.numCycles - output.binstats = [ system.run0.numCycles ] display() return @@ -401,7 +380,6 @@ def commands(options, command, args): if command == 'mpkb': output.stat = misses / (bytes / 1024) - output.binstats = [ misses ] output.ylabel = 'Misses / KB' display() return @@ -409,7 +387,6 @@ def commands(options, command, args): if command == 'ipkb': interrupts = system.run0.kern.faults[4] output.stat = interrupts / kbytes - output.binstats = [ interrupts ] output.ylabel = 'Interrupts / KB' display() return @@ -446,7 +423,6 @@ if __name__ == '__main__': options.runs = None options.system = 'client' options.method = None - options.binned = False options.graph = False options.ticks = False options.printmode = 'G' @@ -454,10 +430,8 @@ if __name__ == '__main__': options.jobfile = None options.all = False - opts, args = getopts(sys.argv[1:], '-BEFJad:g:h:j:m:pr:s:u:T:') + opts, args = getopts(sys.argv[1:], '-EFJad:g:h:j:m:pr:s:u:T:') for o,a in opts: - if o == '-B': - options.binned = True if o == '-E': options.printmode = 'E' if o == '-F': diff --git a/util/tap/tap.cc b/util/tap/tap.cc index f4d0aadf2..b026e0220 100644 --- a/util/tap/tap.cc +++ b/util/tap/tap.cc @@ -24,6 +24,8 @@ * 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 */ extern "C" { diff --git a/util/tracediff b/util/tracediff index f11431293..f2377a999 100755 --- a/util/tracediff +++ b/util/tracediff @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright (c) 2003-2005 The Regents of The University of Michigan +# Copyright (c) 2003-2006 The Regents of The University of Michigan # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -36,7 +36,7 @@ # If you want to pass different arguments to the two instances of m5, # you can embed them in the simulator arguments like this: # -# % tracediff "m5.opt --foo.bar=1" "m5.opt --foo.bar=2" [common args] +# % tracediff "m5.opt --option1" "m5.opt --option2" [common args] # if (@ARGV < 2) { @@ -58,8 +58,8 @@ $dir2 = "tracediff-$$-2"; mkdir($dir1) or die "Can't create dir $dir1\n"; mkdir($dir2) or die "Can't create dir $dir2\n"; -$cmd1 = "$sim1 $simargs -d $dir1 2>&1 |"; -$cmd2 = "$sim2 $simargs -d $dir2 2>&1 |"; +$cmd1 = "$sim1 -d $dir1 $simargs 2>&1 |"; +$cmd2 = "$sim2 -d $dir2 $simargs 2>&1 |"; # This only works if you have rundiff in your path. I just edit it # with an explicit path if necessary. |