最近想采集某程序访存相关的trace,打算用PinTools。
Pin的使用很多博文已经进行了介绍,本文介绍关于VOID INS_InsertCall (INS ins, IPOINT action, AFUNPTR funptr,...)
的相关内容。
以</pin directory>/source/tools/ManualExamples/inscount0为例,该实例生成的.so可用来记录程序运行过程中指令的数量。
/*
* Copyright 2002-2020 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"
using std::cerr;
using std::ofstream;
using std::ios;
using std::string;
using std::endl;
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
VOID Instruction(INS ins, VOID *v)
{
// Insert a call to docount before every instruction, no arguments are passed
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_StartProgram();
return 0;
}
main函数中,PIN_Init是对Pin工具进行了初始化,INS_AddInstrumentFunction(Instruction, 0);
调用了函数Instruction,也就按照指令逐条进行,如下
// Pin calls this function every time a new instruction is encountered
VOID Instruction(INS ins, VOID *v)
{
// Insert a call to docount before every instruction, no arguments are passed
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)docount, IARG_END);
}
其中调用了INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)docount, IARG_END);
INS_InsertCall:
VOID INS_InsertCall ( INS ins,
IPOINT action,
AFUNPTR funptr,
...
)
该函数的作用是“Insert a call to funptr relative to instruction ins.”
其中的参数
ins: Instruction to instrument(将ins数据结构传入)
action: Specifies before, after, etc.(确定操作发生的时间点)
- IPOINT_BEFORE is always valid for all instructions.
- IPOINT_AFTER is valid only when a fall-through exists (i.e. Calls and unconditional branches will fail). It is only allowed when INS_IsValidForIpointAfter(ins) is true.
- IPOINT_TAKEN_BRANCH is invalid for non-branches. It is only allowed when INS_IsValidForIpointTakenBranch is true.
funptr: Insert a call to funptr
…: List of arguments to pass funptr. See IARG_TYPE, terminated with IARG_END。
函数具体使用的方法就是action确定一个操作发生时间例如 IPOINT_BEFORE,下一个参数action是一个自定义的函数,每次INS_InsertCall执行的时候都会触发action的自定义函数例如示例的VOID docount() { icount++; }
,这个自定义函数还可以传递参数,具体传递的内容由自定义函数后面的IARG_TYPE决定。 如下的例子
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
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)printip, IARG_INST_PTR, IARG_END);
}
该例子添加了参数IARG_INST_PTR,就是返回指令的pc,通过printip的*ip传入。
常用的参数如下:更多参数详见Intel tools官网
IARG_INST_PTR 程序的pc | Type: ADDRINT. The address of the instrumented instruction. This value does not change at IPOINT_AFTER. This is simply shorthan |
---|---|
IARG_REG_VALUE 寄存器的值 | Type: ADDRINT for integer registers. |
IARG_MEMORYREAD_EA 读内存操作的地址 | Type: ADDRINT. Effective address of a memory read, only valid if INS_IsMemoryRead is true and at IPOINT_BEFORE. |
IARG_MEMORYWRITE_EA 写内存操作的地址 | Type: ADDRINT. Effective address of a memory write, only valid at IPOINT_BEFORE. |
IARG_MEMORYREAD_SIZE | Type: UINT32. Size in bytes of memory read. |
IARG_BRANCH_TAKEN 分支与否 | Type: BOOL. Non zero if a branch is taken. Argument is invalid for XBEGIN and XEND instructions. |
IARG_BRANCH_TARGET_ADDR 分支地址 | Type: ADDRINT. Target address of branch instruction. |