14684ddb6SLionel Sambuc /*
24684ddb6SLionel Sambuc * Copyright 2012 David Chisnall. All rights reserved.
34684ddb6SLionel Sambuc *
44684ddb6SLionel Sambuc * Permission is hereby granted, free of charge, to any person obtaining a copy
54684ddb6SLionel Sambuc * of this software and associated documentation files (the "Software"), to
64684ddb6SLionel Sambuc * deal in the Software without restriction, including without limitation the
74684ddb6SLionel Sambuc * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
84684ddb6SLionel Sambuc * sell copies of the Software, and to permit persons to whom the Software is
94684ddb6SLionel Sambuc * furnished to do so, subject to the following conditions:
104684ddb6SLionel Sambuc *
114684ddb6SLionel Sambuc * The above copyright notice and this permission notice shall be
124684ddb6SLionel Sambuc * included in all copies or substantial portions of the Software.
134684ddb6SLionel Sambuc *
144684ddb6SLionel Sambuc * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
154684ddb6SLionel Sambuc * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
164684ddb6SLionel Sambuc * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
174684ddb6SLionel Sambuc * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
184684ddb6SLionel Sambuc * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
194684ddb6SLionel Sambuc * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
204684ddb6SLionel Sambuc * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
214684ddb6SLionel Sambuc */
224684ddb6SLionel Sambuc
234684ddb6SLionel Sambuc /**
244684ddb6SLionel Sambuc * ARM-specific unwind definitions. These are taken from the ARM EHABI
254684ddb6SLionel Sambuc * specification.
264684ddb6SLionel Sambuc */
274684ddb6SLionel Sambuc typedef enum
284684ddb6SLionel Sambuc {
294684ddb6SLionel Sambuc _URC_OK = 0, /* operation completed successfully */
304684ddb6SLionel Sambuc _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
314684ddb6SLionel Sambuc _URC_END_OF_STACK = 5,
324684ddb6SLionel Sambuc _URC_HANDLER_FOUND = 6,
334684ddb6SLionel Sambuc _URC_INSTALL_CONTEXT = 7,
344684ddb6SLionel Sambuc _URC_CONTINUE_UNWIND = 8,
354684ddb6SLionel Sambuc _URC_FAILURE = 9, /* unspecified failure of some kind */
364684ddb6SLionel Sambuc _URC_FATAL_PHASE1_ERROR = _URC_FAILURE
374684ddb6SLionel Sambuc } _Unwind_Reason_Code;
384684ddb6SLionel Sambuc
394684ddb6SLionel Sambuc typedef uint32_t _Unwind_State;
404684ddb6SLionel Sambuc #ifdef __clang__
414684ddb6SLionel Sambuc static const _Unwind_State _US_VIRTUAL_UNWIND_FRAME = 0;
424684ddb6SLionel Sambuc static const _Unwind_State _US_UNWIND_FRAME_STARTING = 1;
434684ddb6SLionel Sambuc static const _Unwind_State _US_UNWIND_FRAME_RESUME = 2;
444684ddb6SLionel Sambuc #else // GCC fails at knowing what a constant expression is
454684ddb6SLionel Sambuc # define _US_VIRTUAL_UNWIND_FRAME 0
464684ddb6SLionel Sambuc # define _US_UNWIND_FRAME_STARTING 1
474684ddb6SLionel Sambuc # define _US_UNWIND_FRAME_RESUME 2
484684ddb6SLionel Sambuc #endif
494684ddb6SLionel Sambuc
504684ddb6SLionel Sambuc typedef struct _Unwind_Context _Unwind_Context;
514684ddb6SLionel Sambuc
524684ddb6SLionel Sambuc typedef uint32_t _Unwind_EHT_Header;
534684ddb6SLionel Sambuc
544684ddb6SLionel Sambuc struct _Unwind_Exception
554684ddb6SLionel Sambuc {
564684ddb6SLionel Sambuc uint64_t exception_class;
574684ddb6SLionel Sambuc void (*exception_cleanup)(_Unwind_Reason_Code, struct _Unwind_Exception *);
584684ddb6SLionel Sambuc /* Unwinder cache, private fields for the unwinder's use */
594684ddb6SLionel Sambuc struct
604684ddb6SLionel Sambuc {
614684ddb6SLionel Sambuc uint32_t reserved1;
624684ddb6SLionel Sambuc uint32_t reserved2;
634684ddb6SLionel Sambuc uint32_t reserved3;
644684ddb6SLionel Sambuc uint32_t reserved4;
654684ddb6SLionel Sambuc uint32_t reserved5;
664684ddb6SLionel Sambuc /* init reserved1 to 0, then don't touch */
674684ddb6SLionel Sambuc } unwinder_cache;
684684ddb6SLionel Sambuc /* Propagation barrier cache (valid after phase 1): */
694684ddb6SLionel Sambuc struct
704684ddb6SLionel Sambuc {
714684ddb6SLionel Sambuc uint32_t sp;
724684ddb6SLionel Sambuc uint32_t bitpattern[5];
734684ddb6SLionel Sambuc } barrier_cache;
744684ddb6SLionel Sambuc /* Cleanup cache (preserved over cleanup): */
754684ddb6SLionel Sambuc struct
764684ddb6SLionel Sambuc {
774684ddb6SLionel Sambuc uint32_t bitpattern[4];
784684ddb6SLionel Sambuc } cleanup_cache;
794684ddb6SLionel Sambuc /* Pr cache (for pr's benefit): */
804684ddb6SLionel Sambuc struct
814684ddb6SLionel Sambuc {
824684ddb6SLionel Sambuc /** function start address */
834684ddb6SLionel Sambuc uint32_t fnstart;
844684ddb6SLionel Sambuc /** pointer to EHT entry header word */
854684ddb6SLionel Sambuc _Unwind_EHT_Header *ehtp;
864684ddb6SLionel Sambuc /** additional data */
874684ddb6SLionel Sambuc uint32_t additional;
884684ddb6SLionel Sambuc uint32_t reserved1;
894684ddb6SLionel Sambuc } pr_cache;
904684ddb6SLionel Sambuc /** Force alignment of next item to 8-byte boundary */
914684ddb6SLionel Sambuc long long int :0;
924684ddb6SLionel Sambuc };
934684ddb6SLionel Sambuc
944684ddb6SLionel Sambuc /* Unwinding functions */
954684ddb6SLionel Sambuc _Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception *ucbp);
964684ddb6SLionel Sambuc void _Unwind_Resume(struct _Unwind_Exception *ucbp);
974684ddb6SLionel Sambuc void _Unwind_Complete(struct _Unwind_Exception *ucbp);
984684ddb6SLionel Sambuc void _Unwind_DeleteException(struct _Unwind_Exception *ucbp);
994684ddb6SLionel Sambuc void *_Unwind_GetLanguageSpecificData(struct _Unwind_Context*);
1004684ddb6SLionel Sambuc
1014684ddb6SLionel Sambuc typedef enum
1024684ddb6SLionel Sambuc {
1034684ddb6SLionel Sambuc _UVRSR_OK = 0,
1044684ddb6SLionel Sambuc _UVRSR_NOT_IMPLEMENTED = 1,
1054684ddb6SLionel Sambuc _UVRSR_FAILED = 2
1064684ddb6SLionel Sambuc } _Unwind_VRS_Result;
1074684ddb6SLionel Sambuc typedef enum
1084684ddb6SLionel Sambuc {
1094684ddb6SLionel Sambuc _UVRSC_CORE = 0,
1104684ddb6SLionel Sambuc _UVRSC_VFP = 1,
1114684ddb6SLionel Sambuc _UVRSC_WMMXD = 3,
1124684ddb6SLionel Sambuc _UVRSC_WMMXC = 4
1134684ddb6SLionel Sambuc } _Unwind_VRS_RegClass;
1144684ddb6SLionel Sambuc typedef enum
1154684ddb6SLionel Sambuc {
1164684ddb6SLionel Sambuc _UVRSD_UINT32 = 0,
1174684ddb6SLionel Sambuc _UVRSD_VFPX = 1,
1184684ddb6SLionel Sambuc _UVRSD_UINT64 = 3,
1194684ddb6SLionel Sambuc _UVRSD_FLOAT = 4,
1204684ddb6SLionel Sambuc _UVRSD_DOUBLE = 5
1214684ddb6SLionel Sambuc } _Unwind_VRS_DataRepresentation;
1224684ddb6SLionel Sambuc
1234684ddb6SLionel Sambuc _Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *context,
1244684ddb6SLionel Sambuc _Unwind_VRS_RegClass regclass,
1254684ddb6SLionel Sambuc uint32_t regno,
1264684ddb6SLionel Sambuc _Unwind_VRS_DataRepresentation representation,
1274684ddb6SLionel Sambuc void *valuep);
1284684ddb6SLionel Sambuc _Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *context,
1294684ddb6SLionel Sambuc _Unwind_VRS_RegClass regclass,
1304684ddb6SLionel Sambuc uint32_t regno,
1314684ddb6SLionel Sambuc _Unwind_VRS_DataRepresentation representation,
1324684ddb6SLionel Sambuc void *valuep);
1334684ddb6SLionel Sambuc
1344684ddb6SLionel Sambuc /* Return the base-address for data references. */
1354684ddb6SLionel Sambuc extern unsigned long _Unwind_GetDataRelBase(struct _Unwind_Context *);
1364684ddb6SLionel Sambuc
1374684ddb6SLionel Sambuc /* Return the base-address for text references. */
1384684ddb6SLionel Sambuc extern unsigned long _Unwind_GetTextRelBase(struct _Unwind_Context *);
1394684ddb6SLionel Sambuc extern unsigned long _Unwind_GetRegionStart(struct _Unwind_Context *);
1404684ddb6SLionel Sambuc
1414684ddb6SLionel Sambuc typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (struct _Unwind_Context *,
1424684ddb6SLionel Sambuc void *);
1434684ddb6SLionel Sambuc extern _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn, void *);
1444684ddb6SLionel Sambuc extern _Unwind_Reason_Code
1454684ddb6SLionel Sambuc _Unwind_Resume_or_Rethrow (struct _Unwind_Exception *);
1464684ddb6SLionel Sambuc
1474684ddb6SLionel Sambuc /**
1484684ddb6SLionel Sambuc * The next set of functions are compatibility extensions, implementing Itanium
1494684ddb6SLionel Sambuc * ABI functions on top of ARM ones.
1504684ddb6SLionel Sambuc */
1514684ddb6SLionel Sambuc
1524684ddb6SLionel Sambuc #define _UA_SEARCH_PHASE 1
1534684ddb6SLionel Sambuc #define _UA_CLEANUP_PHASE 2
1544684ddb6SLionel Sambuc #define _UA_HANDLER_FRAME 4
1554684ddb6SLionel Sambuc #define _UA_FORCE_UNWIND 8
1564684ddb6SLionel Sambuc
_Unwind_GetGR(struct _Unwind_Context * context,int reg)1574684ddb6SLionel Sambuc static inline unsigned long _Unwind_GetGR(struct _Unwind_Context *context, int reg)
1584684ddb6SLionel Sambuc {
1594684ddb6SLionel Sambuc unsigned long val;
1604684ddb6SLionel Sambuc _Unwind_VRS_Get(context, _UVRSC_CORE, reg, _UVRSD_UINT32, &val);
1614684ddb6SLionel Sambuc return val;
1624684ddb6SLionel Sambuc }
_Unwind_SetGR(struct _Unwind_Context * context,int reg,unsigned long val)1634684ddb6SLionel Sambuc static inline void _Unwind_SetGR(struct _Unwind_Context *context, int reg, unsigned long val)
1644684ddb6SLionel Sambuc {
1654684ddb6SLionel Sambuc _Unwind_VRS_Set(context, _UVRSC_CORE, reg, _UVRSD_UINT32, &val);
1664684ddb6SLionel Sambuc }
_Unwind_GetIP(_Unwind_Context * context)1674684ddb6SLionel Sambuc static inline unsigned long _Unwind_GetIP(_Unwind_Context *context)
1684684ddb6SLionel Sambuc {
1694684ddb6SLionel Sambuc // Low bit store the thumb state - discard it
1704684ddb6SLionel Sambuc return _Unwind_GetGR(context, 15) & ~1;
1714684ddb6SLionel Sambuc }
_Unwind_SetIP(_Unwind_Context * context,unsigned long val)1724684ddb6SLionel Sambuc static inline void _Unwind_SetIP(_Unwind_Context *context, unsigned long val)
1734684ddb6SLionel Sambuc {
1744684ddb6SLionel Sambuc // The lowest bit of the instruction pointer indicates whether we're in
1754684ddb6SLionel Sambuc // thumb or ARM mode. This is assumed to be fixed throughout a function,
1764684ddb6SLionel Sambuc // so must be propagated when setting the program counter.
1774684ddb6SLionel Sambuc unsigned long thumbState = _Unwind_GetGR(context, 15) & 1;
1784684ddb6SLionel Sambuc _Unwind_SetGR(context, 15, (val | thumbState));
1794684ddb6SLionel Sambuc }
1804684ddb6SLionel Sambuc
1814684ddb6SLionel Sambuc /** GNU API function that unwinds the frame */
1824684ddb6SLionel Sambuc _Unwind_Reason_Code __gnu_unwind_frame(struct _Unwind_Exception*, struct _Unwind_Context*);
1834684ddb6SLionel Sambuc
1844684ddb6SLionel Sambuc
1854684ddb6SLionel Sambuc #define DECLARE_PERSONALITY_FUNCTION(name) \
1864684ddb6SLionel Sambuc _Unwind_Reason_Code name(_Unwind_State state,\
1874684ddb6SLionel Sambuc struct _Unwind_Exception *exceptionObject,\
1884684ddb6SLionel Sambuc struct _Unwind_Context *context);
1894684ddb6SLionel Sambuc
1904684ddb6SLionel Sambuc #define BEGIN_PERSONALITY_FUNCTION(name) \
1914684ddb6SLionel Sambuc _Unwind_Reason_Code name(_Unwind_State state,\
1924684ddb6SLionel Sambuc struct _Unwind_Exception *exceptionObject,\
1934684ddb6SLionel Sambuc struct _Unwind_Context *context)\
1944684ddb6SLionel Sambuc {\
1954684ddb6SLionel Sambuc int version = 1;\
1964684ddb6SLionel Sambuc uint64_t exceptionClass = exceptionObject->exception_class;\
1974684ddb6SLionel Sambuc int actions;\
1984684ddb6SLionel Sambuc switch (state)\
1994684ddb6SLionel Sambuc {\
2004684ddb6SLionel Sambuc default: return _URC_FAILURE;\
2014684ddb6SLionel Sambuc case _US_VIRTUAL_UNWIND_FRAME:\
2024684ddb6SLionel Sambuc {\
2034684ddb6SLionel Sambuc actions = _UA_SEARCH_PHASE;\
2044684ddb6SLionel Sambuc break;\
2054684ddb6SLionel Sambuc }\
2064684ddb6SLionel Sambuc case _US_UNWIND_FRAME_STARTING:\
2074684ddb6SLionel Sambuc {\
2084684ddb6SLionel Sambuc actions = _UA_CLEANUP_PHASE;\
2094684ddb6SLionel Sambuc if (exceptionObject->barrier_cache.sp == _Unwind_GetGR(context, 13))\
2104684ddb6SLionel Sambuc {\
2114684ddb6SLionel Sambuc actions |= _UA_HANDLER_FRAME;\
2124684ddb6SLionel Sambuc }\
2134684ddb6SLionel Sambuc break;\
2144684ddb6SLionel Sambuc }\
2154684ddb6SLionel Sambuc case _US_UNWIND_FRAME_RESUME:\
2164684ddb6SLionel Sambuc {\
2174684ddb6SLionel Sambuc return continueUnwinding(exceptionObject, context);\
2184684ddb6SLionel Sambuc break;\
2194684ddb6SLionel Sambuc }\
2204684ddb6SLionel Sambuc }\
221*0a6a1f1dSLionel Sambuc _Unwind_SetGR (context, 12, reinterpret_cast<unsigned long>(exceptionObject));\
2224684ddb6SLionel Sambuc
2234684ddb6SLionel Sambuc #define CALL_PERSONALITY_FUNCTION(name) name(state,exceptionObject,context)
224