merge mips fix and statetrace changes

This commit is contained in:
Korey Sewell
2009-07-31 10:40:42 -04:00
31 changed files with 1076 additions and 128 deletions

View File

@@ -0,0 +1,37 @@
# 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: Gabe Black
from m5.SimObject import SimObject
from m5.params import *
from NativeTrace import NativeTrace
class ArmNativeTrace(NativeTrace):
type = 'ArmNativeTrace'
cxx_class = 'Trace::ArmNativeTrace'
stop_on_pc_error = Param.Bool(True,
"Stop M5 if it and statetrace's pcs are different")

View File

@@ -39,11 +39,14 @@ if env['TARGET_ISA'] == 'arm':
Source('insts/mem.cc')
Source('insts/pred_inst.cc')
Source('insts/static_inst.cc')
Source('nativetrace.cc')
Source('pagetable.cc')
Source('tlb.cc')
Source('vtophys.cc')
SimObject('ArmNativeTrace.py')
SimObject('ArmTLB.py')
TraceFlag('Arm')
if env['FULL_SYSTEM']:

View File

@@ -48,7 +48,11 @@ namespace ArmISA
public:
void clear()
{
// Unknown startup state currently
memset(miscRegs, 0, sizeof(miscRegs));
CPSR cpsr = 0;
cpsr.mode = MODE_USER;
miscRegs[MISCREG_CPSR] = cpsr;
//XXX We need to initialize the rest of the state.
}
MiscReg

View File

@@ -113,8 +113,7 @@ format DataOp {
0x1: decode OPCODE {
0x9: BranchExchange::bx({{ }});
0xb: PredOp::clz({{
unsigned lsb = findLsbSet(Rm);
Rd = (lsb > 31) ? 32 : lsb;
Rd = ((Rm == 0) ? 32 : (31 - findMsbSet(Rm)));
}});
}
0x2: decode OPCODE {
@@ -319,6 +318,10 @@ format DataOp {
0x12,0x16,0x1a,0x1e: ArmMacroFMOp::sfm_pw({{ }});
0x13,0x17,0x1b,0x1f: ArmMacroFMOp::lfm_pw({{ }});
}
0xb: decode LOADOP {
0x0: WarnUnimpl::fstmx();
0x1: WarnUnimpl::fldmx();
}
}
0x7: decode OPCODE_24 {
0: decode CPNUM {
@@ -417,12 +420,29 @@ format DataOp {
}
}
}
0xa: decode MISC_OPCODE {
0x1: decode MEDIA_OPCODE {
0xf: decode RN {
0x0: FloatOp::fmrx_fpsid({{ Rd = Fpsid; }});
0x1: FloatOp::fmrx_fpscr({{ Rd = Fpscr; }});
0x8: FloatOp::fmrx_fpexc({{ Rd = Fpexc; }});
}
0xe: decode RN {
0x0: FloatOp::fmxr_fpsid({{ Fpsid = Rd; }});
0x1: FloatOp::fmxr_fpscr({{ Fpscr = Rd; }});
0x8: FloatOp::fmxr_fpexc({{ Fpexc = Rd; }});
}
}
}
}
format PredOp {
// ARM System Call (SoftWare Interrupt)
1: swi({{ if (testPredicate(Cpsr, condCode))
{
xc->syscall(IMMED_23_0);
if (IMMED_23_0)
xc->syscall(IMMED_23_0);
else
xc->syscall(R7);
}
}});
}

View File

@@ -105,7 +105,8 @@ let {{
def getCcCode(flagtype):
icReg = icImm = iv = ''
if flagtype == "none":
icReg = icImm = iv = '1'
icReg = icImm = 'Cpsr<29:>'
iv = 'Cpsr<28:>'
elif flagtype == "add":
icReg = icImm = 'findCarry(32, resTemp, Rn, op2)'
iv = 'findOverflow(32, resTemp, Rn, op2)'
@@ -125,7 +126,8 @@ let {{
def getImmCcCode(flagtype):
ivValue = icValue = ''
if flagtype == "none":
icValue = ivValue = '1'
icValue = 'Cpsr<29:>'
ivValue = 'Cpsr<28:>'
elif flagtype == "add":
icValue = 'findCarry(32, resTemp, Rn, rotated_imm)'
ivValue = 'findOverflow(32, resTemp, Rn, rotated_imm)'

View File

@@ -57,6 +57,7 @@ def operands {{
'Rm': ('IntReg', 'uw', 'RM', 'IsInteger', 2, maybePCRead, maybePCWrite),
'Rs': ('IntReg', 'uw', 'RS', 'IsInteger', 3, maybePCRead, maybePCWrite),
'Rn': ('IntReg', 'uw', 'RN', 'IsInteger', 4, maybePCRead, maybePCWrite),
'R7': ('IntReg', 'uw', '7', 'IsInteger', 5),
#Destination register for load/store double instructions
'Rdo': ('IntReg', 'uw', '(RD & ~1)', 'IsInteger', 4, maybePCRead, maybePCWrite),
@@ -81,7 +82,10 @@ def operands {{
'Cpsr': ('ControlReg', 'uw', 'MISCREG_CPSR', 'IsInteger', 40),
'Fpsr': ('ControlReg', 'uw', 'MISCREG_FPSR', 'IsInteger', 41),
'NPC': ('NPC', 'uw', None, (None, None, 'IsControl'), 42),
'NNPC': ('NNPC', 'uw', None, (None, None, 'IsControl'), 43),
'Fpsid': ('ControlReg', 'uw', 'MISCREG_FPSID', 'IsInteger', 42),
'Fpscr': ('ControlReg', 'uw', 'MISCREG_FPSCR', 'IsInteger', 43),
'Fpexc': ('ControlReg', 'uw', 'MISCREG_FPEXC', 'IsInteger', 44),
'NPC': ('NPC', 'uw', None, (None, None, 'IsControl'), 45),
'NNPC': ('NNPC', 'uw', None, (None, None, 'IsControl'), 46)
}};

View File

@@ -66,18 +66,7 @@ class ArmLinux : public Linux
//@}
/// For mmap().
static const unsigned TGT_MAP_ANONYMOUS = 0x800;
//@{
/// For getsysinfo().
static const unsigned GSI_PLATFORM_NAME = 103; //!< platform name as string
static const unsigned GSI_CPU_INFO = 59; //!< CPU information
static const unsigned GSI_PROC_TYPE = 60; //!< get proc_type
static const unsigned GSI_MAX_CPU = 30; //!< max # cpu's on this machine
static const unsigned GSI_CPUS_IN_BOX = 55; //!< number of CPUs in system
static const unsigned GSI_PHYSMEM = 19; //!< Physical memory in KB
static const unsigned GSI_CLK_TCK = 42; //!< clock freq in Hz
//@}
static const unsigned TGT_MAP_ANONYMOUS = 0x20;
//@{
/// For getrusage().
@@ -86,14 +75,9 @@ class ArmLinux : public Linux
static const int TGT_RUSAGE_BOTH = -2;
//@}
//@{
/// For setsysinfo().
static const unsigned SSI_IEEE_FP_CONTROL = 14; //!< ieee_set_fp_control()
//@}
//@{
/// ioctl() command codes.
static const unsigned TIOCGETP_ = 0x40067408;
static const unsigned TIOCGETP_ = 0x5401;
static const unsigned TIOCSETP_ = 0x80067409;
static const unsigned TIOCSETN_ = 0x8006740a;
static const unsigned TIOCSETC_ = 0x80067411;
@@ -114,15 +98,56 @@ class ArmLinux : public Linux
TGT_RLIMIT_DATA = 2,
TGT_RLIMIT_STACK = 3,
TGT_RLIMIT_CORE = 4,
TGT_RLIMIT_NOFILE = 5,
TGT_RLIMIT_AS = 6,
TGT_RLIMIT_RSS = 7,
TGT_RLIMIT_VMEM = 7,
TGT_RLIMIT_NPROC = 8,
TGT_RLIMIT_MEMLOCK = 9,
TGT_RLIMIT_RSS = 5,
TGT_RLIMIT_NPROC = 6,
TGT_RLIMIT_NOFILE = 7,
TGT_RLIMIT_MEMLOCK = 8,
TGT_RLIMIT_AS = 9,
TGT_RLIMIT_LOCKS = 10
};
typedef struct {
uint32_t st_dev;
uint32_t st_ino;
uint16_t st_mode;
uint16_t st_nlink;
uint16_t st_uid;
uint16_t st_gid;
uint32_t st_rdev;
uint32_t st_size;
uint32_t st_blksize;
uint32_t st_blocks;
uint32_t st_atimeX;
uint32_t st_atime_nsec;
uint32_t st_mtimeX;
uint32_t st_mtime_nsec;
uint32_t st_ctimeX;
uint32_t st_ctime_nsec;
} tgt_stat;
typedef struct {
uint64_t st_dev;
uint8_t __pad0[4];
uint32_t __st_ino;
uint32_t st_mode;
uint32_t st_nlink;
uint32_t st_uid;
uint32_t st_gid;
uint64_t st_rdev;
uint8_t __pad3[4];
int64_t __attribute__ ((aligned (8))) st_size;
uint32_t st_blksize;
uint64_t __attribute__ ((aligned (8))) st_blocks;
uint32_t st_atimeX;
uint32_t st_atime_nsec;
uint32_t st_mtimeX;
uint32_t st_mtime_nsec;
uint32_t st_ctimeX;
uint32_t st_ctime_nsec;
uint64_t st_ino;
} tgt_stat64;
};
#endif

View File

@@ -106,7 +106,7 @@ SyscallDesc ArmLinuxProcess::syscallDescs[] = {
/* 40 */ SyscallDesc("rmdir", unimplementedFunc),
/* 41 */ SyscallDesc("dup", unimplementedFunc),
/* 42 */ SyscallDesc("pipe", unimplementedFunc),
/* 43 */ SyscallDesc("times", unimplementedFunc),
/* 43 */ SyscallDesc("times", ignoreFunc),
/* 44 */ SyscallDesc("prof", unimplementedFunc),
/* 45 */ SyscallDesc("brk", brkFunc),
/* 46 */ SyscallDesc("setgid", unimplementedFunc),
@@ -260,7 +260,7 @@ SyscallDesc ArmLinuxProcess::syscallDescs[] = {
/* 194 */ SyscallDesc("ftruncate64", unimplementedFunc),
/* 195 */ SyscallDesc("stat64", unimplementedFunc),
/* 196 */ SyscallDesc("lstat64", lstat64Func<ArmLinux>),
/* 197 */ SyscallDesc("fstat64", fstatFunc<ArmLinux>),
/* 197 */ SyscallDesc("fstat64", fstat64Func<ArmLinux>),
/* 198 */ SyscallDesc("lchown", unimplementedFunc),
/* 199 */ SyscallDesc("getuid", getuidFunc),
/* 200 */ SyscallDesc("getgid", getgidFunc),
@@ -418,7 +418,6 @@ setTLSFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
uint32_t tlsPtr = process->getSyscallArg(tc, 0);
TypedBufferArg<Linux::utsname> name(process->getSyscallArg(tc, 0));
tc->getMemPort()->writeBlob(ArmLinuxProcess::commPage + 0x0ff0,
(uint8_t *)&tlsPtr, sizeof(tlsPtr));
@@ -448,7 +447,8 @@ ArmLinuxProcess::getDesc(int callnum)
// Angel SWI syscalls are unsupported in this release
if (callnum == 0x123456) {
panic("Attempt to execute an ANGEL_SWI system call (newlib-related)");
} else if ((callnum & 0x00f00000) == 0x00900000) {
} else if ((callnum & 0x00f00000) == 0x00900000 ||
(callnum & 0xf0000) == 0xf0000) {
callnum &= 0x000fffff;
if ((callnum & 0x0f0000) == 0xf0000) {
callnum -= 0x0f0001;
@@ -496,7 +496,7 @@ ArmLinuxProcess::startup()
{
0x00, 0x30, 0x92, 0xe5, //ldr r3, [r2]
0x00, 0x30, 0x53, 0xe0, //subs r3, r3, r0
0x00, 0x10, 0x92, 0x05, //streq r1, [r2]
0x00, 0x10, 0x82, 0x05, //streq r1, [r2]
0x03, 0x00, 0xa0, 0xe1, //mov r0, r3
0x0e, 0xf0, 0xa0, 0xe1 //usr_ret lr
};

View File

@@ -62,6 +62,9 @@ namespace ArmISA
MISCREG_SPSR_UND,
MISCREG_SPSR_ABT,
MISCREG_FPSR,
MISCREG_FPSID,
MISCREG_FPSCR,
MISCREG_FPEXC,
NUM_MISCREGS
};

183
src/arch/arm/nativetrace.cc Normal file
View File

@@ -0,0 +1,183 @@
/*
* 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 "arch/arm/isa_traits.hh"
#include "arch/arm/miscregs.hh"
#include "arch/arm/nativetrace.hh"
#include "cpu/thread_context.hh"
#include "params/ArmNativeTrace.hh"
namespace Trace {
#if TRACING_ON
static const char *regNames[] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "fp", "r12", "sp", "lr", "pc",
"cpsr"
};
#endif
void
Trace::ArmNativeTrace::ThreadState::update(NativeTrace *parent)
{
oldState = state[current];
current = (current + 1) % 2;
newState = state[current];
memcpy(newState, oldState, sizeof(state[0]));
uint32_t diffVector;
parent->read(&diffVector, sizeof(diffVector));
diffVector = ArmISA::gtoh(diffVector);
int changes = 0;
for (int i = 0; i < STATE_NUMVALS; i++) {
if (diffVector & 0x1) {
changed[i] = true;
changes++;
} else {
changed[i] = false;
}
diffVector >>= 1;
}
uint32_t values[changes];
parent->read(values, sizeof(values));
int pos = 0;
for (int i = 0; i < STATE_NUMVALS; i++) {
if (changed[i]) {
newState[i] = ArmISA::gtoh(values[pos++]);
changed[i] = (newState[i] != oldState[i]);
}
}
}
void
Trace::ArmNativeTrace::ThreadState::update(ThreadContext *tc)
{
oldState = state[current];
current = (current + 1) % 2;
newState = state[current];
// Regular int regs
for (int i = 0; i < 15; i++) {
newState[i] = tc->readIntReg(i);
changed[i] = (oldState[i] != newState[i]);
}
//R15, aliased with the PC
newState[STATE_PC] = tc->readNextPC();
changed[STATE_PC] = (newState[STATE_PC] != oldState[STATE_PC]);
//CPSR
newState[STATE_CPSR] = tc->readMiscReg(MISCREG_CPSR);
changed[STATE_CPSR] = (newState[STATE_CPSR] != oldState[STATE_CPSR]);
}
void
Trace::ArmNativeTrace::check(NativeTraceRecord *record)
{
ThreadContext *tc = record->getThread();
// This area is read only on the target. It can't stop there to tell us
// what's going on, so we should skip over anything there also.
if (tc->readNextPC() > 0xffff0000)
return;
nState.update(this);
mState.update(tc);
bool errorFound = false;
// Regular int regs
for (int i = 0; i < STATE_NUMVALS; i++) {
if (nState.changed[i] || mState.changed[i]) {
const char *vergence = " ";
bool oldMatch = (mState.oldState[i] == nState.oldState[i]);
bool newMatch = (mState.newState[i] == nState.newState[i]);
if (oldMatch && newMatch) {
// The more things change, the more they stay the same.
continue;
} else if (oldMatch && !newMatch) {
vergence = "<>";
} else if (!oldMatch && newMatch) {
vergence = "><";
}
errorFound = true;
if (!nState.changed[i]) {
DPRINTF(ExecRegDelta, "%s [%5s] "\
"Native: %#010x "\
"M5: %#010x => %#010x\n",
vergence, regNames[i],
nState.newState[i],
mState.oldState[i], mState.newState[i]);
} else if (!mState.changed[i]) {
DPRINTF(ExecRegDelta, "%s [%5s] "\
"Native: %#010x => %#010x "\
"M5: %#010x \n",
vergence, regNames[i],
nState.oldState[i], nState.newState[i],
mState.newState[i]);
} else {
DPRINTF(ExecRegDelta, "%s [%5s] "\
"Native: %#010x => %#010x "\
"M5: %#010x => %#010x\n",
vergence, regNames[i],
nState.oldState[i], nState.newState[i],
mState.oldState[i], mState.newState[i]);
}
}
}
if (errorFound) {
StaticInstPtr inst = record->getStaticInst();
assert(inst);
bool ran = true;
if (inst->isMicroop()) {
ran = false;
inst = record->getMacroStaticInst();
}
assert(inst);
record->traceInst(inst, ran);
bool pcError = (mState.newState[STATE_PC] !=
nState.newState[STATE_PC]);
if (stopOnPCError && pcError)
panic("Native trace detected an error in control flow!");
}
}
} /* namespace Trace */
////////////////////////////////////////////////////////////////////////
//
// ExeTracer Simulation Object
//
Trace::ArmNativeTrace *
ArmNativeTraceParams::create()
{
return new Trace::ArmNativeTrace(this);
};

112
src/arch/arm/nativetrace.hh Normal file
View File

@@ -0,0 +1,112 @@
/*
* 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 __ARCH_ARM_NATIVETRACE_HH__
#define __ARCH_ARM_NATIVETRACE_HH__
#include "base/types.hh"
#include "cpu/nativetrace.hh"
#include "params/ArmNativeTrace.hh"
namespace Trace {
class ArmNativeTrace : public NativeTrace
{
public:
enum StateID {
STATE_R0,
STATE_R1,
STATE_R2,
STATE_R3,
STATE_R4,
STATE_R5,
STATE_R6,
STATE_R7,
STATE_R8,
STATE_R9,
STATE_R10,
STATE_R11,
STATE_FP = STATE_R11,
STATE_R12,
STATE_R13,
STATE_SP = STATE_R13,
STATE_R14,
STATE_LR = STATE_R14,
STATE_R15,
STATE_PC = STATE_R15,
STATE_CPSR,
STATE_NUMVALS
};
protected:
struct ThreadState {
bool changed[STATE_NUMVALS];
uint32_t state[2][STATE_NUMVALS];
uint32_t *newState;
uint32_t *oldState;
int current;
void update(NativeTrace *parent);
void update(ThreadContext *tc);
ThreadState()
{
for (int i = 0; i < STATE_NUMVALS; i++) {
changed[i] = false;
state[0][i] = state[1][i] = 0;
current = 0;
newState = state[0];
oldState = state[1];
}
}
};
ThreadState nState, mState;
bool stopOnPCError;
public:
typedef ArmNativeTraceParams Params;
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
ArmNativeTrace(const Params *p) :
NativeTrace(p), stopOnPCError(p->stop_on_pc_error)
{}
void check(NativeTraceRecord *record);
};
} /* namespace Trace */
#endif // __ARCH_ARM_NATIVETRACE_HH__

View File

@@ -46,7 +46,7 @@ using namespace ArmISA;
ArmLiveProcess::ArmLiveProcess(LiveProcessParams *params, ObjectFile *objFile)
: LiveProcess(params, objFile)
{
stack_base = 0xc0000000L;
stack_base = 0xbf000000L;
// Set pointer for next thread stack. Reserve 8M for main stack.
next_thread_stack_base = stack_base - (8 * 1024 * 1024);
@@ -88,73 +88,239 @@ ArmLiveProcess::copyStringArray32(std::vector<std::string> &strings,
void
ArmLiveProcess::argsInit(int intSize, int pageSize)
{
typedef AuxVector<uint32_t> auxv_t;
std::vector<auxv_t> auxv;
string filename;
if (argv.size() < 1)
filename = "";
else
filename = argv[0];
//We want 16 byte alignment
uint64_t align = 16;
// Overloaded argsInit so that we can fine-tune for ARM architecture
Process::startup();
// load object file into target memory
objFile->loadSections(initVirtMem);
// Calculate how much space we need for arg & env arrays.
int argv_array_size = intSize * (argv.size() + 1);
int envp_array_size = intSize * (envp.size() + 1);
int arg_data_size = 0;
for (int i = 0; i < argv.size(); ++i) {
arg_data_size += argv[i].size() + 1;
enum ArmCpuFeature {
Arm_Swp = 1 << 0,
Arm_Half = 1 << 1,
Arm_Thumb = 1 << 2,
Arm_26Bit = 1 << 3,
Arm_FastMult = 1 << 4,
Arm_Fpa = 1 << 5,
Arm_Vfp = 1 << 6,
Arm_Edsp = 1 << 7,
Arm_Java = 1 << 8,
Arm_Iwmmxt = 1 << 9,
Arm_Crunch = 1 << 10
};
//Setup the auxilliary vectors. These will already have endian conversion.
//Auxilliary vectors are loaded only for elf formatted executables.
ElfObject * elfObject = dynamic_cast<ElfObject *>(objFile);
if (elfObject) {
uint32_t features =
Arm_Swp |
Arm_Half |
Arm_Thumb |
// Arm_26Bit |
Arm_FastMult |
// Arm_Fpa |
Arm_Vfp |
Arm_Edsp |
Arm_Java |
// Arm_Iwmmxt |
// Arm_Crunch |
0;
//Bits which describe the system hardware capabilities
//XXX Figure out what these should be
auxv.push_back(auxv_t(M5_AT_HWCAP, features));
//The system page size
auxv.push_back(auxv_t(M5_AT_PAGESZ, ArmISA::VMPageSize));
//Frequency at which times() increments
auxv.push_back(auxv_t(M5_AT_CLKTCK, 0x64));
// For statically linked executables, this is the virtual address of the
// program header tables if they appear in the executable image
auxv.push_back(auxv_t(M5_AT_PHDR, elfObject->programHeaderTable()));
// This is the size of a program header entry from the elf file.
auxv.push_back(auxv_t(M5_AT_PHENT, elfObject->programHeaderSize()));
// This is the number of program headers from the original elf file.
auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount()));
//This is the address of the elf "interpreter", It should be set
//to 0 for regular executables. It should be something else
//(not sure what) for dynamic libraries.
auxv.push_back(auxv_t(M5_AT_BASE, 0));
//XXX Figure out what this should be.
auxv.push_back(auxv_t(M5_AT_FLAGS, 0));
//The entry point to the program
auxv.push_back(auxv_t(M5_AT_ENTRY, objFile->entryPoint()));
//Different user and group IDs
auxv.push_back(auxv_t(M5_AT_UID, uid()));
auxv.push_back(auxv_t(M5_AT_EUID, euid()));
auxv.push_back(auxv_t(M5_AT_GID, gid()));
auxv.push_back(auxv_t(M5_AT_EGID, egid()));
//Whether to enable "secure mode" in the executable
auxv.push_back(auxv_t(M5_AT_SECURE, 0));
//The filename of the program
auxv.push_back(auxv_t(M5_AT_EXECFN, 0));
//The string "v51" with unknown meaning
auxv.push_back(auxv_t(M5_AT_PLATFORM, 0));
}
//Figure out how big the initial stack nedes to be
// A sentry NULL void pointer at the top of the stack.
int sentry_size = intSize;
string platform = "v51";
int platform_size = platform.size() + 1;
// The aux vectors are put on the stack in two groups. The first group are
// the vectors that are generated as the elf is loaded. The second group
// are the ones that were computed ahead of time and include the platform
// string.
int aux_data_size = filename.size() + 1;
int env_data_size = 0;
for (int i = 0; i < envp.size(); ++i) {
env_data_size += envp[i].size() + 1;
}
int arg_data_size = 0;
for (int i = 0; i < argv.size(); ++i) {
arg_data_size += argv[i].size() + 1;
}
int space_needed =
argv_array_size + envp_array_size + arg_data_size + env_data_size;
if (space_needed < 16*1024)
space_needed = 16*1024;
int info_block_size =
sentry_size + env_data_size + arg_data_size +
aux_data_size + platform_size;
//Each auxilliary vector is two 4 byte words
int aux_array_size = intSize * 2 * (auxv.size() + 1);
int envp_array_size = intSize * (envp.size() + 1);
int argv_array_size = intSize * (argv.size() + 1);
int argc_size = intSize;
//Figure out the size of the contents of the actual initial frame
int frame_size =
info_block_size +
aux_array_size +
envp_array_size +
argv_array_size +
argc_size;
//There needs to be padding after the auxiliary vector data so that the
//very bottom of the stack is aligned properly.
int partial_size = frame_size;
int aligned_partial_size = roundUp(partial_size, align);
int aux_padding = aligned_partial_size - partial_size;
int space_needed = frame_size + aux_padding;
// set bottom of stack
stack_min = stack_base - space_needed;
// align it
stack_min = roundDown(stack_min, pageSize);
stack_min = roundDown(stack_min, align);
stack_size = stack_base - stack_min;
// map memory
pTable->allocate(stack_min, roundUp(stack_size, pageSize));
pTable->allocate(roundDown(stack_min, pageSize),
roundUp(stack_size, pageSize));
// map out initial stack contents
Addr argv_array_base = stack_min + intSize; // room for argc
Addr envp_array_base = argv_array_base + argv_array_size;
Addr arg_data_base = envp_array_base + envp_array_size;
Addr env_data_base = arg_data_base + arg_data_size;
uint32_t sentry_base = stack_base - sentry_size;
uint32_t aux_data_base = sentry_base - aux_data_size;
uint32_t env_data_base = aux_data_base - env_data_size;
uint32_t arg_data_base = env_data_base - arg_data_size;
uint32_t platform_base = arg_data_base - platform_size;
uint32_t auxv_array_base = platform_base - aux_array_size - aux_padding;
uint32_t envp_array_base = auxv_array_base - envp_array_size;
uint32_t argv_array_base = envp_array_base - argv_array_size;
uint32_t argc_base = argv_array_base - argc_size;
DPRINTF(Stack, "The addresses of items on the initial stack:\n");
DPRINTF(Stack, "0x%x - aux data\n", aux_data_base);
DPRINTF(Stack, "0x%x - env data\n", env_data_base);
DPRINTF(Stack, "0x%x - arg data\n", arg_data_base);
DPRINTF(Stack, "0x%x - platform base\n", platform_base);
DPRINTF(Stack, "0x%x - auxv array\n", auxv_array_base);
DPRINTF(Stack, "0x%x - envp array\n", envp_array_base);
DPRINTF(Stack, "0x%x - argv array\n", argv_array_base);
DPRINTF(Stack, "0x%x - argc \n", argc_base);
DPRINTF(Stack, "0x%x - stack min\n", stack_min);
// write contents to stack
uint64_t argc = argv.size();
if (intSize == 8)
argc = htog((uint64_t)argc);
else if (intSize == 4)
argc = htog((uint32_t)argc);
else
panic("Unknown int size");
initVirtMem->writeBlob(stack_min, (uint8_t*)&argc, intSize);
// figure out argc
uint32_t argc = argv.size();
uint32_t guestArgc = ArmISA::htog(argc);
copyStringArray32(argv, argv_array_base, arg_data_base, initVirtMem);
copyStringArray32(envp, envp_array_base, env_data_base, initVirtMem);
//Write out the sentry void *
uint32_t sentry_NULL = 0;
initVirtMem->writeBlob(sentry_base,
(uint8_t*)&sentry_NULL, sentry_size);
/*
//uint8_t insns[] = {0xe5, 0x9f, 0x00, 0x08, 0xe1, 0xa0, 0xf0, 0x0e};
uint8_t insns[] = {0x08, 0x00, 0x9f, 0xe5, 0x0e, 0xf0, 0xa0, 0xe1};
//Fix up the aux vectors which point to other data
for (int i = auxv.size() - 1; i >= 0; i--) {
if (auxv[i].a_type == M5_AT_PLATFORM) {
auxv[i].a_val = platform_base;
initVirtMem->writeString(platform_base, platform.c_str());
} else if (auxv[i].a_type == M5_AT_EXECFN) {
auxv[i].a_val = aux_data_base;
initVirtMem->writeString(aux_data_base, filename.c_str());
}
}
initVirtMem->writeBlob(0xffff0fe0, insns, 8);
*/
//Copy the aux stuff
for(int x = 0; x < auxv.size(); x++)
{
initVirtMem->writeBlob(auxv_array_base + x * 2 * intSize,
(uint8_t*)&(auxv[x].a_type), intSize);
initVirtMem->writeBlob(auxv_array_base + (x * 2 + 1) * intSize,
(uint8_t*)&(auxv[x].a_val), intSize);
}
//Write out the terminating zeroed auxilliary vector
const uint64_t zero = 0;
initVirtMem->writeBlob(auxv_array_base + 2 * intSize * auxv.size(),
(uint8_t*)&zero, 2 * intSize);
copyStringArray(envp, envp_array_base, env_data_base, initVirtMem);
copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem);
initVirtMem->writeBlob(argc_base, (uint8_t*)&guestArgc, intSize);
ThreadContext *tc = system->getThreadContext(contextIds[0]);
tc->setIntReg(ArgumentReg1, argc);
tc->setIntReg(ArgumentReg2, argv_array_base);
//Set the stack pointer register
tc->setIntReg(StackPointerReg, stack_min);
//A pointer to a function to run when the program exits. We'll set this
//to zero explicitly to make sure this isn't used.
tc->setIntReg(ArgumentReg0, 0);
//Set argument regs 1 and 2 to argv[0] and envp[0] respectively
if (argv.size() > 0) {
tc->setIntReg(ArgumentReg1, arg_data_base + arg_data_size -
argv[argv.size() - 1].size() - 1);
} else {
tc->setIntReg(ArgumentReg1, 0);
}
if (envp.size() > 0) {
tc->setIntReg(ArgumentReg2, env_data_base + env_data_size -
envp[envp.size() - 1].size() - 1);
} else {
tc->setIntReg(ArgumentReg2, 0);
}
Addr prog_entry = objFile->entryPoint();
tc->setPC(prog_entry);
tc->setNextPC(prog_entry + sizeof(MachInst));
//Align the "stack_min" to a page boundary.
stack_min = roundDown(stack_min, pageSize);
}
ArmISA::IntReg

View File

@@ -118,7 +118,7 @@ forkThread(TC *tc, Fault &fault, int Rd_bits, int Rs, int Rt)
tc->readRegOtherThread(MISCREG_TC_BIND + Ctrl_Base_DepTag, tid);
TCBindReg tcBind = tc->readMiscRegNoEffect(MISCREG_TC_BIND);
if (tidTCBind.curVPE = tcBind.curVPE) {
if (tidTCBind.curVPE == tcBind.curVPE) {
TCStatusReg tidTCStatus =
tc->readRegOtherThread(MISCREG_TC_STATUS +

View File

@@ -107,7 +107,6 @@ ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data)
{
case ELFOSABI_LINUX:
case ELFOSABI_ARM:
opSys = ObjectFile::Linux;
break;
case ELFOSABI_SOLARIS:
@@ -116,6 +115,9 @@ ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data)
case ELFOSABI_TRU64:
opSys = ObjectFile::Tru64;
break;
case ELFOSABI_ARM:
opSys = ObjectFile::LinuxArmOABI;
break;
default:
opSys = ObjectFile::UnknownOpSys;
}

View File

@@ -59,7 +59,8 @@ class ObjectFile
UnknownOpSys,
Tru64,
Linux,
Solaris
Solaris,
LinuxArmOABI
};
protected:

View File

@@ -28,9 +28,9 @@
from m5.SimObject import SimObject
from m5.params import *
from InstTracer import InstTracer
from ExeTracer import ExeTracer
class NativeTrace(InstTracer):
class NativeTrace(ExeTracer):
abstract = True
type = 'NativeTrace'
cxx_class = 'Trace::NativeTrace'

View File

@@ -38,7 +38,7 @@ using namespace std;
namespace Trace {
NativeTrace::NativeTrace(const Params *p)
: InstTracer(p)
: ExeTracer(p)
{
if (ListenSocket::allDisabled())
fatal("All listeners are disabled!");

View File

@@ -37,8 +37,8 @@
#include "base/socket.hh"
#include "base/trace.hh"
#include "base/types.hh"
#include "cpu/exetrace.hh"
#include "cpu/static_inst.hh"
#include "sim/insttracer.hh"
class ThreadContext;
@@ -46,7 +46,7 @@ namespace Trace {
class NativeTrace;
class NativeTraceRecord : public InstRecord
class NativeTraceRecord : public ExeTracerRecord
{
protected:
NativeTrace * parent;
@@ -56,7 +56,7 @@ class NativeTraceRecord : public InstRecord
Tick _when, ThreadContext *_thread,
const StaticInstPtr _staticInst, Addr _pc, bool spec,
const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0)
: InstRecord(_when, _thread, _staticInst, _pc, spec,
: ExeTracerRecord(_when, _thread, _staticInst, _pc, spec,
_macroStaticInst, _upc),
parent(_parent)
{
@@ -65,7 +65,7 @@ class NativeTraceRecord : public InstRecord
void dump();
};
class NativeTrace : public InstTracer
class NativeTrace : public ExeTracer
{
protected:
int fd;

View File

@@ -262,7 +262,9 @@ class SimpleThread : public ThreadState
{
int flatIndex = isa.flattenIntIndex(reg_idx);
assert(flatIndex < TheISA::NumIntRegs);
return intRegs[flatIndex];
uint64_t regVal = intRegs[flatIndex];
DPRINTF(IntRegs, "Reading int reg %d as %#x.\n", reg_idx, regVal);
return regVal;
}
FloatReg readFloatReg(int reg_idx)
@@ -283,6 +285,7 @@ class SimpleThread : public ThreadState
{
int flatIndex = isa.flattenIntIndex(reg_idx);
assert(flatIndex < TheISA::NumIntRegs);
DPRINTF(IntRegs, "Setting int reg %d to %#x.\n", reg_idx, val);
intRegs[flatIndex] = val;
}

View File

@@ -748,7 +748,9 @@ LiveProcess::create(LiveProcessParams * params)
case ObjectFile::Linux:
process = new ArmLinuxProcess(params, objFile);
break;
case ObjectFile::LinuxArmOABI:
fatal("M5 does not support ARM OABI binaries. Please recompile with an"
" EABI compiler.");
default:
fatal("Unknown/unsupported operating system.");
}

View File

@@ -295,6 +295,10 @@ class LiveProcess : public Process
M5_AT_CLKTCK = 17,
M5_AT_SECURE = 23,
M5_BASE_PLATFORM = 24,
M5_AT_RANDOM = 25,
M5_AT_EXECFN = 31,
M5_AT_VECTOR_SIZE = 44
};

View File

@@ -1,5 +1,5 @@
warn: Sockets disabled, not accepting gdb connections
For more information see: http://www.m5sim.org/warn/d946bea6
warn: allowing mmap of file @ fd 4294967295. This will break if not /dev/zero.
For more information see: http://www.m5sim.org/warn/3a2134f6
warn: instruction 'fstmx' unimplemented
For more information see: http://www.m5sim.org/warn/21b09adb
hack: be nice to actually delete the event here

View File

@@ -5,13 +5,12 @@ The Regents of The University of Michigan
All Rights Reserved
M5 compiled Jun 9 2009 23:46:33
M5 revision 6639f3c716a6 6238 default qtip tip armreg.patch qbase
M5 started Jun 9 2009 23:53:49
M5 compiled Jul 27 2009 00:45:04
M5 revision 44a3d32f3217 6414 default qtip tip runnableagainstatupdate.patch
M5 started Jul 27 2009 00:45:05
M5 executing on fajita
command line: build/ARM_SE/m5.fast -d build/ARM_SE/tests/fast/quick/00.hello/arm/linux/simple-atomic -re tests/run.py build/ARM_SE/tests/fast/quick/00.hello/arm/linux/simple-atomic
Global frequency set at 1000000000000 ticks per second
info: Entering event queue @ 0. Starting simulation...
info: Increasing stack size by one page.
Hello world!
Exiting @ tick 2299000 because target called exit()
Exiting @ tick 2748500 because target called exit()

View File

@@ -1,13 +1,13 @@
---------- Begin Simulation Statistics ----------
host_inst_rate 79163 # Simulator instruction rate (inst/s)
host_mem_usage 189980 # Number of bytes of host memory used
host_seconds 0.06 # Real time elapsed on the host
host_tick_rate 39442081 # Simulator tick rate (ticks/s)
host_inst_rate 9392 # Simulator instruction rate (inst/s)
host_mem_usage 189932 # Number of bytes of host memory used
host_seconds 0.59 # Real time elapsed on the host
host_tick_rate 4693453 # Simulator tick rate (ticks/s)
sim_freq 1000000000000 # Frequency of simulated ticks
sim_insts 4598 # Number of instructions simulated
sim_seconds 0.000002 # Number of seconds simulated
sim_ticks 2299000 # Number of ticks simulated
sim_insts 5498 # Number of instructions simulated
sim_seconds 0.000003 # Number of seconds simulated
sim_ticks 2748500 # Number of ticks simulated
system.cpu.dtb.accesses 0 # DTB accesses
system.cpu.dtb.hits 0 # DTB hits
system.cpu.dtb.misses 0 # DTB misses
@@ -28,9 +28,9 @@ system.cpu.itb.write_accesses 0 # DT
system.cpu.itb.write_hits 0 # DTB write hits
system.cpu.itb.write_misses 0 # DTB write misses
system.cpu.not_idle_fraction 1 # Percentage of non-idle cycles
system.cpu.numCycles 4599 # number of cpu cycles simulated
system.cpu.num_insts 4598 # Number of instructions executed
system.cpu.num_refs 1851 # Number of memory references
system.cpu.workload.PROG:num_syscalls 14 # Number of system calls
system.cpu.numCycles 5498 # number of cpu cycles simulated
system.cpu.num_insts 5498 # Number of instructions executed
system.cpu.num_refs 2127 # Number of memory references
system.cpu.workload.PROG:num_syscalls 13 # Number of system calls
---------- End Simulation Statistics ----------

View File

@@ -26,12 +26,31 @@
#
# Authors: Gabe Black
.PHONY: statetrace
CXX := g++
INCLUDES := -I ./ -I ./arch
CXXFLAGS := -O3 -ggdb
statetrace: statetrace-native
define build-obj
$(CXX) -c $(patsubst %.o,%.cc,$@) -o $@ $(INCLUDES) $(CXXFLAGS)
endef
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
define final-link
$(CXX) $(INCLUDES) $(CXXFLAGS) -o $@ $^
endef
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 -g -I ./ -I ./arch/ -O3 --static -o statetrace
all: statetrace
printer.o: printer.cc printer.hh tracechild.hh refcnt.hh regstate.hh
$(build-obj)
statetrace.o: statetrace.cc printer.hh tracechild.hh refcnt.hh regstate.hh
$(build-obj)
tracechild.o: tracechild.cc tracechild.hh regstate.hh
$(build-obj)
tracechild_arch.o: statetrace.cc printer.hh tracechild.hh refcnt.hh regstate.hh arch/tracechild_arm.hh arch/tracechild_arm.cc arch/tracechild_i386.hh arch/tracechild_i386.cc arch/tracechild_amd64.cc arch/tracechild_amd64.hh arch/tracechild_sparc.cc arch/tracechild_sparc.hh
$(build-obj)
statetrace: printer.o statetrace.o tracechild.o tracechild_arch.o
$(final-link)
clean:
rm -f *.o statetrace

View File

@@ -0,0 +1,236 @@
/*
* 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 <iostream>
#include <errno.h>
#include <stdint.h>
#include <cstring>
#include "tracechild_arm.hh"
using namespace std;
const char* ARMTraceChild::regNames[numregs] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "fp", "r12", "sp", "lr", "pc",
"cpsr" };
ARMTraceChild::ARMTraceChild()
{
for (int x = 0; x < numregs; x++) {
memset(&regs, 0, sizeof(regs));
memset(&oldregs, 0, sizeof(regs));
regDiffSinceUpdate[x] = false;
}
}
bool ARMTraceChild::sendState(int socket)
{
uint32_t regVal = 0;
uint32_t message[numregs + 1];
int pos = 1;
message[0] = 0;
for (int x = 0; x < numregs; x++) {
if (regDiffSinceUpdate[x]) {
message[0] = message[0] | (1 << 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 < numregs && num >= 0);
return myregs.uregs[num];
}
bool ARMTraceChild::update(int pid)
{
oldregs = regs;
if(ptrace(PTRACE_GETREGS, pid, 0, &regs) != 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)
{
return getRegs(regs, num);
}
int64_t ARMTraceChild::getOldRegVal(int num)
{
return getRegs(oldregs, num);
}
char * ARMTraceChild::printReg(int num)
{
sprintf(printBuffer, "0x%08X", (uint32_t)getRegVal(num));
return printBuffer;
}
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;
// 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. If the lr happens to point to the next instruction
// we'll leave out our breakpoint to avoid an infinite loop. This isn't a
// fool proof strategy, but it should work well in all the reasonable
// scenarios I can think of right now.
if (pc != lr) {
lrOp = ptrace(PTRACE_PEEKDATA, pid, lr, 0);
ptrace(PTRACE_POKEDATA, pid, lr, bkpt_inst);
}
ptraceSingleStep();
if (pc != lr) {
ptrace(PTRACE_POKEDATA, pid, lr, lrOp);
}
}
TraceChild * genTraceChild()
{
return new ARMTraceChild;
}

View File

@@ -0,0 +1,113 @@
/*
* 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 <cassert>
#include <string>
#include <sys/user.h>
#include <sys/ptrace.h>
#include "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,
numregs
};
private:
char printBuffer[256];
static const char *regNames[numregs];
uint32_t getRegs(user_regs& myregs, int num);
user_regs regs;
user_regs oldregs;
bool regDiffSinceUpdate[numregs];
protected:
bool update(int pid);
public:
ARMTraceChild();
bool sendState(int socket);
int getNumRegs()
{
return numregs;
}
bool diffSinceUpdate(int num)
{
assert(num < numregs && num >= 0);
return regDiffSinceUpdate[num];
}
std::string getRegName(int num)
{
assert(num < numregs && num >= 0);
return regNames[num];
}
int64_t getRegVal(int num);
int64_t getOldRegVal(int num);
bool step();
uint64_t getPC()
{
return getRegVal(PC);
}
uint64_t getSP()
{
return getRegVal(SP);
}
char * printReg(int num);
std::ostream & outputStartState(std::ostream & os);
};
#endif

View File

@@ -28,19 +28,19 @@
* Authors: Gabe Black
*/
#include <iostream>
#include <cstring>
#include <errno.h>
#include <fstream>
#include <iostream>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string>
#include <sys/ptrace.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include "printer.hh"
#include "tracechild.hh"
@@ -61,6 +61,7 @@ int main(int argc, char * argv[], char * envp[])
//Parse the command line arguments
bool printInitial = false;
bool printTrace = true;
string host = "localhost";
for(int x = 1; x < argc; x++)
{
if(!strcmp(argv[x], "-h"))
@@ -68,6 +69,17 @@ int main(int argc, char * argv[], char * envp[])
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], "-r"))
{
cout << "Legal register names:" << endl;
@@ -111,6 +123,7 @@ int main(int argc, char * argv[], char * envp[])
cerr << "Couldn't start target program" << endl;
return 1;
}
child->step();
if(printInitial)
{
child->outputStartState(cout);
@@ -127,7 +140,7 @@ int main(int argc, char * argv[], char * envp[])
return 1;
}
struct hostent *server;
server = gethostbyname("localhost");
server = gethostbyname(host.c_str());
if(!server)
{
cerr << "Couldn't get host ip! " << strerror(errno) << endl;
@@ -145,7 +158,6 @@ int main(int argc, char * argv[], char * envp[])
cerr << "Couldn't connect to server! " << strerror(errno) << endl;
return 1;
}
child->step();
while(child->isTracing())
{
if(!child->sendState(sock))

View File

@@ -29,10 +29,11 @@
*/
#include "tracechild.hh"
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <iostream>
#include <cstring>
#include <errno.h>
#include <iostream>
#include <sys/ptrace.h>
#include <sys/wait.h>
using namespace std;
@@ -78,11 +79,6 @@ bool TraceChild::startTracing(const char * pathToFile, char * const argv[])
return false;
}
tracing = true;
if(!update(pid))
{
cout << "Didn't update successfully!" << endl;
return false;
}
return true;
}

View File

@@ -33,6 +33,8 @@
#elif defined __amd64__
// #error "AMD64 architecture not implemented"
#include "arch/tracechild_amd64.cc"
#elif defined __arm__
#include "arch/tracechild_arm.cc"
#elif defined __hppa__
#error "Hppa architecture not implemented"
#elif defined __i386__ || defined __i486__ || \