/*
 * Copyright (C) 2020-2021 Intel Corporation.
 * SPDX-License-Identifier: MIT
 */

#ifdef PIN_G_INTERNAL_EXCEPTION_CLIENT_PH
#error duplicate inclusion of internal_exception_client
#else
#define PIN_G_INTERNAL_EXCEPTION_CLIENT_PH
/*! @file
 *  Pin client interface and implementation for internal exception handling
 */
/*! @ingroup PIN_CONTROL
 * Handler (call-back) function when pin/tool generates internal exception.
 * This function can be registered via @ref PIN_AddInternalExceptionHandler() or @ref PIN_TryStart().
 * This function becomes active only after APPLICATION_START_CALLBACK notification is delivered. 
 * Any internal exception prior to this event can't be handled.
 *
 * If the exception occurred while analysis routine is executed, it is legal to modify the execution control
 * path using functions such as @ref PIN_RaiseException() or @ref PIN_ExecuteAt().
 * In this case, any per-thread INTERNAL_EXCEPTION_CALLBACK function registered via @ref PIN_TryStart()
 * will be unregistered automatically (similar semantics to @ref PIN_TryEnd() for all registered notifications)
 *
 * @note It is unsupported to call @ref PIN_CallApplicationFunction() in the scope of this callback
 *
 * @param[in] tid              The Pin thread ID of the thread that generated the exception.
 * @param[in,out] pExceptInfo  Pointer to the @ref EXCEPTION_INFO structure that describes the exception. 
 *                             If the exception should be raised in the context of the application 
 *                             (using @ref PIN_RaiseException()), The tool should update the exception info
 *                             to match the OS logic (e.g. update exception address using @ref PIN_SetExceptionAddress()).
 * @param[in,out] pPhysCtxt    Physical register state when the exception was generated. The tool can change 
 *                             \a pPhysCtxt (make sure that if @ref PIN_TryStart() was called, 
 *                             matching @ref PIN_TryEnd() will be called)
 * @param[in] v                The tool's call-back value.
 *
 * @return an \a EXCEPT_HANDLING_RESULT value
*/
typedef EXCEPT_HANDLING_RESULT (*INTERNAL_EXCEPTION_CALLBACK)(THREADID tid, EXCEPTION_INFO* pExceptInfo,
                                                              PHYSICAL_CONTEXT* pPhysCtxt, VOID* v);

/*! @ingroup PIN_CONTROL
 * Register a global (not per-thread) notification handler function that is called upon receipt of
 * any unhandled internal exception in Pin or the tool.  This handler does not catch exceptions
 * that are generated by the application, nor does it catch exceptions that are handled by
 * PIN_TryStart() / PIN_TryEnd().  The handler is active for all the application's threads,
 * it should be called in tool's main() before @ref PIN_StartProgram().
 * If it is called after @ref PIN_StartProgram() is called, it will be ignored.
 * The user can register up to MAX_IEH_CALLBACKS global notification functions.
 *
 * @note This function should be used for permanent global call-back registration
 * (as opposed to @ref PIN_TryStart() / @ref PIN_TryEnd() pair which should be used for function scope
 * registration).
 *
 * @param[in] fun    Handler function to execute upon receipt of internal exception in pin/tool.
 * @param[in] val    Value to pass to the function.
 *
 * @return PIN_CALLBACK A handle to a callback that can be used to further modify this callback's properties
 *
 * @note The pin client lock is obtained during the call of this API.
 *
 * @par Availability:
 * \b Mode:  JIT\n
 * \b O/S:   Windows\n
 * \b CPU:   All\n
 */
extern PIN_CALLBACK PIN_AddInternalExceptionHandler(INTERNAL_EXCEPTION_CALLBACK fun, VOID* val);

/*! @ingroup PIN_CONTROL
 * Register a per-thread notification handler function that is called upon receipt of an internal
 * exception in pin or the tool in the context of the calling thread.
 * Use @ref PIN_TryEnd() in order to remove the registered handler from the context of the calling thread
 * (do it in the same function scope).
 * The user can register up to MAX_IEH_CALLBACKS per-thread notification functions.\n
 * This function can be used in any thread, including any internal thread spawned by the tool.
 *
 * @note It is unsupported to call @ref PIN_CallApplicationFunction() in the scope of
 * @ref PIN_TryStart() / @ref PIN_TryEnd() pair.\n
 *
 *
 * @param[in] tid      Id of the calling thread.
 * @param[in] fun      Handler function to execute upon receipt of internal exception in pin/tool.
 * @param[in] val      Value to pass to the handler function.
 *
 * @par Availability:
 * \b Mode:  JIT\n
 * \b O/S:   Windows, Linux\n
 * \b CPU:   IA-32 and Intel(R) 64 architectures\n
 */
extern VOID PIN_TryStart(THREADID tid, INTERNAL_EXCEPTION_CALLBACK fun, VOID* val);

/*! @ingroup PIN_CONTROL
 * Unregister the last registered notification function (registered via @ref PIN_TryStart())
 * from the context of the calling thread. This function should be called in the same function
 * scope as the previously registered @ref PIN_TryStart().\n
 * This function can be used in any thread, including any internal thread spawned by the tool.
 *
 * @param[in] tid      Id of the calling thread.
 *
 * @par Availability:
 * \b Mode:  JIT\n
 * \b O/S:   Windows, Linux\n
 * \b CPU:   IA-32 and Intel(R) 64 architectures\n
 */
extern VOID PIN_TryEnd(THREADID tid);

#endif // PIN_G_INTERNAL_EXCEPTION_CLIENT_PH
