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.

504 lines
15 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 <iostream>
#include <fstream>
#include "pin.H"
#include "instlib.H"
using std::ios;
using std::ofstream;
using std::hex;
ofstream OutFile;
// Counters
static UINT64 icountMemRead = 0;
static UINT64 icountMemRead2 = 0;
static UINT64 icountMemWrite = 0;
static UINT64 icountMemOp = 0;
static UINT64 icountMemCall = 0;
static ADDRINT lastIp = 0;
static ADDRINT lastReadAddr = 0;
static ADDRINT lastWriteAddr = 0;
static const ADDRINT mask(~(16 - 1));
static UINT64 errors = 0;
static size_t lastBytes = 0;
static BOOL lastIsPrefetch = 0;
static BOOL lastIsRmw = 0;
static BOOL lastIsAtomic = 0;
static volatile THREADID myThread = INVALID_THREADID;
VOID ThreadStart(THREADID threadid, CONTEXT *ctxt, INT32 flags, VOID *v)
{
if (INVALID_THREADID == myThread) myThread = threadid;
}
VOID PIN_FAST_ANALYSIS_CALL readXmmMemoryFunc(
ADDRINT memea_callback, UINT32 bytes, string *dis, ADDRINT ip)
{
// case of multithreading - we care just about the main thread
if (PIN_ThreadId() != myThread) return;
// Check xmm size
if (16 != lastBytes || bytes != lastBytes)
{
OutFile << "XMM bytes error found: " << lastBytes << " and not 16 for " << *dis << endl;
errors++;
}
}
VOID PIN_FAST_ANALYSIS_CALL verifyPrefetchFunc(
ADDRINT memea_callback, UINT32 bytes, string *dis, ADDRINT ip)
{
// case of multithreading - we care just about the main thread
if (PIN_ThreadId() != myThread) return;
if (!lastIsPrefetch)
{
OutFile << "Prefetch flag not set: " << *dis << endl;
errors++;
}
}
VOID PIN_FAST_ANALYSIS_CALL verifyRmwFunc(
ADDRINT memea_callback, UINT32 bytes, string *dis, ADDRINT ip)
{
// case of multithreading - we care just about the main thread
if (PIN_ThreadId() != myThread) return;
if (!lastIsRmw)
{
OutFile << "RMW flag not set: " << *dis << endl;
errors++;
}
}
VOID PIN_FAST_ANALYSIS_CALL verifyAtomicFunc(
ADDRINT memea_callback, UINT32 bytes, string *dis, ADDRINT ip)
{
// case of multithreading - we care just about the main thread
if (PIN_ThreadId() != myThread) return;
if (!lastIsAtomic)
{
OutFile << "Atomic flag not set: " << *dis << endl;
errors++;
}
}
VOID PIN_FAST_ANALYSIS_CALL readMemoryFunc(
ADDRINT memea_orig,ADDRINT memea_callback,THREADID threadIndex, string *dis, ADDRINT ip)
{
// case of multithreading - we care just about the main thread
if (PIN_ThreadId() != myThread) return;
if (ip != lastIp)
{
OutFile << "read analysis missing: " << hex << ip << " " << *dis << endl;
errors++;
}
if (memea_orig != lastReadAddr)
{
OutFile << "read orig address incorrect: " << hex << memea_orig << " " << *dis << endl;
errors++;
}
if ((memea_callback & 0xf) != 0)
{
OutFile << "read address not 16 aligned: " << hex << memea_callback << " " << *dis << endl;
errors++;
}
if ((memea_orig & mask) != memea_callback)
{
OutFile << "read addresses incorrect: " << hex << memea_orig << " " << memea_callback << " " << *dis << endl;
errors++;
}
icountMemRead++;
}
VOID PIN_FAST_ANALYSIS_CALL read2MemoryFunc(ADDRINT memea_orig,ADDRINT memea_callback,
ADDRINT memea2_orig,ADDRINT memea2_callback,
THREADID threadIndex, string *dis,
CONTEXT *ctxt, ADDRINT ip)
{
// case of multithreading - we care just about the main thread
if (PIN_ThreadId() != myThread) return;
if (ip != lastIp)
{
OutFile << "read2 analysis missing: " << " " << *dis << endl;
errors++;
}
if ((memea_callback & 0xf) != 0)
{
OutFile << "read2 first address not 16 aligned: " << hex << memea_callback << " " << *dis << endl;
errors++;
}
if ((memea_orig & mask) != memea_callback)
{
OutFile << "read2 first addresses incorrect: " << hex << memea_orig << " " << memea_callback << " " << *dis << endl;
errors++;
}
if ((memea2_callback & 0xf) != 0)
{
OutFile << "read2 second address not 16 aligned: " << hex << memea2_callback << " " << *dis << endl;
errors++;
}
if ((memea_orig & mask) != memea_callback)
{
OutFile << "read2 second addresses incorrect: " << hex << memea2_orig << " " << memea2_callback << " " << *dis << endl;
errors++;
}
icountMemRead2++;
}
VOID PIN_FAST_ANALYSIS_CALL writeMemoryFunc(
THREADID threadIndex,ADDRINT memea_orig,ADDRINT memea_callback,ADDRINT ip, string *dis)
{
// case of multithreading - we care just about the main thread
if (PIN_ThreadId() != myThread) return;
if (ip != lastIp)
{
OutFile << "write analysis missing: " << " " << *dis << endl;
errors++;
}
if (memea_orig != lastWriteAddr)
{
OutFile << "write orig address incorrect: " << hex << memea_orig << " " << ip << " " << *dis << endl;
errors++;
}
if ((memea_callback & 0xf) != 0)
{
OutFile << "write address not 16 aligned: " << hex << memea_callback << " " << *dis << endl;
errors++;
}
if ((memea_orig & mask) != memea_callback)
{
OutFile << "write addresses incorrect: " << hex << memea_orig << " " << memea_callback << " " << *dis << endl;
errors++;
}
icountMemWrite++;
}
VOID PIN_FAST_ANALYSIS_CALL opMemoryFunc(
ADDRINT memea_orig,ADDRINT memea_callback, UINT32 bytes, ADDRINT ip, string *dis)
{
// case of multithreading - we care just about the main thread
if (PIN_ThreadId() != myThread) return;
if (ip != lastIp)
{
OutFile << "op analysis missing: " << " " << *dis << endl;
errors++;
}
if (bytes != lastBytes)
{
OutFile << "op bytes error found: " << bytes << " and not " << lastBytes << " for " << *dis << endl;
errors++;
}
if ((memea_callback & 0xf) != 0)
{
OutFile << "op address not 16 aligned: " << hex << memea_callback << " " << *dis << endl;
errors++;
}
if ((memea_orig & mask) != memea_callback)
{
OutFile << "op addresses incorrect: " << hex << memea_orig << " " << memea_callback << " " << ip << " " << *dis << endl;
errors++;
}
icountMemOp++;
}
ADDRINT PIN_FAST_ANALYSIS_CALL memoryCallback(PIN_MEM_TRANS_INFO* memTransInfo, VOID *v)
{
// Test the threadIndex field (Mantis 0003429)
if (memTransInfo->threadIndex != PIN_ThreadId())
{
cout << "PIN_MEM_TRANS_INFO.threadIndex bad value " << memTransInfo->threadIndex << " (should be " << PIN_ThreadId() << ")" << endl;
errors++;
}
if (memTransInfo->flags.bits.isFromPin)
{
// PIN Internal memory dereference
return memTransInfo->addr;
}
if (PIN_ThreadId() == myThread)
{
icountMemCall++;
lastIp = memTransInfo->ip;
lastBytes = memTransInfo->bytes;
lastIsAtomic = memTransInfo->flags.bits.isAtomic;
lastIsPrefetch = memTransInfo->flags.bits.isPrefetch;
lastIsRmw = memTransInfo->flags.bits.isRmw;
}
if (memTransInfo->memOpType == PIN_MEMOP_STORE )
{
if (PIN_ThreadId() == myThread) lastWriteAddr = memTransInfo->addr;
// Verify that we can call PIN API functions inside PIN
PIN_SafeCopy((void*)memTransInfo->addr,
(void*)memTransInfo->addr,
memTransInfo->bytes);
}
else
if (PIN_ThreadId() == myThread) lastReadAddr = memTransInfo->addr;
// Check void parameter
if ((ADDRINT)v != 0xa5a5a5a5)
{
OutFile << "v incorrect inside callback: " << hex << v << endl;
errors++;
}
//OutFile << "callback addresses: " << hex << (memTransInfo->addr) << " " << (memTransInfo->addr & mask) << " " <<memTransInfo->ip << endl;
return (memTransInfo->addr & mask);
}
// Pin calls this function every time a new instruction is encountered
VOID Instruction(INS ins, VOID *v)
{
string *disptr = new string(INS_Disassemble(ins));
// reads
if (INS_IsMemoryRead(ins)) {
INS_InsertCall(ins,
IPOINT_BEFORE,
(AFUNPTR)readMemoryFunc,
IARG_FAST_ANALYSIS_CALL,
IARG_MEMORYREAD_EA,
IARG_MEMORYREAD_PTR,
IARG_THREAD_ID,
IARG_PTR, disptr,
IARG_INST_PTR,
IARG_END);
}
// Handle read from memory to XMM
if (INS_Opcode(ins) == XED_ICLASS_MOVDQU &&
INS_IsMemoryRead(ins) &&
INS_OperandIsReg(ins, 0) &&
INS_OperandIsMemory(ins, 1))
{
if (REG_is_xmm(INS_OperandReg(ins, 0)))
{
INS_InsertCall(ins,
IPOINT_BEFORE,
(AFUNPTR)readXmmMemoryFunc,
IARG_FAST_ANALYSIS_CALL,
IARG_MEMORYREAD_PTR,
IARG_MEMORYREAD_SIZE,
IARG_PTR, disptr,
IARG_INST_PTR,
IARG_END);
}
}
// Handle Prefetch
if (INS_IsMemoryRead(ins) &&
xed_decoded_inst_is_prefetch(INS_XedDec(ins)))
{
INS_InsertCall(ins,
IPOINT_BEFORE,
(AFUNPTR)verifyPrefetchFunc,
IARG_FAST_ANALYSIS_CALL,
IARG_MEMORYREAD_PTR,
IARG_MEMORYREAD_SIZE,
IARG_PTR, disptr,
IARG_INST_PTR,
IARG_END);
}
// Handle Atomic
if (INS_IsAtomicUpdate(ins))
{
INS_InsertCall(ins,
IPOINT_BEFORE,
(AFUNPTR)verifyAtomicFunc,
IARG_FAST_ANALYSIS_CALL,
IARG_MEMORYWRITE_PTR,
IARG_MEMORYWRITE_SIZE,
IARG_PTR, disptr,
IARG_INST_PTR,
IARG_END);
}
// writes
if (INS_IsMemoryWrite(ins)) {
INS_InsertCall(ins,
IPOINT_BEFORE,
(AFUNPTR)writeMemoryFunc,
IARG_FAST_ANALYSIS_CALL,
IARG_THREAD_ID,
IARG_MEMORYWRITE_EA,
IARG_MEMORYWRITE_PTR ,
IARG_INST_PTR,
IARG_PTR, disptr,
IARG_END);
}
UINT32 memOperands = INS_MemoryOperandCount(ins);
if (!INS_IsVgather(ins) && memOperands)
{
// OPs
for (UINT32 memOp = 0; memOp < memOperands; memOp++)
{
if (INS_MemoryOperandIsRead(ins, memOp) ||
INS_MemoryOperandIsWritten(ins, memOp))
{
INS_InsertCall(ins,
IPOINT_BEFORE,
(AFUNPTR)opMemoryFunc,
IARG_FAST_ANALYSIS_CALL,
IARG_MEMORYOP_EA, memOp,
IARG_MEMORYOP_PTR, memOp,
IARG_UINT32,INS_MemoryOperandSize(ins,memOp),
IARG_INST_PTR ,
IARG_PTR, disptr,
IARG_END);
}
// Handle RMW
if (INS_MemoryOperandIsRead(ins, memOp) &&
INS_MemoryOperandIsWritten(ins, memOp))
{
INS_InsertCall(ins,
IPOINT_BEFORE,
(AFUNPTR)verifyRmwFunc,
IARG_FAST_ANALYSIS_CALL,
IARG_MEMORYOP_PTR, memOp,
IARG_UINT32,INS_MemoryOperandSize(ins,memOp),
IARG_PTR, disptr,
IARG_INST_PTR,
IARG_END);
}
}
}
// READ2
if (INS_HasMemoryRead2(ins)) {
INS_InsertCall(ins,
IPOINT_BEFORE,
(AFUNPTR)read2MemoryFunc,
IARG_FAST_ANALYSIS_CALL,
IARG_MEMORYREAD_EA,
IARG_MEMORYREAD_PTR,
IARG_MEMORYREAD2_EA,
IARG_MEMORYREAD2_PTR,
IARG_THREAD_ID,
IARG_PTR, disptr,
IARG_CONTEXT,
IARG_INST_PTR,
IARG_END);
}
}
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
"o", "memaddrcall.out", "specify output file name");
// This function is called when the application exits
VOID Fini(INT32 code, VOID *v)
{
// Write to a file since cout and cerr maybe closed by the application
OutFile.setf(ios::showbase);
OutFile << "Count Mem Reads " << icountMemRead << endl;
OutFile << "Count Mem Read2s " << icountMemRead2 << endl;
OutFile << "Count Mem Writes " << icountMemWrite << endl;
OutFile << "Count Mem Ops " << icountMemOp << endl;
OutFile << "Count Mem callbacks " << icountMemCall << endl;
OutFile << "Errors " << errors << endl;
OutFile.close();
// If we have errors then terminate abnormally
if (errors)
{
cout << "Test memory_addr_callback is terminated cause found " << errors << " errors " << endl;
PIN_ExitProcess(errors);
}
}
/* ===================================================================== */
/* Print Help Message */
/* ===================================================================== */
INT32 Usage()
{
cerr << "This tool tests memory address translation callback" << endl;
cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
return -1;
}
/* ===================================================================== */
/* Main */
/* ===================================================================== */
int main(int argc, char * argv[])
{
ADDRINT dummy = 0xa5a5a5a5;
// Initialize pin
if (PIN_Init(argc, argv)) return Usage();
PIN_AddThreadStartFunction(ThreadStart, NULL);
OutFile.open(KnobOutputFile.Value().c_str());
// Register Instruction to be called to instrument instructions
INS_AddInstrumentFunction(Instruction, 0);
// Verify that the PIN API is null before registration
if (PIN_GetMemoryAddressTransFunction())
{
cout << "Test memory_addr_callback found PIN API callback not null before registration " << endl;
PIN_ExitProcess(-1);
}
// Register memory callback
PIN_AddMemoryAddressTransFunction(memoryCallback,(VOID*)dummy);
// Verify that the PIN API is not null after registration
if (!PIN_GetMemoryAddressTransFunction())
{
cout << "Test memory_addr_callback found PIN API callback null after registration " << endl;
PIN_ExitProcess(-1);
}
// Register Fini to be called when the application exits
PIN_AddFiniFunction(Fini, 0);
// Start the program, never returns
PIN_StartProgram();
return errors;
}