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.
824 lines
20 KiB
824 lines
20 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.
|
|
*/
|
|
|
|
/*! @file
|
|
* This file contains a tool that generates instructions traces with values.
|
|
* It is designed to help debugging.
|
|
*/
|
|
|
|
|
|
|
|
#include <vector>
|
|
#include <iostream>
|
|
#include <iomanip>
|
|
#include <fstream>
|
|
#include <unistd.h>
|
|
#include "pin.H"
|
|
#include "instlib.H"
|
|
#include "control_manager.H"
|
|
|
|
using namespace CONTROLLER;
|
|
using namespace INSTLIB;
|
|
|
|
/* ===================================================================== */
|
|
/* Commandline Switches */
|
|
/* ===================================================================== */
|
|
|
|
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
|
|
"o", "debugtrace.out", "trace file");
|
|
KNOB<BOOL> KnobPid(KNOB_MODE_WRITEONCE, "pintool",
|
|
"i", "0", "append pid to output");
|
|
KNOB<THREADID> KnobWatchThread(KNOB_MODE_WRITEONCE, "pintool",
|
|
"watch_thread", "-1", "thread to watch, -1 for all");
|
|
KNOB<BOOL> KnobFlush(KNOB_MODE_WRITEONCE, "pintool",
|
|
"flush", "0", "Flush output after every instruction");
|
|
KNOB<BOOL> KnobSymbols(KNOB_MODE_WRITEONCE, "pintool",
|
|
"symbols", "1", "Include symbol information");
|
|
KNOB<BOOL> KnobLines(KNOB_MODE_WRITEONCE, "pintool",
|
|
"lines", "0", "Include line number information");
|
|
KNOB<BOOL> KnobTraceInstructions(KNOB_MODE_WRITEONCE, "pintool",
|
|
"instruction", "0", "Trace instructions");
|
|
KNOB<BOOL> KnobTraceCalls(KNOB_MODE_WRITEONCE, "pintool",
|
|
"call", "1", "Trace calls");
|
|
KNOB<BOOL> KnobTraceMemory(KNOB_MODE_WRITEONCE, "pintool",
|
|
"memory", "0", "Trace memory");
|
|
KNOB<BOOL> KnobSilent(KNOB_MODE_WRITEONCE, "pintool",
|
|
"silent", "0", "Do everything but write file (for debugging).");
|
|
KNOB<BOOL> KnobEarlyOut(KNOB_MODE_WRITEONCE, "pintool", "early_out", "0" , "Exit after tracing the first region.");
|
|
|
|
|
|
/* ===================================================================== */
|
|
|
|
INT32 Usage()
|
|
{
|
|
cerr <<
|
|
"This pin tool collects an instruction trace for debugging\n"
|
|
"\n";
|
|
|
|
cerr << KNOB_BASE::StringKnobSummary();
|
|
|
|
cerr << endl;
|
|
|
|
return -1;
|
|
}
|
|
|
|
/* ===================================================================== */
|
|
/* Global Variables */
|
|
/* ===================================================================== */
|
|
|
|
LOCALVAR std::ofstream out;
|
|
|
|
LOCALVAR INT32 enabled = 0;
|
|
|
|
LOCALVAR FILTER filter;
|
|
|
|
LOCALVAR ICOUNT icount;
|
|
|
|
LOCALFUN BOOL Emit(THREADID threadid)
|
|
{
|
|
if (!enabled ||
|
|
KnobSilent ||
|
|
(KnobWatchThread != static_cast<THREADID>(-1) && KnobWatchThread != threadid))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
LOCALFUN VOID Flush()
|
|
{
|
|
if (KnobFlush)
|
|
out << flush;
|
|
}
|
|
|
|
/* ===================================================================== */
|
|
|
|
LOCALFUN VOID Fini(int, VOID * v);
|
|
|
|
LOCALFUN VOID Handler(EVENT_TYPE ev, VOID *, CONTEXT * ctxt, VOID *, THREADID, bool bcast)
|
|
{
|
|
switch(ev)
|
|
{
|
|
case EVENT_START:
|
|
enabled = 1;
|
|
PIN_RemoveInstrumentation();
|
|
#if defined(TARGET_IA32) || defined(TARGET_IA32E)
|
|
// So that the rest of the current trace is re-instrumented.
|
|
if (ctxt) PIN_ExecuteAt (ctxt);
|
|
#endif
|
|
break;
|
|
|
|
case EVENT_STOP:
|
|
enabled = 0;
|
|
PIN_RemoveInstrumentation();
|
|
if (KnobEarlyOut)
|
|
{
|
|
cerr << "Exiting due to -early_out" << endl;
|
|
Fini(0, NULL);
|
|
exit(0);
|
|
}
|
|
#if defined(TARGET_IA32) || defined(TARGET_IA32E)
|
|
// So that the rest of the current trace is re-instrumented.
|
|
if (ctxt) PIN_ExecuteAt (ctxt);
|
|
#endif
|
|
break;
|
|
|
|
default:
|
|
ASSERTX(false);
|
|
}
|
|
}
|
|
|
|
|
|
/* ===================================================================== */
|
|
|
|
VOID EmitNoValues(THREADID threadid, string * str)
|
|
{
|
|
if (!Emit(threadid))
|
|
return;
|
|
|
|
out
|
|
<< *str
|
|
<< endl;
|
|
|
|
Flush();
|
|
}
|
|
|
|
VOID Emit1Values(THREADID threadid, string * str, string * reg1str, ADDRINT reg1val)
|
|
{
|
|
if (!Emit(threadid))
|
|
return;
|
|
|
|
out
|
|
<< *str << " | "
|
|
<< *reg1str << " = " << reg1val
|
|
<< endl;
|
|
|
|
Flush();
|
|
}
|
|
|
|
VOID Emit2Values(THREADID threadid, string * str, string * reg1str, ADDRINT reg1val, string * reg2str, ADDRINT reg2val)
|
|
{
|
|
if (!Emit(threadid))
|
|
return;
|
|
|
|
out
|
|
<< *str << " | "
|
|
<< *reg1str << " = " << reg1val
|
|
<< ", " << *reg2str << " = " << reg2val
|
|
<< endl;
|
|
|
|
Flush();
|
|
}
|
|
|
|
VOID Emit3Values(THREADID threadid, string * str, string * reg1str, ADDRINT reg1val, string * reg2str, ADDRINT reg2val, string * reg3str, ADDRINT reg3val)
|
|
{
|
|
if (!Emit(threadid))
|
|
return;
|
|
|
|
out
|
|
<< *str << " | "
|
|
<< *reg1str << " = " << reg1val
|
|
<< ", " << *reg2str << " = " << reg2val
|
|
<< ", " << *reg3str << " = " << reg3val
|
|
<< endl;
|
|
|
|
Flush();
|
|
}
|
|
|
|
|
|
VOID Emit4Values(THREADID threadid, string * str, string * reg1str, ADDRINT reg1val, string * reg2str, ADDRINT reg2val, string * reg3str, ADDRINT reg3val, string * reg4str, ADDRINT reg4val)
|
|
{
|
|
if (!Emit(threadid))
|
|
return;
|
|
|
|
out
|
|
<< *str << " | "
|
|
<< *reg1str << " = " << reg1val
|
|
<< ", " << *reg2str << " = " << reg2val
|
|
<< ", " << *reg3str << " = " << reg3val
|
|
<< ", " << *reg4str << " = " << reg4val
|
|
<< endl;
|
|
|
|
Flush();
|
|
}
|
|
|
|
|
|
const UINT32 MaxEmitArgs = 4;
|
|
|
|
AFUNPTR emitFuns[] =
|
|
{
|
|
AFUNPTR(EmitNoValues), AFUNPTR(Emit1Values), AFUNPTR(Emit2Values), AFUNPTR(Emit3Values), AFUNPTR(Emit4Values)
|
|
};
|
|
|
|
/* ===================================================================== */
|
|
|
|
VOID EmitXMM(THREADID threadid, UINT32 regno, PIN_REGISTER* xmm)
|
|
{
|
|
if (!Emit(threadid))
|
|
return;
|
|
out << "\t\t\tXMM" << dec << regno << " := " << setfill('0') << hex;
|
|
out.unsetf(ios::showbase);
|
|
for(int i=0;i<16;i++) {
|
|
if (i==4 || i==8 || i==12)
|
|
out << "_";
|
|
out << setw(2) << (int)xmm->byte[15-i]; // msb on the left as in registers
|
|
}
|
|
out << setfill(' ') << endl;
|
|
out.setf(ios::showbase);
|
|
Flush();
|
|
}
|
|
|
|
VOID AddXMMEmit(INS ins, IPOINT point, REG xmm_dst)
|
|
{
|
|
INS_InsertCall(ins, point, AFUNPTR(EmitXMM), IARG_THREAD_ID,
|
|
IARG_UINT32, xmm_dst - REG_XMM0,
|
|
IARG_REG_CONST_REFERENCE, xmm_dst,
|
|
IARG_END);
|
|
}
|
|
|
|
VOID AddEmit(INS ins, IPOINT point, string & traceString, UINT32 regCount, REG regs[])
|
|
{
|
|
if (regCount > MaxEmitArgs)
|
|
regCount = MaxEmitArgs;
|
|
|
|
IARGLIST args = IARGLIST_Alloc();
|
|
for (UINT32 i = 0; i < regCount; i++)
|
|
{
|
|
IARGLIST_AddArguments(args, IARG_PTR, new string(REG_StringShort(regs[i])), IARG_REG_VALUE, regs[i], IARG_END);
|
|
}
|
|
|
|
INS_InsertCall(ins, point, emitFuns[regCount], IARG_THREAD_ID,
|
|
IARG_PTR, new string(traceString),
|
|
IARG_IARGLIST, args,
|
|
IARG_END);
|
|
IARGLIST_Free(args);
|
|
}
|
|
|
|
LOCALVAR VOID *WriteEa[PIN_MAX_THREADS];
|
|
|
|
VOID CaptureWriteEa(THREADID threadid, VOID * addr)
|
|
{
|
|
WriteEa[threadid] = addr;
|
|
}
|
|
|
|
VOID ShowN(UINT32 n, VOID *ea)
|
|
{
|
|
out.unsetf(ios::showbase);
|
|
// Print out the bytes in "big endian even though they are in memory little endian.
|
|
// This is most natural for 8B and 16B quantities that show up most frequently.
|
|
// The address pointed to
|
|
out << std::setfill('0');
|
|
UINT8 b[512];
|
|
UINT8* x;
|
|
if (n > 512)
|
|
x = new UINT8[n];
|
|
else
|
|
x = b;
|
|
PIN_SafeCopy(x,static_cast<UINT8*>(ea),n);
|
|
for (UINT32 i = 0; i < n; i++)
|
|
{
|
|
out << std::setw(2) << static_cast<UINT32>(x[n-i-1]);
|
|
if (((reinterpret_cast<ADDRINT>(ea)+n-i-1)&0x3)==0 && i<n-1)
|
|
out << "_";
|
|
}
|
|
out << std::setfill(' ');
|
|
out.setf(ios::showbase);
|
|
if (n>512)
|
|
delete [] x;
|
|
}
|
|
|
|
|
|
VOID EmitWrite(THREADID threadid, UINT32 size)
|
|
{
|
|
if (!Emit(threadid))
|
|
return;
|
|
|
|
out << " Write ";
|
|
|
|
VOID * ea = WriteEa[threadid];
|
|
|
|
switch(size)
|
|
{
|
|
case 0:
|
|
out << "0 repeat count" << endl;
|
|
break;
|
|
|
|
case 1:
|
|
{
|
|
UINT8 x;
|
|
PIN_SafeCopy(&x, static_cast<UINT8*>(ea), 1);
|
|
out << "*(UINT8*)" << ea << " = " << static_cast<UINT32>(x) << endl;
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
{
|
|
UINT16 x;
|
|
PIN_SafeCopy(&x, static_cast<UINT16*>(ea), 2);
|
|
out << "*(UINT16*)" << ea << " = " << x << endl;
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
{
|
|
UINT32 x;
|
|
PIN_SafeCopy(&x, static_cast<UINT32*>(ea), 4);
|
|
out << "*(UINT32*)" << ea << " = " << x << endl;
|
|
}
|
|
break;
|
|
|
|
case 8:
|
|
{
|
|
UINT64 x;
|
|
PIN_SafeCopy(&x, static_cast<UINT64*>(ea), 8);
|
|
out << "*(UINT64*)" << ea << " = " << x << endl;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
out << "*(UINT" << dec << size * 8 << hex << ")" << ea << " = ";
|
|
ShowN(size,ea);
|
|
out << endl;
|
|
break;
|
|
}
|
|
|
|
Flush();
|
|
}
|
|
|
|
VOID EmitRead(THREADID threadid, VOID * ea, UINT32 size)
|
|
{
|
|
if (!Emit(threadid))
|
|
return;
|
|
|
|
out << " Read ";
|
|
|
|
switch(size)
|
|
{
|
|
case 0:
|
|
out << "0 repeat count" << endl;
|
|
break;
|
|
|
|
case 1:
|
|
{
|
|
UINT8 x;
|
|
PIN_SafeCopy(&x,static_cast<UINT8*>(ea),1);
|
|
out << static_cast<UINT32>(x) << " = *(UINT8*)" << ea << endl;
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
{
|
|
UINT16 x;
|
|
PIN_SafeCopy(&x,static_cast<UINT16*>(ea),2);
|
|
out << x << " = *(UINT16*)" << ea << endl;
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
{
|
|
UINT32 x;
|
|
PIN_SafeCopy(&x,static_cast<UINT32*>(ea),4);
|
|
out << x << " = *(UINT32*)" << ea << endl;
|
|
}
|
|
break;
|
|
|
|
case 8:
|
|
{
|
|
UINT64 x;
|
|
PIN_SafeCopy(&x,static_cast<UINT64*>(ea),8);
|
|
out << x << " = *(UINT64*)" << ea << endl;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ShowN(size,ea);
|
|
out << " = *(UINT" << dec << size * 8 << hex << ")" << ea << endl;
|
|
break;
|
|
}
|
|
|
|
Flush();
|
|
}
|
|
|
|
|
|
LOCALVAR INT32 indent = 0;
|
|
|
|
VOID Indent()
|
|
{
|
|
for (INT32 i = 0; i < indent; i++)
|
|
{
|
|
out << "| ";
|
|
}
|
|
}
|
|
|
|
VOID EmitICount()
|
|
{
|
|
out << setw(10) << dec << icount.Count() << hex << " ";
|
|
}
|
|
|
|
VOID EmitDirectCall(THREADID threadid, string * str, INT32 tailCall, ADDRINT arg0, ADDRINT arg1)
|
|
{
|
|
if (!Emit(threadid))
|
|
return;
|
|
|
|
EmitICount();
|
|
|
|
if (tailCall)
|
|
{
|
|
// A tail call is like an implicit return followed by an immediate call
|
|
indent--;
|
|
}
|
|
|
|
Indent();
|
|
out << *str << "(" << arg0 << ", " << arg1 << ", ...)" << endl;
|
|
|
|
indent++;
|
|
|
|
Flush();
|
|
}
|
|
|
|
string FormatAddress(ADDRINT address, RTN rtn)
|
|
{
|
|
string s = StringFromAddrint(address);
|
|
|
|
if (KnobSymbols && RTN_Valid(rtn))
|
|
{
|
|
IMG img = SEC_Img(RTN_Sec(rtn));
|
|
s+= " ";
|
|
if (IMG_Valid(img))
|
|
{
|
|
s += IMG_Name(img) + ":";
|
|
}
|
|
|
|
s += RTN_Name(rtn);
|
|
|
|
ADDRINT delta = address - RTN_Address(rtn);
|
|
if (delta != 0)
|
|
{
|
|
s += "+" + hexstr(delta, 4);
|
|
}
|
|
}
|
|
|
|
if (KnobLines)
|
|
{
|
|
INT32 line;
|
|
string file;
|
|
|
|
PIN_GetSourceLocation(address, NULL, &line, &file);
|
|
|
|
if (file != "")
|
|
{
|
|
s += " (" + file + ":" + decstr(line) + ")";
|
|
}
|
|
}
|
|
return s;
|
|
}
|
|
|
|
VOID EmitIndirectCall(THREADID threadid, string * str, ADDRINT target, ADDRINT arg0, ADDRINT arg1)
|
|
{
|
|
if (!Emit(threadid))
|
|
return;
|
|
|
|
EmitICount();
|
|
Indent();
|
|
out << *str;
|
|
|
|
PIN_LockClient();
|
|
|
|
string s = FormatAddress(target, RTN_FindByAddress(target));
|
|
|
|
PIN_UnlockClient();
|
|
|
|
out << s << "(" << arg0 << ", " << arg1 << ", ...)" << endl;
|
|
indent++;
|
|
|
|
Flush();
|
|
}
|
|
|
|
VOID EmitReturn(THREADID threadid, string * str, ADDRINT ret0)
|
|
{
|
|
if (!Emit(threadid))
|
|
return;
|
|
|
|
EmitICount();
|
|
indent--;
|
|
if (indent < 0)
|
|
{
|
|
out << "@@@ return underflow\n";
|
|
indent = 0;
|
|
}
|
|
|
|
Indent();
|
|
out << *str << " returns: " << ret0 << endl;
|
|
|
|
Flush();
|
|
}
|
|
|
|
|
|
VOID CallTrace(TRACE trace, INS ins)
|
|
{
|
|
if (!KnobTraceCalls)
|
|
return;
|
|
|
|
if (INS_IsCall(ins) && !INS_IsDirectControlFlow(ins))
|
|
{
|
|
// Indirect call
|
|
string s = "Call " + FormatAddress(INS_Address(ins), TRACE_Rtn(trace));
|
|
s += " -> ";
|
|
|
|
INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(EmitIndirectCall), IARG_THREAD_ID,
|
|
IARG_PTR, new string(s), IARG_BRANCH_TARGET_ADDR,
|
|
IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_FUNCARG_CALLSITE_VALUE, 1, IARG_END);
|
|
}
|
|
else if (INS_IsDirectControlFlow(ins))
|
|
{
|
|
// Is this a tail call?
|
|
RTN sourceRtn = TRACE_Rtn(trace);
|
|
RTN destRtn = RTN_FindByAddress(INS_DirectControlFlowTargetAddress(ins));
|
|
|
|
if (INS_IsCall(ins) // conventional call
|
|
|| sourceRtn != destRtn // tail call
|
|
)
|
|
{
|
|
BOOL tailcall = !INS_IsCall(ins);
|
|
|
|
string s = "";
|
|
if (tailcall)
|
|
{
|
|
s += "Tailcall ";
|
|
}
|
|
else
|
|
{
|
|
if( INS_IsProcedureCall(ins) )
|
|
s += "Call ";
|
|
else
|
|
{
|
|
s += "PcMaterialization ";
|
|
tailcall=1;
|
|
}
|
|
|
|
}
|
|
|
|
//s += INS_Mnemonic(ins) + " ";
|
|
|
|
s += FormatAddress(INS_Address(ins), TRACE_Rtn(trace));
|
|
s += " -> ";
|
|
|
|
ADDRINT target = INS_DirectControlFlowTargetAddress(ins);
|
|
|
|
s += FormatAddress(target, RTN_FindByAddress(target));
|
|
|
|
INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(EmitDirectCall),
|
|
IARG_THREAD_ID, IARG_PTR, new string(s), IARG_BOOL, tailcall,
|
|
IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_FUNCARG_CALLSITE_VALUE, 1, IARG_END);
|
|
}
|
|
}
|
|
else if (INS_IsRet(ins))
|
|
{
|
|
RTN rtn = TRACE_Rtn(trace);
|
|
|
|
#if defined(TARGET_LINUX) && defined(TARGET_IA32)
|
|
// if( RTN_Name(rtn) == "_dl_debug_state") return;
|
|
if( RTN_Valid(rtn) && RTN_Name(rtn) == "_dl_runtime_resolve") return;
|
|
#endif
|
|
string tracestring = "Return " + FormatAddress(INS_Address(ins), rtn);
|
|
INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(EmitReturn),
|
|
IARG_THREAD_ID, IARG_PTR, new string(tracestring), IARG_FUNCRET_EXITPOINT_VALUE, IARG_END);
|
|
}
|
|
}
|
|
|
|
|
|
VOID InstructionTrace(TRACE trace, INS ins)
|
|
{
|
|
if (!KnobTraceInstructions)
|
|
return;
|
|
|
|
ADDRINT addr = INS_Address(ins);
|
|
ASSERTX(addr);
|
|
|
|
// Format the string at instrumentation time
|
|
string traceString = "";
|
|
string astring = FormatAddress(INS_Address(ins), TRACE_Rtn(trace));
|
|
for (INT32 length = astring.length(); length < 30; length++)
|
|
{
|
|
traceString += " ";
|
|
}
|
|
traceString = astring + traceString;
|
|
|
|
traceString += " " + INS_Disassemble(ins);
|
|
|
|
for (INT32 length = traceString.length(); length < 80; length++)
|
|
{
|
|
traceString += " ";
|
|
}
|
|
|
|
INT32 regCount = 0;
|
|
REG regs[20];
|
|
REG xmm_dst = REG_INVALID();
|
|
|
|
for (UINT32 i = 0; i < INS_MaxNumWRegs(ins); i++)
|
|
{
|
|
REG x = REG_FullRegName(INS_RegW(ins, i));
|
|
|
|
if (REG_is_gr(x)
|
|
#if defined(TARGET_IA32)
|
|
|| x == REG_EFLAGS
|
|
#elif defined(TARGET_IA32E)
|
|
|| x == REG_RFLAGS
|
|
#endif
|
|
)
|
|
{
|
|
regs[regCount] = x;
|
|
regCount++;
|
|
}
|
|
|
|
if (REG_is_xmm(x))
|
|
xmm_dst = x;
|
|
}
|
|
|
|
if (INS_IsValidForIpointAfter(ins))
|
|
{
|
|
AddEmit(ins, IPOINT_AFTER, traceString, regCount, regs);
|
|
}
|
|
if (INS_IsValidForIpointTakenBranch(ins))
|
|
{
|
|
AddEmit(ins, IPOINT_TAKEN_BRANCH, traceString, regCount, regs);
|
|
}
|
|
|
|
if (xmm_dst != REG_INVALID())
|
|
{
|
|
if (INS_IsValidForIpointAfter(ins))
|
|
AddXMMEmit(ins, IPOINT_AFTER, xmm_dst);
|
|
if (INS_IsValidForIpointTakenBranch(ins))
|
|
AddXMMEmit(ins, IPOINT_TAKEN_BRANCH, xmm_dst);
|
|
}
|
|
}
|
|
|
|
VOID MemoryTrace(INS ins)
|
|
{
|
|
if (!KnobTraceMemory)
|
|
return;
|
|
|
|
if (INS_IsMemoryWrite(ins) && INS_IsStandardMemop(ins))
|
|
{
|
|
INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(CaptureWriteEa), IARG_THREAD_ID, IARG_MEMORYWRITE_EA, IARG_END);
|
|
|
|
if (INS_IsValidForIpointAfter(ins))
|
|
{
|
|
INS_InsertPredicatedCall(ins, IPOINT_AFTER, AFUNPTR(EmitWrite), IARG_THREAD_ID, IARG_MEMORYWRITE_SIZE, IARG_END);
|
|
}
|
|
if (INS_IsValidForIpointTakenBranch(ins))
|
|
{
|
|
INS_InsertPredicatedCall(ins, IPOINT_TAKEN_BRANCH, AFUNPTR(EmitWrite), IARG_THREAD_ID, IARG_MEMORYWRITE_SIZE, IARG_END);
|
|
}
|
|
}
|
|
|
|
if (INS_HasMemoryRead2(ins) && INS_IsStandardMemop(ins))
|
|
{
|
|
INS_InsertPredicatedCall(ins, IPOINT_BEFORE, AFUNPTR(EmitRead), IARG_THREAD_ID, IARG_MEMORYREAD2_EA, IARG_MEMORYREAD_SIZE, IARG_END);
|
|
}
|
|
|
|
if (INS_IsMemoryRead(ins) && !INS_IsPrefetch(ins) && INS_IsStandardMemop(ins))
|
|
{
|
|
INS_InsertPredicatedCall(ins, IPOINT_BEFORE, AFUNPTR(EmitRead), IARG_THREAD_ID, IARG_MEMORYREAD_EA, IARG_MEMORYREAD_SIZE, IARG_END);
|
|
}
|
|
}
|
|
|
|
|
|
/* ===================================================================== */
|
|
|
|
VOID Trace(TRACE trace, VOID *v)
|
|
{
|
|
if (!filter.SelectTrace(trace))
|
|
return;
|
|
|
|
if (enabled)
|
|
{
|
|
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))
|
|
{
|
|
InstructionTrace(trace, ins);
|
|
|
|
CallTrace(trace, ins);
|
|
|
|
MemoryTrace(ins);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* ===================================================================== */
|
|
|
|
VOID Fini(int, VOID * v)
|
|
{
|
|
out << "# $eof" << endl;
|
|
|
|
out.close();
|
|
}
|
|
|
|
|
|
|
|
/* ===================================================================== */
|
|
|
|
static void OnSig(THREADID threadIndex,
|
|
CONTEXT_CHANGE_REASON reason,
|
|
const CONTEXT *ctxtFrom,
|
|
CONTEXT *ctxtTo,
|
|
INT32 sig,
|
|
VOID *v)
|
|
{
|
|
if (ctxtFrom != 0)
|
|
{
|
|
ADDRINT address = PIN_GetContextReg(ctxtFrom, REG_INST_PTR);
|
|
out << "SIG signal=" << sig << " on thread " << threadIndex
|
|
<< " at address " << hex << address << dec << " ";
|
|
}
|
|
|
|
switch (reason)
|
|
{
|
|
case CONTEXT_CHANGE_REASON_FATALSIGNAL:
|
|
out << "FATALSIG" << sig;
|
|
break;
|
|
case CONTEXT_CHANGE_REASON_SIGNAL:
|
|
out << "SIGNAL " << sig;
|
|
break;
|
|
case CONTEXT_CHANGE_REASON_SIGRETURN:
|
|
out << "SIGRET";
|
|
break;
|
|
|
|
case CONTEXT_CHANGE_REASON_APC:
|
|
out << "APC";
|
|
break;
|
|
|
|
case CONTEXT_CHANGE_REASON_EXCEPTION:
|
|
out << "EXCEPTION";
|
|
break;
|
|
|
|
case CONTEXT_CHANGE_REASON_CALLBACK:
|
|
out << "CALLBACK";
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
out << std::endl;
|
|
}
|
|
|
|
/* ===================================================================== */
|
|
|
|
LOCALVAR CONTROL_MANAGER control;
|
|
LOCALVAR SKIPPER skipper;
|
|
|
|
/* ===================================================================== */
|
|
|
|
int main(int argc, CHAR *argv[])
|
|
{
|
|
PIN_InitSymbols();
|
|
|
|
if( PIN_Init(argc,argv) )
|
|
{
|
|
return Usage();
|
|
}
|
|
|
|
string filename = KnobOutputFile.Value();
|
|
|
|
if (KnobPid)
|
|
{
|
|
filename += "." + decstr(getpid());
|
|
}
|
|
|
|
// Do this before we activate controllers
|
|
out.open(filename.c_str());
|
|
out << hex << right;
|
|
out.setf(ios::showbase);
|
|
|
|
control.RegisterHandler(Handler, 0, FALSE);
|
|
control.Activate();
|
|
skipper.CheckKnobs(0);
|
|
|
|
TRACE_AddInstrumentFunction(Trace, 0);
|
|
PIN_AddContextChangeFunction(OnSig, 0);
|
|
|
|
PIN_AddFiniFunction(Fini, 0);
|
|
|
|
filter.Activate();
|
|
icount.Activate();
|
|
|
|
// Never returns
|
|
|
|
PIN_StartProgram();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ===================================================================== */
|
|
/* eof */
|
|
/* ===================================================================== */
|