xref: /minix3/external/bsd/libc++/dist/libcxxrt/src/unwind-arm.h (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
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