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.

279 lines
8.5 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.
*/
/*! @file
* This test tool verifies correctness of Pin's internal exception handling
* Note - this tool uses Win32 API after initialization phase (after main()).
* This practice is unsupported and used here for testing purposes only.
*/
#include "pin.H"
namespace WIND
{
#include <windows.H>
}
#include <string>
#include <iostream>
using std::cout;
using std::flush;
using std::endl;
//=================================================================================================
/*!
* Global variables
*/
const INT32 MaxNumThreads = 10000;
volatile BOOL isExpected[MaxNumThreads];
volatile BOOL isGlobalExpected1 = FALSE;
volatile WIND::LPVOID ptr1 = NULL;
volatile BOOL isGlobalExpected2 = FALSE;
volatile WIND::LPVOID ptr2 = NULL;
//=================================================================================================
/*!
* Exception handlers
*/
EXCEPT_HANDLING_RESULT AnalysisHandler2(THREADID threadIndex, EXCEPTION_INFO * pExceptInfo,
PHYSICAL_CONTEXT * pPhysCtxt, VOID *v)
{
cout << "AnalysisHandler2: Caught exception. " << PIN_ExceptionToString(pExceptInfo) << endl << flush;
// Excercise *PhysicalContext* APIs
char fpstate[FPSTATE_SIZE];
PIN_GetPhysicalContextFPState(pPhysCtxt, fpstate);
PIN_SetPhysicalContextFPState(pPhysCtxt, fpstate);
ADDRINT ip = PIN_GetPhysicalContextReg(pPhysCtxt, REG_INST_PTR);
PIN_SetPhysicalContextReg(pPhysCtxt, REG_INST_PTR, ip);
if(ip != PIN_GetExceptionAddress(pExceptInfo))
{
cout << "AnalysisHandler2: Unmatching exception address. Abort" << endl << flush;
return EHR_UNHANDLED;
}
else
{
cout << "AnalysisHandler2: Matching exception address. Continue search" << endl << flush;
return EHR_CONTINUE_SEARCH;
}
}
EXCEPT_HANDLING_RESULT AnalysisHandler1(THREADID tid, EXCEPTION_INFO * pExceptInfo,
PHYSICAL_CONTEXT * pPhysCtxt, VOID *v)
{
cout << "AnalysisHandler1: Caught exception. " << PIN_ExceptionToString(pExceptInfo) << endl << flush;
if(isExpected[tid])
{
cout << "AnalysisHandler1: Raising exception on behalf of the application" << endl << flush;
isExpected[tid] = FALSE;
// Raise exception on behalf of the application
CONTEXT * appCtxt = (CONTEXT *)v;
ADDRINT faultIp = PIN_GetContextReg(appCtxt, REG_INST_PTR);
PIN_SetExceptionAddress(pExceptInfo, faultIp);
PIN_RaiseException(appCtxt, tid, pExceptInfo); //never returns
}
return EHR_CONTINUE_SEARCH;
}
EXCEPT_HANDLING_RESULT GlobalHandler2(THREADID threadIndex, EXCEPTION_INFO * pExceptInfo,
PHYSICAL_CONTEXT * pPhysCtxt, VOID *v)
{
cout << "GlobalHandler2: Caught exception. " << PIN_ExceptionToString(pExceptInfo) << endl << flush;
return EHR_CONTINUE_SEARCH;
}
EXCEPT_HANDLING_RESULT GlobalHandler1(THREADID threadIndex, EXCEPTION_INFO * pExceptInfo,
PHYSICAL_CONTEXT * pPhysCtxt, VOID *v)
{
cout << "GlobalHandler1: Caught exception. " << PIN_ExceptionToString(pExceptInfo) << endl << flush;
if(isGlobalExpected1 && (PIN_GetExceptionCode(pExceptInfo) == EXCEPTCODE_RECEIVED_ACCESS_FAULT))
{
isGlobalExpected1 = FALSE;
cout << "GlobalHandler1: Fixing exception and continuing execution" << endl << flush;
//Fix and continue execution
WIND::VirtualAlloc(ptr1, 0x1000, MEM_COMMIT, PAGE_READWRITE);
return EHR_HANDLED;
}
else if(isGlobalExpected2 && (PIN_GetExceptionCode(pExceptInfo) == EXCEPTCODE_RECEIVED_ACCESS_FAULT))
{
isGlobalExpected2 = FALSE;
cout << "GlobalHandler1: Fixing exception and continuing execution" << endl << flush;
//Fix and continue execution
WIND::VirtualAlloc(ptr2, 0x1000, MEM_COMMIT, PAGE_READWRITE);
return EHR_HANDLED;
}
else
{
// Message logging
cout << "GlobalHandler1: Unexpected exception. Abort" << endl << flush;
// Stop searching for internal handler.
return EHR_UNHANDLED;
}
}
//=================================================================================================
/*!
* RTN analysis routines.
*/
static VOID IntDivideByZeroException()
{
volatile int zero = 0;
volatile int i = 1 / zero;
}
static VOID OnRaiseIntDivideByZeroException(CONTEXT * ctxt, THREADID tid)
{
PIN_TryStart(tid, AnalysisHandler1, ctxt);
PIN_TryStart(tid, AnalysisHandler2, ctxt);
isExpected[tid] = TRUE;
IntDivideByZeroException();
PIN_TryEnd(tid);
PIN_TryEnd(tid);
}
static VOID OnRaiseFltDivideByZeroException(CONTEXT * ctxt, THREADID tid)
{
PIN_TryStart(tid, AnalysisHandler1, ctxt);
{
PIN_TryStart(tid, AnalysisHandler2, ctxt);
PIN_TryEnd(tid);
}
isExpected[tid] = TRUE;
volatile float zero = 0.0;
volatile float i = 1.0 / zero;
PIN_TryEnd(tid);
}
/*!
* INS analysis routines.
*/
VOID OnIns()
{
// Generate exception in inlined analysis routine.
isGlobalExpected2 = TRUE;
*(int *)ptr2 = 11111;
}
//=================================================================================================
/*!
* RTN instrumentation routine.
*/
static VOID InstrumentRoutine(RTN rtn, VOID *)
{
if (RTN_Name(rtn) == "RaiseIntDivideByZeroException")
{
PROTO proto = PROTO_Allocate( PIN_PARG(void), CALLINGSTD_DEFAULT,
"RaiseIntDivideByZeroException", PIN_PARG_END() );
RTN_ReplaceSignature(rtn, AFUNPTR(OnRaiseIntDivideByZeroException),
IARG_PROTOTYPE, proto, IARG_CONTEXT, IARG_THREAD_ID, IARG_END);
PROTO_Free(proto);
}
else if (RTN_Name(rtn) == "RaiseFltDivideByZeroException")
{
PROTO proto = PROTO_Allocate( PIN_PARG(void), CALLINGSTD_DEFAULT,
"RaiseFltDivideByZeroException", PIN_PARG_END() );
RTN_ReplaceSignature(rtn, AFUNPTR(OnRaiseFltDivideByZeroException),
IARG_PROTOTYPE, proto, IARG_CONTEXT, IARG_THREAD_ID, IARG_END);
PROTO_Free(proto);
}
}
/*!
* INS instrumentation routine.
*/
VOID Instruction(INS ins, VOID *v)
{
static bool isFirst = true;
static ADDRINT ins_address;
if (isFirst)
{
isFirst = false;
ins_address = INS_Address(ins);
}
if (ins_address == INS_Address(ins))
{
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)OnIns, IARG_END);
}
}
//=================================================================================================
/*!
* Start function
*/
VOID AppStart(VOID *v)
{
isGlobalExpected1 = TRUE;
//Will generate an exception
*(int *)ptr1 = 12345;
//Decommit the memory. Subsequent commit will initialize ptr1 range to 0.
WIND::VirtualFree(ptr1, 0x1000, MEM_DECOMMIT);
}
//=================================================================================================
/*!
* Fini function
*/
VOID Fini(INT32 code, VOID *v)
{
isGlobalExpected1 = TRUE;
//Will generate an exception
int j = *(int *)ptr1;
if(j != 0)
{
cout << "internal_exception_handler : Unexpected value: " << j << endl << flush;
}
else
{
cout << "internal_exception_handler : Completed successfully" << endl << flush;
}
}
//=================================================================================================
/*!
* The main procedure of the tool.
*/
int main(int argc, char *argv[])
{
PIN_InitSymbols();
PIN_Init(argc, argv);
PIN_AddInternalExceptionHandler(GlobalHandler1, NULL);
PIN_AddInternalExceptionHandler(GlobalHandler2, NULL);
RTN_AddInstrumentFunction(InstrumentRoutine, 0);
INS_AddInstrumentFunction(Instruction, 0);
PIN_AddApplicationStartFunction(AppStart, 0);
PIN_AddFiniFunction(Fini, 0);
//Reserve memory
ptr1 = WIND::VirtualAlloc(NULL, 0x1000, MEM_RESERVE, PAGE_READWRITE);
ptr2 = WIND::VirtualAlloc(NULL, 0x1000, MEM_RESERVE, PAGE_READWRITE);
// Initialize icount[]
for (INT32 t = 0; t < MaxNumThreads; t++)
{
isExpected[t] = FALSE;
}
PIN_StartProgram();
return 0;
}