You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

142 lines
4.0 KiB

/*
* Copyright 2002-2019 Intel Corporation.
*
* This software is provided to you as Sample Source Code as defined in the accompanying
* End User License Agreement for the Intel(R) Software Development Products ("Agreement")
* section 1.L.
*
* This software and the related documents are provided as is, with no express or implied
* warranties, other than those that are expressly stated in the License.
*/
#ifndef TIME_WARP_H
#define TIME_WARP_H
namespace INSTLIB
{
/*! @defgroup TIME_WARPER
It is often desirable to use instrumentation to change behavior of program
in certain ways so that different runs of the program (with the same input)
are same. Time_warper allows uses to modify non-repitative constructs
such as instructions reading the cycle counters and system calls reading
time of the day.
*/
/*! @defgroup TIME_WARPER_RDTSC
@ingroup TIME_WARPER
Modify the behaviors of RDTSC instruction on IA-32 and Intel(R) 64 architectures.
*/
/*! @ingroup TIME_WARPER_RDTSC
*/
class TIME_WARP_RDTSC
{
public:
TIME_WARP_RDTSC():_enableKnob(KNOB_MODE_WRITEONCE, "pintool", "rdtsc_warp", "0",
"Modify the behavior of RDTSC")
{
_edx_eax = 1ULL;
_eax= 0;
_edx= 0;
}
bool IsActive()
{
return (_enableKnob);
}
/*! @ingroup TIME_WARPER_RDTSC
Activate the controller if the -length knob is provided
@return 1 if controller can start an interval, otherwise 0
*/
INT32 CheckKnobs(VOID * val)
{
if (_enableKnob==0)
return 0;
#if defined(TARGET_IA32) || defined(TARGET_IA32E)
// Register Instruction to be called to instrument instructions
TRACE_AddInstrumentFunction(ProcessRDTSC, this);
#endif
return 1;
}
private:
KNOB<BOOL> _enableKnob;
UINT64 _edx_eax;
UINT32 _eax;
UINT32 _edx;
static UINT32 SwizzleEdx(TIME_WARP_RDTSC *rd)
{
rd->_edx = (rd->_edx_eax & 0xffffffff00000000ULL) >> 32;
// cerr << "SwizzleEdx() returning 0x"<< hex << edx << endl;
return rd->_edx;
}
static UINT32 SwizzleEax(TIME_WARP_RDTSC *rd)
{
rd->_eax = rd->_edx_eax & 0x00000000ffffffffULL;
rd->_edx_eax+=100;
// cerr << "SwizzleEax() edx_eax= 0x"<< hex << edx_eax << endl;
// cerr << "SwizzleEax() returning 0x"<< hex << eax << endl;
return rd->_eax;
}
static VOID PrintEaxEdx(ADDRINT reax, ADDRINT redx)
{
cerr << "PrintEaxEdx():reg eax = 0x"<< hex << reax << endl;
cerr << "PrintEaxEdx():reg edx = 0x"<< hex << redx << endl;
}
#if defined(TARGET_IA32) || defined(TARGET_IA32E)
// Pin calls this function every time a new trace is encountered
// Goal: Make rdtsc repeatable across runs
// NOTE: We are using TRACE instrumentation because it has higher
// precedence than INS instrumentation.
static VOID ProcessRDTSC(TRACE trace, VOID *v)
{
for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl))
{
for (INS ins = BBL_InsHead(bbl); INS_Valid(ins); ins = INS_Next(ins))
{
if(INS_IsRDTSC(ins))
{
INS_InsertCall(ins, IPOINT_AFTER,
(AFUNPTR)SwizzleEdx,IARG_PTR, v, IARG_RETURN_REGS, REG_GDX, IARG_END);
INS_InsertCall(ins, IPOINT_AFTER,
(AFUNPTR)SwizzleEax,IARG_PTR, v, IARG_RETURN_REGS, REG_GAX, IARG_END);
}
}
}
}
#endif
};
/*! @ingroup TIME_WARPER_MULTI
*/
class TIME_WARP
{
public:
/*! @ingroup TIME_WARPER_MULTI
*/
/*! @ingroup TIME_WARPER_MULTI
Activate all the component controllers
*/
INT32 CheckKnobs(VOID * val)
{
_val = val;
INT32 start = 0;
start = start + _rdtsc.CheckKnobs(this);
return start;
}
bool RDTSC_modified() { return _rdtsc.IsActive(); };
private:
VOID * _val;
TIME_WARP_RDTSC _rdtsc;
};
}
#endif