6

A typical PIN code snippet looks like this (taken from the official manual):

// 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
    INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)printip, IARG_INST_PTR, IARG_END);
}

I just can't figure out how to access the ins object from within printip(VOID *p). The other way round seems easy, i.e. getting the IP from from the ins object:

INS_Address (INS ins)(see here)

I tried passing a INS *ins pointer to printip(VOID *ip, INS *ins) ins via IARG_PTR, &ins but this ended in either casting errors or Segmentation faults.

How can I access the ins object (type INS) from inside an analysis function?

Side note: I got to this problem when trying to call INS_Disassemble (INS ins) for every executed instruction.

2 Answers 2

5

You may note that printip is a function pointer, it is lazily called internally by Pin; moreover ins is an automatic variable (it is passed into Instruction from the stack). Consequently, passing &ins into printip (through IARG_PTR), then using it will lead to segmentation faults.

Pin declares INS by specializing the class template INDEX, as you can observe the following declaration in type_core.TLH:

/*! @ingroup INS_BASIC_API
Handle for INS */  
typedef class INDEX<6> INS;

where constructors and assignment operators of class template INDEX are both default. So, in principle^^, we can always declare a persistent variable to share an object of INS between instrumentation and analysis functions, for example:

static INS per_ins;
...
VOID Instruction(INS ins, VOID *v)
{
  per_ins = ins;
  ...
}
...
VOID printip(VOID *ip)
{
  INS_Disassemble(per_ins);
}

This method does not work, unfortunately, this is an example for "well-typed program still can go wrong" in C/C++^^. Since Pin does not guarantee that internal variables, accessed by an object of type INS, are persistent in analysis time, the result of calling INS_Disassemble(per_ins) in an analysis function can be meaningless.

For your case, you may not want to call INS_Disassemble(ins) each time ins executes. We don't need that, for example, if ins is in a loop then this function will be called multiple times (with the same ins) to get the same result.

All static information of an instruction (e.g. the disassembled form of ins in this case) should be obtained in instrumentation time. Particularly, INS_Disassemble should be called single time only in some instrumentation function. One way to obtain the same effect as you want is:

static std::unordered_map<ADDRINT, std::string> str_of_ins_at;

VOID Instruction(INS ins, VOID *v)
{
  str_of_ins_at[INS_Address(ins)] = INS_Disassemble(ins);
  ...
}

VOID printip(VOID *ip, ADDRINT addr) 
{
  std::string ins_str = str_of_ins_at[addr];
  ...
}
4
  • Thank you for the detailed answer. I wanted to place the INS_Disassemble(ins) into the analysis function to check (manually by looking at it) if the analysis function works as intended. If I place the INS_Disassemble(ins) into the Instrumentation function, the output of INS_Disassemble(ins) is separated from the output of the analysis function. In other words: I wanted the output of the analysis function be entitled with the instruction to easily check if it is correct. Apr 12, 2016 at 11:02
  • You are correct, we can always obtain opcode of an instruction using PIN_SafeCopy and INS_Size, then use whatever disassemble tool e.g. Capstone, or even Xed of Intel. Apr 12, 2016 at 11:11
  • Oh sorry, I deleted my comment regarding this approach because your idea to store the strings looked more elegant to me. Apr 12, 2016 at 11:12
  • But anyway, great explanation of what is going on with this ins object. Apr 12, 2016 at 11:14
1

typedef class INDEX<6> INS; is defined in types_core.TLH (types not type). The following code works for me to disassamble at analysis time.

void disasmIns(ADDRINT tid, ADDRINT insarg)
{
  INS ins;
  ins.q_set(insarg);
  std::cout << "Disassembly: " << INS_Disassemble(ins) << std::endl;
}

VOID Instruction(INS ins, VOID *v) {
  INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)disasmIns, 
  IARG_FAST_ANALYSIS_CALL, IARG_ADDRINT, ins.q(), IARG_END);
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.