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.
317 lines
8.2 KiB
317 lines
8.2 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.
|
|
*/
|
|
|
|
/*
|
|
* Rewrite all memory operands, though we don't actually change the addresses they access.
|
|
*/
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <iomanip>
|
|
|
|
#include <string.h>
|
|
#include "pin.H"
|
|
using std::hex;
|
|
using std::ofstream;
|
|
using std::dec;
|
|
using std::string;
|
|
using std::endl;
|
|
|
|
KNOB<BOOL> KnobTrace(KNOB_MODE_WRITEONCE, "pintool", "t", "0", "trace rewrites");
|
|
KNOB<BOOL> KnobOne(KNOB_MODE_WRITEONCE, "pintool", "1", "0", "Don't rewrite the first memory operand");
|
|
KNOB<BOOL> KnobTwo(KNOB_MODE_WRITEONCE, "pintool", "2", "0", "Don't rewrite the second memory operand");
|
|
KNOB<string> KnobOutput(KNOB_MODE_WRITEONCE,"pintool", "o", "rewritememop1.out", "Name for log file");
|
|
|
|
KNOB<BOOL> KnobUseIargConstContext(KNOB_MODE_WRITEONCE, "pintool",
|
|
"const_context", "0", "use IARG_CONST_CONTEXT");
|
|
|
|
static ofstream out;
|
|
static UINT64 rewritten = 0;
|
|
static UINT64 afterBranch = 0;
|
|
static BOOL rewriteOp[32];
|
|
|
|
#define STRINGIZE(v) #v
|
|
#define REGENTRY(n) { REG_##n, STRINGIZE(n) }
|
|
|
|
/* ===================================================================== */
|
|
/* Tracing code. It prints each instruction, and, after it, the register state
|
|
* changes it made.
|
|
*/
|
|
|
|
/* Information for each thread. */
|
|
class threadState
|
|
{
|
|
public:
|
|
UINT32 iCount;
|
|
CONTEXT context;
|
|
};
|
|
|
|
static threadState threadStates[32];
|
|
|
|
/************************************************************************/
|
|
/* We simply allocate space for the dis-assembled instruction strings and
|
|
* let them leak.
|
|
*/
|
|
static char const * formatInstruction(INS ins)
|
|
{
|
|
ADDRINT ip = INS_Address(ins);
|
|
string formatted = hexstr(ip) + " " + INS_Disassemble(ins);
|
|
char * res = new char [formatted.length()+1];
|
|
|
|
strcpy (res, formatted.c_str());
|
|
|
|
return res;
|
|
}
|
|
|
|
// This function is called before every instruction is executed
|
|
// and prints the pre-formatted dis-assembled instruction
|
|
static VOID printInstruction(THREADID thread, ADDRINT disas)
|
|
{
|
|
threadState * s = &threadStates[thread];
|
|
UINT32 seqNo = ++s->iCount;
|
|
|
|
out << dec << seqNo << ":" << ((const char *)Addrint2VoidStar(disas)) << endl;
|
|
}
|
|
|
|
|
|
// Table of registers to check and display
|
|
static const struct
|
|
{
|
|
REG regnum;
|
|
const char * name;
|
|
} checkedRegisters[] =
|
|
#if defined(TARGET_IA32E)
|
|
{
|
|
REGENTRY(RFLAGS),
|
|
REGENTRY(RAX),
|
|
REGENTRY(RBX),
|
|
REGENTRY(RCX),
|
|
REGENTRY(RDX),
|
|
REGENTRY(RBP),
|
|
REGENTRY(RSP),
|
|
REGENTRY(RDI),
|
|
REGENTRY(RSI),
|
|
REGENTRY(R8),
|
|
REGENTRY(R9),
|
|
REGENTRY(R10),
|
|
REGENTRY(R11),
|
|
REGENTRY(R12),
|
|
REGENTRY(R13),
|
|
REGENTRY(R14),
|
|
REGENTRY(R15)
|
|
};
|
|
#elif defined(TARGET_IA32)
|
|
{
|
|
REGENTRY(EFLAGS),
|
|
REGENTRY(EAX),
|
|
REGENTRY(EBX),
|
|
REGENTRY(ECX),
|
|
REGENTRY(EDX),
|
|
REGENTRY(EBP),
|
|
REGENTRY(ESP),
|
|
REGENTRY(EDI),
|
|
REGENTRY(ESI),
|
|
};
|
|
#else
|
|
# error Unknown processor
|
|
#endif
|
|
|
|
static VOID printRegisterDiffs(THREADID tid, CONTEXT *ctx)
|
|
{
|
|
threadState * s = &threadStates[tid];
|
|
UINT32 seqNo = s->iCount;
|
|
CONTEXT * savedCtx = &s->context;
|
|
|
|
// Save the context if this was the first instruction
|
|
if (seqNo == 0)
|
|
PIN_SaveContext(ctx, savedCtx);
|
|
else
|
|
{
|
|
for (UINT32 i=0; i<sizeof(checkedRegisters)/sizeof(checkedRegisters[0]); i++)
|
|
{
|
|
REG r = checkedRegisters[i].regnum;
|
|
ADDRINT newValue = PIN_GetContextReg(ctx, r);
|
|
|
|
if (PIN_GetContextReg(savedCtx, r) != newValue)
|
|
{
|
|
out << dec << seqNo << ": " << checkedRegisters[i].name << " = " << hex << newValue << endl;
|
|
PIN_SetContextReg(savedCtx, r, newValue);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static UINT32 opcodesRewritten[XED_ICLASS_LAST];
|
|
|
|
static void printHex (ADDRINT p)
|
|
{
|
|
out << std::setw(2*(sizeof(p)+1)) << std::hex << p << std::dec ;
|
|
}
|
|
|
|
static ADDRINT ProcessAddress(UINT32 operand, ADDRINT val, ADDRINT ip)
|
|
{
|
|
if (KnobTrace)
|
|
{
|
|
out << " ";
|
|
printHex (ip);
|
|
out << ": [" << operand << "] ";
|
|
printHex (val);
|
|
out << endl;
|
|
}
|
|
rewritten++;
|
|
return val;
|
|
}
|
|
|
|
static void BranchTaken(ADDRINT ip)
|
|
{
|
|
if (KnobTrace)
|
|
{
|
|
out << " ";
|
|
printHex (ip);
|
|
out << ": on branch taken" << endl;
|
|
}
|
|
afterBranch++;
|
|
}
|
|
|
|
// Choose the classes of instruction to rewrite addressing on.
|
|
// Useful to track down bugs to specific instructions.
|
|
static BOOL doTranslate(INS ins)
|
|
{
|
|
if (!INS_IsStandardMemop(ins) && !INS_HasMemoryVector(ins))
|
|
{
|
|
// We don't know how to treat these instructions
|
|
return FALSE;
|
|
}
|
|
switch (INS_Category(ins))
|
|
{
|
|
case XED_CATEGORY_CALL:
|
|
case XED_CATEGORY_RET:
|
|
case XED_CATEGORY_PUSH:
|
|
case XED_CATEGORY_POP:
|
|
case XED_CATEGORY_STRINGOP:
|
|
return TRUE;
|
|
|
|
case XED_CATEGORY_MISC:
|
|
switch (INS_Opcode(ins))
|
|
{
|
|
case XED_ICLASS_ENTER:
|
|
return TRUE;
|
|
case XED_ICLASS_LEAVE:
|
|
return TRUE;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
default:
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
static VOID RewriteIns(INS ins)
|
|
{
|
|
/* Rewrite all the memory operands */
|
|
int memops = INS_MemoryOperandCount(ins);
|
|
|
|
if (KnobTrace)
|
|
{
|
|
INS_InsertCall(ins, IPOINT_BEFORE,
|
|
AFUNPTR(printRegisterDiffs),
|
|
IARG_THREAD_ID,
|
|
(KnobUseIargConstContext)?IARG_CONST_CONTEXT:IARG_CONTEXT,
|
|
IARG_END);
|
|
INS_InsertCall(ins,IPOINT_BEFORE,
|
|
AFUNPTR(printInstruction),
|
|
IARG_THREAD_ID,
|
|
IARG_ADDRINT, formatInstruction(ins),
|
|
IARG_END);
|
|
|
|
}
|
|
|
|
if (memops && doTranslate(ins))
|
|
{
|
|
UINT32 op = INS_Opcode(ins);
|
|
|
|
opcodesRewritten[op]++;
|
|
|
|
for (int i=0; i<memops; i++)
|
|
{
|
|
// Only rewrite the operands we were asked to.
|
|
if (rewriteOp[i])
|
|
{
|
|
INS_RewriteMemoryOperand(ins, i, REG(REG_INST_G0+i));
|
|
|
|
INS_InsertCall(ins, IPOINT_BEFORE,
|
|
AFUNPTR(ProcessAddress),
|
|
IARG_UINT32, i,
|
|
IARG_MEMORYOP_EA, i,
|
|
IARG_INST_PTR,
|
|
IARG_RETURN_REGS, REG_INST_G0+i,
|
|
IARG_END);
|
|
}
|
|
}
|
|
|
|
if (INS_IsValidForIpointTakenBranch(ins))
|
|
{ // Check that IPOINT_TAKEN_BRANCH instrumentation is called.
|
|
INS_InsertCall(ins, IPOINT_TAKEN_BRANCH,
|
|
AFUNPTR (BranchTaken),
|
|
IARG_INST_PTR,
|
|
IARG_END);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID Trace(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))
|
|
{
|
|
RewriteIns(ins);
|
|
}
|
|
}
|
|
}
|
|
|
|
void AtEnd(INT32 code, VOID *arg)
|
|
{
|
|
out << "Target exited with code : " << code << endl << endl;
|
|
out << "Dynamically rewrote " << rewritten << " memory operands" << endl;
|
|
out << "Branch taken " << afterBranch << endl;
|
|
|
|
out << "Statically rewritten opcodes" << endl;
|
|
for (UINT32 i=0; i<XED_ICLASS_LAST; i++)
|
|
{
|
|
if (opcodesRewritten[i])
|
|
{
|
|
out << std::setw(12) << std::left << xed_iclass_enum_t2str(xed_iclass_enum_t(i)) << std::right <<
|
|
" " << std::setw(9) << opcodesRewritten[i] << endl;
|
|
}
|
|
}
|
|
out.close();
|
|
}
|
|
|
|
int main(int argc, char * argv[])
|
|
{
|
|
PIN_InitSymbols();
|
|
PIN_Init(argc, argv);
|
|
|
|
out.open(KnobOutput.Value().c_str());
|
|
|
|
rewriteOp[0] = ! KnobOne;
|
|
rewriteOp[1] = ! KnobTwo;
|
|
|
|
TRACE_AddInstrumentFunction(Trace, 0);
|
|
PIN_AddFiniFunction(AtEnd, 0);
|
|
|
|
// Never returns
|
|
PIN_StartProgram();
|
|
|
|
return 0;
|
|
}
|