summaryrefslogtreecommitdiff
path: root/src/unwind-arm.h
blob: 8c1fa16263e3c03daf097fe285c55f7bbdbbe378 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
/* 
 * Copyright 2012 David Chisnall. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */ 

/**
 * ARM-specific unwind definitions.  These are taken from the ARM EHABI
 * specification.
 */
 typedef enum
{
	_URC_OK = 0,                /* operation completed successfully */
	_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
    _URC_END_OF_STACK = 5,
	_URC_HANDLER_FOUND = 6,
	_URC_INSTALL_CONTEXT = 7,
	_URC_CONTINUE_UNWIND = 8,
	_URC_FAILURE = 9,            /* unspecified failure of some kind */
	_URC_FATAL_PHASE1_ERROR = _URC_FAILURE
} _Unwind_Reason_Code;

typedef uint32_t _Unwind_State;
#ifdef __clang__
static const _Unwind_State _US_VIRTUAL_UNWIND_FRAME  = 0;
static const _Unwind_State _US_UNWIND_FRAME_STARTING = 1;
static const _Unwind_State _US_UNWIND_FRAME_RESUME   = 2;
#else // GCC fails at knowing what a constant expression is
#	define _US_VIRTUAL_UNWIND_FRAME  0
#	define _US_UNWIND_FRAME_STARTING 1
#	define _US_UNWIND_FRAME_RESUME 2
#endif

typedef struct _Unwind_Context _Unwind_Context;

typedef uint32_t _Unwind_EHT_Header;

struct _Unwind_Exception
{
	uint64_t exception_class;
	void (*exception_cleanup)(_Unwind_Reason_Code, struct _Unwind_Exception *);
	/* Unwinder cache, private fields for the unwinder's use */
	struct
	{
		uint32_t reserved1;
		uint32_t reserved2;
		uint32_t reserved3;
		uint32_t reserved4;
		uint32_t reserved5;
	/* init reserved1 to 0, then don't touch */
	} unwinder_cache;
	/* Propagation barrier cache (valid after phase 1): */
	struct
	{
		uint32_t sp;
		uint32_t bitpattern[5];
	} barrier_cache;
	/* Cleanup cache (preserved over cleanup): */
	struct
	{
		uint32_t bitpattern[4];
	} cleanup_cache;
	/* Pr cache (for pr's benefit): */
	struct
	{
		/** function start address */
		uint32_t fnstart;
		/** pointer to EHT entry header word */
		_Unwind_EHT_Header *ehtp;
		/** additional data */
		uint32_t additional;
		uint32_t reserved1;
	} pr_cache;
	/** Force alignment of next item to 8-byte boundary */
	long long int :0;
};

/* Unwinding functions */
_Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception *ucbp);
void _Unwind_Resume(struct _Unwind_Exception *ucbp);
void _Unwind_Complete(struct _Unwind_Exception *ucbp);
void _Unwind_DeleteException(struct _Unwind_Exception *ucbp);
void *_Unwind_GetLanguageSpecificData(struct _Unwind_Context*);

typedef enum
{
	_UVRSR_OK = 0,
	_UVRSR_NOT_IMPLEMENTED = 1,
	_UVRSR_FAILED = 2
} _Unwind_VRS_Result;
typedef enum
{
	_UVRSC_CORE = 0,
	_UVRSC_VFP = 1,
	_UVRSC_WMMXD = 3,
	_UVRSC_WMMXC = 4
} _Unwind_VRS_RegClass;
typedef enum
{
	_UVRSD_UINT32 = 0,
	_UVRSD_VFPX = 1,
	_UVRSD_UINT64 = 3,
	_UVRSD_FLOAT = 4,
	_UVRSD_DOUBLE = 5
} _Unwind_VRS_DataRepresentation;

_Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *context,
                                   _Unwind_VRS_RegClass regclass,
                                   uint32_t regno,
                                   _Unwind_VRS_DataRepresentation representation,
                                   void *valuep);
_Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *context,
                                   _Unwind_VRS_RegClass regclass,
                                   uint32_t regno,
                                   _Unwind_VRS_DataRepresentation representation,
                                   void *valuep);

/* Return the base-address for data references.  */
extern unsigned long _Unwind_GetDataRelBase(struct _Unwind_Context *);

/* Return the base-address for text references.  */
extern unsigned long _Unwind_GetTextRelBase(struct _Unwind_Context *);
extern unsigned long _Unwind_GetRegionStart(struct _Unwind_Context *);

typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (struct _Unwind_Context *,
						 void *);
extern _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn, void *);
extern _Unwind_Reason_Code
	  _Unwind_Resume_or_Rethrow (struct _Unwind_Exception *);

/**
 * The next set of functions are compatibility extensions, implementing Itanium
 * ABI functions on top of ARM ones.
 */

#define _UA_SEARCH_PHASE	1
#define _UA_CLEANUP_PHASE	2
#define _UA_HANDLER_FRAME	4
#define _UA_FORCE_UNWIND	8

static inline unsigned long _Unwind_GetGR(struct _Unwind_Context *context, int reg)
{
	unsigned long val;
	_Unwind_VRS_Get(context, _UVRSC_CORE, reg, _UVRSD_UINT32, &val);
	return val;
}
static inline  void _Unwind_SetGR(struct _Unwind_Context *context, int reg, unsigned long val)
{
	_Unwind_VRS_Set(context, _UVRSC_CORE, reg, _UVRSD_UINT32, &val);
}
static inline unsigned long _Unwind_GetIP(_Unwind_Context *context)
{
	// Low bit store the thumb state - discard it
	return _Unwind_GetGR(context, 15) & ~1;
}
static inline void _Unwind_SetIP(_Unwind_Context *context, unsigned long val)
{
	// The lowest bit of the instruction pointer indicates whether we're in
	// thumb or ARM mode.  This is assumed to be fixed throughout a function,
	// so must be propagated when setting the program counter.
	unsigned long thumbState = _Unwind_GetGR(context, 15) & 1;
   _Unwind_SetGR(context, 15, (val | thumbState));
}

/** GNU API function that unwinds the frame */
_Unwind_Reason_Code __gnu_unwind_frame(struct _Unwind_Exception*, struct _Unwind_Context*);


#define DECLARE_PERSONALITY_FUNCTION(name) \
_Unwind_Reason_Code name(_Unwind_State state,\
                         struct _Unwind_Exception *exceptionObject,\
                         struct _Unwind_Context *context);

#define BEGIN_PERSONALITY_FUNCTION(name) \
_Unwind_Reason_Code name(_Unwind_State state,\
                         struct _Unwind_Exception *exceptionObject,\
                         struct _Unwind_Context *context)\
{\
	int version = 1;\
	uint64_t exceptionClass = exceptionObject->exception_class;\
	int actions;\
	switch (state)\
	{\
		default: return _URC_FAILURE;\
		case _US_VIRTUAL_UNWIND_FRAME:\
		{\
			actions = _UA_SEARCH_PHASE;\
			break;\
		}\
		case _US_UNWIND_FRAME_STARTING:\
		{\
			actions = _UA_CLEANUP_PHASE;\
			if (exceptionObject->barrier_cache.sp == _Unwind_GetGR(context, 13))\
			{\
				actions |= _UA_HANDLER_FRAME;\
			}\
			break;\
		}\
		case _US_UNWIND_FRAME_RESUME:\
		{\
			return continueUnwinding(exceptionObject, context);\
			break;\
		}\
	}\
	_Unwind_SetGR (context, 12, (unsigned long)exceptionObject);\

#define CALL_PERSONALITY_FUNCTION(name) name(state,exceptionObject,context)