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.
896 lines
27 KiB
896 lines
27 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.
|
|
*/
|
|
|
|
#include <cstdio>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <iomanip>
|
|
#include <fstream>
|
|
#include <cstdlib>
|
|
|
|
#ifdef TARGET_LINUX
|
|
#include <unistd.h>
|
|
#include <sys/syscall.h>
|
|
#include <errno.h>
|
|
# ifdef TARGET_IA32E
|
|
# include <asm/prctl.h>
|
|
# include <sys/prctl.h>
|
|
# endif // TARGET_IA32E
|
|
#endif // TARGET_LINUX
|
|
|
|
#include "pin.H"
|
|
#include "instlib.H"
|
|
using std::iostream;
|
|
using std::ostringstream;
|
|
|
|
// windows.h must be included after pin.H
|
|
#ifdef TARGET_WINDOWS
|
|
namespace WIND
|
|
{
|
|
#include <windows.h>
|
|
}
|
|
#endif // TARGET_WINDOWS
|
|
|
|
FILE *log_inl;
|
|
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
|
|
"o", "inlined-stack-arg1.out", "output file");
|
|
|
|
typedef struct {
|
|
ADDRINT tid;
|
|
ADDRINT pc;
|
|
ADDRINT flagsVal;
|
|
ADDRINT nextAddress;
|
|
UINT32 readRegCount;
|
|
UINT32 writeRegCount;
|
|
UINT32 instrSize;
|
|
UINT8 readByte;
|
|
UINT16 readWord;
|
|
UINT32 readDWord;
|
|
ADDRINT readAddrInt;
|
|
UINT8 readValue1;
|
|
UINT16 readValue2;
|
|
UINT32 readValue3;
|
|
INT32 readValue4;
|
|
INT32 readValue5;
|
|
INT32 readValue6;
|
|
} AnalysisInfo;
|
|
|
|
AnalysisInfo accessInfo;
|
|
AnalysisInfo accessInfoNonFastCall;
|
|
AnalysisInfo accessInfoFastCall;
|
|
|
|
//main app thread utils
|
|
|
|
THREADID myThread = INVALID_THREADID;
|
|
|
|
VOID ThreadStart(THREADID threadid, CONTEXT *ctxt, INT32 flags, VOID *v)
|
|
{
|
|
if (myThread == INVALID_THREADID)
|
|
{
|
|
myThread = threadid;
|
|
}
|
|
}
|
|
|
|
ADDRINT IfMyThread(THREADID threadId)
|
|
{
|
|
return threadId == myThread;
|
|
}
|
|
|
|
|
|
|
|
static char nibble_to_ascii_hex(UINT8 i) {
|
|
if (i<10) return i+'0';
|
|
if (i<16) return i-10+'A';
|
|
return '?';
|
|
}
|
|
|
|
static void print_hex_line(char* buf, const UINT8* array, const int length) {
|
|
int n = length;
|
|
int i=0;
|
|
if (length == 0)
|
|
n = XED_MAX_INSTRUCTION_BYTES;
|
|
for( i=0 ; i< n; i++) {
|
|
buf[2*i+0] = nibble_to_ascii_hex(array[i]>>4);
|
|
buf[2*i+1] = nibble_to_ascii_hex(array[i]&0xF);
|
|
}
|
|
buf[2*i]=0;
|
|
}
|
|
|
|
static string
|
|
disassemble(UINT64 start, UINT64 stop) {
|
|
UINT64 pc = start;
|
|
xed_state_t dstate;
|
|
xed_syntax_enum_t syntax = XED_SYNTAX_INTEL;
|
|
xed_error_enum_t xed_error;
|
|
xed_decoded_inst_t xedd;
|
|
ostringstream os;
|
|
if (sizeof(ADDRINT) == 4)
|
|
xed_state_init(&dstate,
|
|
XED_MACHINE_MODE_LEGACY_32,
|
|
XED_ADDRESS_WIDTH_32b,
|
|
XED_ADDRESS_WIDTH_32b);
|
|
else
|
|
xed_state_init(&dstate,
|
|
XED_MACHINE_MODE_LONG_64,
|
|
XED_ADDRESS_WIDTH_64b,
|
|
XED_ADDRESS_WIDTH_64b);
|
|
|
|
/*while( pc < stop )*/ {
|
|
xed_decoded_inst_zero_set_mode(&xedd, &dstate);
|
|
UINT32 len = 15;
|
|
if (stop - pc < 15)
|
|
len = stop-pc;
|
|
|
|
xed_error = xed_decode(&xedd, reinterpret_cast<const UINT8*>(pc), len);
|
|
bool okay = (xed_error == XED_ERROR_NONE);
|
|
iostream::fmtflags fmt = os.flags();
|
|
os << std::setfill('0')
|
|
<< "XDIS "
|
|
<< std::hex
|
|
<< std::setw(sizeof(ADDRINT)*2)
|
|
<< pc
|
|
<< std::dec
|
|
<< ": "
|
|
<< std::setfill(' ')
|
|
<< std::setw(4);
|
|
|
|
if (okay) {
|
|
char buffer[200];
|
|
unsigned int dec_len, sp;
|
|
|
|
os << xed_extension_enum_t2str(xed_decoded_inst_get_extension(&xedd));
|
|
dec_len = xed_decoded_inst_get_length(&xedd);
|
|
print_hex_line(buffer, reinterpret_cast<UINT8*>(pc), dec_len);
|
|
os << " " << buffer;
|
|
for ( sp=dec_len; sp < 12; sp++) // pad out the instruction bytes
|
|
os << " ";
|
|
os << " ";
|
|
memset(buffer,0,200);
|
|
int dis_okay = xed_format_context(syntax, &xedd, buffer, 200, pc, 0, 0);
|
|
if (dis_okay)
|
|
os << buffer << endl;
|
|
else
|
|
os << "Error disasassembling pc 0x" << std::hex << pc << std::dec << endl;
|
|
pc += dec_len;
|
|
}
|
|
else { // print the byte and keep going.
|
|
UINT8 memval = *reinterpret_cast<UINT8*>(pc);
|
|
os << "???? " // no extension
|
|
<< std::hex
|
|
<< std::setw(2)
|
|
<< std::setfill('0')
|
|
<< static_cast<UINT32>(memval)
|
|
<< std::endl;
|
|
pc += 1;
|
|
}
|
|
os.flags(fmt);
|
|
}
|
|
return os.str();
|
|
}
|
|
|
|
VOID RecordInstructionInfo(
|
|
UINT32 dummy1, UINT32 dummy2, UINT32 dummy3, UINT32 dummy4,
|
|
ADDRINT tid,
|
|
ADDRINT pcval,
|
|
ADDRINT flagsval,
|
|
ADDRINT nxtaddr,
|
|
UINT32 rregcnt,
|
|
UINT32 wregcnt,
|
|
ADDRINT inssz,
|
|
ADDRINT readValue,
|
|
UINT8 readValue1,
|
|
UINT16 readValue2,
|
|
UINT32 readValue3,
|
|
INT8 readValue4,
|
|
INT16 readValue5,
|
|
INT32 readValue6)
|
|
{
|
|
accessInfoNonFastCall.tid = tid;
|
|
accessInfoNonFastCall.pc = pcval;
|
|
accessInfoNonFastCall.flagsVal = flagsval;
|
|
accessInfoNonFastCall.nextAddress = nxtaddr;
|
|
accessInfoNonFastCall.readRegCount = rregcnt;
|
|
accessInfoNonFastCall.writeRegCount = wregcnt;
|
|
accessInfoNonFastCall.instrSize = inssz;
|
|
accessInfoNonFastCall.readByte = readValue;
|
|
accessInfoNonFastCall.readWord = readValue;
|
|
accessInfoNonFastCall.readDWord = readValue;
|
|
accessInfoNonFastCall.readAddrInt = readValue;
|
|
accessInfoNonFastCall.readValue1 = readValue1;
|
|
accessInfoNonFastCall.readValue2 = readValue2;
|
|
accessInfoNonFastCall.readValue3 = readValue3;
|
|
accessInfoNonFastCall.readValue4 = readValue4;
|
|
accessInfoNonFastCall.readValue5 = readValue5;
|
|
accessInfoNonFastCall.readValue6 = readValue6;
|
|
}
|
|
|
|
VOID PIN_FAST_ANALYSIS_CALL RecordInstructionInfoFastCall(
|
|
ADDRINT tid,
|
|
ADDRINT pcval,
|
|
ADDRINT flagsval,
|
|
ADDRINT nxtaddr,
|
|
UINT32 rregcnt,
|
|
UINT32 wregcnt,
|
|
ADDRINT inssz,
|
|
ADDRINT readValue,
|
|
UINT8 readValue1,
|
|
UINT16 readValue2,
|
|
UINT32 readValue3,
|
|
INT8 readValue4,
|
|
INT16 readValue5,
|
|
INT32 readValue6)
|
|
{
|
|
accessInfoFastCall.tid = tid;
|
|
accessInfoFastCall.pc = pcval;
|
|
accessInfoFastCall.flagsVal = flagsval;
|
|
accessInfoFastCall.nextAddress = nxtaddr;
|
|
accessInfoFastCall.readRegCount = rregcnt;
|
|
accessInfoFastCall.writeRegCount = wregcnt;
|
|
accessInfoFastCall.instrSize = inssz;
|
|
accessInfoFastCall.readByte = readValue;
|
|
accessInfoFastCall.readWord = readValue;
|
|
accessInfoFastCall.readDWord = readValue;
|
|
accessInfoFastCall.readAddrInt = readValue;
|
|
accessInfoFastCall.readValue1 = readValue1;
|
|
accessInfoFastCall.readValue2 = readValue2;
|
|
accessInfoFastCall.readValue3 = readValue3;
|
|
accessInfoFastCall.readValue4 = readValue4;
|
|
accessInfoFastCall.readValue5 = readValue5;
|
|
accessInfoFastCall.readValue6 = readValue6;
|
|
}
|
|
|
|
|
|
VOID VerifyInstructionInfo(
|
|
ADDRINT tid,
|
|
ADDRINT pcval,
|
|
ADDRINT flagsval,
|
|
ADDRINT nxtaddr,
|
|
UINT32 rregcnt,
|
|
UINT32 wregcnt,
|
|
ADDRINT inssz,
|
|
ADDRINT readValue,
|
|
UINT8 readValue1,
|
|
UINT16 readValue2,
|
|
UINT32 readValue3,
|
|
INT8 readValue4,
|
|
INT16 readValue5,
|
|
INT32 readValue6)
|
|
{
|
|
BOOL hadError = FALSE;
|
|
|
|
accessInfo.tid = tid;
|
|
accessInfo.pc = pcval;
|
|
accessInfo.flagsVal = flagsval;
|
|
accessInfo.nextAddress = nxtaddr;
|
|
accessInfo.readRegCount = rregcnt;
|
|
accessInfo.writeRegCount = wregcnt;
|
|
accessInfo.instrSize = inssz;
|
|
accessInfo.readByte = readValue;
|
|
accessInfo.readWord = readValue;
|
|
accessInfo.readDWord = readValue;
|
|
accessInfo.readAddrInt = readValue;
|
|
accessInfo.readValue1 = readValue1;
|
|
accessInfo.readValue2 = readValue2;
|
|
accessInfo.readValue3 = readValue3;
|
|
accessInfo.readValue4 = readValue4;
|
|
accessInfo.readValue5 = readValue5;
|
|
accessInfo.readValue6 = readValue6;
|
|
if (accessInfoNonFastCall.tid != accessInfo.tid)
|
|
{
|
|
fprintf (log_inl, "***tid in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoNonFastCall.pc != accessInfo.pc)
|
|
{
|
|
fprintf (log_inl, "***pc in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoNonFastCall.flagsVal != accessInfo.flagsVal)
|
|
{
|
|
fprintf (log_inl, "***flagsVal in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoNonFastCall.nextAddress != accessInfo.nextAddress)
|
|
{
|
|
fprintf (log_inl, "***nextAddress in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoNonFastCall.readRegCount != accessInfo.readRegCount)
|
|
{
|
|
fprintf (log_inl, "***readRegCount in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoNonFastCall.writeRegCount != accessInfo.writeRegCount)
|
|
{
|
|
fprintf (log_inl, "***writeRegCount in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoNonFastCall.instrSize != accessInfo.instrSize)
|
|
{
|
|
fprintf (log_inl, "***instrSize in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoNonFastCall.readByte != accessInfo.readByte)
|
|
{
|
|
fprintf (log_inl, "***readByte in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoNonFastCall.readWord != accessInfo.readWord)
|
|
{
|
|
fprintf (log_inl, "***readWord in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoNonFastCall.readDWord != accessInfo.readDWord)
|
|
{
|
|
fprintf (log_inl, "***readDWord in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoNonFastCall.readAddrInt != accessInfo.readAddrInt)
|
|
{
|
|
fprintf (log_inl, "***readAddrInt in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoNonFastCall.readValue1 != accessInfo.readValue1)
|
|
{
|
|
fprintf (log_inl, "***readValue1 in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoNonFastCall.readValue2 != accessInfo.readValue2)
|
|
{
|
|
fprintf (log_inl, "***readValue2 in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoNonFastCall.readValue3 != accessInfo.readValue3)
|
|
{
|
|
fprintf (log_inl, "***readValue3 in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoNonFastCall.readValue4 != accessInfo.readValue4)
|
|
{
|
|
fprintf (log_inl, "***readValue4 in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoNonFastCall.readValue5 != accessInfo.readValue5)
|
|
{
|
|
fprintf (log_inl, "***readValue5 in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoNonFastCall.readValue6 != accessInfo.readValue6)
|
|
{
|
|
fprintf (log_inl, "***readValue6 in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (hadError)
|
|
{
|
|
fprintf (log_inl, "In accessInfoNonFastCall\n");
|
|
string s = disassemble ((pcval),(pcval)+15);
|
|
fprintf (log_inl, " %s\n", s.c_str());
|
|
exit (-1);
|
|
}
|
|
hadError = FALSE;
|
|
if (accessInfoFastCall.tid != accessInfo.tid)
|
|
{
|
|
fprintf (log_inl, "***tid in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoFastCall.pc != accessInfo.pc)
|
|
{
|
|
fprintf (log_inl, "***pc in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoFastCall.flagsVal != accessInfo.flagsVal)
|
|
{
|
|
fprintf (log_inl, "***flagsVal in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoFastCall.nextAddress != accessInfo.nextAddress)
|
|
{
|
|
fprintf (log_inl, "***nextAddress in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoFastCall.readRegCount != accessInfo.readRegCount)
|
|
{
|
|
fprintf (log_inl, "***readRegCount in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoFastCall.writeRegCount != accessInfo.writeRegCount)
|
|
{
|
|
fprintf (log_inl, "***writeRegCount in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoFastCall.instrSize != accessInfo.instrSize)
|
|
{
|
|
fprintf (log_inl, "***instrSize in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoFastCall.readByte != accessInfo.readByte)
|
|
{
|
|
fprintf (log_inl, "***readByte in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoFastCall.readWord != accessInfo.readWord)
|
|
{
|
|
fprintf (log_inl, "***readWord in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoFastCall.readDWord != accessInfo.readDWord)
|
|
{
|
|
fprintf (log_inl, "***readDWord in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoFastCall.readAddrInt != accessInfo.readAddrInt)
|
|
{
|
|
fprintf (log_inl, "***readAddrInt in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoFastCall.readValue1 != accessInfo.readValue1)
|
|
{
|
|
fprintf (log_inl, "***readValue1 in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoFastCall.readValue2 != accessInfo.readValue2)
|
|
{
|
|
fprintf (log_inl, "***readValue2 in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (accessInfoFastCall.readValue3 != accessInfo.readValue3)
|
|
{
|
|
fprintf (log_inl, "***readValue3 in Error\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (hadError)
|
|
{
|
|
fprintf (log_inl, "In accessInfoFastCall\n");
|
|
string s = disassemble ((pcval),(pcval)+15);
|
|
fprintf (log_inl, " %s\n", s.c_str());
|
|
exit (-1);
|
|
}
|
|
}
|
|
CONTEXT contextAtVerify;
|
|
CONTEXT contextAtRecordFastCall;
|
|
CONTEXT contextAtRecordNonFastCall;
|
|
|
|
|
|
|
|
VOID RecordContext(
|
|
UINT32 dummy1, UINT32 dummy2, UINT32 dummy3, UINT32 dummy4,
|
|
CONTEXT * context, THREADID tid)
|
|
{
|
|
if (tid == myThread)
|
|
{
|
|
PIN_SaveContext (context, &contextAtRecordNonFastCall);
|
|
}
|
|
}
|
|
|
|
VOID PIN_FAST_ANALYSIS_CALL RecordContextFastCall(
|
|
CONTEXT * context, THREADID tid)
|
|
{
|
|
if (tid == myThread)
|
|
{
|
|
PIN_SaveContext (context, &contextAtRecordFastCall);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL CompareIntContext (CONTEXT *context1, CONTEXT *context2)
|
|
{
|
|
BOOL compareOk = TRUE;
|
|
if (PIN_GetContextReg( context1, REG_INST_PTR ) != PIN_GetContextReg( context2, REG_INST_PTR ))
|
|
{
|
|
fprintf (log_inl,"REG_INST_PTR ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if (PIN_GetContextReg( context1, REG_GAX ) != PIN_GetContextReg( context2, REG_GAX ))
|
|
{
|
|
fprintf (log_inl,"REG_GAX ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if (PIN_GetContextReg( context1, REG_GBX ) != PIN_GetContextReg( context2, REG_GBX ))
|
|
{
|
|
fprintf (log_inl,"REG_GBX ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if (PIN_GetContextReg( context1, REG_GCX ) != PIN_GetContextReg( context2, REG_GCX ))
|
|
{
|
|
fprintf (log_inl,"REG_GCX ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if (PIN_GetContextReg( context1, REG_GDX ) != PIN_GetContextReg( context2, REG_GDX ))
|
|
{
|
|
fprintf (log_inl,"REG_GDX ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if (PIN_GetContextReg( context1, REG_GSI ) != PIN_GetContextReg( context2, REG_GSI ))
|
|
{
|
|
fprintf (log_inl,"REG_GSI ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if (PIN_GetContextReg( context1, REG_GDI ) != PIN_GetContextReg( context2, REG_GDI ))
|
|
{
|
|
fprintf (log_inl,"REG_GDI ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if (PIN_GetContextReg( context1, REG_GBP ) != PIN_GetContextReg( context2, REG_GBP ))
|
|
{
|
|
fprintf (log_inl,"REG_GBP ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if (PIN_GetContextReg( context1, REG_STACK_PTR ) != PIN_GetContextReg( context2, REG_STACK_PTR ))
|
|
{
|
|
fprintf (log_inl,"REG_STACK_PTR ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if (PIN_GetContextReg( context1, REG_SEG_SS ) != PIN_GetContextReg( context2, REG_SEG_SS ))
|
|
{
|
|
fprintf (log_inl,"REG_SEG_SS ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if (PIN_GetContextReg( context1, REG_SEG_CS ) != PIN_GetContextReg( context2, REG_SEG_CS ))
|
|
{
|
|
fprintf (log_inl,"REG_SEG_CS ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if (PIN_GetContextReg( context1, REG_SEG_DS ) != PIN_GetContextReg( context2, REG_SEG_DS ))
|
|
{
|
|
fprintf (log_inl,"REG_SEG_DS ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if (PIN_GetContextReg( context1, REG_SEG_ES ) != PIN_GetContextReg( context2, REG_SEG_ES ))
|
|
{
|
|
fprintf (log_inl,"REG_SEG_ES ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if (PIN_GetContextReg( context1, REG_SEG_FS ) != PIN_GetContextReg( context2, REG_SEG_FS ))
|
|
{
|
|
fprintf (log_inl,"REG_SEG_FS ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if (PIN_GetContextReg( context1, REG_SEG_GS ) != PIN_GetContextReg( context2, REG_SEG_GS ))
|
|
{
|
|
fprintf (log_inl,"REG_SEG_GS ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if (PIN_GetContextReg( context1, REG_GFLAGS ) != PIN_GetContextReg( context2, REG_GFLAGS ))
|
|
{
|
|
fprintf (log_inl,"REG_GFLAGS ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
#ifdef TARGET_IA32E
|
|
if (PIN_GetContextReg( context1, REG_R8 ) != PIN_GetContextReg( context2, REG_R8 ))
|
|
{
|
|
fprintf (log_inl,"REG_R8 ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if (PIN_GetContextReg( context1, REG_R9 ) != PIN_GetContextReg( context2, REG_R9 ))
|
|
{
|
|
fprintf (log_inl,"REG_R9 ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if (PIN_GetContextReg( context1, REG_R10 ) != PIN_GetContextReg( context2, REG_R10 ))
|
|
{
|
|
fprintf (log_inl,"REG_R10 ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if (PIN_GetContextReg( context1, REG_R11 ) != PIN_GetContextReg( context2, REG_R11 ))
|
|
{
|
|
fprintf (log_inl,"REG_R11 ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if (PIN_GetContextReg( context1, REG_R12 ) != PIN_GetContextReg( context2, REG_R12 ))
|
|
{
|
|
fprintf (log_inl,"REG_R12 ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if (PIN_GetContextReg( context1, REG_R13 ) != PIN_GetContextReg( context2, REG_R13 ))
|
|
{
|
|
fprintf (log_inl,"REG_R13 ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if (PIN_GetContextReg( context1, REG_R14 ) != PIN_GetContextReg( context2, REG_R14 ))
|
|
{
|
|
fprintf (log_inl,"REG_R14 ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if (PIN_GetContextReg( context1, REG_R15 ) != PIN_GetContextReg( context2, REG_R15 ))
|
|
{
|
|
fprintf (log_inl,"REG_R15 ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
#endif
|
|
return (compareOk);
|
|
}
|
|
|
|
|
|
|
|
BOOL CompareFpContext(CONTEXT *context1, CONTEXT *context2)
|
|
{
|
|
BOOL compareOk = TRUE;
|
|
FPSTATE fpContext1, fpContext2;
|
|
FPSTATE *fpContextPtr1 = &fpContext1;
|
|
FPSTATE *fpContextPtr2 = &fpContext2;
|
|
PIN_GetContextFPState(context1, fpContextPtr1);
|
|
PIN_GetContextFPState(context2, fpContextPtr2);
|
|
|
|
if ( fpContextPtr1->fxsave_legacy._fcw != fpContextPtr2->fxsave_legacy._fcw)
|
|
{
|
|
fprintf (log_inl,"fcw ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if ( fpContextPtr1->fxsave_legacy._fsw != fpContextPtr2->fxsave_legacy._fsw)
|
|
{
|
|
fprintf (log_inl,"_fsw ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if ( fpContextPtr1->fxsave_legacy._ftw != fpContextPtr2->fxsave_legacy._ftw)
|
|
{
|
|
fprintf (log_inl,"_ftw ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if ( fpContextPtr1->fxsave_legacy._fop != fpContextPtr2->fxsave_legacy._fop)
|
|
{
|
|
fprintf (log_inl,"_fop ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if ( fpContextPtr1->fxsave_legacy._fpuip != fpContextPtr2->fxsave_legacy._fpuip)
|
|
{
|
|
fprintf (log_inl,"_fpuip ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
/* the _cs field seems to be changing randomly when running 32on64 linux
|
|
needs further investigation to prove it is not a Pin bug */
|
|
if ( fpContextPtr1->fxsave_legacy._cs != fpContextPtr2->fxsave_legacy._cs)
|
|
{
|
|
fprintf (log_inl,"_cs ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if ( fpContextPtr1->fxsave_legacy._fpudp != fpContextPtr2->fxsave_legacy._fpudp)
|
|
{
|
|
fprintf (log_inl,"_fpudp ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
/* the _ds field seems to be changing randomly when running 32on64 linux
|
|
needs further investigation to prove it is not a Pin bug */
|
|
if ( fpContextPtr1->fxsave_legacy._ds != fpContextPtr2->fxsave_legacy._ds)
|
|
{
|
|
fprintf (log_inl,"_ds ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if ( fpContextPtr1->fxsave_legacy._mxcsr != fpContextPtr2->fxsave_legacy._mxcsr)
|
|
{
|
|
fprintf (log_inl,"_mxcsr ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
if ( fpContextPtr1->fxsave_legacy._mxcsrmask != fpContextPtr2->fxsave_legacy._mxcsrmask)
|
|
{
|
|
fprintf (log_inl,"_mxcsrmask ERROR\n");
|
|
compareOk = FALSE;
|
|
}
|
|
int i;
|
|
for (i=0; i< 8; i++)
|
|
{
|
|
if ((fpContextPtr1->fxsave_legacy._sts[i]._raw._lo != fpContextPtr2->fxsave_legacy._sts[i]._raw._lo) ||
|
|
(fpContextPtr1->fxsave_legacy._sts[i]._raw._hi != fpContextPtr2->fxsave_legacy._sts[i]._raw._hi))
|
|
{
|
|
fprintf (log_inl,"_st[%d] ERROR\n", i);
|
|
compareOk = FALSE;
|
|
}
|
|
}
|
|
for (i=0;
|
|
#ifdef TARGET_IA32E
|
|
i< 16;
|
|
#else
|
|
i< 8;
|
|
#endif
|
|
i++)
|
|
{
|
|
if ((fpContextPtr1->fxsave_legacy._xmms[i]._vec64[0] != fpContextPtr2->fxsave_legacy._xmms[i]._vec64[0]) ||
|
|
(fpContextPtr1->fxsave_legacy._xmms[i]._vec64[1] != fpContextPtr2->fxsave_legacy._xmms[i]._vec64[1]))
|
|
{
|
|
fprintf (log_inl,"_xmm[%d] ERROR\n", i);
|
|
compareOk = FALSE;
|
|
}
|
|
}
|
|
|
|
return (compareOk);
|
|
}
|
|
|
|
BOOL CompareContext (CONTEXT *context1, CONTEXT *context2)
|
|
{
|
|
BOOL compareIntOk = CompareIntContext (context1, context2);
|
|
BOOL compareFpOk = CompareFpContext (context1, context2);
|
|
return (compareIntOk && compareFpOk);
|
|
}
|
|
|
|
VOID VerifyContext(
|
|
ADDRINT pcval,
|
|
CONTEXT * context, THREADID tid)
|
|
{
|
|
if (tid == myThread)
|
|
{
|
|
PIN_SaveContext(context, &contextAtVerify);
|
|
|
|
BOOL hadError = FALSE;
|
|
if (!CompareContext (&contextAtVerify,&contextAtRecordFastCall))
|
|
{
|
|
fprintf (log_inl,"contextAtRecordFastCall ERROR\n");
|
|
hadError = TRUE;
|
|
}
|
|
|
|
if (!CompareContext (&contextAtVerify,&contextAtRecordNonFastCall))
|
|
{
|
|
fprintf (log_inl,"contextAtRecordNonFastCall ERROR\n");
|
|
hadError = TRUE;
|
|
}
|
|
if (hadError)
|
|
{
|
|
string s = disassemble ((pcval),(pcval)+15);
|
|
fprintf (log_inl," %s\n", s.c_str());
|
|
exit (-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
INT32 Usage()
|
|
{
|
|
cerr <<
|
|
"This tests if the stack arguments are passed correctly by an inlined analysis function"
|
|
"\n";
|
|
|
|
cerr << endl;
|
|
|
|
return -1;
|
|
}
|
|
|
|
int numContextsInstrumented = 0;
|
|
int numRegularInstrumented = 0;
|
|
ADDRINT readValue1;
|
|
|
|
|
|
VOID Instruction(INS ins, VOID *v)
|
|
{
|
|
|
|
ADDRINT nextAddr = INS_NextAddress(ins);
|
|
UINT32 maxRRegs = INS_MaxNumRRegs(ins);
|
|
UINT32 maxWRegs = INS_MaxNumWRegs(ins);
|
|
ADDRINT sz = INS_Size(ins);
|
|
|
|
|
|
|
|
|
|
|
|
if (numContextsInstrumented < 100)
|
|
{
|
|
numContextsInstrumented++;
|
|
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)RecordContext,
|
|
// 4 dummy params to get the real params to be pushed on the stack in Intel64
|
|
IARG_UINT32, 1, IARG_UINT32, 2, IARG_UINT32, 3, IARG_UINT32, 4,
|
|
IARG_CONTEXT, IARG_THREAD_ID,
|
|
IARG_END);
|
|
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)RecordContextFastCall,
|
|
IARG_FAST_ANALYSIS_CALL,
|
|
IARG_CONTEXT, IARG_THREAD_ID,
|
|
IARG_END);
|
|
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)VerifyContext,
|
|
IARG_INST_PTR,
|
|
IARG_CONTEXT, IARG_THREAD_ID,
|
|
IARG_END);
|
|
}
|
|
else if (numRegularInstrumented < 100)
|
|
{
|
|
numRegularInstrumented++;
|
|
INS_InsertIfCall(ins, IPOINT_BEFORE, AFUNPTR(IfMyThread), IARG_THREAD_ID, IARG_END);
|
|
INS_InsertThenCall(ins, IPOINT_BEFORE, (AFUNPTR)RecordInstructionInfoFastCall,
|
|
IARG_FAST_ANALYSIS_CALL,
|
|
IARG_THREAD_ID,
|
|
IARG_INST_PTR,
|
|
IARG_REG_VALUE, REG_GFLAGS,
|
|
IARG_ADDRINT, nextAddr,
|
|
IARG_UINT32, maxRRegs,
|
|
IARG_UINT32, maxWRegs,
|
|
IARG_ADDRINT, sz,
|
|
#ifdef TARGET_IA32E
|
|
IARG_ADDRINT, 0xdeadbeefdeadbeefLL,
|
|
#else
|
|
IARG_ADDRINT, 0xdeadbeef,
|
|
#endif
|
|
IARG_REG_VALUE, REG_GDX,
|
|
IARG_REG_VALUE, REG_GDX,
|
|
IARG_REG_VALUE, REG_GDX,
|
|
IARG_REG_VALUE, REG_GDX,
|
|
IARG_REG_VALUE, REG_GDX,
|
|
IARG_REG_VALUE, REG_GDX,
|
|
IARG_END);
|
|
|
|
INS_InsertIfCall(ins, IPOINT_BEFORE, AFUNPTR(IfMyThread), IARG_THREAD_ID, IARG_END);
|
|
INS_InsertThenCall(ins, IPOINT_BEFORE, (AFUNPTR)RecordInstructionInfo,
|
|
// 4 dummy params to get the real params to be pushed on the stack in Intel64
|
|
IARG_UINT32, 1, IARG_UINT32, 2, IARG_UINT32, 3, IARG_UINT32, 4,
|
|
IARG_THREAD_ID,
|
|
IARG_INST_PTR,
|
|
IARG_REG_VALUE, REG_GFLAGS,
|
|
IARG_ADDRINT, nextAddr,
|
|
IARG_UINT32, maxRRegs,
|
|
IARG_UINT32, maxWRegs,
|
|
IARG_ADDRINT, sz,
|
|
#ifdef TARGET_IA32E
|
|
IARG_ADDRINT, 0xdeadbeefdeadbeefLL,
|
|
#else
|
|
IARG_ADDRINT, 0xdeadbeef,
|
|
#endif
|
|
IARG_REG_VALUE, REG_GDX,
|
|
IARG_REG_VALUE, REG_GDX,
|
|
IARG_REG_VALUE, REG_GDX,
|
|
IARG_REG_VALUE, REG_GDX,
|
|
IARG_REG_VALUE, REG_GDX,
|
|
IARG_REG_VALUE, REG_GDX,
|
|
IARG_END);
|
|
|
|
|
|
INS_InsertIfCall(ins, IPOINT_BEFORE, AFUNPTR(IfMyThread), IARG_THREAD_ID, IARG_END);
|
|
INS_InsertThenCall(ins, IPOINT_BEFORE, (AFUNPTR)VerifyInstructionInfo,
|
|
IARG_THREAD_ID,
|
|
IARG_INST_PTR,
|
|
IARG_REG_VALUE, REG_GFLAGS,
|
|
IARG_ADDRINT, nextAddr,
|
|
IARG_UINT32, maxRRegs,
|
|
IARG_UINT32, maxWRegs,
|
|
IARG_ADDRINT, sz,
|
|
#ifdef TARGET_IA32E
|
|
IARG_ADDRINT, 0xdeadbeefdeadbeefLL,
|
|
#else
|
|
IARG_ADDRINT, 0xdeadbeef,
|
|
#endif
|
|
IARG_REG_VALUE, REG_GDX,
|
|
IARG_REG_VALUE, REG_GDX,
|
|
IARG_REG_VALUE, REG_GDX,
|
|
IARG_REG_VALUE, REG_GDX,
|
|
IARG_REG_VALUE, REG_GDX,
|
|
IARG_REG_VALUE, REG_GDX,
|
|
IARG_END);
|
|
}
|
|
|
|
}
|
|
|
|
VOID Fini(INT32 code, VOID *v)
|
|
{
|
|
fprintf (log_inl, "SUCCESS\n");
|
|
fclose(log_inl);
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
if( PIN_Init(argc,argv) )
|
|
{
|
|
return Usage();
|
|
}
|
|
|
|
string logfile = KnobOutputFile.Value();
|
|
|
|
log_inl = fopen(logfile.c_str(), "w");
|
|
|
|
INS_AddInstrumentFunction(Instruction, NULL);
|
|
PIN_AddFiniFunction(Fini, NULL);
|
|
|
|
PIN_AddThreadStartFunction(ThreadStart, NULL);
|
|
|
|
// Never returns
|
|
PIN_StartProgram();
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ===================================================================== */
|
|
/* eof */
|
|
/* ===================================================================== */
|