Saleem Abdulrasool | b1b1911 | 2015-04-24 19:39:17 +0000 | [diff] [blame] | 1 | //===------------------------------- unwind.h -----------------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open |
| 6 | // Source Licenses. See LICENSE.TXT for details. |
| 7 | // |
| 8 | // |
| 9 | // C++ ABI Level 1 ABI documented at: |
| 10 | // http://mentorembedded.github.io/cxx-abi/abi-eh.html |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #ifndef __UNWIND_H__ |
| 15 | #define __UNWIND_H__ |
| 16 | |
Logan Chien | 5191fe9 | 2015-07-19 15:23:10 +0000 | [diff] [blame] | 17 | #include <__libunwind_config.h> |
| 18 | |
Saleem Abdulrasool | b1b1911 | 2015-04-24 19:39:17 +0000 | [diff] [blame] | 19 | #include <stdint.h> |
| 20 | #include <stddef.h> |
| 21 | |
| 22 | #if defined(__APPLE__) |
| 23 | #define LIBUNWIND_UNAVAIL __attribute__ (( unavailable )) |
| 24 | #else |
| 25 | #define LIBUNWIND_UNAVAIL |
| 26 | #endif |
| 27 | |
Saleem Abdulrasool | b1b1911 | 2015-04-24 19:39:17 +0000 | [diff] [blame] | 28 | typedef enum { |
| 29 | _URC_NO_REASON = 0, |
| 30 | _URC_OK = 0, |
| 31 | _URC_FOREIGN_EXCEPTION_CAUGHT = 1, |
| 32 | _URC_FATAL_PHASE2_ERROR = 2, |
| 33 | _URC_FATAL_PHASE1_ERROR = 3, |
| 34 | _URC_NORMAL_STOP = 4, |
| 35 | _URC_END_OF_STACK = 5, |
| 36 | _URC_HANDLER_FOUND = 6, |
| 37 | _URC_INSTALL_CONTEXT = 7, |
| 38 | _URC_CONTINUE_UNWIND = 8, |
Logan Chien | 5191fe9 | 2015-07-19 15:23:10 +0000 | [diff] [blame] | 39 | #if _LIBUNWIND_ARM_EHABI |
Saleem Abdulrasool | b1b1911 | 2015-04-24 19:39:17 +0000 | [diff] [blame] | 40 | _URC_FAILURE = 9 |
| 41 | #endif |
| 42 | } _Unwind_Reason_Code; |
| 43 | |
| 44 | typedef enum { |
| 45 | _UA_SEARCH_PHASE = 1, |
| 46 | _UA_CLEANUP_PHASE = 2, |
| 47 | _UA_HANDLER_FRAME = 4, |
| 48 | _UA_FORCE_UNWIND = 8, |
| 49 | _UA_END_OF_STACK = 16 // gcc extension to C++ ABI |
| 50 | } _Unwind_Action; |
| 51 | |
| 52 | typedef struct _Unwind_Context _Unwind_Context; // opaque |
| 53 | |
Logan Chien | 5191fe9 | 2015-07-19 15:23:10 +0000 | [diff] [blame] | 54 | #if _LIBUNWIND_ARM_EHABI |
Saleem Abdulrasool | b1b1911 | 2015-04-24 19:39:17 +0000 | [diff] [blame] | 55 | typedef uint32_t _Unwind_State; |
| 56 | |
| 57 | static const _Unwind_State _US_VIRTUAL_UNWIND_FRAME = 0; |
| 58 | static const _Unwind_State _US_UNWIND_FRAME_STARTING = 1; |
| 59 | static const _Unwind_State _US_UNWIND_FRAME_RESUME = 2; |
Dimitry Andric | 84af6d1 | 2016-09-05 18:01:13 +0000 | [diff] [blame^] | 60 | static const _Unwind_State _US_ACTION_MASK = 3; |
Saleem Abdulrasool | b1b1911 | 2015-04-24 19:39:17 +0000 | [diff] [blame] | 61 | /* Undocumented flag for force unwinding. */ |
| 62 | static const _Unwind_State _US_FORCE_UNWIND = 8; |
| 63 | |
| 64 | typedef uint32_t _Unwind_EHT_Header; |
| 65 | |
| 66 | struct _Unwind_Control_Block; |
| 67 | typedef struct _Unwind_Control_Block _Unwind_Control_Block; |
| 68 | typedef struct _Unwind_Control_Block _Unwind_Exception; /* Alias */ |
| 69 | |
| 70 | struct _Unwind_Control_Block { |
| 71 | uint64_t exception_class; |
| 72 | void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block*); |
| 73 | |
| 74 | /* Unwinder cache, private fields for the unwinder's use */ |
| 75 | struct { |
| 76 | uint32_t reserved1; /* init reserved1 to 0, then don't touch */ |
| 77 | uint32_t reserved2; |
| 78 | uint32_t reserved3; |
| 79 | uint32_t reserved4; |
| 80 | uint32_t reserved5; |
| 81 | } unwinder_cache; |
| 82 | |
| 83 | /* Propagation barrier cache (valid after phase 1): */ |
| 84 | struct { |
| 85 | uint32_t sp; |
| 86 | uint32_t bitpattern[5]; |
| 87 | } barrier_cache; |
| 88 | |
| 89 | /* Cleanup cache (preserved over cleanup): */ |
| 90 | struct { |
| 91 | uint32_t bitpattern[4]; |
| 92 | } cleanup_cache; |
| 93 | |
| 94 | /* Pr cache (for pr's benefit): */ |
| 95 | struct { |
| 96 | uint32_t fnstart; /* function start address */ |
| 97 | _Unwind_EHT_Header* ehtp; /* pointer to EHT entry header word */ |
| 98 | uint32_t additional; |
| 99 | uint32_t reserved1; |
| 100 | } pr_cache; |
| 101 | |
| 102 | long long int :0; /* Enforce the 8-byte alignment */ |
| 103 | }; |
| 104 | |
| 105 | typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) |
| 106 | (_Unwind_State state, |
| 107 | _Unwind_Exception* exceptionObject, |
| 108 | struct _Unwind_Context* context); |
| 109 | |
| 110 | typedef _Unwind_Reason_Code (*__personality_routine) |
| 111 | (_Unwind_State state, |
| 112 | _Unwind_Exception* exceptionObject, |
| 113 | struct _Unwind_Context* context); |
| 114 | #else |
| 115 | struct _Unwind_Context; // opaque |
| 116 | struct _Unwind_Exception; // forward declaration |
| 117 | typedef struct _Unwind_Exception _Unwind_Exception; |
| 118 | |
| 119 | struct _Unwind_Exception { |
| 120 | uint64_t exception_class; |
| 121 | void (*exception_cleanup)(_Unwind_Reason_Code reason, |
| 122 | _Unwind_Exception *exc); |
| 123 | uintptr_t private_1; // non-zero means forced unwind |
| 124 | uintptr_t private_2; // holds sp that phase1 found for phase2 to use |
| 125 | #ifndef __LP64__ |
Eric Fiselier | 19f802f | 2016-07-20 23:56:42 +0000 | [diff] [blame] | 126 | // The implementation of _Unwind_Exception uses an attribute mode on the |
| 127 | // above fields which has the side effect of causing this whole struct to |
Saleem Abdulrasool | b1b1911 | 2015-04-24 19:39:17 +0000 | [diff] [blame] | 128 | // round up to 32 bytes in size. To be more explicit, we add pad fields |
| 129 | // added for binary compatibility. |
| 130 | uint32_t reserved[3]; |
| 131 | #endif |
Eric Fiselier | 19f802f | 2016-07-20 23:56:42 +0000 | [diff] [blame] | 132 | // The Itanium ABI requires that _Unwind_Exception objects are "double-word |
| 133 | // aligned". GCC has interpreted this to mean "use the maximum useful |
| 134 | // alignment for the target"; so do we. |
| 135 | } __attribute__((__aligned__)); |
Saleem Abdulrasool | b1b1911 | 2015-04-24 19:39:17 +0000 | [diff] [blame] | 136 | |
| 137 | typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) |
| 138 | (int version, |
| 139 | _Unwind_Action actions, |
| 140 | uint64_t exceptionClass, |
| 141 | _Unwind_Exception* exceptionObject, |
| 142 | struct _Unwind_Context* context, |
| 143 | void* stop_parameter ); |
| 144 | |
| 145 | typedef _Unwind_Reason_Code (*__personality_routine) |
| 146 | (int version, |
| 147 | _Unwind_Action actions, |
| 148 | uint64_t exceptionClass, |
| 149 | _Unwind_Exception* exceptionObject, |
| 150 | struct _Unwind_Context* context); |
| 151 | #endif |
| 152 | |
| 153 | #ifdef __cplusplus |
| 154 | extern "C" { |
| 155 | #endif |
| 156 | |
| 157 | // |
| 158 | // The following are the base functions documented by the C++ ABI |
| 159 | // |
| 160 | #ifdef __USING_SJLJ_EXCEPTIONS__ |
| 161 | extern _Unwind_Reason_Code |
| 162 | _Unwind_SjLj_RaiseException(_Unwind_Exception *exception_object); |
| 163 | extern void _Unwind_SjLj_Resume(_Unwind_Exception *exception_object); |
| 164 | #else |
| 165 | extern _Unwind_Reason_Code |
| 166 | _Unwind_RaiseException(_Unwind_Exception *exception_object); |
| 167 | extern void _Unwind_Resume(_Unwind_Exception *exception_object); |
| 168 | #endif |
| 169 | extern void _Unwind_DeleteException(_Unwind_Exception *exception_object); |
| 170 | |
Logan Chien | 5191fe9 | 2015-07-19 15:23:10 +0000 | [diff] [blame] | 171 | #if _LIBUNWIND_ARM_EHABI |
Saleem Abdulrasool | b1b1911 | 2015-04-24 19:39:17 +0000 | [diff] [blame] | 172 | typedef enum { |
| 173 | _UVRSC_CORE = 0, /* integer register */ |
| 174 | _UVRSC_VFP = 1, /* vfp */ |
| 175 | _UVRSC_WMMXD = 3, /* Intel WMMX data register */ |
| 176 | _UVRSC_WMMXC = 4 /* Intel WMMX control register */ |
| 177 | } _Unwind_VRS_RegClass; |
| 178 | |
| 179 | typedef enum { |
| 180 | _UVRSD_UINT32 = 0, |
| 181 | _UVRSD_VFPX = 1, |
| 182 | _UVRSD_UINT64 = 3, |
| 183 | _UVRSD_FLOAT = 4, |
| 184 | _UVRSD_DOUBLE = 5 |
| 185 | } _Unwind_VRS_DataRepresentation; |
| 186 | |
| 187 | typedef enum { |
| 188 | _UVRSR_OK = 0, |
| 189 | _UVRSR_NOT_IMPLEMENTED = 1, |
| 190 | _UVRSR_FAILED = 2 |
| 191 | } _Unwind_VRS_Result; |
| 192 | |
| 193 | extern void _Unwind_Complete(_Unwind_Exception* exception_object); |
| 194 | |
| 195 | extern _Unwind_VRS_Result |
| 196 | _Unwind_VRS_Get(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, |
| 197 | uint32_t regno, _Unwind_VRS_DataRepresentation representation, |
| 198 | void *valuep); |
| 199 | |
| 200 | extern _Unwind_VRS_Result |
| 201 | _Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, |
| 202 | uint32_t regno, _Unwind_VRS_DataRepresentation representation, |
| 203 | void *valuep); |
| 204 | |
| 205 | extern _Unwind_VRS_Result |
| 206 | _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, |
| 207 | uint32_t discriminator, |
| 208 | _Unwind_VRS_DataRepresentation representation); |
| 209 | #endif |
| 210 | |
Logan Chien | ff8fbf9 | 2015-07-24 00:16:48 +0000 | [diff] [blame] | 211 | #if !_LIBUNWIND_ARM_EHABI |
| 212 | |
Saleem Abdulrasool | b1b1911 | 2015-04-24 19:39:17 +0000 | [diff] [blame] | 213 | extern uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index); |
| 214 | extern void _Unwind_SetGR(struct _Unwind_Context *context, int index, |
| 215 | uintptr_t new_value); |
| 216 | extern uintptr_t _Unwind_GetIP(struct _Unwind_Context *context); |
| 217 | extern void _Unwind_SetIP(struct _Unwind_Context *, uintptr_t new_value); |
| 218 | |
Logan Chien | ff8fbf9 | 2015-07-24 00:16:48 +0000 | [diff] [blame] | 219 | #else // _LIBUNWIND_ARM_EHABI |
| 220 | |
| 221 | #if defined(_LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE) |
| 222 | #define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 extern |
| 223 | #else |
| 224 | #define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 static __inline__ |
| 225 | #endif |
| 226 | |
| 227 | // These are de facto helper functions for ARM, which delegate the function |
| 228 | // calls to _Unwind_VRS_Get/Set(). These are not a part of ARM EHABI |
| 229 | // specification, thus these function MUST be inlined. Please don't replace |
| 230 | // these with the "extern" function declaration; otherwise, the program |
| 231 | // including this <unwind.h> header won't be ABI compatible and will result in |
| 232 | // link error when we are linking the program with libgcc. |
| 233 | |
| 234 | _LIBUNWIND_EXPORT_UNWIND_LEVEL1 |
| 235 | uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index) { |
| 236 | uintptr_t value = 0; |
| 237 | _Unwind_VRS_Get(context, _UVRSC_CORE, (uint32_t)index, _UVRSD_UINT32, &value); |
| 238 | return value; |
| 239 | } |
| 240 | |
| 241 | _LIBUNWIND_EXPORT_UNWIND_LEVEL1 |
| 242 | void _Unwind_SetGR(struct _Unwind_Context *context, int index, |
| 243 | uintptr_t value) { |
| 244 | _Unwind_VRS_Set(context, _UVRSC_CORE, (uint32_t)index, _UVRSD_UINT32, &value); |
| 245 | } |
| 246 | |
| 247 | _LIBUNWIND_EXPORT_UNWIND_LEVEL1 |
| 248 | uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { |
| 249 | // remove the thumb-bit before returning |
| 250 | return _Unwind_GetGR(context, 15) & (~(uintptr_t)0x1); |
| 251 | } |
| 252 | |
| 253 | _LIBUNWIND_EXPORT_UNWIND_LEVEL1 |
| 254 | void _Unwind_SetIP(struct _Unwind_Context *context, uintptr_t value) { |
| 255 | uintptr_t thumb_bit = _Unwind_GetGR(context, 15) & ((uintptr_t)0x1); |
| 256 | _Unwind_SetGR(context, 15, value | thumb_bit); |
| 257 | } |
| 258 | #endif // _LIBUNWIND_ARM_EHABI |
| 259 | |
Saleem Abdulrasool | b1b1911 | 2015-04-24 19:39:17 +0000 | [diff] [blame] | 260 | extern uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *context); |
| 261 | extern uintptr_t |
| 262 | _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context); |
| 263 | #ifdef __USING_SJLJ_EXCEPTIONS__ |
| 264 | extern _Unwind_Reason_Code |
| 265 | _Unwind_SjLj_ForcedUnwind(_Unwind_Exception *exception_object, |
| 266 | _Unwind_Stop_Fn stop, void *stop_parameter); |
| 267 | #else |
| 268 | extern _Unwind_Reason_Code |
| 269 | _Unwind_ForcedUnwind(_Unwind_Exception *exception_object, |
| 270 | _Unwind_Stop_Fn stop, void *stop_parameter); |
| 271 | #endif |
| 272 | |
| 273 | #ifdef __USING_SJLJ_EXCEPTIONS__ |
| 274 | typedef struct _Unwind_FunctionContext *_Unwind_FunctionContext_t; |
| 275 | extern void _Unwind_SjLj_Register(_Unwind_FunctionContext_t fc); |
| 276 | extern void _Unwind_SjLj_Unregister(_Unwind_FunctionContext_t fc); |
| 277 | #endif |
| 278 | |
| 279 | // |
| 280 | // The following are semi-suppoted extensions to the C++ ABI |
| 281 | // |
| 282 | |
| 283 | // |
| 284 | // called by __cxa_rethrow(). |
| 285 | // |
| 286 | #ifdef __USING_SJLJ_EXCEPTIONS__ |
| 287 | extern _Unwind_Reason_Code |
| 288 | _Unwind_SjLj_Resume_or_Rethrow(_Unwind_Exception *exception_object); |
| 289 | #else |
| 290 | extern _Unwind_Reason_Code |
| 291 | _Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object); |
| 292 | #endif |
| 293 | |
| 294 | // _Unwind_Backtrace() is a gcc extension that walks the stack and calls the |
| 295 | // _Unwind_Trace_Fn once per frame until it reaches the bottom of the stack |
| 296 | // or the _Unwind_Trace_Fn function returns something other than _URC_NO_REASON. |
| 297 | typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context *, |
| 298 | void *); |
| 299 | extern _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void *); |
| 300 | |
| 301 | // _Unwind_GetCFA is a gcc extension that can be called from within a |
| 302 | // personality handler to get the CFA (stack pointer before call) of |
| 303 | // current frame. |
| 304 | extern uintptr_t _Unwind_GetCFA(struct _Unwind_Context *); |
| 305 | |
| 306 | |
| 307 | // _Unwind_GetIPInfo is a gcc extension that can be called from within a |
| 308 | // personality handler. Similar to _Unwind_GetIP() but also returns in |
| 309 | // *ipBefore a non-zero value if the instruction pointer is at or before the |
| 310 | // instruction causing the unwind. Normally, in a function call, the IP returned |
| 311 | // is the return address which is after the call instruction and may be past the |
| 312 | // end of the function containing the call instruction. |
| 313 | extern uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context, |
| 314 | int *ipBefore); |
| 315 | |
| 316 | |
| 317 | // __register_frame() is used with dynamically generated code to register the |
| 318 | // FDE for a generated (JIT) code. The FDE must use pc-rel addressing to point |
| 319 | // to its function and optional LSDA. |
| 320 | // __register_frame() has existed in all versions of Mac OS X, but in 10.4 and |
| 321 | // 10.5 it was buggy and did not actually register the FDE with the unwinder. |
| 322 | // In 10.6 and later it does register properly. |
| 323 | extern void __register_frame(const void *fde); |
| 324 | extern void __deregister_frame(const void *fde); |
| 325 | |
| 326 | // _Unwind_Find_FDE() will locate the FDE if the pc is in some function that has |
| 327 | // an associated FDE. Note, Mac OS X 10.6 and later, introduces "compact unwind |
Ed Maste | c073b1b | 2016-07-19 17:15:50 +0000 | [diff] [blame] | 328 | // info" which the runtime uses in preference to DWARF unwind info. This |
Saleem Abdulrasool | b1b1911 | 2015-04-24 19:39:17 +0000 | [diff] [blame] | 329 | // function will only work if the target function has an FDE but no compact |
| 330 | // unwind info. |
| 331 | struct dwarf_eh_bases { |
| 332 | uintptr_t tbase; |
| 333 | uintptr_t dbase; |
| 334 | uintptr_t func; |
| 335 | }; |
| 336 | extern const void *_Unwind_Find_FDE(const void *pc, struct dwarf_eh_bases *); |
| 337 | |
| 338 | |
| 339 | // This function attempts to find the start (address of first instruction) of |
| 340 | // a function given an address inside the function. It only works if the |
Ed Maste | c073b1b | 2016-07-19 17:15:50 +0000 | [diff] [blame] | 341 | // function has an FDE (DWARF unwind info). |
Saleem Abdulrasool | b1b1911 | 2015-04-24 19:39:17 +0000 | [diff] [blame] | 342 | // This function is unimplemented on Mac OS X 10.6 and later. Instead, use |
| 343 | // _Unwind_Find_FDE() and look at the dwarf_eh_bases.func result. |
| 344 | extern void *_Unwind_FindEnclosingFunction(void *pc); |
| 345 | |
| 346 | // Mac OS X does not support text-rel and data-rel addressing so these functions |
| 347 | // are unimplemented |
| 348 | extern uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context *context) |
| 349 | LIBUNWIND_UNAVAIL; |
| 350 | extern uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context *context) |
| 351 | LIBUNWIND_UNAVAIL; |
| 352 | |
| 353 | // Mac OS X 10.4 and 10.5 had implementations of these functions in |
| 354 | // libgcc_s.dylib, but they never worked. |
| 355 | /// These functions are no longer available on Mac OS X. |
| 356 | extern void __register_frame_info_bases(const void *fde, void *ob, void *tb, |
| 357 | void *db) LIBUNWIND_UNAVAIL; |
| 358 | extern void __register_frame_info(const void *fde, void *ob) |
| 359 | LIBUNWIND_UNAVAIL; |
| 360 | extern void __register_frame_info_table_bases(const void *fde, void *ob, |
| 361 | void *tb, void *db) |
| 362 | LIBUNWIND_UNAVAIL; |
| 363 | extern void __register_frame_info_table(const void *fde, void *ob) |
| 364 | LIBUNWIND_UNAVAIL; |
| 365 | extern void __register_frame_table(const void *fde) |
| 366 | LIBUNWIND_UNAVAIL; |
| 367 | extern void *__deregister_frame_info(const void *fde) |
| 368 | LIBUNWIND_UNAVAIL; |
| 369 | extern void *__deregister_frame_info_bases(const void *fde) |
| 370 | LIBUNWIND_UNAVAIL; |
| 371 | |
| 372 | #ifdef __cplusplus |
| 373 | } |
| 374 | #endif |
| 375 | |
| 376 | #endif // __UNWIND_H__ |