pin
可以理解成一个"Just in time" 的编译器,只不过他接收的不是字节码,而是可执行文件. PIN接收可执行文件,然后解析代码段的第一条指令,再重新生成新的code.然后执行这个新的code(几乎和原来的指令一样).
在just in time 这种模式下,只会执行新产生的code.生成新的code的时候,pin让user来决定注入 那些代码(插桩)
pin只会对那些 执行的code 进行插桩, 换句话说就是不执行的代码不会被插桩
pintool
插桩包含两个部分:
1. 决定 代码插入位置和内容 的机制 (instrumentation code)
2. 插入点执行的 代码(analysis code)
pintool 就包含了这两个部分.它其实就是 可以修改 pin 新生成的代码的 插件.通过使用pintool来 注入代码 到 Pin新产生的code中
插桩粒度(Instrumentation Granularity
)
在第一次执行代码序列之前立即执行检测。称这种操作模式为 trace instrumentation .trace 通常从目标执行分支开始,以无条件分支结束,包括调用和返回。Pin breaks the trace into basic blocks, BBLs(基本块).基本块是单进单出的一组指令.Trace instrumentation utilizes the TRACE_AddInstrumentFunction
API call.
由于pin是动态的去查看 程序控制流,所以这里的BBL和编译原理书说的不一样.
switch(i)
{
case 4: total++;
case 3: total++;
case 2: total++;
case 1: total++;
case 0:
default: break;
}
It will generate instructions something like this (for the IA-32 architecture)
.L7:
addl $1, -4(%ebp)
.L6:
addl $1, -4(%ebp)
.L5:
addl $1, -4(%ebp)
.L4:
addl $1, -4(%ebp)
根据书上 这里应该产生4个基本块,每个基本快1个指令(每个分支),但是pin产生的基本块 数取决于分支怎么执行.这个pin只会产生一个基本快 假如是进入.L7就会只产生一个基本块包含四个指令,加入进入.L6则包含3个指令,以此类推. 反正就是pin的BBL 与 常规的BBL不同
为了方便Pintool的编写,pin提供了 instruction instrumentation 模式.该模式和trace instrumentation基本相同,但是可以让pintool的编写者不用管 指令的迭代.Instruction instrumentation utilizes the INS_AddInstrumentFunction
API call.
pin也提供更大粒度的插桩 image and routine instrumentation.These modes are implemented by “caching” instrumentation(缓存插桩) requests and hence incur a space overhead(造成空间开销), these modes are aslo referred to as ahead-of-time instrumentation.
Image instrumentation.可以让Pintool 获取整个image(类似于内存快照,就是较大块的code),Image instrumentation lets the Pintool inspect and instrument an entire image, IMG, when it is first loaded. A Pintool can walk the sections, SEC, of the image, the routines, RTN, of a section, and the instructions, INS of a routine. Instrumentation can be inserted so that it is executed before or after a routine is executed, or before or after an instruction is executed. Image instrumentation utilizes the IMG_AddInstrumentFunction
API call. Image instrumentation depends on symbol information(符号表信息) to determine routine boundaries hence PIN_InitSymbols
must be called before PIN_Init
.
Routine instrumentation lets the Pintool inspect and instrument an entire routine when the image it is contained in is first loaded. A Pintool can walk the instructions of a routine. There is not enough information available to break the instructions into BBLs. Instrumentation can be inserted so that it is executed before or after a routine is executed, or before or after an instruction is executed. Routine instrumentation is provided as a convenience for Pintool writers, as an alternative to walking the sections and routines of the image during the Image instrumentation, as described in the previous paragraph.
Routine instrumentation utilizes the RTN_AddInstrumentFunction
API call. Instrumentation of routine exits does not work reliably in the presence of tail calls or when return instructions cannot reliably be detected.(当routine在末尾调用或者return指令不能被可靠检测的时候 ,在程序退出插桩不那么可靠)
Note that in both Image and Routine instrumentation, it is not possible to know whether or not a routine will actually be executed (since these instrumentations are done at image load time). It is possible to walk the instructions only of routines that are executed, in the Trace or Instruction instrumentation routines, by identifying instructions that are the start of routines. See the tool Tests/parse_executed_rtns.cpp.
(Image and Routine instrumentation不知道那个routine会被执行,因为他是在程序进行内存映射的时候进行插装的)
符号
pin通过symbol object(SYM) 提供对函数名称的访问.SYM只提供在application中的函数的信息 .Information about other types of symbols (e.g. data symbols), must be obtained independently by the tool.
On Linux, libelf.so or libdwarf.so can be used to access symbol information.
PIN_InitSymbols
must be called to access functions by name. See SYM: Symbol Object for more information.
Examples
Simple Instruction Count (Instruction Instrumentation)
这个程序统计执行了多少条指令.在每条指令之前call docount
,程序退出,就把count 保存到inscount.out文件
#include <iostream>
#include <fstream>
#include "pin.H"
ofstream OutFile;
// The running count of instructions is kept here
// make it static to help the compiler optimize docount
static UINT64 icount = 0;
// This function is called before every instruction is executed
VOID docount() { icount++; }
// Pin calls this function every time a new instruction is encountered
//每遇到一个指令 就call
// 插桩的函数
VOID Instruction(INS ins, VOID *v)
{
// Insert a call to docount before every instruction, no arguments are passed
//指令, 常量, 函数指针 表示没有arg
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)docount, IARG_END);
}
// 用来处理参数
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
"o", "inscount.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 " << icount << endl;
OutFile.close();
}
/* ===================================================================== */
/* Print Help Message */
/* ===================================================================== */
INT32 Usage()
{
cerr << "This tool counts the number of dynamic instructions executed" << endl;
cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
return -1;
}
/* ===================================================================== */
/* Main */
/* ===================================================================== */
/* argc, argv are the entire command line: pin -t <toolname> -- ... */
/* ===================================================================== */
int main(int argc, char * argv[])
{
// Initialize pin
if (PIN_Init(argc, argv)) return Usage();
OutFile.open(KnobOutputFile.Value().c_str());
// Register Instruction to be called to instrument instructions
//注册插桩函数
INS_AddInstrumentFunction(Instruction, 0);
// Register Fini to be called when the application exits
//注册 结束函数
PIN_AddFiniFunction(Fini, 0);
// Start the program, never returns
// 开始执行程序,就是 执行需要进行插桩的程序,然后根据之前的pin初始化 进行插桩,分析
PIN_StartProgram();
return 0;
}
Instruction Address Trace (Instruction Instrumentation)
之前那个例子,没有给分析程序传递参数.这个例子展示了怎么传递参数
Pin allows you to pass the instruction pointer, current value of registers, effective address of memory operations, constants, etc(可以传递指令指针,当前寄存器的值,内存有效地址,常数等) For a complete list, see IARG_TYPE.
#include <stdio.h>
#include "pin.H"
FILE * trace;
// This function is called before every instruction is executed
// and prints the IP
VOID printip(VOID *ip) { fprintf(trace, "%p\n", ip); }
// Pin calls this function every time a new instruction is encountered
VOID Instruction(INS ins, VOID *v)
{
// Insert a call to printip before every instruction, and pass it the IP
// 1指令, 表示指令怎么插入(前后.), 函数指针, 表示传什么参数到函数(IP)
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)printip, IARG_INST_PTR, IARG_END);
}
// This function is called when the application exits
VOID Fini(INT32 code, VOID *v)
{
fprintf(trace, "#eof\n");
fclose(trace);
}
/* ===================================================================== */
/* Print Help Message */
/* ===================================================================== */
INT32 Usage()
{
PIN_ERROR("This Pintool prints the IPs of every instruction executed\n"
+ KNOB_BASE::StringKnobSummary() + "\n");
return -1;
}
/* ===================================================================== */
/* Main */
/* ===================================================================== */
int main(int argc, char * argv[])
{
trace = fopen("itrace.out", "w");
// Initialize pin
if (PIN_Init(argc, argv)) return Usage();
// Register Instruction to be called to instrument instructions
INS_AddInstrumentFunction(Instruction, 0);
// Register Fini to be called when the application exits
PIN_AddFiniFunction(Fini, 0);
// Start the program, never returns
PIN_StartProgram();
return 0;
}
Memory Reference Trace (Instruction Instrumentation)
这个例子展示了如何通过使用PIN提供的API来筛选指令,The basic API is common to all instruction sets and is described here.
/*
* This file contains an ISA-portable PIN tool for tracing memory accesses.
*/
#include <stdio.h>
#include "pin.H"
FILE * trace;
// Print a memory read record
VOID RecordMemRead(VOID * ip, VOID * addr)
{
fprintf(trace,"%p: R %p\n", ip, addr);
}
// Print a memory write record
VOID RecordMemWrite(VOID * ip, VOID * addr)
{
fprintf(trace,"%p: W %p\n", ip, addr);
}
// Is called for every instruction and instruments reads and writes
VOID Instruction(INS ins, VOID *v)
{
// Instruments memory accesses using a predicated call, i.e.
// the instrumentation is called iff the instruction will actually be executed.
//
// On the IA-32 and Intel(R) 64 architectures conditional moves and REP
// prefixed instructions appear as predicated instructions in Pin.
// pin 提供的API,统计有多少天内存操作指令
UINT32 memOperands = INS_MemoryOperandCount(ins);
// Iterate over each memory operand of the instruction.
for (UINT32 memOp = 0; memOp < memOperands; memOp++)
{
// pin提供的API ,, 指令, 通过ID来识别是第几条内存指令
if (INS_MemoryOperandIsRead(ins, memOp))
{
INS_InsertPredicatedCall(
ins, IPOINT_BEFORE, (AFUNPTR)RecordMemRead,
IARG_INST_PTR,
//表明传入内存有效地址,下个参数必须是memOp的ID
IARG_MEMORYOP_EA, memOp,
IARG_END);
}
// Note that in some architectures a single memory operand can be
// both read and written (for instance incl (%eax) on IA-32)
// In that case we instrument it once for read and once for write.
if (INS_MemoryOperandIsWritten(ins, memOp))
{
INS_InsertPredicatedCall(
ins, IPOINT_BEFORE, (AFUNPTR)RecordMemWrite,
IARG_INST_PTR,
IARG_MEMORYOP_EA, memOp,
IARG_END);
}
}
}
VOID Fini(INT32 code, VOID *v)
{
fprintf(trace, "#eof\n");
fclose(trace);
}
/* ===================================================================== */
/* Print Help Message */
/* ===================================================================== */
INT32 Usage()
{
PIN_ERROR( "This Pintool prints a trace of memory addresses\n"
+ KNOB_BASE::StringKnobSummary() + "\n");
return -1;
}
/* ===================================================================== */
/* Main */
/* ===================================================================== */
int main(int argc, char *argv[])
{
if (PIN_Init(argc, argv)) return Usage();
trace = fopen("pinatrace.out", "w");
INS_AddInstrumentFunction(Instruction, 0);
PIN_AddFiniFunction(Fini, 0);
// Never returns
PIN_StartProgram();
return 0;
}
Detecting the Loading and Unloading of Images (Image Instrumentation) 检测内存映射的换入换出?
//
// This tool prints a trace of image load and unload events
//
#include "pin.H"
#include <iostream>
#include <fstream>
#include <stdlib.h>
using namespace std;
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
"o", "imageload.out", "specify file name");
ofstream TraceFile;
// Pin calls this function every time a new img is loaded
// It can instrument the image, but this example does not
// Note that imgs (including shared libraries) are loaded lazily
VOID ImageLoad(IMG img, VOID *v)
{
TraceFile << "Loading " << IMG_Name(img) << ", Image id = " << IMG_Id(img) << endl;
}
// Pin calls this function every time a new img is unloaded
// You can't instrument an image that is about to be unloaded
VOID ImageUnload(IMG img, VOID *v)
{
TraceFile << "Unloading " << IMG_Name(img) << endl;
}
// This function is called when the application exits
// It closes the output file.
VOID Fini(INT32 code, VOID *v)
{
if (TraceFile.is_open()) { TraceFile.close(); }
}
/* ===================================================================== */
/* Print Help Message */
/* ===================================================================== */
INT32 Usage()
{
PIN_ERROR("This tool prints a log of image load and unload events\n"
+ KNOB_BASE::StringKnobSummary() + "\n");
return -1;
}
/* ===================================================================== */
/* Main */
/* ===================================================================== */
int main(int argc, char * argv[])
{
// Initialize symbol processing
PIN_InitSymbols();
// Initialize pin
if (PIN_Init(argc, argv)) return Usage();
TraceFile.open(KnobOutputFile.Value().c_str());
// Register ImageLoad to be called when an image is loaded
IMG_AddInstrumentFunction(ImageLoad, 0);
// Register ImageUnload to be called when an image is unloaded
IMG_AddUnloadFunction(ImageUnload, 0);
// Register Fini to be called when the application exits
PIN_AddFiniFunction(Fini, 0);
// Start the program, never returns
PIN_StartProgram();
return 0;
}
More Efficient Instruction Counting (Trace Instrumentation)
展示了如何使用BBL粒度的Trace插桩
#include <iostream>
#include <fstream>
#include "pin.H"
ofstream OutFile;
// The running count of instructions is kept here
// make it static to help the compiler optimize docount
static UINT64 icount = 0;
// This function is called before every block
VOID docount(UINT32 c) { icount += c; }
// Pin calls this function every time a new basic block is encountered
// It inserts a call to docount
VOID Trace(TRACE trace, VOID *v)
{
// Visit every basic block in the trace
for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl))
{
// Insert a call to docount before every bbl, passing the number of instructions
BBL_InsertCall(bbl, IPOINT_BEFORE, (AFUNPTR)docount, IARG_UINT32, BBL_NumIns(bbl), IARG_END);
}
}
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
"o", "inscount.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 " << icount << endl;
OutFile.close();
}
/* ===================================================================== */
/* Print Help Message */
/* ===================================================================== */
INT32 Usage()
{
cerr << "This tool counts the number of dynamic instructions executed" << endl;
cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
return -1;
}
/* ===================================================================== */
/* Main */
/* ===================================================================== */
int main(int argc, char * argv[])
{
// Initialize pin
if (PIN_Init(argc, argv)) return Usage();
OutFile.open(KnobOutputFile.Value().c_str());
// Register Instruction to be called to instrument instructions
//使用的是TRACE_ 而不是INS_
TRACE_AddInstrumentFunction(Trace, 0);
// Register Fini to be called when the application exits
PIN_AddFiniFunction(Fini, 0);
// Start the program, never returns
PIN_StartProgram();
return 0;
}
Procedure Instruction Count (Routine Instrumentation)
展示了如何使用Routine粒度的插桩 去统计函数CALL的次数,每个函数执行了多少指令,
$ ../../../pin -t obj-intel64/proccount.so -- /bin/grep proccount.cpp Makefile
proccount_SOURCES = proccount.cpp
$ head proccount.out
Procedure Image Address Calls Instructions
_fini libc.so.6 0x40144d00 1 21
__deregister_frame_info libc.so.6 0x40143f60 2 70
__register_frame_info libc.so.6 0x40143df0 2 62
fde_merge libc.so.6 0x40143870 0 8
__init_misc libc.so.6 0x40115824 1 85
__getclktck libc.so.6 0x401157f4 0 2
munmap libc.so.6 0x40112ca0 1 9
mmap libc.so.6 0x40112bb0 1 23
getpagesize libc.so.6 0x4010f934 2 26
$
//
// This tool counts the number of times a routine is executed and
// the number of instructions executed in a routine
//
#include <fstream>
#include <iomanip>
#include <iostream>
#include <string.h>
#include "pin.H"
ofstream outFile;
// Holds instruction count for a single procedure
typedef struct RtnCount
{
string _name;
string _image;
ADDRINT _address;
RTN _rtn;
UINT64 _rtnCount;
UINT64 _icount;
struct RtnCount * _next;
} RTN_COUNT;
// Linked list of instruction counts for each routine
RTN_COUNT * RtnList = 0;
// This function is called before every instruction is executed
VOID docount(UINT64 * counter)
{
(*counter)++;
}
const char * StripPath(const char * path)
{
const char * file = strrchr(path,'/');
if (file)
return file+1;
else
return path;
}
// Pin calls this function every time a new rtn is executed
VOID Routine(RTN rtn, VOID *v)
{
// Allocate a counter for this routine
RTN_COUNT * rc = new RTN_COUNT;
// The RTN goes away when the image is unloaded, so save it now
// because we need it in the fini
rc->_name = RTN_Name(rtn);
rc->_image = StripPath(IMG_Name(SEC_Img(RTN_Sec(rtn))).c_str());
rc->_address = RTN_Address(rtn);
rc->_icount = 0;
rc->_rtnCount = 0;
// Add to list of routines
rc->_next = RtnList;
RtnList = rc;
RTN_Open(rtn);
// Insert a call at the entry point of a routine to increment the call count
RTN_InsertCall(rtn, IPOINT_BEFORE, (AFUNPTR)docount, IARG_PTR, &(rc->_rtnCount), IARG_END);
// For each instruction of the routine
for (INS ins = RTN_InsHead(rtn); INS_Valid(ins); ins = INS_Next(ins))
{
// Insert a call to docount to increment the instruction counter for this rtn
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)docount, IARG_PTR, &(rc->_icount), IARG_END);
}
RTN_Close(rtn);
}
// This function is called when the application exits
// It prints the name and count for each procedure
VOID Fini(INT32 code, VOID *v)
{
outFile << setw(23) << "Procedure" << " "
<< setw(15) << "Image" << " "
<< setw(18) << "Address" << " "
<< setw(12) << "Calls" << " "
<< setw(12) << "Instructions" << endl;
for (RTN_COUNT * rc = RtnList; rc; rc = rc->_next)
{
if (rc->_icount > 0)
outFile << setw(23) << rc->_name << " "
<< setw(15) << rc->_image << " "
<< setw(18) << hex << rc->_address << dec <<" "
<< setw(12) << rc->_rtnCount << " "
<< setw(12) << rc->_icount << endl;
}
}
/* ===================================================================== */
/* Print Help Message */
/* ===================================================================== */
INT32 Usage()
{
cerr << "This Pintool counts the number of times a routine is executed" << endl;
cerr << "and the number of instructions executed in a routine" << endl;
cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
return -1;
}
/* ===================================================================== */
/* Main */
/* ===================================================================== */
int main(int argc, char * argv[])
{
// Initialize symbol table code, needed for rtn instrumentation
PIN_InitSymbols();
outFile.open("proccount.out");
// Initialize pin
if (PIN_Init(argc, argv)) return Usage();
// Register Routine to be called to instrument rtn
RTN_AddInstrumentFunction(Routine, 0);
// Register Fini to be called when the application exits
PIN_AddFiniFunction(Fini, 0);
// Start the program, never returns
PIN_StartProgram();
return 0;
}
Using PIN_SafeCopy()
展示了使用PIN_SafeCopy()去模拟LOAD操作,删除原来的指令
Using PIN_SafeCopy() allows the tool to read or write the application’s values for these fields.
使用这个API 可以让PIN tool 读写应用的制定内存单元
#include <stdio.h>
#include "pin.H"
#include "pin_isa.H"
#include <iostream>
#include <fstream>
std::ofstream* out = 0;
//=======================================================
// Analysis routines
//=======================================================
// Move from memory to register
ADDRINT DoLoad(REG reg, ADDRINT * addr)
{
*out << "Emulate loading from addr " << addr << " to " << REG_StringShort(reg) << endl;
ADDRINT value;
// (dest , src,size)
PIN_SafeCopy(&value, addr, sizeof(ADDRINT));
return value;
}
//=======================================================
// Instrumentation routines
//=======================================================
VOID EmulateLoad(INS ins, VOID* v)
{
// Find the instructions that move a value from memory to a register
if (INS_Opcode(ins) == XED_ICLASS_MOV &&
INS_IsMemoryRead(ins) &&
INS_OperandIsReg(ins, 0) &&
INS_OperandIsMemory(ins, 1))
{
// op0 <- *op1
//INS_OperandReg 返回指令设计的寄存器
//IARG_RETURN_REGS 把函数返回的值写入寄存器,下个参数表明写到那个寄存器
INS_InsertCall(ins,
IPOINT_BEFORE,
AFUNPTR(DoLoad),
IARG_UINT32,
REG(INS_OperandReg(ins, 0)),
IARG_MEMORYREAD_EA,
IARG_RETURN_REGS,
INS_OperandReg(ins, 0),
IARG_END);
// Delete the instruction
INS_Delete(ins);
}
}
/* ===================================================================== */
/* Print Help Message */
/* ===================================================================== */
INT32 Usage()
{
cerr << "This tool demonstrates the use of SafeCopy" << endl;
cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
return -1;
}
/* ===================================================================== */
/* Main */
/* ===================================================================== */
int main(int argc, char * argv[])
{
// Write to a file since cout and cerr maybe closed by the application
out = new std::ofstream("safecopy.out");
// Initialize pin & symbol manager
if (PIN_Init(argc, argv)) return Usage();
PIN_InitSymbols();
// Register EmulateLoad to be called to instrument instructions
INS_AddInstrumentFunction(EmulateLoad, 0);
// Never returns
PIN_StartProgram();
return 0;
}
Order of Instrumentation
展示了如何利用IPOINT_BEFORE
IPOINT_TAKEN_BRANCH
IPOINT_AFTER
,等来控制 analysis程序的执行顺序
#include "pin.H"
#include <iostream>
#include <fstream>
using namespace std;
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
"o", "invocation.out", "specify output file name");
ofstream OutFile;
/*
* Analysis routines
*/
VOID Taken( const CONTEXT * ctxt)
{
ADDRINT TakenIP = (ADDRINT)PIN_GetContextReg( ctxt, REG_INST_PTR );
OutFile << "Taken: IP = " << hex << TakenIP << dec << endl;
}
VOID Before(CONTEXT * ctxt)
{
ADDRINT BeforeIP = (ADDRINT)PIN_GetContextReg( ctxt, REG_INST_PTR);
OutFile << "Before: IP = " << hex << BeforeIP << dec << endl;
}
VOID After(CONTEXT * ctxt)
{
ADDRINT AfterIP = (ADDRINT)PIN_GetContextReg( ctxt, REG_INST_PTR);
OutFile << "After: IP = " << hex << AfterIP << dec << endl;
}
/*
* Instrumentation routines
*/
VOID ImageLoad(IMG img, VOID *v)
{
for (SEC sec = IMG_SecHead(img); SEC_Valid(sec); sec = SEC_Next(sec))
{
// RTN_InsertCall() and INS_InsertCall() are executed in order of
// appearance. In the code sequence below, the IPOINT_AFTER is
// executed before the IPOINT_BEFORE.
for (RTN rtn = SEC_RtnHead(sec); RTN_Valid(rtn); rtn = RTN_Next(rtn))
{
// Open the RTN.
RTN_Open( rtn );
// IPOINT_AFTER is implemented by instrumenting each return
// instruction in a routine. Pin tries to find all return
// instructions, but success is not guaranteed.
RTN_InsertCall( rtn, IPOINT_AFTER, (AFUNPTR)After,
IARG_CONTEXT, IARG_END);
// Examine each instruction in the routine.
for( INS ins = RTN_InsHead(rtn); INS_Valid(ins); ins = INS_Next(ins) )
{
if( INS_IsRet(ins) )
{
// instrument each return instruction.
// IPOINT_TAKEN_BRANCH always occurs last.
//IARG_CONTEXT 指令的上下文?
INS_InsertCall( ins, IPOINT_BEFORE, (AFUNPTR)Before,
IARG_CONTEXT, IARG_END);
INS_InsertCall( ins, IPOINT_TAKEN_BRANCH, (AFUNPTR)Taken,
IARG_CONTEXT, IARG_END);
}
}
// Close the RTN.
RTN_Close( rtn );
}
}
}
VOID Fini(INT32 code, VOID *v)
{
OutFile.close();
}
/* ===================================================================== */
/* Print Help Message */
/* ===================================================================== */
INT32 Usage()
{
cerr << "This is the invocation pintool" << endl;
cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
return -1;
}
/* ===================================================================== */
/* Main */
/* ===================================================================== */
int main(int argc, char * argv[])
{
// Initialize pin & symbol manager
if (PIN_Init(argc, argv)) return Usage();
PIN_InitSymbols();
// Register ImageLoad to be called to instrument instructions
IMG_AddInstrumentFunction(ImageLoad, 0);
PIN_AddFiniFunction(Fini, 0);
// Write to a file since cout and cerr maybe closed by the application
OutFile.open(KnobOutputFile.Value().c_str());
OutFile.setf(ios::showbase);
// Start the program, never returns
PIN_StartProgram();
return 0;
}
/* ===================================================================== */
Finding the Value of Function Arguments
展示如何获取 传入函数的参数和函数的返回值