You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
287 lines
7.2 KiB
287 lines
7.2 KiB
/*
|
|
* Copyright 2002-2019 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.
|
|
*/
|
|
|
|
/*
|
|
* Emulate instruction that implicitly touch the stack:
|
|
* push, pop, leave.
|
|
* call and return
|
|
*/
|
|
#include <stdio.h>
|
|
#include "pin.H"
|
|
using std::string;
|
|
|
|
KNOB<UINT32> KnobDetach(KNOB_MODE_WRITEONCE, "pintool", "d", "-1", "stop tracing at this point");
|
|
KNOB<BOOL> KnobLog(KNOB_MODE_WRITEONCE, "pintool", "l", "0", "log all instructions");
|
|
|
|
static UINT32 scount = 0;
|
|
FILE *out = 0;
|
|
static REG scratchReg;
|
|
|
|
VOID PrintIns(void *p, const char *s)
|
|
{
|
|
if(!out)
|
|
return;
|
|
|
|
fprintf(out, "%6d: %p %s\n", scount, p, s);
|
|
fflush(out);
|
|
}
|
|
|
|
ADDRINT EmuPushValue(ADDRINT rsp, ADDRINT value)
|
|
{
|
|
rsp = rsp - sizeof(ADDRINT);
|
|
ADDRINT *psp = (ADDRINT *)rsp;
|
|
*psp = value;
|
|
return rsp;
|
|
}
|
|
|
|
ADDRINT EmuPushMem(ADDRINT rsp, ADDRINT *ea)
|
|
{
|
|
rsp = rsp - sizeof(ADDRINT);
|
|
ADDRINT *psp = (ADDRINT *)rsp;
|
|
*psp = *ea;
|
|
return rsp;
|
|
}
|
|
|
|
ADDRINT EmuPopReg(ADDRINT rsp, ADDRINT *reg)
|
|
{
|
|
ADDRINT *psp = (ADDRINT *)rsp;
|
|
*reg = *psp;
|
|
return rsp + sizeof(ADDRINT);
|
|
}
|
|
|
|
ADDRINT EmuPopMem(ADDRINT rsp, ADDRINT *ea)
|
|
{
|
|
ADDRINT *psp = (ADDRINT *)rsp;
|
|
*ea = *psp;
|
|
return rsp + sizeof(ADDRINT);
|
|
}
|
|
|
|
ADDRINT EmuLeave(ADDRINT rsp, ADDRINT *rbp)
|
|
{
|
|
rsp = *rbp;
|
|
ADDRINT *psp = (ADDRINT *)rsp;
|
|
*rbp = *psp;
|
|
return rsp + sizeof(ADDRINT);
|
|
}
|
|
|
|
ADDRINT EmuCall(ADDRINT nextip, ADDRINT tgtip, ADDRINT *rsp)
|
|
{
|
|
//*rsp = EmuPushValue(*rsp, nextip);
|
|
|
|
ADDRINT rspVal = *rsp;
|
|
|
|
rspVal = rspVal - sizeof(ADDRINT);
|
|
ADDRINT *psp = (ADDRINT *)rspVal;
|
|
*psp = nextip;
|
|
*rsp = rspVal;
|
|
|
|
|
|
return tgtip;
|
|
}
|
|
|
|
ADDRINT EmuRet(ADDRINT *rsp, UINT32 framesize)
|
|
{
|
|
ADDRINT retval;
|
|
|
|
//*rsp = EmuPopMem(*rsp, &retval);
|
|
|
|
ADDRINT rspVal = *rsp;
|
|
ADDRINT *psp = (ADDRINT *)rspVal;
|
|
retval = *psp;
|
|
*rsp = rspVal + sizeof(ADDRINT);
|
|
|
|
|
|
*rsp += framesize;
|
|
return retval;
|
|
}
|
|
|
|
ADDRINT EmuIndJmp(ADDRINT tgtip)
|
|
{
|
|
return tgtip;
|
|
}
|
|
|
|
VOID Ins( INS ins, VOID *v )
|
|
{
|
|
if (KnobDetach > 0 && scount > KnobDetach)
|
|
return;
|
|
|
|
if (KnobLog)
|
|
{
|
|
void *addr = Addrint2VoidStar(INS_Address(ins));
|
|
string disasm = INS_Disassemble(ins);
|
|
PrintIns(addr, disasm.c_str());
|
|
}
|
|
|
|
scount++;
|
|
|
|
if (INS_Opcode(ins) == XED_ICLASS_PUSH)
|
|
{
|
|
if (INS_OperandIsImmediate(ins, 0))
|
|
{
|
|
ADDRINT value = INS_OperandImmediate(ins, 0);
|
|
INS_InsertCall(ins, IPOINT_BEFORE,
|
|
AFUNPTR(EmuPushValue),
|
|
IARG_REG_VALUE, REG_STACK_PTR,
|
|
IARG_ADDRINT, value,
|
|
IARG_RETURN_REGS, REG_STACK_PTR, IARG_END);
|
|
|
|
INS_Delete(ins);
|
|
}
|
|
else if(INS_OperandIsReg(ins, 0))
|
|
{
|
|
REG reg = INS_OperandReg(ins, 0);
|
|
INS_InsertCall(ins, IPOINT_BEFORE,
|
|
AFUNPTR(EmuPushValue),
|
|
IARG_REG_VALUE, REG_STACK_PTR,
|
|
IARG_REG_VALUE, reg,
|
|
IARG_RETURN_REGS, REG_STACK_PTR, IARG_END);
|
|
|
|
INS_Delete(ins);
|
|
}
|
|
else if(INS_OperandIsMemory(ins, 0))
|
|
{
|
|
INS_InsertCall(ins, IPOINT_BEFORE,
|
|
AFUNPTR(EmuPushMem),
|
|
IARG_REG_VALUE, REG_STACK_PTR,
|
|
IARG_MEMORYREAD_EA,
|
|
IARG_RETURN_REGS, REG_STACK_PTR, IARG_END);
|
|
|
|
INS_Delete(ins);
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "EmuPush: unsupported operand type (%p:'%s')\n",
|
|
Addrint2VoidStar(INS_Address(ins)), INS_Disassemble(ins).c_str());
|
|
}
|
|
}
|
|
else if (INS_Opcode(ins) == XED_ICLASS_POP)
|
|
{
|
|
if(INS_OperandIsReg(ins, 0))
|
|
{
|
|
INS_InsertCall(ins, IPOINT_BEFORE,
|
|
AFUNPTR(EmuPopReg),
|
|
IARG_REG_VALUE, REG_STACK_PTR,
|
|
IARG_REG_REFERENCE, INS_OperandReg(ins, 0),
|
|
IARG_RETURN_REGS, REG_STACK_PTR, IARG_END);
|
|
|
|
INS_Delete(ins);
|
|
}
|
|
else if(INS_OperandIsMemory(ins, 0))
|
|
{
|
|
INS_InsertCall(ins, IPOINT_BEFORE,
|
|
AFUNPTR(EmuPopMem),
|
|
IARG_REG_VALUE, REG_STACK_PTR,
|
|
IARG_MEMORYWRITE_EA,
|
|
IARG_RETURN_REGS, REG_STACK_PTR, IARG_END);
|
|
|
|
INS_Delete(ins);
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "EmuPop: unsupported operand type (%p:'%s')\n",
|
|
Addrint2VoidStar(INS_Address(ins)), INS_Disassemble(ins).c_str());
|
|
}
|
|
}
|
|
else if (INS_Opcode(ins) == XED_ICLASS_LEAVE)
|
|
{
|
|
INS_InsertCall(ins, IPOINT_BEFORE,
|
|
AFUNPTR(EmuLeave),
|
|
IARG_REG_VALUE, REG_STACK_PTR,
|
|
IARG_REG_REFERENCE, REG_GBP,
|
|
IARG_RETURN_REGS, REG_STACK_PTR, IARG_END);
|
|
|
|
INS_Delete(ins);
|
|
}
|
|
else if (INS_IsCall(ins))
|
|
{
|
|
INS_InsertCall(ins, IPOINT_BEFORE,
|
|
AFUNPTR(EmuCall),
|
|
IARG_ADDRINT, INS_NextAddress(ins),
|
|
IARG_BRANCH_TARGET_ADDR,
|
|
IARG_REG_REFERENCE, REG_STACK_PTR,
|
|
IARG_RETURN_REGS, scratchReg, IARG_END);
|
|
|
|
INS_InsertIndirectJump(ins, IPOINT_AFTER, scratchReg);
|
|
|
|
INS_Delete(ins);
|
|
}
|
|
else if (INS_IsRet(ins))
|
|
{
|
|
UINT64 imm = 0;
|
|
if (INS_OperandCount(ins) > 0 && INS_OperandIsImmediate(ins, 0))
|
|
{
|
|
imm = INS_OperandImmediate(ins, 0);
|
|
}
|
|
|
|
INS_InsertCall(ins, IPOINT_BEFORE,
|
|
AFUNPTR(EmuRet),
|
|
IARG_CALL_ORDER, CALL_ORDER_FIRST,
|
|
IARG_REG_REFERENCE, REG_STACK_PTR,
|
|
IARG_ADDRINT, (ADDRINT)imm,
|
|
IARG_RETURN_REGS, scratchReg, IARG_END);
|
|
|
|
INS_InsertIndirectJump(ins, IPOINT_AFTER, scratchReg);
|
|
|
|
INS_Delete(ins);
|
|
}
|
|
else if (INS_IsIndirectControlFlow(ins))
|
|
{
|
|
// This is not a call (it was checked before) so this is indirect jump
|
|
INS_InsertCall(ins, IPOINT_BEFORE,
|
|
AFUNPTR(EmuIndJmp),
|
|
IARG_BRANCH_TARGET_ADDR,
|
|
IARG_RETURN_REGS, scratchReg, IARG_END);
|
|
|
|
INS_InsertIndirectJump(ins, IPOINT_AFTER, scratchReg);
|
|
|
|
INS_Delete(ins);
|
|
}
|
|
}
|
|
|
|
VOID Fini(INT32 code, VOID *v)
|
|
{
|
|
if (out)
|
|
fclose(out);
|
|
}
|
|
|
|
// argc, argv are the entire command line, including pin -t <toolname> -- ...
|
|
int main(int argc, char * argv[])
|
|
{
|
|
// Initialize pin
|
|
PIN_Init(argc, argv);
|
|
|
|
if (KnobLog)
|
|
{
|
|
out = fopen("emu_stack.txt", "w");
|
|
if (!out)
|
|
fprintf(stderr, "Can't open log file emu_stack.txt\n");
|
|
}
|
|
|
|
scratchReg = PIN_ClaimToolRegister();
|
|
if (!REG_valid(scratchReg))
|
|
{
|
|
fprintf (stderr, "Cannot allocate a scratch register.\n");
|
|
return 1;
|
|
}
|
|
|
|
// Register instruction instrumentation callback.
|
|
INS_AddInstrumentFunction(Ins, 0);
|
|
|
|
// Register Fini to be called when the application exits
|
|
PIN_AddFiniFunction(Fini, 0);
|
|
|
|
// Start the program, never returns
|
|
PIN_StartProgram();
|
|
|
|
return 0;
|
|
}
|
|
|