I am pretty new in using Intel PIN. Currently I am using a hardware simulator which implements PIN to process instructions.
For my application, I need to catch some variables of workload in hardware level by using PIN functions. Unfortunately, variable pointer address which is logged by workload itself doesn't exist among the log of IARG_MEMORYREAD_EA, IARG_MEMORYREAD2_EA and IARG_MEMORYWRITE_EA values.
I am sure that I am missing a very simple point because the operation that I am trying to do with pin, cannot be more simple than this.
What could be the reason of that? Do I need an address translation or is there some other functions which I am supposed to use for this?
Thanks
Well, I'm afraid this answer falls in the range of "It works for me!"...
Here my "simple" pintool to catch read and write access in main module (sorry if it's a bit long: it is based on the example pintool so some comments or codes might be out of context, i just coded it quickly):
/*! @file
* This is an example of the PIN tool that demonstrates some basic PIN APIs
* and could serve as the starting point for developing your first PIN tool
*/
#include "pin.H"
#include <iostream>
#include <fstream>
typedef enum _tag_ReadWrite{
Unknown = 0UL,
Read = 2UL,
Write = 4UL
}ENUM_READWRITE;
typedef struct _tag_ImgAddr{
ADDRINT low;
ADDRINT high;
}IMG_ADDR, *PIMG_ADDR;
/* ================================================================== */
// Global variables
/* ================================================================== */
IMG_ADDR g_MainImg = { 0 };
std::ostream * out = &cerr;
/* ===================================================================== */
// Command line switches
/* ===================================================================== */
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
"o", "", "specify file name for MyPinTool output");
KNOB<BOOL> KnobCount(KNOB_MODE_WRITEONCE, "pintool",
"count", "1", "count instructions, basic blocks and threads in the application");
/* ===================================================================== */
// Utilities
/* ===================================================================== */
/*!
* Print out help message.
*/
INT32 Usage()
{
cerr << "This tool prints out the number of dynamically executed " << endl <<
"instructions, basic blocks and threads in the application." << endl << endl;
cerr << KNOB_BASE::StringKnobSummary() << endl;
return -1;
}
/* ===================================================================== */
// Analysis routines
/* ===================================================================== */
VOID InsAnalysis(ADDRINT addr, ADDRINT rw_ea, UINT32 rw_size, UINT32 type)
{
if (g_MainImg.low == 0){
return;
}
//restrict trace to main module only
if (addr >= g_MainImg.low && addr < g_MainImg.high){
std::string str_type;
switch (type){
case Read:
str_type = "[R] ";
break;
case Write:
str_type = "[W] ";
break;
default:
break;
}
*out << str_type << std::hex << addr <<
" [" << rw_ea << "] " <<
" (" << rw_size << ") " <<
std::endl;
}
}
/* ===================================================================== */
// Instrumentation callbacks
/* ===================================================================== */
VOID ImageLoad(IMG img, VOID * pData){
if (!IMG_Valid(img))
return;
if (IMG_IsMainExecutable(img)){
g_MainImg.low = IMG_LowAddress(img);
g_MainImg.high = IMG_HighAddress(img);
}
}
/*!
* This function is called every time a new instruction is encountered.
* @param[in] trace trace to be instrumented
* @param[in] v value specified by the tool in the INS_AddInstrumentFunction
* function call
*/
VOID InsInstrument(INS ins, VOID *v)
{
if (g_MainImg.low == 0){
return;
}
if (INS_IsMemoryRead(ins)){
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)InsAnalysis,
IARG_INST_PTR,
IARG_MEMORYREAD_EA,
IARG_MEMORYREAD_SIZE,
IARG_UINT32, Read,
IARG_END);
}
if (INS_IsMemoryWrite(ins)){
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)InsAnalysis,
IARG_INST_PTR,
IARG_MEMORYWRITE_EA,
IARG_MEMORYWRITE_SIZE,
IARG_UINT32, Write,
IARG_END);
}
}
/*!
* Print out analysis results.
* This function is called when the application exits.
* @param[in] code exit code of the application
* @param[in] v value specified by the tool in the
* PIN_AddFiniFunction function call
*/
VOID Fini(INT32 code, VOID *v)
{
*out << "[*] Fini called!" << endl;
}
/*!
* The main procedure of the tool.
* This function is called when the application image is loaded but not yet started.
* @param[in] argc total number of elements in the argv array
* @param[in] argv array of command line arguments,
* including pin -t <toolname> -- ...
*/
int main(int argc, char *argv[])
{
// Initialize PIN library. Print help message if -h(elp) is specified
// in the command line or the command line is invalid
if( PIN_Init(argc,argv) )
{
return Usage();
}
string fileName = KnobOutputFile.Value();
if (!fileName.empty()) { out = new std::ofstream(fileName.c_str());}
if (KnobCount)
{
// Register function to be called to instrument traces
INS_AddInstrumentFunction(InsInstrument, 0);
IMG_AddInstrumentFunction(ImageLoad, 0);
// Register function to be called when the application exits
PIN_AddFiniFunction(Fini, 0);
}
cerr << "===============================================" << endl;
cerr << "This application is instrumented by MyPinTool" << endl;
if (!KnobOutputFile.Value().empty())
{
cerr << "See file " << KnobOutputFile.Value() << " for analysis results" << endl;
}
cerr << "===============================================" << endl;
// Start the program, never returns
PIN_StartProgram();
return 0;
}
/* ===================================================================== */
/* eof */
/* ===================================================================== */
My program:
#include <cstdint>
#include <iostream>
int main(){
uint8_t a = 0x35;
uint8_t * b;
b = &a;
std::cout << &b;
return 0;
}
The assembly:
CPU Disasm
Address Command Comments
004012A0 < PUSH EBP ; INT Test.<ModuleEntryPoint>(void)
004012A1 MOV EBP,ESP
004012A3 SUB ESP,0C
004012A6 MOV EAX,DWORD PTR DS:[__security_cookie]
004012AB XOR EAX,EBP
004012AD MOV DWORD PTR SS:[EBP-4],EAX
004012B0 MOV ECX,DWORD PTR DS:[<&MSVCP120.std::cout>]
004012B6 LEA EAX,[EBP-5]
004012B9 MOV DWORD PTR SS:[EBP-0C],EAX
004012BC LEA EAX,[EBP-0C]
004012BF PUSH EAX
004012C0 MOV BYTE PTR SS:[EBP-5],35
004012C4 CALL NEAR DWORD PTR DS:[<&MSVCP120.std::basic_ostream<char,std::char_traits<char> >::operator<<>]
004012CA MOV ECX,DWORD PTR SS:[EBP-4]
004012CD XOR EAX,EAX
004012CF XOR ECX,EBP
004012D1 CALL __security_check_cookie
004012D6 MOV ESP,EBP
004012D8 POP EBP
004012D9 RETN
Output from the pintool:
[Read|Write] <ins address> [Read|Write target] (Read|Write size)
[W] 4012a0 [18ff80] (4)
[R] 4012a6 [403000] (4)
[W] 4012ad [18ff7c] (4)
[R] 4012b0 [402028] (4)
[W] 4012b9 [18ff74] (4)
[W] 4012bf [18ff70] (4)
[W] 4012c0 [18ff7b] (1)
[R] 4012c4 [402018] (4)
[W] 4012c4 [18ff6c] (4)
[R] 4012ca [18ff7c] (4)
[W] 4012d1 [18ff70] (4)
[R] 40171d [403000] (4)
[R] 401725 [18ff70] (4)
[R] 4012d8 [18ff80] (4)
[R] 4012d9 [18ff84] (4)
[*] Fini called!
Console output:
Z:\data\CPP\Test\Release>pin -t MyPinTool.dll -o out.txt -- test.exe
===============================================
This application is instrumented by MyPinTool
See file out.txt for analysis results
===============================================
0018FF74
So if we mix up everything together:
console output: 0018FF74
Pin output: [W] 4012b9 [18ff74] (4)
asm: 004012B9 MOV DWORD PTR SS:[EBP-0C],EAX
Which is right: the address written at 0x4012b9 is then passed to std::cout
at 0x4012bf to display the result.
Could you test this pintool on your program and see if it's working? Do not neglect the disassembly of your test program to see if anything is optimized away, just in case...