ovr_sdk

diff LibOVR/Src/Kernel/OVR_DebugHelp.h @ 0:1b39a1b46319

initial 0.4.4
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 14 Jan 2015 06:51:16 +0200
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/LibOVR/Src/Kernel/OVR_DebugHelp.h	Wed Jan 14 06:51:16 2015 +0200
     1.3 @@ -0,0 +1,461 @@
     1.4 +/************************************************************************************
     1.5 +
     1.6 +Filename    :   OVR_DebugHelp.h
     1.7 +Content     :   Platform-independent exception handling interface
     1.8 +Created     :   October 6, 2014
     1.9 +
    1.10 +Copyright   :   Copyright 2014 Oculus VR, LLC. All Rights reserved.
    1.11 +
    1.12 +Licensed under the Apache License, Version 2.0 (the "License");
    1.13 +you may not use this file except in compliance with the License.
    1.14 +You may obtain a copy of the License at
    1.15 +
    1.16 +http://www.apache.org/licenses/LICENSE-2.0
    1.17 +
    1.18 +Unless required by applicable law or agreed to in writing, software
    1.19 +distributed under the License is distributed on an "AS IS" BASIS,
    1.20 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1.21 +See the License for the specific language governing permissions and
    1.22 +limitations under the License.
    1.23 +
    1.24 +************************************************************************************/
    1.25 +
    1.26 +#ifndef OVR_ExceptionHandler_h
    1.27 +#define OVR_ExceptionHandler_h
    1.28 +
    1.29 +
    1.30 +#include "OVR_Types.h"
    1.31 +#include "OVR_String.h"
    1.32 +#include "OVR_Threads.h"
    1.33 +#include "OVR_Atomic.h"
    1.34 +#include "OVR_Nullptr.h"
    1.35 +#include <stdio.h>
    1.36 +#include <time.h>
    1.37 +
    1.38 +#if defined(OVR_OS_WIN32) || defined(OVR_OS_WIN64)
    1.39 +    #include <Windows.h>
    1.40 +
    1.41 +#elif defined(OVR_OS_APPLE)
    1.42 +    #include <pthread.h>
    1.43 +    #include <mach/thread_status.h>
    1.44 +    #include <mach/mach_types.h>
    1.45 +
    1.46 +    extern "C" void* MachHandlerThreadFunctionStatic(void*);
    1.47 +    extern "C" int   catch_mach_exception_raise_state_identity_OVR(mach_port_t, mach_port_t, mach_port_t, exception_type_t, mach_exception_data_type_t*,
    1.48 +                                       mach_msg_type_number_t, int*, thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t*);
    1.49 +#elif defined(OVR_OS_LINUX)
    1.50 +    #include <pthread.h>
    1.51 +#endif
    1.52 +
    1.53 +
    1.54 +OVR_DISABLE_MSVC_WARNING(4351) // new behavior: elements of array will be default initialized
    1.55 +
    1.56 +
    1.57 +namespace OVR { 
    1.58 +
    1.59 +    // Thread identifiers
    1.60 +    //typedef void*     ThreadHandle;  // Already defined by OVR Threads. Same as Windows thread handle, Unix pthread_t.
    1.61 +    //typedef void*     ThreadId;      // Already defined by OVR Threads. Used by Windows as DWORD thread id, by Unix as pthread_t. 
    1.62 +    typedef uintptr_t   ThreadSysId;   // System thread identifier. Used by Windows the same as ThreadId (DWORD), thread_act_t on Mac/BSD, lwp id on Linux.
    1.63 +
    1.64 +    // Thread constants
    1.65 +    // To do: Move to OVR Threads
    1.66 +    #define OVR_THREADHANDLE_INVALID ((ThreadHandle*)nullptr)
    1.67 +    #define OVR_THREADID_INVALID     ((ThreadId*)nullptr)
    1.68 +    #define OVR_THREADSYSID_INVALID  ((uintptr_t)0)
    1.69 +
    1.70 +    OVR::ThreadSysId  ConvertThreadHandleToThreadSysId(OVR::ThreadHandle threadHandle);
    1.71 +    OVR::ThreadHandle ConvertThreadSysIdToThreadHandle(OVR::ThreadSysId threadSysId);   // The returned handle must be freed with FreeThreadHandle.
    1.72 +    void              FreeThreadHandle(OVR::ThreadHandle threadHandle);                 // Frees the handle returned by ConvertThreadSysIdToThreadHandle.
    1.73 +    OVR::ThreadSysId  GetCurrentThreadSysId();
    1.74 +
    1.75 +    // CPUContext
    1.76 +    #if defined(OVR_OS_MS)
    1.77 +        typedef CONTEXT CPUContext; 
    1.78 +    #elif defined(OVR_OS_MAC)
    1.79 +        struct CPUContext
    1.80 +        {
    1.81 +            x86_thread_state_t  threadState; // This works for both x86 and x64.
    1.82 +            x86_float_state_t   floatState;
    1.83 +            x86_debug_state_t   debugState;
    1.84 +            x86_avx_state_t     avxState;
    1.85 +            x86_exception_state exceptionState;
    1.86 +            
    1.87 +            CPUContext() { memset(this, 0, sizeof(CPUContext)); }
    1.88 +        };
    1.89 +    #elif defined(OVR_OS_LINUX)
    1.90 +        typedef int CPUContext; // To do.
    1.91 +    #endif
    1.92 +
    1.93 +
    1.94 +    // Tells if the current process appears to be running under a debugger. Does not attempt to 
    1.95 +    // detect the case of sleath debuggers (malware-related for example).
    1.96 +    bool OVRIsDebuggerPresent();
    1.97 +
    1.98 +    // Exits the process with the given exit code.
    1.99 +    #if !defined(OVR_NORETURN)
   1.100 +        #if defined(OVR_CC_MSVC)
   1.101 +            #define OVR_NORETURN __declspec(noreturn)
   1.102 +        #else
   1.103 +            #define OVR_NORETURN __attribute__((noreturn))
   1.104 +        #endif
   1.105 +    #endif
   1.106 +    OVR_NORETURN void ExitProcess(intptr_t processReturnValue);
   1.107 +
   1.108 +    // Returns the instruction pointer of the caller for the position right after the call.
   1.109 +    OVR_NO_INLINE void GetInstructionPointer(void*& pInstruction);
   1.110 +
   1.111 +    // Returns the stack base and limit addresses for the given thread, or for the current thread if the threadHandle is default.
   1.112 +    // The stack limit is a value less than the stack base on most platforms, as stacks usually grow downward.
   1.113 +    // Some platforms (e.g. Microsoft) have dynamically resizing stacks, in which case the stack limit reflects the current limit.
   1.114 +    void GetThreadStackBounds(void*& pStackBase, void*& pStackLimit, ThreadHandle threadHandle = OVR_THREADHANDLE_INVALID);
   1.115 +
   1.116 +
   1.117 +    // Equates to VirtualAlloc/VirtualFree on Windows, mmap/munmap on Unix.
   1.118 +    // These are useful for when you need system-supplied memory pages. 
   1.119 +    // These are also useful for when you need to allocate memory in a way 
   1.120 +    // that doesn't affect the application heap.
   1.121 +    void* SafeMMapAlloc(size_t size);
   1.122 +    void  SafeMMapFree(const void* memory, size_t size);
   1.123 +
   1.124 +
   1.125 +    // OVR_MAX_PATH
   1.126 +    // Max file path length (for most uses).
   1.127 +    // To do: move this to OVR_File.
   1.128 +    #if defined(OVR_OS_MS)         // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx
   1.129 +        #define OVR_MAX_PATH  260  // Windows can use paths longer than this in some cases (network paths, UNC paths).
   1.130 +    #else
   1.131 +        #define OVR_MAX_PATH 1024  // This isn't a strict limit on all Unix-based platforms.
   1.132 +    #endif
   1.133 +
   1.134 +
   1.135 +    // ModuleHandle
   1.136 +    #if defined(OVR_OS_MS)
   1.137 +        typedef void* ModuleHandle;  // from LoadLibrary()
   1.138 +    #elif defined(OVR_OS_APPLE) || defined(OVR_OS_UNIX)
   1.139 +        typedef void* ModuleHandle;  // from dlopen()
   1.140 +    #endif
   1.141 +
   1.142 +    #define OVR_MODULEHANDLE_INVALID ((ModuleHandle*)nullptr)
   1.143 +
   1.144 +
   1.145 +
   1.146 +    // Module info constants
   1.147 +    static const ModuleHandle kMIHandleInvalid          = OVR_MODULEHANDLE_INVALID;
   1.148 +    static const uint64_t     kMIAddressInvalid         = 0xffffffffffffffffull;
   1.149 +    static const uint64_t     kMISizeInvalid            = 0xffffffffffffffffull;
   1.150 +    static const int32_t      kMILineNumberInvalid      = -1;
   1.151 +    static const int32_t      kMIFunctionOffsetInvalid  = -1;
   1.152 +    static const uint64_t     kMIBaseAddressInvalid     = 0xffffffffffffffffull;
   1.153 +    static const uint64_t     kMIBaseAddressUnspecified = 0xffffffffffffffffull;
   1.154 +
   1.155 +    struct ModuleInfo
   1.156 +    {
   1.157 +        ModuleHandle handle;
   1.158 +        uint64_t     baseAddress;           // The actual runtime base address of the module. May be different from the base address specified in the debug symbol file.
   1.159 +        uint64_t     size;
   1.160 +        char         filePath[OVR_MAX_PATH];
   1.161 +        char         name[32];
   1.162 +        char         type[8];               // Unix-specific. e.g. __TEXT
   1.163 +        char         permissions[8];        // Unix specific. e.g. "drwxr-xr-x"
   1.164 +
   1.165 +        ModuleInfo() : handle(kMIHandleInvalid), baseAddress(kMIBaseAddressInvalid), size(0), filePath(), name(){}
   1.166 +    };
   1.167 +
   1.168 +
   1.169 +    // Refers to symbol info for an instruction address. 
   1.170 +    // Info includes function name, source code file/line, and source code itself.
   1.171 +    struct SymbolInfo
   1.172 +    {
   1.173 +        uint64_t          address;
   1.174 +        uint64_t          size;
   1.175 +        const ModuleInfo* pModuleInfo;
   1.176 +        char              filePath[OVR_MAX_PATH];
   1.177 +        int32_t           fileLineNumber;
   1.178 +        char              function[128];            // This is a fixed size because we need to use it during application exceptions.
   1.179 +        int32_t           functionOffset;
   1.180 +        char              sourceCode[1024];         // This is a string representing the code itself and not a file path to the code.
   1.181 +
   1.182 +        SymbolInfo() : address(kMIAddressInvalid), size(kMISizeInvalid), pModuleInfo(nullptr), filePath(), 
   1.183 +                        fileLineNumber(kMILineNumberInvalid), function(), functionOffset(kMIFunctionOffsetInvalid), sourceCode() {}
   1.184 +    };
   1.185 +
   1.186 +
   1.187 +    // Implements support for reading thread lists, module lists, backtraces, and backtrace symbols.
   1.188 +    class SymbolLookup
   1.189 +    {
   1.190 +    public:
   1.191 +        SymbolLookup();
   1.192 +       ~SymbolLookup();
   1.193 +
   1.194 +        void AddSourceCodeDirectory(const char* pDirectory);
   1.195 +
   1.196 +        bool Initialize();
   1.197 +        void Shutdown();
   1.198 +
   1.199 +        // Should be disabled when within an exception handler.
   1.200 +        void EnableMemoryAllocation(bool enabled);
   1.201 +        
   1.202 +        // Retrieves the backtrace (call stack) of the given thread. There may be some per-platform restrictions on this.
   1.203 +        // Returns the number written, which will be <= addressArrayCapacity.
   1.204 +        // This may not work on some platforms unless stack frames are enabled.
   1.205 +        // For Microsoft platforms the platformThreadContext is CONTEXT*.
   1.206 +        // For Apple platforms the platformThreadContext is x86_thread_state_t* or arm_thread_state_t*.
   1.207 +        // If threadSysIdHelp is non-zero, it may be used by the implementation to help produce a better backtrace.
   1.208 +        size_t GetBacktrace(void* addressArray[], size_t addressArrayCapacity, size_t skipCount = 0, void* platformThreadContext = nullptr, OVR::ThreadSysId threadSysIdHelp = OVR_THREADSYSID_INVALID);
   1.209 +
   1.210 +        // Retrieves the backtrace for the given ThreadHandle.
   1.211 +        // Returns the number written, which will be <= addressArrayCapacity.
   1.212 +        size_t GetBacktraceFromThreadHandle(void* addressArray[], size_t addressArrayCapacity, size_t skipCount = 0, OVR::ThreadHandle threadHandle = OVR_THREADHANDLE_INVALID);
   1.213 +
   1.214 +        // Retrieves the backtrace for the given ThreadSysId.
   1.215 +        // Returns the number written, which will be <= addressArrayCapacity.
   1.216 +        size_t GetBacktraceFromThreadSysId(void* addressArray[], size_t addressArrayCapacity, size_t skipCount = 0, OVR::ThreadSysId threadSysId = OVR_THREADSYSID_INVALID);
   1.217 +
   1.218 +        // Gets a list of the modules (e.g. DLLs) present in the current process.
   1.219 +        // Writes as many ModuleInfos as possible to pModuleInfoArray.
   1.220 +        // Returns the required count of ModuleInfos, which will be > moduleInfoArrayCapacity if the capacity needs to be larger.
   1.221 +        size_t GetModuleInfoArray(ModuleInfo* pModuleInfoArray, size_t moduleInfoArrayCapacity);
   1.222 +
   1.223 +        // Retrieves a list of the current threads. Unless the process is paused the list is volatile.
   1.224 +        // Returns the required capacity, which may be larger than threadArrayCapacity.
   1.225 +        // Either array can be NULL to specify that it's not written to.
   1.226 +        // For Windows the caller needs to CloseHandle the returned ThreadHandles. This can be done by calling DoneThreadList.
   1.227 +        size_t GetThreadList(ThreadHandle* threadHandleArray, ThreadSysId* threadSysIdArray, size_t threadArrayCapacity);
   1.228 +
   1.229 +        // Frees any references to thread handles or ids returned by GetThreadList;
   1.230 +        void DoneThreadList(ThreadHandle* threadHandleArray, ThreadSysId* threadSysIdArray, size_t threadArrayCount);
   1.231 +
   1.232 +        // Writes a given thread's callstack with symbols to the given output.
   1.233 +        // It may not be safe to call this from an exception handler, as sOutput allocates memory.
   1.234 +        bool ReportThreadCallstack(OVR::String& sOutput, size_t skipCount = 0, ThreadSysId threadSysId = OVR_THREADSYSID_INVALID);
   1.235 +
   1.236 +        // Writes all thread's callstacks with symbols to the given output.
   1.237 +        // It may not be safe to call this from an exception handler, as sOutput allocates memory.
   1.238 +        bool ReportThreadCallstacks(OVR::String& sOutput, size_t skipCount = 0);
   1.239 +
   1.240 +        // Retrieves symbol info for the given address. 
   1.241 +        bool LookupSymbol(uint64_t address, SymbolInfo& symbolInfo);
   1.242 +        bool LookupSymbols(uint64_t* addressArray, SymbolInfo* pSymbolInfoArray, size_t arraySize);
   1.243 +
   1.244 +        const ModuleInfo* GetModuleInfoForAddress(uint64_t address);  // The returned ModuleInfo points to an internal structure.
   1.245 +
   1.246 +    protected:
   1.247 +        bool RefreshModuleList();
   1.248 +
   1.249 +    protected:
   1.250 +        bool       initialized;
   1.251 +        bool       allowMemoryAllocation;   // True by default. If true then we allow allocating memory (and as a result provide less information). This is useful for when in an exception handler.
   1.252 +        bool       moduleListUpdated;
   1.253 +        ModuleInfo moduleInfoArray[96];     // Cached list of modules we use. This is a fixed size because we need to use it during application exceptions.
   1.254 +        size_t     moduleInfoArraySize;
   1.255 +    };
   1.256 +
   1.257 +
   1.258 +
   1.259 +    // ExceptionInfo
   1.260 +    // We need to be careful to avoid data types that can allocate memory while we are 
   1.261 +    // handling an exception, as the memory system may be corrupted at that point in time.
   1.262 +    struct ExceptionInfo
   1.263 +    {
   1.264 +        tm            time;                             // GM time.
   1.265 +        time_t        timeVal;                          // GM time_t (seconds since 1970).
   1.266 +        void*         backtrace[64];
   1.267 +        size_t        backtraceCount;
   1.268 +        ThreadHandle  threadHandle;                     // 
   1.269 +        ThreadSysId   threadSysId;                      // 
   1.270 +        char          threadName[32];                   // Cannot be an allocating String object.
   1.271 +        void*         pExceptionInstructionAddress;
   1.272 +        void*         pExceptionMemoryAddress;
   1.273 +        CPUContext    cpuContext;
   1.274 +        char          exceptionDescription[1024];       // Cannot be an allocating String object.
   1.275 +        SymbolInfo    symbolInfo;                       // SymbolInfo for the exception location.
   1.276 +
   1.277 +        #if defined(OVR_OS_MS)
   1.278 +            EXCEPTION_RECORD exceptionRecord;           // This is a Windows SDK struct.
   1.279 +        #elif defined(OVR_OS_APPLE)
   1.280 +            uint64_t         exceptionType;             // e.g. EXC_BAD_INSTRUCTION, EXC_BAD_ACCESS, etc.
   1.281 +            uint32_t         cpuExceptionId;            // The x86/x64 CPU trap id.
   1.282 +            uint32_t         cpuExceptionIdError;       // The x86/x64 CPU trap id extra info.
   1.283 +            int64_t          machExceptionDetail[4];    // Kernel exception code info.
   1.284 +            int              machExceptionDetailCount;  // Count of valid entries.
   1.285 +        #endif
   1.286 +
   1.287 +        ExceptionInfo();
   1.288 +    };
   1.289 +
   1.290 +
   1.291 +    // Implments support for asynchronous exception handling and basic exception report generation.
   1.292 +    // If you are implementing exception handling for a commercial application and want auto-uploading
   1.293 +    // functionality you may want to consider using something like Google Breakpad. This exception handler
   1.294 +    // is for in-application debug/diagnostic services, though it can write a report that has similar
   1.295 +    // information to Breakpad or OS-provided reports such as Apple .crash files.
   1.296 +    //
   1.297 +    // Example usage:
   1.298 +    //     ExceptionHandler exceptionHandler;
   1.299 +    //
   1.300 +    //     int main(int, char**)
   1.301 +    //     {
   1.302 +    //          exceptionHandler.Enable(true);
   1.303 +    //          exceptionHandler.SetExceptionListener(pSomeListener, 0);  // Optional listener hook.
   1.304 +    //     }
   1.305 +    // 
   1.306 +    class ExceptionHandler
   1.307 +    {
   1.308 +    public:
   1.309 +        ExceptionHandler();
   1.310 +       ~ExceptionHandler();
   1.311 +
   1.312 +        bool Enable(bool enable);
   1.313 +        
   1.314 +        // Some report info can be considered private information of the user, such as the current process list,
   1.315 +        // computer name, IP address or other identifying info, etc. We should not report this information for
   1.316 +        // external users unless they agree to this.
   1.317 +        void EnableReportPrivacy(bool enable);
   1.318 +
   1.319 +        struct ExceptionListener
   1.320 +        {
   1.321 +            virtual ~ExceptionListener(){}
   1.322 +            virtual int HandleException(uintptr_t userValue, ExceptionHandler* pExceptionHandler, ExceptionInfo* pExceptionInfo, const char* reportFilePath) = 0;
   1.323 +        };
   1.324 +
   1.325 +        void SetExceptionListener(ExceptionListener* pExceptionListener, uintptr_t userValue);
   1.326 +
   1.327 +        // What we do after handling the exception.
   1.328 +        enum ExceptionResponse
   1.329 +        {
   1.330 +            kERContinue,    // Continue execution. Will result in the exception being re-generated unless the application has fixed the cause. Similar to Windows EXCEPTION_CONTINUE_EXECUTION.
   1.331 +            kERHandle,      // Causes the OS to handle the exception as it normally would. Similar to Windows EXCEPTION_EXECUTE_HANDLER.
   1.332 +            kERTerminate,   // Exit the application.
   1.333 +            kERThrow,       // Re-throw the exception. Other handlers may catch it. Similar to Windows EXCEPTION_CONTINUE_SEARCH.
   1.334 +            kERDefault      // Usually set to kERTerminate.
   1.335 +        };
   1.336 +
   1.337 +        void SetExceptionResponse(ExceptionResponse er)
   1.338 +            { exceptionResponse = er; }
   1.339 +
   1.340 +        // Allws you to add an arbitrary description of the current application, which will be added to exception reports.
   1.341 +        void SetAppDescription(const char* appDescription);
   1.342 +
   1.343 +        // If the report path has a "%s" in its name, then assume the path is a sprintf format and write it 
   1.344 +        // with the %s specified as a date/time string.
   1.345 +        // The report path can be "default" to signify that you want to use the default user location.
   1.346 +        // Example usage:
   1.347 +        //     handler.SetExceptionPaths("/Users/Current/Exceptions/Exception %s.txt");
   1.348 +        void SetExceptionPaths(const char* exceptionReportPath, const char* exceptionMinidumpPath = nullptr);
   1.349 +
   1.350 +        // Allows you to specify base directories for code paths, which can be used to associate exception addresses to lines 
   1.351 +        // of code as opposed to just file names and line numbers, or function names plus binary offsets.
   1.352 +        void SetCodeBaseDirectoryPaths(const char* codeBaseDirectoryPathArray[], size_t codeBaseDirectoryPathCount);
   1.353 +
   1.354 +		// Given an exception report at a given file path, returns a string suitable for displaying in a message
   1.355 +		// box or similar user interface during the handling of an exception. The returned string must be passed
   1.356 +		// to FreeMessageBoxText when complete.
   1.357 +		static const char* GetExceptionUIText(const char* exceptionReportPath);
   1.358 +		static void FreeExceptionUIText(const char* messageBoxText);
   1.359 +
   1.360 +    protected:
   1.361 +        void WriteExceptionDescription();
   1.362 +        void WriteReport();
   1.363 +        void WriteReportLine(const char* pLine);
   1.364 +        void WriteReportLineF(const char* format, ...);
   1.365 +        void WriteThreadCallstack(ThreadHandle threadHandle, ThreadSysId threadSysId, const char* additionalInfo);
   1.366 +        void WriteMiniDump();
   1.367 +
   1.368 +        // Runtime constants
   1.369 +        bool               enabled;
   1.370 +        bool               reportPrivacyEnabled;        // Defaults to true.
   1.371 +        ExceptionResponse  exceptionResponse;           // Defaults to kERHandle
   1.372 +        ExceptionListener* exceptionListener;
   1.373 +        uintptr_t          exceptionListenerUserValue;
   1.374 +        String             appDescription;
   1.375 +        String             codeBasePathArray[6];        // 6 is arbitrary.
   1.376 +        char               reportFilePath[OVR_MAX_PATH];// May be an encoded path, in that it has "%s" in it or is named "default". See reporFiletPathActual for the runtime actual report path.
   1.377 +        int                miniDumpFlags;
   1.378 +        char               miniDumpFilePath[OVR_MAX_PATH];
   1.379 +        FILE*              file;                        // Can/should we use OVR Files for this?
   1.380 +        char               scratchBuffer[4096];
   1.381 +        SymbolLookup       symbolLookup;
   1.382 +
   1.383 +        // Runtime variables
   1.384 +        bool                     exceptionOccurred;
   1.385 +        OVR::AtomicInt<uint32_t> handlingBusy;
   1.386 +        char                     reportFilePathActual[OVR_MAX_PATH];
   1.387 +        char                     minidumpFilePathActual[OVR_MAX_PATH];
   1.388 +        int                      terminateReturnValue;
   1.389 +        ExceptionInfo            exceptionInfo;
   1.390 +
   1.391 +        #if defined(OVR_OS_MS)
   1.392 +            void*                        vectoredHandle;
   1.393 +            LPTOP_LEVEL_EXCEPTION_FILTER previousFilter;
   1.394 +            LPEXCEPTION_POINTERS         pExceptionPointers;
   1.395 +
   1.396 +            friend LONG WINAPI Win32ExceptionFilter(LPEXCEPTION_POINTERS pExceptionPointers);
   1.397 +            LONG ExceptionFilter(LPEXCEPTION_POINTERS pExceptionPointers);
   1.398 +
   1.399 +        #elif defined(OVR_OS_APPLE)
   1.400 +            struct SavedExceptionPorts
   1.401 +            {
   1.402 +                SavedExceptionPorts() : count(0) { memset(this, 0, sizeof(SavedExceptionPorts)); }
   1.403 +
   1.404 +                mach_msg_type_number_t count;
   1.405 +                exception_mask_t       masks[6];
   1.406 +                exception_handler_t    ports[6];
   1.407 +                exception_behavior_t   behaviors[6];
   1.408 +                thread_state_flavor_t  flavors[6];
   1.409 +            };
   1.410 +
   1.411 +            friend void* ::MachHandlerThreadFunctionStatic(void*);
   1.412 +            friend int ::catch_mach_exception_raise_state_identity_OVR(mach_port_t, mach_port_t, mach_port_t, exception_type_t,
   1.413 +                                        mach_exception_data_type_t*, mach_msg_type_number_t, int*, thread_state_t,
   1.414 +                                        mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t*);
   1.415 +        
   1.416 +            bool          InitMachExceptionHandler();
   1.417 +            void          ShutdownMachExceptionHandler();
   1.418 +            void*         MachHandlerThreadFunction();
   1.419 +            kern_return_t HandleMachException(mach_port_t port, mach_port_t thread, mach_port_t task, exception_type_t exceptionType,
   1.420 +                                              mach_exception_data_type_t* pExceptionDetail, mach_msg_type_number_t exceptionDetailCount, 
   1.421 +                                              int* pFlavor, thread_state_t pOldState, mach_msg_type_number_t oldStateCount, thread_state_t pNewState,
   1.422 +                                              mach_msg_type_number_t* pNewStateCount);
   1.423 +            kern_return_t ForwardMachException(mach_port_t thread, mach_port_t task, exception_type_t exceptionType,
   1.424 +                                               mach_exception_data_t pExceptionDetail, mach_msg_type_number_t exceptionDetailCount);
   1.425 +
   1.426 +            bool                machHandlerInitialized;
   1.427 +            mach_port_t         machExceptionPort;
   1.428 +            SavedExceptionPorts machExceptionPortsSaved;
   1.429 +            volatile bool       machThreadShouldContinue;
   1.430 +            volatile bool       machThreadExecuting;
   1.431 +            pthread_t           machThread;
   1.432 +
   1.433 +        #elif defined(OVR_OS_LINUX)
   1.434 +            // To do.
   1.435 +        #endif
   1.436 +    };
   1.437 +
   1.438 +
   1.439 +    // Identifies basic exception types for the CreateException function.
   1.440 +    enum CreateExceptionType
   1.441 +    {
   1.442 +        kCETAccessViolation,      // Read or write to inaccessable memory.
   1.443 +        kCETAlignment,            // Misaligned read or write.
   1.444 +        kCETDivideByZero,         // Integer divide by zero.
   1.445 +        kCETFPU,                  // Floating point / VPU exception.
   1.446 +        kCETIllegalInstruction,   // Illegal opcode.
   1.447 +        kCETStackCorruption,      // Stack frame was corrupted.
   1.448 +        kCETStackOverflow,        // Stack ran out of space, often due to infinite recursion.
   1.449 +        kCETTrap                  // System/OS trap (system call).
   1.450 +    };
   1.451 +
   1.452 +
   1.453 +    // Creates an exception of the given type, primarily for testing.
   1.454 +    void CreateException(CreateExceptionType exceptionType);
   1.455 +
   1.456 +
   1.457 +
   1.458 +} // namespace OVR
   1.459 +
   1.460 +
   1.461 +OVR_RESTORE_MSVC_WARNING()
   1.462 +
   1.463 +
   1.464 +#endif // Header include guard