/* * 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 application verifies that pin tool can correctly emulate exceptions on behalf of the application */ #include #include #include #include #include #if defined(TARGET_WINDOWS) #include "windows.h" #define EXPORT_CSYM extern "C" __declspec( dllexport ) #else #error Unsupported OS #endif using std::string; using std::cout; using std::endl; using std::flush; using std::hex; //========================================================================== // Printing utilities //========================================================================== string UnitTestName("internal_exception_handler_app"); string FunctionTestName; static void StartFunctionTest(const string & functionTestName) { if (FunctionTestName != "") { cout << UnitTestName << "[" << FunctionTestName << "] Success" << endl << flush; } FunctionTestName = functionTestName; } static void ExitUnitTest() { if (FunctionTestName != "") { cout << UnitTestName << "[" << FunctionTestName << "] Success" << endl << flush; } cout << UnitTestName << " : Completed successfully" << endl << flush; exit(0); } static void Abort(const string & msg) { cout << UnitTestName << "[" << FunctionTestName << "] Failure: " << msg << endl << flush; exit(1); } //========================================================================== // Exception handling utilities //========================================================================== /*! * Exception filter for the ExecuteSafe function: copy the exception record * to the specified structure. * @param[in] exceptPtr pointers to the exception context and the exception * record prepared by the system * @param[in] pExceptRecord pointer to the structure that receives the * exception record * @return the exception disposition */ static int SafeExceptionFilter(LPEXCEPTION_POINTERS exceptPtr) { return EXCEPTION_EXECUTE_HANDLER; } static int SafeExceptionFilterFloating( _FPIEEE_RECORD * pieee ) { return EXCEPTION_EXECUTE_HANDLER; } /*! * Execute the specified function and return to the caller even if the function raises * an exception. * @param[in] pExceptRecord pointer to the structure that receives the * exception record if the function raises an exception * @return TRUE, if the function raised an exception */ template bool ExecuteSafe(FUNC fp, DWORD * pExceptCode) { __try { fp(); return false; } __except (*pExceptCode = GetExceptionCode(), SafeExceptionFilter(GetExceptionInformation())) { return true; } } #pragma float_control (except,on) template bool ExecuteSafeFloating(FUNC fp, DWORD * pExceptCode) { unsigned int currentControl; errno_t err = _controlfp_s(¤tControl, ~_EM_ZERODIVIDE, _MCW_EM); __try { fp(); return false; } __except ( *pExceptCode = GetExceptionCode(), SafeExceptionFilter(GetExceptionInformation()) /*_fpieee_flt( GetExceptionCode(), GetExceptionInformation(), SafeExceptionFilterFloating )*/ ) { return true; } } /*! * The tool replaces this function and raises the EXCEPTION_INT_DIVIDE_BY_ZERO system exception. */ EXPORT_CSYM void RaiseIntDivideByZeroException() { volatile int zero = 0; volatile int i = 1 / zero; } /*! * The tool replaces this function and raises the EXCEPTION_FLT_DIVIDE_BY_ZERO system exception. */ EXPORT_CSYM void RaiseFltDivideByZeroException() { volatile float zero = 0.0; volatile float i = 1.0 / zero; } EXPORT_CSYM void End() { return; } /*! * The tool replace this function and raises the specified system exception. */ EXPORT_CSYM void RaiseSystemException(unsigned int sysExceptCode) { RaiseException(sysExceptCode, 0, 0, NULL); } /*! * Check to see if the specified exception record represents an exception with the * specified exception code. */ static bool CheckExceptionCode(DWORD exceptCode, DWORD expectedExceptCode) { if (exceptCode != expectedExceptCode) { cout << "Unexpected exception code " << hex << exceptCode << ". Should be " << hex << expectedExceptCode << endl << flush; return false; } return true; } /*! * Convert a pointer to type into a pointer to type. * Allows any combination of data/function types. */ #if defined(TARGET_IA32) || defined(TARGET_IA32E) template DST * CastPtr(SRC * src) { union CAST { DST * dstPtr; SRC * srcPtr; } cast; cast.srcPtr = src; return cast.dstPtr; } #else #error Unsupported architechture #endif typedef void FUNC_NOARGS(); /*! * The main procedure of the application. */ int main(int argc, char *argv[]) { DWORD exceptCode; bool exceptionCaught; // Raise int divide by zero exception in the tool StartFunctionTest("Raise int divide by zero in the tool"); exceptionCaught = ExecuteSafe(RaiseIntDivideByZeroException, &exceptCode); if (!exceptionCaught) {Abort("Unhandled exception");} if (!CheckExceptionCode(exceptCode, EXCEPTION_INT_DIVIDE_BY_ZERO)) { Abort("Incorrect exception information (EXCEPTION_INT_DIVIDE_BY_ZERO)"); } // Raise flt divide by zero exception in the tool StartFunctionTest("Raise FP divide by zero in the tool"); exceptionCaught = ExecuteSafeFloating(RaiseFltDivideByZeroException, &exceptCode); if (!exceptionCaught) {Abort("Unhandled exception");} if (EXCEPTION_FLT_DIVIDE_BY_ZERO != exceptCode && STATUS_FLOAT_MULTIPLE_TRAPS != exceptCode) { CheckExceptionCode(exceptCode, EXCEPTION_FLT_DIVIDE_BY_ZERO); // For reporting only Abort("Incorrect exception information (EXCEPTION_FLT_DIVIDE_BY_ZERO)"); } ExitUnitTest(); }