Adding gem5 source to svn.

git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1819 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
friemel
2012-10-24 19:18:57 +00:00
parent f7ff71bd46
commit b41eec3f65
3222 changed files with 658579 additions and 1 deletions

View File

@ -0,0 +1,39 @@
# Copyright (c) 2011 Gabe Black
# 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
import os
Import('env', 'arch')
env.Append(CPPPATH=Dir('.'))
sources = [os.path.join('base', 'statetrace.cc'),
os.path.join('base', 'tracechild.cc'),
os.path.join('arch', arch, 'tracechild.cc')]
objects = [env.Object(source) for source in sources]
env.Program('statetrace', objects)

View File

@ -0,0 +1,67 @@
# Copyright (c) 2011 Gabe Black
# 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
Help('''
To build a version of statetrace suitable to run on a particular ISA, use a
target of the form build/<arch>/statetrace. For example, to build statetrace
for ARM binaries, run:
scons build/arm/statetrace
You may need a cross compiler in order to build statetrace successfully. To
specify an alternative compiler, set the CXX scons argument on the command
line. The CXX environment variable is NOT considered when selecting the
compiler. To override the compiler for a particular target ISA, set the
<arch>CXX scons argument. For example, to build both the AMD64 version and
the ARM version at the same time using the system compiler for the AMD64
version and a cross compiler for arm, your command line would look like the
following:
scons ARMCXX=arm-cross-g++ build/amd64/statetrace build/arm/statetrace
After a successful build, the statetrace binary(binaries) will be located in
the build/<arch>/ directories you specified on the command line.
''')
arches = 'amd64', 'arm', 'i686', 'sparc'
import os
main = Environment()
main.SetOption('duplicate', 'soft-copy')
main['CXXFLAGS'] = "-O3 -ggdb $_CPPINCFLAGS"
main['CXX'] = ARGUMENTS.get('CXX', main['CXX'])
for arch in arches:
env = main.Clone()
env['CXX'] = ARGUMENTS.get(arch.upper() + 'CXX', env['CXX'])
env.Append(CPPFLAGS = '-D__STATETRACE_%s__' % arch.upper())
Export('env', 'arch')
env.SConscript('SConscript', variant_dir = os.path.join('build', arch))

View File

@ -0,0 +1,405 @@
/*
* Copyright (c) 2007 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Gabe Black
*/
#include <sys/ptrace.h>
#include <stdint.h>
#include <cerrno>
#include <cstring>
#include <iomanip>
#include <iostream>
#include "arch/amd64/tracechild.hh"
using namespace std;
bool
AMD64TraceChild::sendState(int socket)
{
uint64_t regVal64 = 0;
uint32_t regVal32 = 0;
for (int x = 0; x <= R15; x++) {
regVal64 = getRegVal(x);
if (write(socket, &regVal64, sizeof(regVal64)) == -1) {
cerr << "Write failed! " << strerror(errno) << endl;
tracing = false;
return false;
}
}
regVal64 = getRegVal(RIP);
if (write(socket, &regVal64, sizeof(regVal64)) == -1) {
cerr << "Write failed! " << strerror(errno) << endl;
tracing = false;
return false;
}
for (int x = MMX0_0; x <= MMX7_1; x++) {
regVal32 = getRegVal(x);
if (write(socket, &regVal32, sizeof(regVal32)) == -1) {
cerr << "Write failed! " << strerror(errno) << endl;
tracing = false;
return false;
}
}
for (int x = XMM0_0; x <= XMM15_3; x++) {
regVal32 = getRegVal(x);
if (write(socket, &regVal32, sizeof(regVal32)) == -1) {
cerr << "Write failed! " << strerror(errno) << endl;
tracing = false;
return false;
}
}
return true;
}
int64_t
AMD64TraceChild::getRegs(user_regs_struct & myregs,
user_fpregs_struct & myfpregs, int num)
{
assert(num < numregs && num >= 0);
switch (num) {
//GPRs
case RAX: return myregs.rax;
case RBX: return myregs.rbx;
case RCX: return myregs.rcx;
case RDX: return myregs.rdx;
//Index registers
case RSI: return myregs.rsi;
case RDI: return myregs.rdi;
//Base pointer and stack pointer
case RBP: return myregs.rbp;
case RSP: return myregs.rsp;
//New 64 bit mode registers
case R8: return myregs.r8;
case R9: return myregs.r9;
case R10: return myregs.r10;
case R11: return myregs.r11;
case R12: return myregs.r12;
case R13: return myregs.r13;
case R14: return myregs.r14;
case R15: return myregs.r15;
//Segmentation registers
case CS: return myregs.cs;
case DS: return myregs.ds;
case ES: return myregs.es;
case FS: return myregs.fs;
case GS: return myregs.gs;
case SS: return myregs.ss;
case FS_BASE: return myregs.fs_base;
case GS_BASE: return myregs.gs_base;
//PC
case RIP: return myregs.rip;
//Flags
case EFLAGS: return myregs.eflags;
//MMX
case MMX0_0: return myfpregs.st_space[0];
case MMX0_1: return myfpregs.st_space[1];
case MMX1_0: return myfpregs.st_space[2];
case MMX1_1: return myfpregs.st_space[3];
case MMX2_0: return myfpregs.st_space[4];
case MMX2_1: return myfpregs.st_space[5];
case MMX3_0: return myfpregs.st_space[6];
case MMX3_1: return myfpregs.st_space[7];
case MMX4_0: return myfpregs.st_space[8];
case MMX4_1: return myfpregs.st_space[9];
case MMX5_0: return myfpregs.st_space[10];
case MMX5_1: return myfpregs.st_space[11];
case MMX6_0: return myfpregs.st_space[12];
case MMX6_1: return myfpregs.st_space[13];
case MMX7_0: return myfpregs.st_space[14];
case MMX7_1: return myfpregs.st_space[15];
//XMM
case XMM0_0: return myfpregs.xmm_space[0];
case XMM0_1: return myfpregs.xmm_space[1];
case XMM0_2: return myfpregs.xmm_space[2];
case XMM0_3: return myfpregs.xmm_space[3];
case XMM1_0: return myfpregs.xmm_space[4];
case XMM1_1: return myfpregs.xmm_space[5];
case XMM1_2: return myfpregs.xmm_space[6];
case XMM1_3: return myfpregs.xmm_space[7];
case XMM2_0: return myfpregs.xmm_space[8];
case XMM2_1: return myfpregs.xmm_space[9];
case XMM2_2: return myfpregs.xmm_space[10];
case XMM2_3: return myfpregs.xmm_space[11];
case XMM3_0: return myfpregs.xmm_space[12];
case XMM3_1: return myfpregs.xmm_space[13];
case XMM3_2: return myfpregs.xmm_space[14];
case XMM3_3: return myfpregs.xmm_space[15];
case XMM4_0: return myfpregs.xmm_space[16];
case XMM4_1: return myfpregs.xmm_space[17];
case XMM4_2: return myfpregs.xmm_space[18];
case XMM4_3: return myfpregs.xmm_space[19];
case XMM5_0: return myfpregs.xmm_space[20];
case XMM5_1: return myfpregs.xmm_space[21];
case XMM5_2: return myfpregs.xmm_space[22];
case XMM5_3: return myfpregs.xmm_space[23];
case XMM6_0: return myfpregs.xmm_space[24];
case XMM6_1: return myfpregs.xmm_space[25];
case XMM6_2: return myfpregs.xmm_space[26];
case XMM6_3: return myfpregs.xmm_space[27];
case XMM7_0: return myfpregs.xmm_space[28];
case XMM7_1: return myfpregs.xmm_space[29];
case XMM7_2: return myfpregs.xmm_space[30];
case XMM7_3: return myfpregs.xmm_space[31];
case XMM8_0: return myfpregs.xmm_space[32];
case XMM8_1: return myfpregs.xmm_space[33];
case XMM8_2: return myfpregs.xmm_space[34];
case XMM8_3: return myfpregs.xmm_space[35];
case XMM9_0: return myfpregs.xmm_space[36];
case XMM9_1: return myfpregs.xmm_space[37];
case XMM9_2: return myfpregs.xmm_space[38];
case XMM9_3: return myfpregs.xmm_space[39];
case XMM10_0: return myfpregs.xmm_space[40];
case XMM10_1: return myfpregs.xmm_space[41];
case XMM10_2: return myfpregs.xmm_space[42];
case XMM10_3: return myfpregs.xmm_space[43];
case XMM11_0: return myfpregs.xmm_space[44];
case XMM11_1: return myfpregs.xmm_space[45];
case XMM11_2: return myfpregs.xmm_space[46];
case XMM11_3: return myfpregs.xmm_space[47];
case XMM12_0: return myfpregs.xmm_space[48];
case XMM12_1: return myfpregs.xmm_space[49];
case XMM12_2: return myfpregs.xmm_space[50];
case XMM12_3: return myfpregs.xmm_space[51];
case XMM13_0: return myfpregs.xmm_space[52];
case XMM13_1: return myfpregs.xmm_space[53];
case XMM13_2: return myfpregs.xmm_space[54];
case XMM13_3: return myfpregs.xmm_space[55];
case XMM14_0: return myfpregs.xmm_space[56];
case XMM14_1: return myfpregs.xmm_space[57];
case XMM14_2: return myfpregs.xmm_space[58];
case XMM14_3: return myfpregs.xmm_space[59];
case XMM15_0: return myfpregs.xmm_space[60];
case XMM15_1: return myfpregs.xmm_space[61];
case XMM15_2: return myfpregs.xmm_space[62];
case XMM15_3: return myfpregs.xmm_space[63];
default:
assert(0);
return 0;
}
}
bool
AMD64TraceChild::update(int pid)
{
oldregs = regs;
oldfpregs = fpregs;
if (ptrace(PTRACE_GETREGS, pid, 0, &regs) != 0) {
cerr << "update: " << strerror(errno) << endl;
return false;
}
if (ptrace(PTRACE_GETFPREGS, pid, 0, &fpregs) != 0) {
cerr << "update: " << strerror(errno) << endl;
return false;
}
for (unsigned int x = 0; x < numregs; x++)
regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x));
return true;
}
AMD64TraceChild::AMD64TraceChild()
{
for (unsigned int x = 0; x < numregs; x++)
regDiffSinceUpdate[x] = false;
}
int64_t
AMD64TraceChild::getRegVal(int num)
{
return getRegs(regs, fpregs, num);
}
int64_t
AMD64TraceChild::getOldRegVal(int num)
{
return getRegs(oldregs, oldfpregs, num);
}
ostream &
AMD64TraceChild::outputStartState(ostream & os)
{
uint64_t sp = getSP();
uint64_t pc = getPC();
uint64_t highestInfo = 0;
char obuf[1024];
sprintf(obuf, "Initial stack pointer = 0x%016lx\n", sp);
os << obuf;
sprintf(obuf, "Initial program counter = 0x%016lx\n", pc);
os << obuf;
//Output the argument count
uint64_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
sprintf(obuf, "0x%016lx: Argc = 0x%016lx\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%016lx: argv[%d] = 0x%016lx\n",
sp, argCount++, cargv);
if (cargv)
if (highestInfo < cargv)
highestInfo = 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%016lx: envp[%d] = 0x%016lx\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%016lx: Auxiliary vector = {0x%016lx, 0x%016lx}\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%016lx: \"%s\"\n",
currentStart, current.c_str());
os << obuf;
current = "";
currentStart = sp + x + 1;
}
}
sp += 8;
clearedInitialPadding = clearedInitialPadding || buf != 0;
} while (!clearedInitialPadding || buf != 0 || sp <= highestInfo);
return os;
}
uint64_t
AMD64TraceChild::findSyscall()
{
uint64_t rip = getPC();
bool foundOpcode = false;
bool twoByteOpcode = false;
for (;;) {
uint64_t buf = ptrace(PTRACE_PEEKDATA, pid, rip, 0);
for (int i = 0; i < sizeof(uint64_t); i++) {
unsigned char byte = buf & 0xFF;
if (!foundOpcode) {
if(!(byte == 0x66 || //operand override
byte == 0x67 || //address override
byte == 0x2E || //cs
byte == 0x3E || //ds
byte == 0x26 || //es
byte == 0x64 || //fs
byte == 0x65 || //gs
byte == 0x36 || //ss
byte == 0xF0 || //lock
byte == 0xF2 || //repe
byte == 0xF3 || //repne
(byte >= 0x40 && byte <= 0x4F) // REX
)) {
foundOpcode = true;
}
}
if (foundOpcode) {
if (twoByteOpcode) {
//SYSCALL or SYSENTER
if (byte == 0x05 || byte == 0x34)
return rip + 1;
else
return 0;
}
if (!twoByteOpcode) {
if (byte == 0xCC) // INT3
return rip + 1;
else if (byte == 0xCD) // INT with byte immediate
return rip + 2;
else if (byte == 0x0F) // two byte opcode prefix
twoByteOpcode = true;
else
return 0;
}
}
buf >>= 8;
rip++;
}
}
}
bool
AMD64TraceChild::step()
{
uint64_t ripAfterSyscall = findSyscall();
if (ripAfterSyscall) {
//Get the original contents of memory
uint64_t buf = ptrace(PTRACE_PEEKDATA, pid, ripAfterSyscall, 0);
//Patch the first two bytes of the memory immediately after this with
//jmp -2. Either single stepping will take over before this
//instruction, leaving the rip where it should be, or it will take
//over after this instruction, -still- leaving the rip where it should
//be.
uint64_t newBuf = (buf & ~0xFFFF) | 0xFEEB;
//Write the patched memory to the processes address space
ptrace(PTRACE_POKEDATA, pid, ripAfterSyscall, newBuf);
//Step and hit it
ptraceSingleStep();
//Put things back to the way they started
ptrace(PTRACE_POKEDATA, pid, ripAfterSyscall, buf);
} else {
//Get all the way past repe and repne string instructions in one shot.
uint64_t newPC, origPC = getPC();
do {
ptraceSingleStep();
newPC = getPC();
} while(newPC == origPC);
}
}
TraceChild * genTraceChild()
{
return new AMD64TraceChild;
}

View File

@ -0,0 +1,119 @@
/*
* Copyright (c) 2007 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Gabe Black
*/
#ifndef REGSTATE_AMD64_HH
#define REGSTATE_AMD64_HH
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/user.h>
#include <cassert>
#include <string>
#include "base/tracechild.hh"
class AMD64TraceChild : public TraceChild
{
public:
enum RegNum
{
//GPRs
RAX, RCX, RDX, RBX,
//Base pointer and stack pointer
RSP, RBP,
//Index registers
RSI, RDI,
//New 64 bit mode registers
R8, R9, R10, R11, R12, R13, R14, R15,
//Segmentation registers
CS, DS, ES, FS, GS, SS, FS_BASE, GS_BASE,
//PC
RIP,
//Flags
EFLAGS,
//MMX
MMX0_0, MMX0_1,
MMX1_0, MMX1_1,
MMX2_0, MMX2_1,
MMX3_0, MMX3_1,
MMX4_0, MMX4_1,
MMX5_0, MMX5_1,
MMX6_0, MMX6_1,
MMX7_0, MMX7_1,
//XMM
XMM0_0, XMM0_1, XMM0_2, XMM0_3,
XMM1_0, XMM1_1, XMM1_2, XMM1_3,
XMM2_0, XMM2_1, XMM2_2, XMM2_3,
XMM3_0, XMM3_1, XMM3_2, XMM3_3,
XMM4_0, XMM4_1, XMM4_2, XMM4_3,
XMM5_0, XMM5_1, XMM5_2, XMM5_3,
XMM6_0, XMM6_1, XMM6_2, XMM6_3,
XMM7_0, XMM7_1, XMM7_2, XMM7_3,
XMM8_0, XMM8_1, XMM8_2, XMM8_3,
XMM9_0, XMM9_1, XMM9_2, XMM9_3,
XMM10_0, XMM10_1, XMM10_2, XMM10_3,
XMM11_0, XMM11_1, XMM11_2, XMM11_3,
XMM12_0, XMM12_1, XMM12_2, XMM12_3,
XMM13_0, XMM13_1, XMM13_2, XMM13_3,
XMM14_0, XMM14_1, XMM14_2, XMM14_3,
XMM15_0, XMM15_1, XMM15_2, XMM15_3,
numregs
};
private:
int64_t getRegs(user_regs_struct & myregs,
user_fpregs_struct &myfpregs,int num);
user_regs_struct regs;
user_regs_struct oldregs;
user_fpregs_struct fpregs;
user_fpregs_struct oldfpregs;
bool regDiffSinceUpdate[numregs];
uint64_t findSyscall();
protected:
bool update(int pid);
public:
AMD64TraceChild();
bool sendState(int socket);
int64_t getRegVal(int num);
int64_t getOldRegVal(int num);
uint64_t getPC() {return getRegVal(RIP);}
uint64_t getSP() {return getRegVal(RSP);}
std::ostream & outputStartState(std::ostream & output);
bool step();
};
#endif

View File

@ -0,0 +1,286 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2006-2009 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: Ali Saidi
* Gabe Black
*/
#include <stdint.h>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <iostream>
#include "arch/arm/tracechild.hh"
using namespace std;
ARMTraceChild::ARMTraceChild()
{
foundMvn = false;
memset(&regs, 0, sizeof(regs));
memset(&oldregs, 0, sizeof(regs));
memset(&fpregs, 0, sizeof(vfp_regs));
memset(&oldfpregs, 0, sizeof(vfp_regs));
for (int x = 0; x < numregs; x++) {
regDiffSinceUpdate[x] = false;
}
assert(sizeof(regs.uregs)/sizeof(regs.uregs[0]) > CPSR);
}
bool
ARMTraceChild::sendState(int socket)
{
uint32_t regVal = 0;
uint64_t message[numregs + 1];
int pos = 1;
message[0] = 0;
for (int x = 0; x < numregs; x++) {
if (regDiffSinceUpdate[x]) {
message[0] = message[0] | (1ULL << x);
message[pos++] = getRegVal(x);
}
}
size_t sent = 0;
size_t toSend = pos * sizeof(message[0]);
uint8_t *messagePtr = (uint8_t *)message;
while (toSend != 0) {
sent = write(socket, messagePtr, toSend);
if (sent == -1) {
cerr << "Write failed! " << strerror(errno) << endl;
tracing = false;
return false;
}
toSend -= sent;
messagePtr += sent;
}
return true;
}
uint32_t
ARMTraceChild::getRegs(user_regs &myregs, int num)
{
assert(num <= CPSR && num >= 0);
return myregs.uregs[num];
}
uint64_t
ARMTraceChild::getFpRegs(vfp_regs &my_fp_regs, int num)
{
assert(num >= F0 && num < numregs);
if (num == FPSCR)
return my_fp_regs.fpscr;
num -= F0;
return my_fp_regs.fpregs[num];
}
bool
ARMTraceChild::update(int pid)
{
oldregs = regs;
if (ptrace(PTRACE_GETREGS, pid, 0, &regs) != 0) {
cerr << "update: " << strerror(errno) << endl;
return false;
}
const uint32_t get_vfp_regs = 32;
oldfpregs = fpregs;
if (ptrace((__ptrace_request)get_vfp_regs, pid, 0, &fpregs) != 0) {
cerr << "update: " << strerror(errno) << endl;
return false;
}
for (unsigned int x = 0; x < numregs; x++)
regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x));
return true;
}
int64_t
ARMTraceChild::getRegVal(int num)
{
if (num <= CPSR)
return getRegs(regs, num);
else
return (int64_t)getFpRegs(fpregs, num);
}
int64_t
ARMTraceChild::getOldRegVal(int num)
{
if (num <= CPSR)
return getRegs(oldregs, num);
else
return (int64_t)getFpRegs(oldfpregs, num);
}
ostream &
ARMTraceChild::outputStartState(ostream & os)
{
uint32_t sp = getSP();
uint32_t pc = getPC();
uint32_t highestInfo = 0;
char obuf[1024];
sprintf(obuf, "Initial stack pointer = 0x%08x\n", sp);
os << obuf;
sprintf(obuf, "Initial program counter = 0x%08x\n", pc);
os << obuf;
//Output the argument count
int32_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
sprintf(obuf, "0x%08x: Argc = 0x%08x\n", sp, cargc);
os << obuf;
sp += 4;
//Output argv pointers
int argCount = 0;
int32_t cargv;
do {
cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
sprintf(obuf, "0x%08x: argv[%d] = 0x%08x\n",
sp, argCount++, cargv);
if(cargv)
if(highestInfo < cargv)
highestInfo = cargv;
os << obuf;
sp += 4;
} while(cargv);
//Output the envp pointers
int envCount = 0;
uint32_t cenvp;
do {
cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
sprintf(obuf, "0x%08x: envp[%d] = 0x%08x\n",
sp, envCount++, cenvp);
os << obuf;
sp += 4;
} while(cenvp);
uint32_t auxType, auxVal;
do {
auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
sp += 4;
auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
sp += 4;
sprintf(obuf, "0x%08x: Auxiliary vector = {0x%08x, 0x%08x}\n",
sp - 8, auxType, auxVal);
os << obuf;
} while(auxType != 0 || auxVal != 0);
//Print out the argument strings, environment strings, and file name.
string current;
uint32_t buf;
uint32_t currentStart = sp;
bool clearedInitialPadding = false;
do {
buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
char * cbuf = (char *)&buf;
for (int x = 0; x < sizeof(uint32_t); x++) {
if (cbuf[x])
current += cbuf[x];
else {
sprintf(obuf, "0x%08x: \"%s\"\n",
currentStart, current.c_str());
os << obuf;
current = "";
currentStart = sp + x + 1;
}
}
sp += 4;
clearedInitialPadding = clearedInitialPadding || buf != 0;
} while(!clearedInitialPadding || buf != 0 || sp <= highestInfo);
return os;
}
bool
ARMTraceChild::step()
{
const uint32_t bkpt_inst = 0xe7f001f0;
uint32_t lr = getRegVal(14);
uint32_t pc = getPC();
uint32_t lrOp, subsOp;
char obuf[128];
bool patch = false;
// Since ARM uses software breakpoints behind the scenes, they don't work
// in read only areas like the page of routines provided by the kernel. The
// link register generally holds the address the process wants to the
// kernel to return to after it's done, so we'll install a software
// breakpoint there.
//
// Calls into the kernel user page always follow the form:
// MVN ...
// <possible MOV lr,...>
// SUB PC, ...
//
// So we look for this pattern and set a breakpoint on the LR at the SUB
// instruction.
subsOp = ptrace(PTRACE_PEEKDATA, pid, pc, 0);
if ((subsOp & 0xFFFF0FFF) == 0xe3e00a0f)
foundMvn = true;
if (foundMvn && ((subsOp & 0xFFF0F000) == 0xe240f000)) {
foundMvn = false;
lrOp = ptrace(PTRACE_PEEKDATA, pid, lr, 0);
ptrace(PTRACE_POKEDATA, pid, lr, bkpt_inst);
patch = true;
}
ptraceSingleStep();
if (patch)
ptrace(PTRACE_POKEDATA, pid, lr, lrOp);
}
TraceChild *
genTraceChild()
{
return new ARMTraceChild;
}

View File

@ -0,0 +1,123 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2009 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: Ali Saidi
* Gabe Black
*/
#ifndef TRACECHILD_ARM_HH
#define TRACECHILD_ARM_HH
#include <sys/ptrace.h>
#include <sys/user.h>
#include <cassert>
#include <string>
#include "base/tracechild.hh"
class ARMTraceChild : public TraceChild
{
public:
enum RegNum
{
// r0 - r3 argument, temp, caller save
// r4 - r10 callee save
// r11 - FP
// r12 - temp
// r13 - stack
// r14 - link
// r15 - pc
R0, R1, R2, R3, R4, R5, R6, R7,
R8, R9, R10, FP, R12, SP, LR, PC,
CPSR,
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, FPSCR,
numregs
};
struct vfp_regs {
uint64_t fpregs[32];
uint32_t fpscr;
};
private:
uint32_t getRegs(user_regs& myregs, int num);
uint64_t getFpRegs(vfp_regs &myfpregs, int num);
user_regs regs;
user_regs oldregs;
vfp_regs fpregs;
vfp_regs oldfpregs;
bool regDiffSinceUpdate[numregs];
bool foundMvn;
protected:
bool update(int pid);
public:
ARMTraceChild();
bool sendState(int socket);
int64_t getRegVal(int num);
int64_t getOldRegVal(int num);
bool step();
uint64_t
getPC()
{
return getRegVal(PC);
}
uint64_t
getSP()
{
return getRegVal(SP);
}
std::ostream & outputStartState(std::ostream & os);
};
#endif

View File

@ -0,0 +1,111 @@
/*
* 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 <sys/ptrace.h>
#include <stdint.h>
#include <cerrno>
#include <iostream>
#include "arch/i686/tracechild.hh"
using namespace std;
int64_t
I686TraceChild::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.xcs;
case DS: return myregs.xds;
case ES: return myregs.xes;
case FS: return myregs.xfs;
case GS: return myregs.xgs;
case SS: return myregs.xss;
//PC
case EIP: return myregs.eip;
default:
assert(0);
return 0;
}
}
bool
I686TraceChild::update(int pid)
{
oldregs = regs;
if (ptrace(PTRACE_GETREGS, pid, 0, &regs) != 0)
return false;
for (unsigned int x = 0; x < numregs; x++) {
regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x));
}
}
I686TraceChild::I686TraceChild()
{
for (unsigned int x = 0; x < numregs; x++)
regDiffSinceUpdate[x] = false;
}
int64_t
I686TraceChild::getRegVal(int num)
{
return getRegs(regs, num);
}
int64_t
I686TraceChild::getOldRegVal(int num)
{
return getRegs(oldregs, num);
}
bool
I686TraceChild::sendState(int socket)
{
return false;
}
TraceChild *
genTraceChild()
{
return new I686TraceChild;
}

View File

@ -0,0 +1,87 @@
/*
* 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_I686_HH
#define REGSTATE_I686_HH
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/user.h>
#include <cassert>
#include <string>
#include "base/tracechild.hh"
class I686TraceChild : 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:
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:
I686TraceChild();
int64_t getRegVal(int num);
int64_t getOldRegVal(int num);
uint64_t getPC() {return getRegVal(EIP);}
uint64_t getSP() {return getRegVal(ESP);}
bool sendState(int socket);
std::ostream &
outputStartState(std::ostream & output)
{
output << "Printing i686 initial state not yet implemented"
<< std::endl;
return output;
}
};
#endif

View File

@ -0,0 +1,473 @@
/*
* Copyright (c) 2006-2007 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* 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 <sys/ptrace.h>
#include <stdint.h>
#include <cerrno>
#include <iostream>
#include "arch/sparc/tracechild.hh"
using namespace std;
bool
SparcTraceChild::sendState(int socket)
{
uint64_t regVal = 0;
for (int x = 0; x <= I7; x++) {
regVal = getRegVal(x);
if (write(socket, &regVal, sizeof(regVal)) == -1) {
cerr << "Write failed! " << strerror(errno) << endl;
tracing = false;
return false;
}
}
regVal = getRegVal(PC);
if (write(socket, &regVal, sizeof(regVal)) == -1) {
cerr << "Write failed! " << strerror(errno) << endl;
tracing = false;
return false;
}
regVal = getRegVal(NPC);
if (write(socket, &regVal, sizeof(regVal)) == -1) {
cerr << "Write failed! " << strerror(errno) << endl;
tracing = false;
return false;
}
regVal = getRegVal(CCR);
if (write(socket, &regVal, sizeof(regVal)) == -1) {
cerr << "Write failed! " << strerror(errno) << endl;
tracing = false;
return false;
}
return true;
}
int64_t
getRegs(regs & myregs, fpu & myfpu, uint64_t * locals,
uint64_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::F2: return myfpu.f_fpstatus.fpu_fr[1];
case SparcTraceChild::F4: return myfpu.f_fpstatus.fpu_fr[2];
case SparcTraceChild::F6: return myfpu.f_fpstatus.fpu_fr[3];
case SparcTraceChild::F8: return myfpu.f_fpstatus.fpu_fr[4];
case SparcTraceChild::F10: return myfpu.f_fpstatus.fpu_fr[5];
case SparcTraceChild::F12: return myfpu.f_fpstatus.fpu_fr[6];
case SparcTraceChild::F14: return myfpu.f_fpstatus.fpu_fr[7];
case SparcTraceChild::F16: return myfpu.f_fpstatus.fpu_fr[8];
case SparcTraceChild::F18: return myfpu.f_fpstatus.fpu_fr[9];
case SparcTraceChild::F20: return myfpu.f_fpstatus.fpu_fr[10];
case SparcTraceChild::F22: return myfpu.f_fpstatus.fpu_fr[11];
case SparcTraceChild::F24: return myfpu.f_fpstatus.fpu_fr[12];
case SparcTraceChild::F26: return myfpu.f_fpstatus.fpu_fr[13];
case SparcTraceChild::F28: return myfpu.f_fpstatus.fpu_fr[14];
case SparcTraceChild::F30: return myfpu.f_fpstatus.fpu_fr[15];
case SparcTraceChild::F32: return myfpu.f_fpstatus.fpu_fr[16];
case SparcTraceChild::F34: return myfpu.f_fpstatus.fpu_fr[17];
case SparcTraceChild::F36: return myfpu.f_fpstatus.fpu_fr[18];
case SparcTraceChild::F38: return myfpu.f_fpstatus.fpu_fr[19];
case SparcTraceChild::F40: return myfpu.f_fpstatus.fpu_fr[20];
case SparcTraceChild::F42: return myfpu.f_fpstatus.fpu_fr[21];
case SparcTraceChild::F44: return myfpu.f_fpstatus.fpu_fr[22];
case SparcTraceChild::F46: return myfpu.f_fpstatus.fpu_fr[23];
case SparcTraceChild::F48: return myfpu.f_fpstatus.fpu_fr[24];
case SparcTraceChild::F50: return myfpu.f_fpstatus.fpu_fr[25];
case SparcTraceChild::F52: return myfpu.f_fpstatus.fpu_fr[26];
case SparcTraceChild::F54: return myfpu.f_fpstatus.fpu_fr[27];
case SparcTraceChild::F56: return myfpu.f_fpstatus.fpu_fr[28];
case SparcTraceChild::F58: return myfpu.f_fpstatus.fpu_fr[29];
case SparcTraceChild::F60: return myfpu.f_fpstatus.fpu_fr[30];
case SparcTraceChild::F62: 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)
{
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 = getSP();
uint64_t stackBias = 2047;
bool v9 = stackPointer % 2;
for (unsigned int x = 0; x < 8; x++) {
uint64_t localAddr = stackPointer +
(v9 ? (stackBias + x * 8) : (x * 4));
locals[x] = ptrace(PTRACE_PEEKTEXT, pid, localAddr, 0);
if (!v9) locals[x] >>= 32;
uint64_t inputAddr = stackPointer +
(v9 ? (stackBias + x * 8 + (8 * 8)) : (x * 4 + 8 * 4));
inputs[x] = ptrace(PTRACE_PEEKTEXT, pid, inputAddr, 0);
if (!v9) inputs[x] >>= 32;
}
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;
}
int
SparcTraceChild::getTargets(uint32_t inst, uint64_t pc, uint64_t npc,
uint64_t &target1, uint64_t &target2)
{
//We can identify the instruction categories we care about using the top
//10 bits of the instruction, excluding the annul bit in the 3rd most
//significant bit position and the condition field. We'll call these
//bits the "sig" for signature.
uint32_t sig = (inst >> 22) & 0x307;
uint32_t cond = (inst >> 25) & 0xf;
bool annul = (inst & (1 << 29));
//Check if it's a ba...
bool ba = (cond == 0x8) &&
(sig == 0x1 || sig == 0x2 || sig == 0x5 || sig == 0x6);
//or a bn...
bool bn = (cond == 0x0) &&
(sig == 0x1 || sig == 0x2 || sig == 0x5 || sig == 0x6);
//or a bcc
bool bcc = (cond & 0x7) &&
(sig == 0x1 || sig == 0x2 || sig == 0x3 || sig == 0x5 || sig == 0x6);
if (annul) {
if (bcc) {
target1 = npc;
target2 = npc + 4;
return 2;
} else if(ba) {
//This branches immediately to the effective address of the branch
//which we'll have to calculate.
uint64_t disp = 0;
int64_t extender = 0;
//Figure out how big the displacement field is, and grab the bits
if (sig == 0x1 || sig == 0x5) {
disp = inst & ((1 << 19) - 1);
extender = 1 << 18;
} else {
disp = inst & ((1 << 22) - 1);
extender = 1 << 21;
}
//This does sign extension, believe it or not.
disp = (disp ^ extender) - extender;
//Multiply the displacement by 4. I'm assuming the compiler is
//smart enough to turn this into a shift.
disp *= 4;
target1 = pc + disp;
} else if(bn)
target1 = npc + 4;
else
target1 = npc;
return 1;
} else {
target1 = npc;
return 1;
}
}
bool
SparcTraceChild::step()
{
//Increment the count of the number of instructions executed
instructions++;
//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.
/*
* Useful constants
*/
const static uint64_t breakInst = 0x91d02001;
const static uint64_t lowBreakInst = breakInst;
const static uint64_t highBreakInst = breakInst << 32;
const static uint64_t breakWord = breakInst | (breakInst << 32);
const static uint64_t lowMask = 0xFFFFFFFFULL;
const static uint64_t highMask = lowMask << 32;
/*
* storage for the original contents of the child process's memory
*/
uint64_t originalInst, originalAnnulInst;
/*
* Get information about where the process is and is headed next.
*/
uint64_t currentPC = getRegVal(PC);
bool unalignedPC = currentPC & 7;
uint64_t alignedPC = currentPC & (~7);
uint64_t nextPC = getRegVal(NPC);
bool unalignedNPC = nextPC & 7;
uint64_t alignedNPC = nextPC & (~7);
//Get the current instruction
uint64_t curInst = ptrace(PTRACE_PEEKTEXT, pid, alignedPC);
curInst = unalignedPC ? (curInst & 0xffffffffULL) : (curInst >> 32);
uint64_t bp1, bp2;
int numTargets = getTargets(curInst, currentPC, nextPC, bp1, bp2);
assert(numTargets == 1 || numTargets == 2);
bool unalignedBp1 = bp1 & 7;
uint64_t alignedBp1 = bp1 & (~7);
bool unalignedBp2 = bp2 & 7;
uint64_t alignedBp2 = bp2 & (~7);
uint64_t origBp1, origBp2;
/*
* Set the first breakpoint
*/
origBp1 = ptrace(PTRACE_PEEKTEXT, pid, alignedBp1, 0);
uint64_t newBp1 = origBp1;
newBp1 &= unalignedBp1 ? highMask : lowMask;
newBp1 |= unalignedBp1 ? lowBreakInst : highBreakInst;
if (ptrace(PTRACE_POKETEXT, pid, alignedBp1, newBp1) != 0)
cerr << "Poke failed" << endl;
/*
* Set the second breakpoint if necessary
*/
if (numTargets == 2) {
origBp2 = ptrace(PTRACE_PEEKTEXT, pid, alignedBp2, 0);
uint64_t newBp2 = origBp2;
newBp2 &= unalignedBp2 ? highMask : lowMask;
newBp2 |= unalignedBp2 ? lowBreakInst : highBreakInst;
if (ptrace(PTRACE_POKETEXT, pid, alignedBp2, newBp2) != 0)
cerr << "Poke failed" << endl;
}
/*
* Restart the child process
*/
//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, 1, 0) != 0)
cerr << "Cont failed" << endl;
doWait();
/*
* Update our record of the child's state
*/
update(pid);
/*
* Put back the original contents of the childs address space in the
* reverse order.
*/
if (numTargets == 2) {
if (ptrace(PTRACE_POKETEXT, pid, alignedBp2, origBp2) != 0)
cerr << "Poke failed" << endl;
}
if (ptrace(PTRACE_POKETEXT, pid, alignedBp1, origBp1) != 0)
cerr << "Poke failed" << endl;
}
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);
}
ostream &
SparcTraceChild::outputStartState(ostream & os)
{
bool v8 = false;
uint64_t sp = getSP();
if (sp % 2) {
os << "Detected a 64 bit executable.\n";
v8 = false;
} else {
os << "Detected a 32 bit executable.\n";
v8 = true;
}
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;
if (!v8) {
//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);
if (v8) regspot = regspot >> 32;
sprintf(obuf, "0x%016llx: Window save %d = 0x%016llx\n",
sp, x+1, regspot);
os << obuf;
sp += v8 ? 4 : 8;
}
//Output the argument count
uint64_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
if (v8) cargc = cargc >> 32;
sprintf(obuf, "0x%016llx: Argc = 0x%016llx\n", sp, cargc);
os << obuf;
sp += v8 ? 4 : 8;
//Output argv pointers
int argCount = 0;
uint64_t cargv;
do {
cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
if (v8) cargv = cargv >> 32;
sprintf(obuf, "0x%016llx: argv[%d] = 0x%016llx\n",
sp, argCount++, cargv);
os << obuf;
sp += v8 ? 4 : 8;
} while(cargv);
//Output the envp pointers
int envCount = 0;
uint64_t cenvp;
do {
cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
if (v8) cenvp = cenvp >> 32;
sprintf(obuf, "0x%016llx: envp[%d] = 0x%016llx\n",
sp, envCount++, cenvp);
os << obuf;
sp += v8 ? 4 : 8;
} while (cenvp);
uint64_t auxType, auxVal;
do {
auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
if (v8) auxType = auxType >> 32;
sp += (v8 ? 4 : 8);
auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
if (v8) auxVal = auxVal >> 32;
sp += (v8 ? 4 : 8);
sprintf(obuf, "0x%016llx: Auxiliary vector = {0x%016llx, 0x%016llx}\n",
sp - 8, auxType, auxVal);
os << obuf;
} while (auxType != 0 || auxVal != 0);
//Print out the argument strings, environment strings, and file name.
string current;
uint64_t buf;
uint64_t currentStart = sp;
bool clearedInitialPadding = false;
do {
buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
char * cbuf = (char *)&buf;
for (int x = 0; x < sizeof(uint32_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 += (v8 ? 4 : 8);
clearedInitialPadding = clearedInitialPadding || buf != 0;
} while (!clearedInitialPadding || buf != 0);
return os;
}
TraceChild *
genTraceChild()
{
return new SparcTraceChild;
}

View File

@ -0,0 +1,115 @@
/*
* Copyright (c) 2006-2007 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* 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 <sys/ptrace.h>
#include <sys/types.h>
#include <stdint.h>
#include <cassert>
#include <ostream>
#include <string>
#include "base/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, F2, F4, F6, F8, F10, F12, F14,
F16, F18, F20, F22, F24, F26, F28, F30,
F32, F34, F36, F38, F40, F42, F44, F46,
F48, F50, F52, F54, F56, F58, F60, F62,
//Miscelaneous
FSR, FPRS, PC, NPC, Y, CWP, PSTATE, ASI, CCR,
numregs
};
private:
regs theregs;
regs oldregs;
fpu thefpregs;
fpu oldfpregs;
uint64_t locals[8];
uint64_t oldLocals[8];
uint64_t inputs[8];
uint64_t oldInputs[8];
bool regDiffSinceUpdate[numregs];
//This calculates where the pc might go after the current instruction.
//while this equals npc for most instructions, it doesn't for all of
//them. The return value is the number of actual potential targets.
int getTargets(uint32_t inst, uint64_t pc, uint64_t npc,
uint64_t &target1, uint64_t &target2);
protected:
bool update(int pid);
public:
SparcTraceChild();
bool sendState(int socket);
int64_t getRegVal(int num);
int64_t getOldRegVal(int num);
bool step();
uint64_t
getPC()
{
return getRegVal(PC);
}
uint64_t
getSP()
{
return getRegVal(O6);
}
std::ostream & outputStartState(std::ostream & os);
};
#endif

View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2006-2007 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* 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 __STATETRACE_ALPHA__
#if !defined __alpha__
#error "Alpha toolchain required."
#endif
#elif defined __STATETRACE_AMD64__
#if !defined __amd64__
#error "Amd64 toolchain required."
#endif
#elif defined __STATETRACE_ARM__
#if !defined __arm__
#error "Arm toolchain required."
#endif
#elif defined __STATETRACE_HPPA__
#if !defined __hppa__
#error "Hppa toolchain required."
#endif
#elif defined __STATETRACE_I686__
#if !(defined __i386__ || defined __i486__ || \
defined __i586__ || defined __i686__)
#error "I686 toolchain required."
#endif
#elif defined __STATETRACE_IA64__
#if !defined __ia64__
#error "IA64 toolchain required."
#endif
#elif defined __STATETRACE_MIPS__
#if !defined __mips__
#error "Mips toolchain required."
#endif
#elif defined __STATETRACE_POWERPC__
#if !defined __powerpc__
#error "PowerPC toolchain required."
#endif
#elif defined __STATETRACE_SPARC__
#if !defined __sparc__
#error "Sparc toolchain required."
#endif
#elif defined __STATETRACE_SH__
#if !defined __sh__
#error "SuperH toolchain required."
#endif
#elif defined __STATETRACE__S390__
#if !defined __s390__
#error "System/390 toolchain required."
#endif
#else
#error "Couldn't determine architecture."
#endif

View File

@ -0,0 +1,47 @@
/*
* 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 <stdint.h>
#include <string>
class RegState
{
protected:
virtual bool update(int pid) = 0;
public:
virtual int64_t getRegVal(int num) = 0;
virtual int64_t getOldRegVal(int num) = 0;
};
#endif

View File

@ -0,0 +1,156 @@
/*
* Copyright (c) 2006-2007 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* 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 <netinet/in.h>
#include <sys/ptrace.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netdb.h>
#include <unistd.h>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
#include "base/arch_check.h"
#include "tracechild.hh"
using namespace std;
void
printUsage(const char * execName)
{
cout << execName << " <options> -- <command> <arguments>" << endl;
cout << "options:" << endl;
cout << " -h print this help" << endl;
cout << " --host remote m5 host to connect to" << endl;
cout << " -i print initial stack state" << endl;
cout << " -nt don't trace execution" << endl;
}
int
main(int argc, char * argv[], char * envp[])
{
TraceChild * child = genTraceChild();
string args;
int startProgramArgs;
//Parse the command line arguments
bool printInitial = false;
bool printTrace = true;
string host = "localhost";
if (argc == 1) {
printUsage(argv[0]);
return 0;
}
for (int x = 1; x < argc; x++) {
if (!strcmp(argv[x], "-h")) {
printUsage(argv[0]);
return 0;
}
if (!strcmp(argv[x], "--host")) {
x++;
if (x >= argc) {
cerr << "Incorrect usage.\n" << endl;
printUsage(argv[0]);
return 1;
}
host = argv[x];
} 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;
}
}
if (!child->startTracing(argv[startProgramArgs],
argv + startProgramArgs)) {
cerr << "Couldn't start target program" << endl;
return 1;
}
child->step();
if (printInitial)
child->outputStartState(cout);
if (printTrace) {
// Connect to m5
bool portSet = false;
int port;
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
cerr << "Error opening socket! " << strerror(errno) << endl;
return 1;
}
struct hostent *server;
server = gethostbyname(host.c_str());
if (!server) {
cerr << "Couldn't get host ip! " << strerror(errno) << endl;
return 1;
}
struct sockaddr_in serv_addr;
bzero((char *)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(8000);
if (connect(sock, (sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
cerr << "Couldn't connect to server! " << strerror(errno) << endl;
return 1;
}
while (child->isTracing()) {
if (!child->sendState(sock))
break;
child->step();
}
}
if (!child->stopTracing()) {
cerr << "Couldn't stop child" << endl;
return 1;
}
return 0;
}

View File

@ -0,0 +1,149 @@
/*
* Copyright (c) 2006-2007 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* 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 <sys/ptrace.h>
#include <sys/wait.h>
#include <cerrno>
#include <cstring>
#include <iostream>
#include "tracechild.hh"
using namespace std;
bool
TraceChild::startTracing(const char * pathToFile, char * const argv[])
{
instructions = 0;
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
if (ptrace(PTRACE_TRACEME, 0, 0, 0) == -1) {
cout << "Failure calling TRACEME\n" << strerror(errno) << endl;
return false;
}
//Set up an empty environment for the child... We would want to
//specify this somehow at some point
char * env[] = {NULL};
//Start the program to trace
execve(pathToFile, argv, env);
//We should never get here, so this is an error!
cout << "Exec failed\n" << strerror(errno) << endl;
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;
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;
cerr << "Executed " << instructions
<< " instructions." << 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;
cerr << "Executed " << instructions
<< " instructions." << endl;
return false;
}
if (WIFSTOPPED(wait_val) && WSTOPSIG(wait_val) != SIGTRAP) {
cerr << "Program stopped by signal " << WSTOPSIG(wait_val) << endl;
tracing = false;
cerr << "Executed " << instructions << " instructions." << endl;
return false;
}
return true;
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2006-2007 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* 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 "base/regstate.hh"
class TraceChild : public RegState
{
protected:
int pid;
uint64_t instructions;
bool tracing;
public:
TraceChild() : tracing(false), instructions(0)
{;}
virtual bool sendState(int socket) = 0;
virtual bool startTracing(const char * pathToFile, char * const argv[]);
virtual bool stopTracing();
virtual bool step();
virtual std::ostream & outputStartState(std::ostream & os) = 0;
bool
isTracing()
{
return tracing;
}
protected:
bool ptraceSingleStep();
bool doWait();
};
TraceChild * genTraceChild();
#endif