nuclear@0: /************************************************************************************ nuclear@0: nuclear@0: Filename : OVR_DebugHelp.h nuclear@0: Content : Platform-independent exception handling interface nuclear@0: Created : October 6, 2014 nuclear@0: nuclear@0: Copyright : Copyright 2014 Oculus VR, LLC. All Rights reserved. nuclear@0: nuclear@0: Licensed under the Apache License, Version 2.0 (the "License"); nuclear@0: you may not use this file except in compliance with the License. nuclear@0: You may obtain a copy of the License at nuclear@0: nuclear@0: http://www.apache.org/licenses/LICENSE-2.0 nuclear@0: nuclear@0: Unless required by applicable law or agreed to in writing, software nuclear@0: distributed under the License is distributed on an "AS IS" BASIS, nuclear@0: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. nuclear@0: See the License for the specific language governing permissions and nuclear@0: limitations under the License. nuclear@0: nuclear@0: ************************************************************************************/ nuclear@0: nuclear@0: #ifndef OVR_ExceptionHandler_h nuclear@0: #define OVR_ExceptionHandler_h nuclear@0: nuclear@0: nuclear@0: #include "OVR_Types.h" nuclear@0: #include "OVR_String.h" nuclear@0: #include "OVR_Threads.h" nuclear@0: #include "OVR_Atomic.h" nuclear@0: #include "OVR_Nullptr.h" nuclear@0: #include nuclear@0: #include nuclear@0: nuclear@0: #if defined(OVR_OS_WIN32) || defined(OVR_OS_WIN64) nuclear@0: #include nuclear@0: nuclear@0: #elif defined(OVR_OS_APPLE) nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: nuclear@0: extern "C" void* MachHandlerThreadFunctionStatic(void*); nuclear@0: 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*, nuclear@0: mach_msg_type_number_t, int*, thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t*); nuclear@0: #elif defined(OVR_OS_LINUX) nuclear@0: #include nuclear@0: #endif nuclear@0: nuclear@0: nuclear@0: OVR_DISABLE_MSVC_WARNING(4351) // new behavior: elements of array will be default initialized nuclear@0: nuclear@0: nuclear@0: namespace OVR { nuclear@0: nuclear@0: // Thread identifiers nuclear@0: //typedef void* ThreadHandle; // Already defined by OVR Threads. Same as Windows thread handle, Unix pthread_t. nuclear@0: //typedef void* ThreadId; // Already defined by OVR Threads. Used by Windows as DWORD thread id, by Unix as pthread_t. nuclear@0: 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. nuclear@0: nuclear@0: // Thread constants nuclear@0: // To do: Move to OVR Threads nuclear@0: #define OVR_THREADHANDLE_INVALID ((ThreadHandle*)nullptr) nuclear@0: #define OVR_THREADID_INVALID ((ThreadId*)nullptr) nuclear@0: #define OVR_THREADSYSID_INVALID ((uintptr_t)0) nuclear@0: nuclear@0: OVR::ThreadSysId ConvertThreadHandleToThreadSysId(OVR::ThreadHandle threadHandle); nuclear@0: OVR::ThreadHandle ConvertThreadSysIdToThreadHandle(OVR::ThreadSysId threadSysId); // The returned handle must be freed with FreeThreadHandle. nuclear@0: void FreeThreadHandle(OVR::ThreadHandle threadHandle); // Frees the handle returned by ConvertThreadSysIdToThreadHandle. nuclear@0: OVR::ThreadSysId GetCurrentThreadSysId(); nuclear@0: nuclear@0: // CPUContext nuclear@0: #if defined(OVR_OS_MS) nuclear@0: typedef CONTEXT CPUContext; nuclear@0: #elif defined(OVR_OS_MAC) nuclear@0: struct CPUContext nuclear@0: { nuclear@0: x86_thread_state_t threadState; // This works for both x86 and x64. nuclear@0: x86_float_state_t floatState; nuclear@0: x86_debug_state_t debugState; nuclear@0: x86_avx_state_t avxState; nuclear@0: x86_exception_state exceptionState; nuclear@0: nuclear@0: CPUContext() { memset(this, 0, sizeof(CPUContext)); } nuclear@0: }; nuclear@0: #elif defined(OVR_OS_LINUX) nuclear@0: typedef int CPUContext; // To do. nuclear@0: #endif nuclear@0: nuclear@0: nuclear@0: // Tells if the current process appears to be running under a debugger. Does not attempt to nuclear@0: // detect the case of sleath debuggers (malware-related for example). nuclear@0: bool OVRIsDebuggerPresent(); nuclear@0: nuclear@0: // Exits the process with the given exit code. nuclear@0: #if !defined(OVR_NORETURN) nuclear@0: #if defined(OVR_CC_MSVC) nuclear@0: #define OVR_NORETURN __declspec(noreturn) nuclear@0: #else nuclear@0: #define OVR_NORETURN __attribute__((noreturn)) nuclear@0: #endif nuclear@0: #endif nuclear@0: OVR_NORETURN void ExitProcess(intptr_t processReturnValue); nuclear@0: nuclear@0: // Returns the instruction pointer of the caller for the position right after the call. nuclear@0: OVR_NO_INLINE void GetInstructionPointer(void*& pInstruction); nuclear@0: nuclear@0: // Returns the stack base and limit addresses for the given thread, or for the current thread if the threadHandle is default. nuclear@0: // The stack limit is a value less than the stack base on most platforms, as stacks usually grow downward. nuclear@0: // Some platforms (e.g. Microsoft) have dynamically resizing stacks, in which case the stack limit reflects the current limit. nuclear@0: void GetThreadStackBounds(void*& pStackBase, void*& pStackLimit, ThreadHandle threadHandle = OVR_THREADHANDLE_INVALID); nuclear@0: nuclear@0: nuclear@0: // Equates to VirtualAlloc/VirtualFree on Windows, mmap/munmap on Unix. nuclear@0: // These are useful for when you need system-supplied memory pages. nuclear@0: // These are also useful for when you need to allocate memory in a way nuclear@0: // that doesn't affect the application heap. nuclear@0: void* SafeMMapAlloc(size_t size); nuclear@0: void SafeMMapFree(const void* memory, size_t size); nuclear@0: nuclear@0: nuclear@0: // OVR_MAX_PATH nuclear@0: // Max file path length (for most uses). nuclear@0: // To do: move this to OVR_File. nuclear@0: #if defined(OVR_OS_MS) // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx nuclear@0: #define OVR_MAX_PATH 260 // Windows can use paths longer than this in some cases (network paths, UNC paths). nuclear@0: #else nuclear@0: #define OVR_MAX_PATH 1024 // This isn't a strict limit on all Unix-based platforms. nuclear@0: #endif nuclear@0: nuclear@0: nuclear@0: // ModuleHandle nuclear@0: #if defined(OVR_OS_MS) nuclear@0: typedef void* ModuleHandle; // from LoadLibrary() nuclear@0: #elif defined(OVR_OS_APPLE) || defined(OVR_OS_UNIX) nuclear@0: typedef void* ModuleHandle; // from dlopen() nuclear@0: #endif nuclear@0: nuclear@0: #define OVR_MODULEHANDLE_INVALID ((ModuleHandle*)nullptr) nuclear@0: nuclear@0: nuclear@0: nuclear@0: // Module info constants nuclear@0: static const ModuleHandle kMIHandleInvalid = OVR_MODULEHANDLE_INVALID; nuclear@0: static const uint64_t kMIAddressInvalid = 0xffffffffffffffffull; nuclear@0: static const uint64_t kMISizeInvalid = 0xffffffffffffffffull; nuclear@0: static const int32_t kMILineNumberInvalid = -1; nuclear@0: static const int32_t kMIFunctionOffsetInvalid = -1; nuclear@0: static const uint64_t kMIBaseAddressInvalid = 0xffffffffffffffffull; nuclear@0: static const uint64_t kMIBaseAddressUnspecified = 0xffffffffffffffffull; nuclear@0: nuclear@0: struct ModuleInfo nuclear@0: { nuclear@0: ModuleHandle handle; nuclear@0: uint64_t baseAddress; // The actual runtime base address of the module. May be different from the base address specified in the debug symbol file. nuclear@0: uint64_t size; nuclear@0: char filePath[OVR_MAX_PATH]; nuclear@0: char name[32]; nuclear@0: char type[8]; // Unix-specific. e.g. __TEXT nuclear@0: char permissions[8]; // Unix specific. e.g. "drwxr-xr-x" nuclear@0: nuclear@0: ModuleInfo() : handle(kMIHandleInvalid), baseAddress(kMIBaseAddressInvalid), size(0), filePath(), name(){} nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: // Refers to symbol info for an instruction address. nuclear@0: // Info includes function name, source code file/line, and source code itself. nuclear@0: struct SymbolInfo nuclear@0: { nuclear@0: uint64_t address; nuclear@0: uint64_t size; nuclear@0: const ModuleInfo* pModuleInfo; nuclear@0: char filePath[OVR_MAX_PATH]; nuclear@0: int32_t fileLineNumber; nuclear@0: char function[128]; // This is a fixed size because we need to use it during application exceptions. nuclear@0: int32_t functionOffset; nuclear@0: char sourceCode[1024]; // This is a string representing the code itself and not a file path to the code. nuclear@0: nuclear@0: SymbolInfo() : address(kMIAddressInvalid), size(kMISizeInvalid), pModuleInfo(nullptr), filePath(), nuclear@0: fileLineNumber(kMILineNumberInvalid), function(), functionOffset(kMIFunctionOffsetInvalid), sourceCode() {} nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: // Implements support for reading thread lists, module lists, backtraces, and backtrace symbols. nuclear@0: class SymbolLookup nuclear@0: { nuclear@0: public: nuclear@0: SymbolLookup(); nuclear@0: ~SymbolLookup(); nuclear@0: nuclear@0: void AddSourceCodeDirectory(const char* pDirectory); nuclear@0: nuclear@0: bool Initialize(); nuclear@0: void Shutdown(); nuclear@0: nuclear@0: // Should be disabled when within an exception handler. nuclear@0: void EnableMemoryAllocation(bool enabled); nuclear@0: nuclear@0: // Retrieves the backtrace (call stack) of the given thread. There may be some per-platform restrictions on this. nuclear@0: // Returns the number written, which will be <= addressArrayCapacity. nuclear@0: // This may not work on some platforms unless stack frames are enabled. nuclear@0: // For Microsoft platforms the platformThreadContext is CONTEXT*. nuclear@0: // For Apple platforms the platformThreadContext is x86_thread_state_t* or arm_thread_state_t*. nuclear@0: // If threadSysIdHelp is non-zero, it may be used by the implementation to help produce a better backtrace. nuclear@0: size_t GetBacktrace(void* addressArray[], size_t addressArrayCapacity, size_t skipCount = 0, void* platformThreadContext = nullptr, OVR::ThreadSysId threadSysIdHelp = OVR_THREADSYSID_INVALID); nuclear@0: nuclear@0: // Retrieves the backtrace for the given ThreadHandle. nuclear@0: // Returns the number written, which will be <= addressArrayCapacity. nuclear@0: size_t GetBacktraceFromThreadHandle(void* addressArray[], size_t addressArrayCapacity, size_t skipCount = 0, OVR::ThreadHandle threadHandle = OVR_THREADHANDLE_INVALID); nuclear@0: nuclear@0: // Retrieves the backtrace for the given ThreadSysId. nuclear@0: // Returns the number written, which will be <= addressArrayCapacity. nuclear@0: size_t GetBacktraceFromThreadSysId(void* addressArray[], size_t addressArrayCapacity, size_t skipCount = 0, OVR::ThreadSysId threadSysId = OVR_THREADSYSID_INVALID); nuclear@0: nuclear@0: // Gets a list of the modules (e.g. DLLs) present in the current process. nuclear@0: // Writes as many ModuleInfos as possible to pModuleInfoArray. nuclear@0: // Returns the required count of ModuleInfos, which will be > moduleInfoArrayCapacity if the capacity needs to be larger. nuclear@0: size_t GetModuleInfoArray(ModuleInfo* pModuleInfoArray, size_t moduleInfoArrayCapacity); nuclear@0: nuclear@0: // Retrieves a list of the current threads. Unless the process is paused the list is volatile. nuclear@0: // Returns the required capacity, which may be larger than threadArrayCapacity. nuclear@0: // Either array can be NULL to specify that it's not written to. nuclear@0: // For Windows the caller needs to CloseHandle the returned ThreadHandles. This can be done by calling DoneThreadList. nuclear@0: size_t GetThreadList(ThreadHandle* threadHandleArray, ThreadSysId* threadSysIdArray, size_t threadArrayCapacity); nuclear@0: nuclear@0: // Frees any references to thread handles or ids returned by GetThreadList; nuclear@0: void DoneThreadList(ThreadHandle* threadHandleArray, ThreadSysId* threadSysIdArray, size_t threadArrayCount); nuclear@0: nuclear@0: // Writes a given thread's callstack with symbols to the given output. nuclear@0: // It may not be safe to call this from an exception handler, as sOutput allocates memory. nuclear@0: bool ReportThreadCallstack(OVR::String& sOutput, size_t skipCount = 0, ThreadSysId threadSysId = OVR_THREADSYSID_INVALID); nuclear@0: nuclear@0: // Writes all thread's callstacks with symbols to the given output. nuclear@0: // It may not be safe to call this from an exception handler, as sOutput allocates memory. nuclear@0: bool ReportThreadCallstacks(OVR::String& sOutput, size_t skipCount = 0); nuclear@0: nuclear@0: // Retrieves symbol info for the given address. nuclear@0: bool LookupSymbol(uint64_t address, SymbolInfo& symbolInfo); nuclear@0: bool LookupSymbols(uint64_t* addressArray, SymbolInfo* pSymbolInfoArray, size_t arraySize); nuclear@0: nuclear@0: const ModuleInfo* GetModuleInfoForAddress(uint64_t address); // The returned ModuleInfo points to an internal structure. nuclear@0: nuclear@0: protected: nuclear@0: bool RefreshModuleList(); nuclear@0: nuclear@0: protected: nuclear@0: bool initialized; nuclear@0: 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. nuclear@0: bool moduleListUpdated; nuclear@0: ModuleInfo moduleInfoArray[96]; // Cached list of modules we use. This is a fixed size because we need to use it during application exceptions. nuclear@0: size_t moduleInfoArraySize; nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: nuclear@0: // ExceptionInfo nuclear@0: // We need to be careful to avoid data types that can allocate memory while we are nuclear@0: // handling an exception, as the memory system may be corrupted at that point in time. nuclear@0: struct ExceptionInfo nuclear@0: { nuclear@0: tm time; // GM time. nuclear@0: time_t timeVal; // GM time_t (seconds since 1970). nuclear@0: void* backtrace[64]; nuclear@0: size_t backtraceCount; nuclear@0: ThreadHandle threadHandle; // nuclear@0: ThreadSysId threadSysId; // nuclear@0: char threadName[32]; // Cannot be an allocating String object. nuclear@0: void* pExceptionInstructionAddress; nuclear@0: void* pExceptionMemoryAddress; nuclear@0: CPUContext cpuContext; nuclear@0: char exceptionDescription[1024]; // Cannot be an allocating String object. nuclear@0: SymbolInfo symbolInfo; // SymbolInfo for the exception location. nuclear@0: nuclear@0: #if defined(OVR_OS_MS) nuclear@0: EXCEPTION_RECORD exceptionRecord; // This is a Windows SDK struct. nuclear@0: #elif defined(OVR_OS_APPLE) nuclear@0: uint64_t exceptionType; // e.g. EXC_BAD_INSTRUCTION, EXC_BAD_ACCESS, etc. nuclear@0: uint32_t cpuExceptionId; // The x86/x64 CPU trap id. nuclear@0: uint32_t cpuExceptionIdError; // The x86/x64 CPU trap id extra info. nuclear@0: int64_t machExceptionDetail[4]; // Kernel exception code info. nuclear@0: int machExceptionDetailCount; // Count of valid entries. nuclear@0: #endif nuclear@0: nuclear@0: ExceptionInfo(); nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: // Implments support for asynchronous exception handling and basic exception report generation. nuclear@0: // If you are implementing exception handling for a commercial application and want auto-uploading nuclear@0: // functionality you may want to consider using something like Google Breakpad. This exception handler nuclear@0: // is for in-application debug/diagnostic services, though it can write a report that has similar nuclear@0: // information to Breakpad or OS-provided reports such as Apple .crash files. nuclear@0: // nuclear@0: // Example usage: nuclear@0: // ExceptionHandler exceptionHandler; nuclear@0: // nuclear@0: // int main(int, char**) nuclear@0: // { nuclear@0: // exceptionHandler.Enable(true); nuclear@0: // exceptionHandler.SetExceptionListener(pSomeListener, 0); // Optional listener hook. nuclear@0: // } nuclear@0: // nuclear@0: class ExceptionHandler nuclear@0: { nuclear@0: public: nuclear@0: ExceptionHandler(); nuclear@0: ~ExceptionHandler(); nuclear@0: nuclear@0: bool Enable(bool enable); nuclear@0: nuclear@0: // Some report info can be considered private information of the user, such as the current process list, nuclear@0: // computer name, IP address or other identifying info, etc. We should not report this information for nuclear@0: // external users unless they agree to this. nuclear@0: void EnableReportPrivacy(bool enable); nuclear@0: nuclear@0: struct ExceptionListener nuclear@0: { nuclear@0: virtual ~ExceptionListener(){} nuclear@0: virtual int HandleException(uintptr_t userValue, ExceptionHandler* pExceptionHandler, ExceptionInfo* pExceptionInfo, const char* reportFilePath) = 0; nuclear@0: }; nuclear@0: nuclear@0: void SetExceptionListener(ExceptionListener* pExceptionListener, uintptr_t userValue); nuclear@0: nuclear@0: // What we do after handling the exception. nuclear@0: enum ExceptionResponse nuclear@0: { nuclear@0: kERContinue, // Continue execution. Will result in the exception being re-generated unless the application has fixed the cause. Similar to Windows EXCEPTION_CONTINUE_EXECUTION. nuclear@0: kERHandle, // Causes the OS to handle the exception as it normally would. Similar to Windows EXCEPTION_EXECUTE_HANDLER. nuclear@0: kERTerminate, // Exit the application. nuclear@0: kERThrow, // Re-throw the exception. Other handlers may catch it. Similar to Windows EXCEPTION_CONTINUE_SEARCH. nuclear@0: kERDefault // Usually set to kERTerminate. nuclear@0: }; nuclear@0: nuclear@0: void SetExceptionResponse(ExceptionResponse er) nuclear@0: { exceptionResponse = er; } nuclear@0: nuclear@0: // Allws you to add an arbitrary description of the current application, which will be added to exception reports. nuclear@0: void SetAppDescription(const char* appDescription); nuclear@0: nuclear@0: // If the report path has a "%s" in its name, then assume the path is a sprintf format and write it nuclear@0: // with the %s specified as a date/time string. nuclear@0: // The report path can be "default" to signify that you want to use the default user location. nuclear@0: // Example usage: nuclear@0: // handler.SetExceptionPaths("/Users/Current/Exceptions/Exception %s.txt"); nuclear@0: void SetExceptionPaths(const char* exceptionReportPath, const char* exceptionMinidumpPath = nullptr); nuclear@0: nuclear@0: // Allows you to specify base directories for code paths, which can be used to associate exception addresses to lines nuclear@0: // of code as opposed to just file names and line numbers, or function names plus binary offsets. nuclear@0: void SetCodeBaseDirectoryPaths(const char* codeBaseDirectoryPathArray[], size_t codeBaseDirectoryPathCount); nuclear@0: nuclear@0: // Given an exception report at a given file path, returns a string suitable for displaying in a message nuclear@0: // box or similar user interface during the handling of an exception. The returned string must be passed nuclear@0: // to FreeMessageBoxText when complete. nuclear@0: static const char* GetExceptionUIText(const char* exceptionReportPath); nuclear@0: static void FreeExceptionUIText(const char* messageBoxText); nuclear@0: nuclear@0: protected: nuclear@0: void WriteExceptionDescription(); nuclear@0: void WriteReport(); nuclear@0: void WriteReportLine(const char* pLine); nuclear@0: void WriteReportLineF(const char* format, ...); nuclear@0: void WriteThreadCallstack(ThreadHandle threadHandle, ThreadSysId threadSysId, const char* additionalInfo); nuclear@0: void WriteMiniDump(); nuclear@0: nuclear@0: // Runtime constants nuclear@0: bool enabled; nuclear@0: bool reportPrivacyEnabled; // Defaults to true. nuclear@0: ExceptionResponse exceptionResponse; // Defaults to kERHandle nuclear@0: ExceptionListener* exceptionListener; nuclear@0: uintptr_t exceptionListenerUserValue; nuclear@0: String appDescription; nuclear@0: String codeBasePathArray[6]; // 6 is arbitrary. nuclear@0: 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. nuclear@0: int miniDumpFlags; nuclear@0: char miniDumpFilePath[OVR_MAX_PATH]; nuclear@0: FILE* file; // Can/should we use OVR Files for this? nuclear@0: char scratchBuffer[4096]; nuclear@0: SymbolLookup symbolLookup; nuclear@0: nuclear@0: // Runtime variables nuclear@0: bool exceptionOccurred; nuclear@0: OVR::AtomicInt handlingBusy; nuclear@0: char reportFilePathActual[OVR_MAX_PATH]; nuclear@0: char minidumpFilePathActual[OVR_MAX_PATH]; nuclear@0: int terminateReturnValue; nuclear@0: ExceptionInfo exceptionInfo; nuclear@0: nuclear@0: #if defined(OVR_OS_MS) nuclear@0: void* vectoredHandle; nuclear@0: LPTOP_LEVEL_EXCEPTION_FILTER previousFilter; nuclear@0: LPEXCEPTION_POINTERS pExceptionPointers; nuclear@0: nuclear@0: friend LONG WINAPI Win32ExceptionFilter(LPEXCEPTION_POINTERS pExceptionPointers); nuclear@0: LONG ExceptionFilter(LPEXCEPTION_POINTERS pExceptionPointers); nuclear@0: nuclear@0: #elif defined(OVR_OS_APPLE) nuclear@0: struct SavedExceptionPorts nuclear@0: { nuclear@0: SavedExceptionPorts() : count(0) { memset(this, 0, sizeof(SavedExceptionPorts)); } nuclear@0: nuclear@0: mach_msg_type_number_t count; nuclear@0: exception_mask_t masks[6]; nuclear@0: exception_handler_t ports[6]; nuclear@0: exception_behavior_t behaviors[6]; nuclear@0: thread_state_flavor_t flavors[6]; nuclear@0: }; nuclear@0: nuclear@0: friend void* ::MachHandlerThreadFunctionStatic(void*); nuclear@0: friend int ::catch_mach_exception_raise_state_identity_OVR(mach_port_t, mach_port_t, mach_port_t, exception_type_t, nuclear@0: mach_exception_data_type_t*, mach_msg_type_number_t, int*, thread_state_t, nuclear@0: mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t*); nuclear@0: nuclear@0: bool InitMachExceptionHandler(); nuclear@0: void ShutdownMachExceptionHandler(); nuclear@0: void* MachHandlerThreadFunction(); nuclear@0: kern_return_t HandleMachException(mach_port_t port, mach_port_t thread, mach_port_t task, exception_type_t exceptionType, nuclear@0: mach_exception_data_type_t* pExceptionDetail, mach_msg_type_number_t exceptionDetailCount, nuclear@0: int* pFlavor, thread_state_t pOldState, mach_msg_type_number_t oldStateCount, thread_state_t pNewState, nuclear@0: mach_msg_type_number_t* pNewStateCount); nuclear@0: kern_return_t ForwardMachException(mach_port_t thread, mach_port_t task, exception_type_t exceptionType, nuclear@0: mach_exception_data_t pExceptionDetail, mach_msg_type_number_t exceptionDetailCount); nuclear@0: nuclear@0: bool machHandlerInitialized; nuclear@0: mach_port_t machExceptionPort; nuclear@0: SavedExceptionPorts machExceptionPortsSaved; nuclear@0: volatile bool machThreadShouldContinue; nuclear@0: volatile bool machThreadExecuting; nuclear@0: pthread_t machThread; nuclear@0: nuclear@0: #elif defined(OVR_OS_LINUX) nuclear@0: // To do. nuclear@0: #endif nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: // Identifies basic exception types for the CreateException function. nuclear@0: enum CreateExceptionType nuclear@0: { nuclear@0: kCETAccessViolation, // Read or write to inaccessable memory. nuclear@0: kCETAlignment, // Misaligned read or write. nuclear@0: kCETDivideByZero, // Integer divide by zero. nuclear@0: kCETFPU, // Floating point / VPU exception. nuclear@0: kCETIllegalInstruction, // Illegal opcode. nuclear@0: kCETStackCorruption, // Stack frame was corrupted. nuclear@0: kCETStackOverflow, // Stack ran out of space, often due to infinite recursion. nuclear@0: kCETTrap // System/OS trap (system call). nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: // Creates an exception of the given type, primarily for testing. nuclear@0: void CreateException(CreateExceptionType exceptionType); nuclear@0: nuclear@0: nuclear@0: nuclear@0: } // namespace OVR nuclear@0: nuclear@0: nuclear@0: OVR_RESTORE_MSVC_WARNING() nuclear@0: nuclear@0: nuclear@0: #endif // Header include guard