Search code examples
c++intelcpu-architectureintel-pin

Using IARG_MEMORYREAD_EA


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


Solution

  • 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...