rev |
line source |
nuclear@0
|
1 /************************************************************************************
|
nuclear@0
|
2
|
nuclear@0
|
3 Filename : OVR_DebugHelp.h
|
nuclear@0
|
4 Content : Platform-independent exception handling interface
|
nuclear@0
|
5 Created : October 6, 2014
|
nuclear@0
|
6
|
nuclear@0
|
7 Copyright : Copyright 2014 Oculus VR, LLC. All Rights reserved.
|
nuclear@0
|
8
|
nuclear@0
|
9 Licensed under the Apache License, Version 2.0 (the "License");
|
nuclear@0
|
10 you may not use this file except in compliance with the License.
|
nuclear@0
|
11 You may obtain a copy of the License at
|
nuclear@0
|
12
|
nuclear@0
|
13 http://www.apache.org/licenses/LICENSE-2.0
|
nuclear@0
|
14
|
nuclear@0
|
15 Unless required by applicable law or agreed to in writing, software
|
nuclear@0
|
16 distributed under the License is distributed on an "AS IS" BASIS,
|
nuclear@0
|
17 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
nuclear@0
|
18 See the License for the specific language governing permissions and
|
nuclear@0
|
19 limitations under the License.
|
nuclear@0
|
20
|
nuclear@0
|
21 ************************************************************************************/
|
nuclear@0
|
22
|
nuclear@0
|
23 #ifndef OVR_ExceptionHandler_h
|
nuclear@0
|
24 #define OVR_ExceptionHandler_h
|
nuclear@0
|
25
|
nuclear@0
|
26
|
nuclear@0
|
27 #include "OVR_Types.h"
|
nuclear@0
|
28 #include "OVR_String.h"
|
nuclear@0
|
29 #include "OVR_Threads.h"
|
nuclear@0
|
30 #include "OVR_Atomic.h"
|
nuclear@0
|
31 #include "OVR_Nullptr.h"
|
nuclear@0
|
32 #include <stdio.h>
|
nuclear@0
|
33 #include <time.h>
|
nuclear@0
|
34
|
nuclear@0
|
35 #if defined(OVR_OS_WIN32) || defined(OVR_OS_WIN64)
|
nuclear@0
|
36 #include <Windows.h>
|
nuclear@0
|
37
|
nuclear@0
|
38 #elif defined(OVR_OS_APPLE)
|
nuclear@0
|
39 #include <pthread.h>
|
nuclear@0
|
40 #include <mach/thread_status.h>
|
nuclear@0
|
41 #include <mach/mach_types.h>
|
nuclear@0
|
42
|
nuclear@0
|
43 extern "C" void* MachHandlerThreadFunctionStatic(void*);
|
nuclear@0
|
44 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
|
45 mach_msg_type_number_t, int*, thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t*);
|
nuclear@0
|
46 #elif defined(OVR_OS_LINUX)
|
nuclear@0
|
47 #include <pthread.h>
|
nuclear@0
|
48 #endif
|
nuclear@0
|
49
|
nuclear@0
|
50
|
nuclear@0
|
51 OVR_DISABLE_MSVC_WARNING(4351) // new behavior: elements of array will be default initialized
|
nuclear@0
|
52
|
nuclear@0
|
53
|
nuclear@0
|
54 namespace OVR {
|
nuclear@0
|
55
|
nuclear@0
|
56 // Thread identifiers
|
nuclear@0
|
57 //typedef void* ThreadHandle; // Already defined by OVR Threads. Same as Windows thread handle, Unix pthread_t.
|
nuclear@0
|
58 //typedef void* ThreadId; // Already defined by OVR Threads. Used by Windows as DWORD thread id, by Unix as pthread_t.
|
nuclear@0
|
59 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
|
60
|
nuclear@0
|
61 // Thread constants
|
nuclear@0
|
62 // To do: Move to OVR Threads
|
nuclear@0
|
63 #define OVR_THREADHANDLE_INVALID ((ThreadHandle*)nullptr)
|
nuclear@0
|
64 #define OVR_THREADID_INVALID ((ThreadId*)nullptr)
|
nuclear@0
|
65 #define OVR_THREADSYSID_INVALID ((uintptr_t)0)
|
nuclear@0
|
66
|
nuclear@0
|
67 OVR::ThreadSysId ConvertThreadHandleToThreadSysId(OVR::ThreadHandle threadHandle);
|
nuclear@0
|
68 OVR::ThreadHandle ConvertThreadSysIdToThreadHandle(OVR::ThreadSysId threadSysId); // The returned handle must be freed with FreeThreadHandle.
|
nuclear@0
|
69 void FreeThreadHandle(OVR::ThreadHandle threadHandle); // Frees the handle returned by ConvertThreadSysIdToThreadHandle.
|
nuclear@0
|
70 OVR::ThreadSysId GetCurrentThreadSysId();
|
nuclear@0
|
71
|
nuclear@0
|
72 // CPUContext
|
nuclear@0
|
73 #if defined(OVR_OS_MS)
|
nuclear@0
|
74 typedef CONTEXT CPUContext;
|
nuclear@0
|
75 #elif defined(OVR_OS_MAC)
|
nuclear@0
|
76 struct CPUContext
|
nuclear@0
|
77 {
|
nuclear@0
|
78 x86_thread_state_t threadState; // This works for both x86 and x64.
|
nuclear@0
|
79 x86_float_state_t floatState;
|
nuclear@0
|
80 x86_debug_state_t debugState;
|
nuclear@0
|
81 x86_avx_state_t avxState;
|
nuclear@0
|
82 x86_exception_state exceptionState;
|
nuclear@0
|
83
|
nuclear@0
|
84 CPUContext() { memset(this, 0, sizeof(CPUContext)); }
|
nuclear@0
|
85 };
|
nuclear@0
|
86 #elif defined(OVR_OS_LINUX)
|
nuclear@0
|
87 typedef int CPUContext; // To do.
|
nuclear@0
|
88 #endif
|
nuclear@0
|
89
|
nuclear@0
|
90
|
nuclear@0
|
91 // Tells if the current process appears to be running under a debugger. Does not attempt to
|
nuclear@0
|
92 // detect the case of sleath debuggers (malware-related for example).
|
nuclear@0
|
93 bool OVRIsDebuggerPresent();
|
nuclear@0
|
94
|
nuclear@0
|
95 // Exits the process with the given exit code.
|
nuclear@0
|
96 #if !defined(OVR_NORETURN)
|
nuclear@0
|
97 #if defined(OVR_CC_MSVC)
|
nuclear@0
|
98 #define OVR_NORETURN __declspec(noreturn)
|
nuclear@0
|
99 #else
|
nuclear@0
|
100 #define OVR_NORETURN __attribute__((noreturn))
|
nuclear@0
|
101 #endif
|
nuclear@0
|
102 #endif
|
nuclear@0
|
103 OVR_NORETURN void ExitProcess(intptr_t processReturnValue);
|
nuclear@0
|
104
|
nuclear@0
|
105 // Returns the instruction pointer of the caller for the position right after the call.
|
nuclear@0
|
106 OVR_NO_INLINE void GetInstructionPointer(void*& pInstruction);
|
nuclear@0
|
107
|
nuclear@0
|
108 // Returns the stack base and limit addresses for the given thread, or for the current thread if the threadHandle is default.
|
nuclear@0
|
109 // The stack limit is a value less than the stack base on most platforms, as stacks usually grow downward.
|
nuclear@0
|
110 // Some platforms (e.g. Microsoft) have dynamically resizing stacks, in which case the stack limit reflects the current limit.
|
nuclear@0
|
111 void GetThreadStackBounds(void*& pStackBase, void*& pStackLimit, ThreadHandle threadHandle = OVR_THREADHANDLE_INVALID);
|
nuclear@0
|
112
|
nuclear@0
|
113
|
nuclear@0
|
114 // Equates to VirtualAlloc/VirtualFree on Windows, mmap/munmap on Unix.
|
nuclear@0
|
115 // These are useful for when you need system-supplied memory pages.
|
nuclear@0
|
116 // These are also useful for when you need to allocate memory in a way
|
nuclear@0
|
117 // that doesn't affect the application heap.
|
nuclear@0
|
118 void* SafeMMapAlloc(size_t size);
|
nuclear@0
|
119 void SafeMMapFree(const void* memory, size_t size);
|
nuclear@0
|
120
|
nuclear@0
|
121
|
nuclear@0
|
122 // OVR_MAX_PATH
|
nuclear@0
|
123 // Max file path length (for most uses).
|
nuclear@0
|
124 // To do: move this to OVR_File.
|
nuclear@0
|
125 #if defined(OVR_OS_MS) // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx
|
nuclear@0
|
126 #define OVR_MAX_PATH 260 // Windows can use paths longer than this in some cases (network paths, UNC paths).
|
nuclear@0
|
127 #else
|
nuclear@0
|
128 #define OVR_MAX_PATH 1024 // This isn't a strict limit on all Unix-based platforms.
|
nuclear@0
|
129 #endif
|
nuclear@0
|
130
|
nuclear@0
|
131
|
nuclear@0
|
132 // ModuleHandle
|
nuclear@0
|
133 #if defined(OVR_OS_MS)
|
nuclear@0
|
134 typedef void* ModuleHandle; // from LoadLibrary()
|
nuclear@0
|
135 #elif defined(OVR_OS_APPLE) || defined(OVR_OS_UNIX)
|
nuclear@0
|
136 typedef void* ModuleHandle; // from dlopen()
|
nuclear@0
|
137 #endif
|
nuclear@0
|
138
|
nuclear@0
|
139 #define OVR_MODULEHANDLE_INVALID ((ModuleHandle*)nullptr)
|
nuclear@0
|
140
|
nuclear@0
|
141
|
nuclear@0
|
142
|
nuclear@0
|
143 // Module info constants
|
nuclear@0
|
144 static const ModuleHandle kMIHandleInvalid = OVR_MODULEHANDLE_INVALID;
|
nuclear@0
|
145 static const uint64_t kMIAddressInvalid = 0xffffffffffffffffull;
|
nuclear@0
|
146 static const uint64_t kMISizeInvalid = 0xffffffffffffffffull;
|
nuclear@0
|
147 static const int32_t kMILineNumberInvalid = -1;
|
nuclear@0
|
148 static const int32_t kMIFunctionOffsetInvalid = -1;
|
nuclear@0
|
149 static const uint64_t kMIBaseAddressInvalid = 0xffffffffffffffffull;
|
nuclear@0
|
150 static const uint64_t kMIBaseAddressUnspecified = 0xffffffffffffffffull;
|
nuclear@0
|
151
|
nuclear@0
|
152 struct ModuleInfo
|
nuclear@0
|
153 {
|
nuclear@0
|
154 ModuleHandle handle;
|
nuclear@0
|
155 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
|
156 uint64_t size;
|
nuclear@0
|
157 char filePath[OVR_MAX_PATH];
|
nuclear@0
|
158 char name[32];
|
nuclear@0
|
159 char type[8]; // Unix-specific. e.g. __TEXT
|
nuclear@0
|
160 char permissions[8]; // Unix specific. e.g. "drwxr-xr-x"
|
nuclear@0
|
161
|
nuclear@0
|
162 ModuleInfo() : handle(kMIHandleInvalid), baseAddress(kMIBaseAddressInvalid), size(0), filePath(), name(){}
|
nuclear@0
|
163 };
|
nuclear@0
|
164
|
nuclear@0
|
165
|
nuclear@0
|
166 // Refers to symbol info for an instruction address.
|
nuclear@0
|
167 // Info includes function name, source code file/line, and source code itself.
|
nuclear@0
|
168 struct SymbolInfo
|
nuclear@0
|
169 {
|
nuclear@0
|
170 uint64_t address;
|
nuclear@0
|
171 uint64_t size;
|
nuclear@0
|
172 const ModuleInfo* pModuleInfo;
|
nuclear@0
|
173 char filePath[OVR_MAX_PATH];
|
nuclear@0
|
174 int32_t fileLineNumber;
|
nuclear@0
|
175 char function[128]; // This is a fixed size because we need to use it during application exceptions.
|
nuclear@0
|
176 int32_t functionOffset;
|
nuclear@0
|
177 char sourceCode[1024]; // This is a string representing the code itself and not a file path to the code.
|
nuclear@0
|
178
|
nuclear@0
|
179 SymbolInfo() : address(kMIAddressInvalid), size(kMISizeInvalid), pModuleInfo(nullptr), filePath(),
|
nuclear@0
|
180 fileLineNumber(kMILineNumberInvalid), function(), functionOffset(kMIFunctionOffsetInvalid), sourceCode() {}
|
nuclear@0
|
181 };
|
nuclear@0
|
182
|
nuclear@0
|
183
|
nuclear@0
|
184 // Implements support for reading thread lists, module lists, backtraces, and backtrace symbols.
|
nuclear@0
|
185 class SymbolLookup
|
nuclear@0
|
186 {
|
nuclear@0
|
187 public:
|
nuclear@0
|
188 SymbolLookup();
|
nuclear@0
|
189 ~SymbolLookup();
|
nuclear@0
|
190
|
nuclear@0
|
191 void AddSourceCodeDirectory(const char* pDirectory);
|
nuclear@0
|
192
|
nuclear@0
|
193 bool Initialize();
|
nuclear@0
|
194 void Shutdown();
|
nuclear@0
|
195
|
nuclear@0
|
196 // Should be disabled when within an exception handler.
|
nuclear@0
|
197 void EnableMemoryAllocation(bool enabled);
|
nuclear@0
|
198
|
nuclear@0
|
199 // Retrieves the backtrace (call stack) of the given thread. There may be some per-platform restrictions on this.
|
nuclear@0
|
200 // Returns the number written, which will be <= addressArrayCapacity.
|
nuclear@0
|
201 // This may not work on some platforms unless stack frames are enabled.
|
nuclear@0
|
202 // For Microsoft platforms the platformThreadContext is CONTEXT*.
|
nuclear@0
|
203 // For Apple platforms the platformThreadContext is x86_thread_state_t* or arm_thread_state_t*.
|
nuclear@0
|
204 // If threadSysIdHelp is non-zero, it may be used by the implementation to help produce a better backtrace.
|
nuclear@0
|
205 size_t GetBacktrace(void* addressArray[], size_t addressArrayCapacity, size_t skipCount = 0, void* platformThreadContext = nullptr, OVR::ThreadSysId threadSysIdHelp = OVR_THREADSYSID_INVALID);
|
nuclear@0
|
206
|
nuclear@0
|
207 // Retrieves the backtrace for the given ThreadHandle.
|
nuclear@0
|
208 // Returns the number written, which will be <= addressArrayCapacity.
|
nuclear@0
|
209 size_t GetBacktraceFromThreadHandle(void* addressArray[], size_t addressArrayCapacity, size_t skipCount = 0, OVR::ThreadHandle threadHandle = OVR_THREADHANDLE_INVALID);
|
nuclear@0
|
210
|
nuclear@0
|
211 // Retrieves the backtrace for the given ThreadSysId.
|
nuclear@0
|
212 // Returns the number written, which will be <= addressArrayCapacity.
|
nuclear@0
|
213 size_t GetBacktraceFromThreadSysId(void* addressArray[], size_t addressArrayCapacity, size_t skipCount = 0, OVR::ThreadSysId threadSysId = OVR_THREADSYSID_INVALID);
|
nuclear@0
|
214
|
nuclear@0
|
215 // Gets a list of the modules (e.g. DLLs) present in the current process.
|
nuclear@0
|
216 // Writes as many ModuleInfos as possible to pModuleInfoArray.
|
nuclear@0
|
217 // Returns the required count of ModuleInfos, which will be > moduleInfoArrayCapacity if the capacity needs to be larger.
|
nuclear@0
|
218 size_t GetModuleInfoArray(ModuleInfo* pModuleInfoArray, size_t moduleInfoArrayCapacity);
|
nuclear@0
|
219
|
nuclear@0
|
220 // Retrieves a list of the current threads. Unless the process is paused the list is volatile.
|
nuclear@0
|
221 // Returns the required capacity, which may be larger than threadArrayCapacity.
|
nuclear@0
|
222 // Either array can be NULL to specify that it's not written to.
|
nuclear@0
|
223 // For Windows the caller needs to CloseHandle the returned ThreadHandles. This can be done by calling DoneThreadList.
|
nuclear@0
|
224 size_t GetThreadList(ThreadHandle* threadHandleArray, ThreadSysId* threadSysIdArray, size_t threadArrayCapacity);
|
nuclear@0
|
225
|
nuclear@0
|
226 // Frees any references to thread handles or ids returned by GetThreadList;
|
nuclear@0
|
227 void DoneThreadList(ThreadHandle* threadHandleArray, ThreadSysId* threadSysIdArray, size_t threadArrayCount);
|
nuclear@0
|
228
|
nuclear@0
|
229 // Writes a given thread's callstack with symbols to the given output.
|
nuclear@0
|
230 // It may not be safe to call this from an exception handler, as sOutput allocates memory.
|
nuclear@0
|
231 bool ReportThreadCallstack(OVR::String& sOutput, size_t skipCount = 0, ThreadSysId threadSysId = OVR_THREADSYSID_INVALID);
|
nuclear@0
|
232
|
nuclear@0
|
233 // Writes all thread's callstacks with symbols to the given output.
|
nuclear@0
|
234 // It may not be safe to call this from an exception handler, as sOutput allocates memory.
|
nuclear@0
|
235 bool ReportThreadCallstacks(OVR::String& sOutput, size_t skipCount = 0);
|
nuclear@0
|
236
|
nuclear@0
|
237 // Retrieves symbol info for the given address.
|
nuclear@0
|
238 bool LookupSymbol(uint64_t address, SymbolInfo& symbolInfo);
|
nuclear@0
|
239 bool LookupSymbols(uint64_t* addressArray, SymbolInfo* pSymbolInfoArray, size_t arraySize);
|
nuclear@0
|
240
|
nuclear@0
|
241 const ModuleInfo* GetModuleInfoForAddress(uint64_t address); // The returned ModuleInfo points to an internal structure.
|
nuclear@0
|
242
|
nuclear@0
|
243 protected:
|
nuclear@0
|
244 bool RefreshModuleList();
|
nuclear@0
|
245
|
nuclear@0
|
246 protected:
|
nuclear@0
|
247 bool initialized;
|
nuclear@0
|
248 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
|
249 bool moduleListUpdated;
|
nuclear@0
|
250 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
|
251 size_t moduleInfoArraySize;
|
nuclear@0
|
252 };
|
nuclear@0
|
253
|
nuclear@0
|
254
|
nuclear@0
|
255
|
nuclear@0
|
256 // ExceptionInfo
|
nuclear@0
|
257 // We need to be careful to avoid data types that can allocate memory while we are
|
nuclear@0
|
258 // handling an exception, as the memory system may be corrupted at that point in time.
|
nuclear@0
|
259 struct ExceptionInfo
|
nuclear@0
|
260 {
|
nuclear@0
|
261 tm time; // GM time.
|
nuclear@0
|
262 time_t timeVal; // GM time_t (seconds since 1970).
|
nuclear@0
|
263 void* backtrace[64];
|
nuclear@0
|
264 size_t backtraceCount;
|
nuclear@0
|
265 ThreadHandle threadHandle; //
|
nuclear@0
|
266 ThreadSysId threadSysId; //
|
nuclear@0
|
267 char threadName[32]; // Cannot be an allocating String object.
|
nuclear@0
|
268 void* pExceptionInstructionAddress;
|
nuclear@0
|
269 void* pExceptionMemoryAddress;
|
nuclear@0
|
270 CPUContext cpuContext;
|
nuclear@0
|
271 char exceptionDescription[1024]; // Cannot be an allocating String object.
|
nuclear@0
|
272 SymbolInfo symbolInfo; // SymbolInfo for the exception location.
|
nuclear@0
|
273
|
nuclear@0
|
274 #if defined(OVR_OS_MS)
|
nuclear@0
|
275 EXCEPTION_RECORD exceptionRecord; // This is a Windows SDK struct.
|
nuclear@0
|
276 #elif defined(OVR_OS_APPLE)
|
nuclear@0
|
277 uint64_t exceptionType; // e.g. EXC_BAD_INSTRUCTION, EXC_BAD_ACCESS, etc.
|
nuclear@0
|
278 uint32_t cpuExceptionId; // The x86/x64 CPU trap id.
|
nuclear@0
|
279 uint32_t cpuExceptionIdError; // The x86/x64 CPU trap id extra info.
|
nuclear@0
|
280 int64_t machExceptionDetail[4]; // Kernel exception code info.
|
nuclear@0
|
281 int machExceptionDetailCount; // Count of valid entries.
|
nuclear@0
|
282 #endif
|
nuclear@0
|
283
|
nuclear@0
|
284 ExceptionInfo();
|
nuclear@0
|
285 };
|
nuclear@0
|
286
|
nuclear@0
|
287
|
nuclear@0
|
288 // Implments support for asynchronous exception handling and basic exception report generation.
|
nuclear@0
|
289 // If you are implementing exception handling for a commercial application and want auto-uploading
|
nuclear@0
|
290 // functionality you may want to consider using something like Google Breakpad. This exception handler
|
nuclear@0
|
291 // is for in-application debug/diagnostic services, though it can write a report that has similar
|
nuclear@0
|
292 // information to Breakpad or OS-provided reports such as Apple .crash files.
|
nuclear@0
|
293 //
|
nuclear@0
|
294 // Example usage:
|
nuclear@0
|
295 // ExceptionHandler exceptionHandler;
|
nuclear@0
|
296 //
|
nuclear@0
|
297 // int main(int, char**)
|
nuclear@0
|
298 // {
|
nuclear@0
|
299 // exceptionHandler.Enable(true);
|
nuclear@0
|
300 // exceptionHandler.SetExceptionListener(pSomeListener, 0); // Optional listener hook.
|
nuclear@0
|
301 // }
|
nuclear@0
|
302 //
|
nuclear@0
|
303 class ExceptionHandler
|
nuclear@0
|
304 {
|
nuclear@0
|
305 public:
|
nuclear@0
|
306 ExceptionHandler();
|
nuclear@0
|
307 ~ExceptionHandler();
|
nuclear@0
|
308
|
nuclear@0
|
309 bool Enable(bool enable);
|
nuclear@0
|
310
|
nuclear@0
|
311 // Some report info can be considered private information of the user, such as the current process list,
|
nuclear@0
|
312 // computer name, IP address or other identifying info, etc. We should not report this information for
|
nuclear@0
|
313 // external users unless they agree to this.
|
nuclear@0
|
314 void EnableReportPrivacy(bool enable);
|
nuclear@0
|
315
|
nuclear@0
|
316 struct ExceptionListener
|
nuclear@0
|
317 {
|
nuclear@0
|
318 virtual ~ExceptionListener(){}
|
nuclear@0
|
319 virtual int HandleException(uintptr_t userValue, ExceptionHandler* pExceptionHandler, ExceptionInfo* pExceptionInfo, const char* reportFilePath) = 0;
|
nuclear@0
|
320 };
|
nuclear@0
|
321
|
nuclear@0
|
322 void SetExceptionListener(ExceptionListener* pExceptionListener, uintptr_t userValue);
|
nuclear@0
|
323
|
nuclear@0
|
324 // What we do after handling the exception.
|
nuclear@0
|
325 enum ExceptionResponse
|
nuclear@0
|
326 {
|
nuclear@0
|
327 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
|
328 kERHandle, // Causes the OS to handle the exception as it normally would. Similar to Windows EXCEPTION_EXECUTE_HANDLER.
|
nuclear@0
|
329 kERTerminate, // Exit the application.
|
nuclear@0
|
330 kERThrow, // Re-throw the exception. Other handlers may catch it. Similar to Windows EXCEPTION_CONTINUE_SEARCH.
|
nuclear@0
|
331 kERDefault // Usually set to kERTerminate.
|
nuclear@0
|
332 };
|
nuclear@0
|
333
|
nuclear@0
|
334 void SetExceptionResponse(ExceptionResponse er)
|
nuclear@0
|
335 { exceptionResponse = er; }
|
nuclear@0
|
336
|
nuclear@0
|
337 // Allws you to add an arbitrary description of the current application, which will be added to exception reports.
|
nuclear@0
|
338 void SetAppDescription(const char* appDescription);
|
nuclear@0
|
339
|
nuclear@0
|
340 // If the report path has a "%s" in its name, then assume the path is a sprintf format and write it
|
nuclear@0
|
341 // with the %s specified as a date/time string.
|
nuclear@0
|
342 // The report path can be "default" to signify that you want to use the default user location.
|
nuclear@0
|
343 // Example usage:
|
nuclear@0
|
344 // handler.SetExceptionPaths("/Users/Current/Exceptions/Exception %s.txt");
|
nuclear@0
|
345 void SetExceptionPaths(const char* exceptionReportPath, const char* exceptionMinidumpPath = nullptr);
|
nuclear@0
|
346
|
nuclear@0
|
347 // Allows you to specify base directories for code paths, which can be used to associate exception addresses to lines
|
nuclear@0
|
348 // of code as opposed to just file names and line numbers, or function names plus binary offsets.
|
nuclear@0
|
349 void SetCodeBaseDirectoryPaths(const char* codeBaseDirectoryPathArray[], size_t codeBaseDirectoryPathCount);
|
nuclear@0
|
350
|
nuclear@0
|
351 // Given an exception report at a given file path, returns a string suitable for displaying in a message
|
nuclear@0
|
352 // box or similar user interface during the handling of an exception. The returned string must be passed
|
nuclear@0
|
353 // to FreeMessageBoxText when complete.
|
nuclear@0
|
354 static const char* GetExceptionUIText(const char* exceptionReportPath);
|
nuclear@0
|
355 static void FreeExceptionUIText(const char* messageBoxText);
|
nuclear@0
|
356
|
nuclear@0
|
357 protected:
|
nuclear@0
|
358 void WriteExceptionDescription();
|
nuclear@0
|
359 void WriteReport();
|
nuclear@0
|
360 void WriteReportLine(const char* pLine);
|
nuclear@0
|
361 void WriteReportLineF(const char* format, ...);
|
nuclear@0
|
362 void WriteThreadCallstack(ThreadHandle threadHandle, ThreadSysId threadSysId, const char* additionalInfo);
|
nuclear@0
|
363 void WriteMiniDump();
|
nuclear@0
|
364
|
nuclear@0
|
365 // Runtime constants
|
nuclear@0
|
366 bool enabled;
|
nuclear@0
|
367 bool reportPrivacyEnabled; // Defaults to true.
|
nuclear@0
|
368 ExceptionResponse exceptionResponse; // Defaults to kERHandle
|
nuclear@0
|
369 ExceptionListener* exceptionListener;
|
nuclear@0
|
370 uintptr_t exceptionListenerUserValue;
|
nuclear@0
|
371 String appDescription;
|
nuclear@0
|
372 String codeBasePathArray[6]; // 6 is arbitrary.
|
nuclear@0
|
373 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
|
374 int miniDumpFlags;
|
nuclear@0
|
375 char miniDumpFilePath[OVR_MAX_PATH];
|
nuclear@0
|
376 FILE* file; // Can/should we use OVR Files for this?
|
nuclear@0
|
377 char scratchBuffer[4096];
|
nuclear@0
|
378 SymbolLookup symbolLookup;
|
nuclear@0
|
379
|
nuclear@0
|
380 // Runtime variables
|
nuclear@0
|
381 bool exceptionOccurred;
|
nuclear@0
|
382 OVR::AtomicInt<uint32_t> handlingBusy;
|
nuclear@0
|
383 char reportFilePathActual[OVR_MAX_PATH];
|
nuclear@0
|
384 char minidumpFilePathActual[OVR_MAX_PATH];
|
nuclear@0
|
385 int terminateReturnValue;
|
nuclear@0
|
386 ExceptionInfo exceptionInfo;
|
nuclear@0
|
387
|
nuclear@0
|
388 #if defined(OVR_OS_MS)
|
nuclear@0
|
389 void* vectoredHandle;
|
nuclear@0
|
390 LPTOP_LEVEL_EXCEPTION_FILTER previousFilter;
|
nuclear@0
|
391 LPEXCEPTION_POINTERS pExceptionPointers;
|
nuclear@0
|
392
|
nuclear@0
|
393 friend LONG WINAPI Win32ExceptionFilter(LPEXCEPTION_POINTERS pExceptionPointers);
|
nuclear@0
|
394 LONG ExceptionFilter(LPEXCEPTION_POINTERS pExceptionPointers);
|
nuclear@0
|
395
|
nuclear@0
|
396 #elif defined(OVR_OS_APPLE)
|
nuclear@0
|
397 struct SavedExceptionPorts
|
nuclear@0
|
398 {
|
nuclear@0
|
399 SavedExceptionPorts() : count(0) { memset(this, 0, sizeof(SavedExceptionPorts)); }
|
nuclear@0
|
400
|
nuclear@0
|
401 mach_msg_type_number_t count;
|
nuclear@0
|
402 exception_mask_t masks[6];
|
nuclear@0
|
403 exception_handler_t ports[6];
|
nuclear@0
|
404 exception_behavior_t behaviors[6];
|
nuclear@0
|
405 thread_state_flavor_t flavors[6];
|
nuclear@0
|
406 };
|
nuclear@0
|
407
|
nuclear@0
|
408 friend void* ::MachHandlerThreadFunctionStatic(void*);
|
nuclear@0
|
409 friend int ::catch_mach_exception_raise_state_identity_OVR(mach_port_t, mach_port_t, mach_port_t, exception_type_t,
|
nuclear@0
|
410 mach_exception_data_type_t*, mach_msg_type_number_t, int*, thread_state_t,
|
nuclear@0
|
411 mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t*);
|
nuclear@0
|
412
|
nuclear@0
|
413 bool InitMachExceptionHandler();
|
nuclear@0
|
414 void ShutdownMachExceptionHandler();
|
nuclear@0
|
415 void* MachHandlerThreadFunction();
|
nuclear@0
|
416 kern_return_t HandleMachException(mach_port_t port, mach_port_t thread, mach_port_t task, exception_type_t exceptionType,
|
nuclear@0
|
417 mach_exception_data_type_t* pExceptionDetail, mach_msg_type_number_t exceptionDetailCount,
|
nuclear@0
|
418 int* pFlavor, thread_state_t pOldState, mach_msg_type_number_t oldStateCount, thread_state_t pNewState,
|
nuclear@0
|
419 mach_msg_type_number_t* pNewStateCount);
|
nuclear@0
|
420 kern_return_t ForwardMachException(mach_port_t thread, mach_port_t task, exception_type_t exceptionType,
|
nuclear@0
|
421 mach_exception_data_t pExceptionDetail, mach_msg_type_number_t exceptionDetailCount);
|
nuclear@0
|
422
|
nuclear@0
|
423 bool machHandlerInitialized;
|
nuclear@0
|
424 mach_port_t machExceptionPort;
|
nuclear@0
|
425 SavedExceptionPorts machExceptionPortsSaved;
|
nuclear@0
|
426 volatile bool machThreadShouldContinue;
|
nuclear@0
|
427 volatile bool machThreadExecuting;
|
nuclear@0
|
428 pthread_t machThread;
|
nuclear@0
|
429
|
nuclear@0
|
430 #elif defined(OVR_OS_LINUX)
|
nuclear@0
|
431 // To do.
|
nuclear@0
|
432 #endif
|
nuclear@0
|
433 };
|
nuclear@0
|
434
|
nuclear@0
|
435
|
nuclear@0
|
436 // Identifies basic exception types for the CreateException function.
|
nuclear@0
|
437 enum CreateExceptionType
|
nuclear@0
|
438 {
|
nuclear@0
|
439 kCETAccessViolation, // Read or write to inaccessable memory.
|
nuclear@0
|
440 kCETAlignment, // Misaligned read or write.
|
nuclear@0
|
441 kCETDivideByZero, // Integer divide by zero.
|
nuclear@0
|
442 kCETFPU, // Floating point / VPU exception.
|
nuclear@0
|
443 kCETIllegalInstruction, // Illegal opcode.
|
nuclear@0
|
444 kCETStackCorruption, // Stack frame was corrupted.
|
nuclear@0
|
445 kCETStackOverflow, // Stack ran out of space, often due to infinite recursion.
|
nuclear@0
|
446 kCETTrap // System/OS trap (system call).
|
nuclear@0
|
447 };
|
nuclear@0
|
448
|
nuclear@0
|
449
|
nuclear@0
|
450 // Creates an exception of the given type, primarily for testing.
|
nuclear@0
|
451 void CreateException(CreateExceptionType exceptionType);
|
nuclear@0
|
452
|
nuclear@0
|
453
|
nuclear@0
|
454
|
nuclear@0
|
455 } // namespace OVR
|
nuclear@0
|
456
|
nuclear@0
|
457
|
nuclear@0
|
458 OVR_RESTORE_MSVC_WARNING()
|
nuclear@0
|
459
|
nuclear@0
|
460
|
nuclear@0
|
461 #endif // Header include guard
|