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.

209 lines
7.3 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.
*/
/* This test verifies the IARG_BRANCH_TARGET_ADDR and the values of the PC (IP) recorded in the context *,
when instrumenting indirect branches
*/
#include <iostream>
#include <fstream>
#include <string>
#include <set>
#include <cassert>
#include <stdlib.h>
#include "pin.H"
KNOB<std::string> KnobOutfile(KNOB_MODE_WRITEONCE, "pintool",
"o", "context-pc.out", "Output file name");
std::ofstream Out;
BOOL haveError = FALSE;
// The tool assumes single-threaded application.
// This may not be the case on Windows 10.
// We arbitrary choose single thread to profile.
THREADID myThread = INVALID_THREADID;
ADDRINT IfMyThread(THREADID threadId)
{
// Profile only single thread at any time
return threadId == myThread;
}
VOID ThreadStart(THREADID tid, CONTEXT *ctxt, INT32 flags, VOID *v)
{
// Determine single thread to profile.
if (myThread == INVALID_THREADID) myThread = tid;
}
static ADDRINT GetDisassembly(INS ins)
{
typedef std::set<std::string> STRING_SET;
typedef std::pair<STRING_SET::iterator, bool> STRING_SET_INSERT;
static STRING_SET UniqueStrings;
std::string dis = INS_Disassemble(ins);
STRING_SET_INSERT ret = UniqueStrings.insert(dis);
const char *ptr = ret.first->c_str();
return reinterpret_cast<ADDRINT>(ptr);
}
ADDRINT branchTargetAddrBefore = 0;
static void RecordTargetAddrBefore (ADDRINT branchTargetAddr)
{
branchTargetAddrBefore = branchTargetAddr;
}
static void CheckTargetAddrAfter (ADDRINT branchTargetAddr, ADDRINT pc, const char *dis)
{
if (branchTargetAddrBefore != branchTargetAddr)
{
haveError = TRUE;
Out << "***Error1 branchTargetAddr received from IPOINT_BEFORE instrumentation at pc 0x" << std::hex << pc << " is " << std::hex << branchTargetAddrBefore
<< ", is different form branchTargetAddr at IOPINT_TAKEN_BRANCH 0x" << std::hex << branchTargetAddr << ": " << dis << std::endl;
}
}
static void CheckPcAtBranchTarget(ADDRINT branchTargetAddr, ADDRINT pcExpectedInstPtr,
CONTEXT *ctxt,
CONTEXT *constCtxt,
ADDRINT pcInstPtr, const char *dis)
{
ADDRINT pcCtxt = PIN_GetContextReg(ctxt, REG_INST_PTR);
ADDRINT pcConstCtxt = PIN_GetContextReg(constCtxt, REG_INST_PTR);
if (pcConstCtxt != pcCtxt)
{
haveError = TRUE;
Out << "***Error2 CONTEXT pc is 0x" << std::hex << pcCtxt << " at IPOINT_TAKEN_BRANCH " <<
" is not equal to CONST_CONTEXT pc 0x" << std::hex << pcConstCtxt << std::endl;
}
if (pcCtxt != branchTargetAddr)
{
haveError = TRUE;
Out << "***Error2 CONTEXT pc is 0x" << std::hex << pcCtxt << " at IPOINT_TAKEN_BRANCH " <<
", but expected 0x" << std::hex << branchTargetAddr <<
". PC of INS is 0x" << std::hex << pcExpectedInstPtr << ": " << dis << std::endl;
}
if (pcInstPtr != pcExpectedInstPtr)
{
haveError = TRUE;
Out << "***Error2 INST_PTR pc is 0x" << std::hex << pcInstPtr << " at IPOINT_TAKEN_BRANCH " <<
", but expected 0x" << std::hex << pcExpectedInstPtr << ": " << dis << std::endl;
}
if (branchTargetAddrBefore != branchTargetAddr)
{
haveError = TRUE;
Out << "***Error2 branchTargetAddr received from IPOINT_BEFORE instrumentation at pc 0x" << std::hex << pcInstPtr << " is " << std::hex << branchTargetAddrBefore
<< ", is different form branchTargetAddr at IOPINT_TAKEN_BRANCH 0x" << std::hex << branchTargetAddr << ": " << dis << std::endl;
}
}
static void CheckPcBefore (ADDRINT pcExpectedInstPtr,
CONTEXT *ctxt,
CONTEXT *constCtxt,
ADDRINT pcInstPtr, const char *dis)
{
ADDRINT pcCtxt = PIN_GetContextReg(ctxt, REG_INST_PTR);
ADDRINT pcConstCtxt = PIN_GetContextReg(constCtxt, REG_INST_PTR);
if (pcConstCtxt != pcCtxt)
{
haveError = TRUE;
Out << "***Error3 CONTEXT pc is 0x" << std::hex << pcCtxt << " at IPOINT_BEFORE " <<
" is not equal to CONST_CONTEXT pc 0x" << std::hex << pcConstCtxt << std::endl;
}
if (pcCtxt != pcExpectedInstPtr)
{
haveError = TRUE;
Out << "***Error3 CONTEXT pc is 0x" << std::hex << pcCtxt << " at IPOINT_BEFORE " <<
", but expected 0x" << std::hex << pcExpectedInstPtr <<
". PC of INS is 0x" << std::hex << pcExpectedInstPtr << ": " << dis << std::endl;
}
if (pcInstPtr != pcExpectedInstPtr)
{
haveError = TRUE;
Out << "***Error3 INST_PTR pc is 0x" << std::hex << pcInstPtr << " at IPOINT_BEFORE " <<
", but expected 0x" << std::hex << pcExpectedInstPtr << ": " << dis << std::endl;
}
}
static void InstrumentIndirects(INS ins, VOID *)
{
if (INS_IsIndirectControlFlow(ins))
{
Out << "Instrumenting Indirect branch or call at 0x" << std::hex << INS_Address(ins) << " " << INS_Disassemble(ins) << std::endl;
INS_InsertIfCall(ins, IPOINT_BEFORE, AFUNPTR(IfMyThread), IARG_THREAD_ID, IARG_END);
INS_InsertThenCall(ins, IPOINT_BEFORE, AFUNPTR(RecordTargetAddrBefore),
IARG_BRANCH_TARGET_ADDR,
IARG_END);
INS_InsertIfCall(ins, IPOINT_BEFORE, AFUNPTR(IfMyThread), IARG_THREAD_ID, IARG_END);
INS_InsertThenCall(ins, IPOINT_BEFORE, AFUNPTR(CheckPcBefore),
IARG_ADDRINT, INS_Address(ins), IARG_CONTEXT, IARG_CONST_CONTEXT, IARG_INST_PTR, IARG_ADDRINT, GetDisassembly(ins), IARG_END);
INS_InsertIfCall(ins, IPOINT_TAKEN_BRANCH, AFUNPTR(IfMyThread), IARG_THREAD_ID, IARG_END);
INS_InsertThenCall(ins, IPOINT_TAKEN_BRANCH, AFUNPTR(CheckTargetAddrAfter),
IARG_BRANCH_TARGET_ADDR, IARG_INST_PTR, IARG_ADDRINT, GetDisassembly(ins), IARG_END);
INS_InsertIfCall(ins, IPOINT_TAKEN_BRANCH, AFUNPTR(IfMyThread), IARG_THREAD_ID, IARG_END);
INS_InsertThenCall(ins, IPOINT_TAKEN_BRANCH, AFUNPTR(CheckPcAtBranchTarget),
IARG_BRANCH_TARGET_ADDR, // is also expected CONTEXT PC
IARG_ADDRINT, INS_Address(ins), // expected INST_PTR PC
IARG_CONTEXT,
IARG_CONST_CONTEXT,
IARG_INST_PTR,
IARG_ADDRINT, GetDisassembly(ins),
IARG_END);
}
}
VOID Fini(INT32 code, VOID *v)
{
if (haveError)
{
std::cerr << "***error in expected values, see the file " << KnobOutfile.Value() << std::endl;
exit (-1);
}
}
int main(int argc, char * argv[])
{
PIN_Init(argc, argv);
Out.open(KnobOutfile.Value().c_str());
if (!Out.good())
{
std::cerr << "Unable to open '" << KnobOutfile.Value() << "'" << std::endl;
return 1;
}
INS_AddInstrumentFunction(InstrumentIndirects, 0);
// Add callbacks
PIN_AddThreadStartFunction(ThreadStart, 0);
PIN_AddFiniFunction(Fini, 0);
PIN_StartProgram();
return 0;
}