-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy patharm-unwind-pr.h
198 lines (153 loc) · 5.56 KB
/
arm-unwind-pr.h
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
#pragma once
#include <linux/types.h>
#include <stdbool.h>
// ARM EABI Exception Handling
//
// NOTE: Except for function names there's no worry here about polluting the
// global namespace, hence absolutely no excuse to use the hideous
// underscore-prefixed identifiers that the official definitions use.
//
// I've taken significant liberties in renaming things to increase readability.
//
// This header is biased towards the perspective of a personality routine.
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
US_SCAN = 0, // virtual unwinding (stack-scanning)
// valid responses:
// PRC_SCAN_CONTINUE
// PRC_SCAN_CATCH should be avoided if state.no_catch
// PRC_FAILURE
//
// If scanning with state.no_catch (used e.g. to generate backtrace),
// unwinder will ignore PRC_SCAN_CATCH and continue scanning anyway.
US_UNWIND = 1, // actual unwinding
US_UNWIND_RESUME= 2, // resume unwinding after catch/cleanup
// valid responses:
// PRC_UNWIND_CONTINUE
// PRC_UNWIND_CATCH unless state.no_catch (forced unwind)
// PRC_UNWIND_CLEANUP
// Note: other responses are treated as PRC_FAILURE, and during unwind
// usually results in immediate abort().
} unwind_action_t;
typedef struct {
unwind_action_t action : 2;
bool : 1;
bool no_catch : 1;
__u32 : 0;
} unwind_state_t;
typedef enum {
// catch/cleanup is treated the same by the unwinder, but the p.r. had
// better know the difference to be able to honor US_NO_CATCH.
//
PRC_UNWIND_CONTINUE = 8,
PRC_UNWIND_CATCH = 7,
PRC_UNWIND_CLEANUP = PRC_UNWIND_CATCH,
PRC_SCAN_CONTINUE = PRC_UNWIND_CONTINUE,
PRC_SCAN_CATCH = 6,
PRC_FAILURE = 9, // unspecified fatal error
} pr_response_t;
// Reasons for the destructor to be called. Note that if you recognize your
// own exceptions you may use other reasons, or not use it at all. But these
// two codes are used generically by the unwinder in response to failure or a
// call to _Unwind_DeleteException( exc ). The latter is what you should do if
// you catch an foreign exception.
//
typedef enum {
DEL_EXCEPTION_FAILURE = 9,
DEL_EXCEPTION_CAUGHT = 1,
} del_reason_t;
struct __attribute__((aligned(8))) Unwind_Exception {
// officially called _Unwind_Control_Block
// Identifies originating language and implementation.
char originator[8];
// See explanation above.
void (*destructor)( del_reason_t, struct Unwind_Exception *exc );
// Initialize first field to zero before throwing exception.
__u32 unwinder_private[5];
// Filled in by personality routine when returning PRC_SCAN_CATCH, to
// be able to easily recognize the same frame during unwind. The only
// mandatory field is the stack frame pointer, remainder may be used
// freely as needed by the language.
__u32 catch_sp;
__u32 catch_cache[5];
// Filled in by personality routine when returning PRC_UNWIND_CATCH or
// PRC_UNWIND_CLEANUP to pass info it may need to resume unwinding.
__u32 cleanup_cache[4];
// Data passed from unwinder to personality routine:
__u32 fnstart; // function start address
__u32 *ehtp; // pointer to EHT entry
__u32 compact_eht : 1; // single-word EHT entry embedded in index table
};
// dispose of exception after having been caught
void _Unwind_DeleteException( struct Unwind_Exception *exc );
// resume unwinding after cleanup; reenters p.r. with US_UNWIND_RESUME
__attribute__(( noreturn ))
void _Unwind_Resume( struct Unwind_Exception *exc );
// Access virtual register set (low-level functions)
//
// Don't use the primitives, use the wrapper functions below. The exception
// handling spec may give you the impression there are more ways you can call
// these primitives -- there aren't, libgcc doesn't implement them.
struct Unwind_Context;
void _Unwind_VRS_Set( struct Unwind_Context *, int, int, int, const void * );
void _Unwind_VRS_Get( struct Unwind_Context *, int, int, int, void * );
void _Unwind_VRS_Pop( struct Unwind_Context *, int, __u32, int );
// Access virtual core registers (r0 .. r15)
// Note that bit 0 of PC is used as thumb-bit, just like LR
#define R_PC 15
#define R_LR 14
#define R_SP 13
static inline __u32 get_reg( struct Unwind_Context *ctx, int reg )
{
__u32 val;
_Unwind_VRS_Get( ctx, 0, reg, 0, &val );
return val;
}
static inline void set_reg( struct Unwind_Context *ctx, int reg, __u32 val )
{
_Unwind_VRS_Set( ctx, 0, reg, 0, &val );
}
static inline void *get_sp( struct Unwind_Context *ctx )
{
return (void *) get_reg( ctx, R_SP );
}
static inline void set_sp( struct Unwind_Context *ctx, void *sp )
{
set_reg( ctx, R_SP, (__u32) sp );
}
static inline void set_lr( struct Unwind_Context *ctx, void *lr )
{
set_reg( ctx, R_LR, (__u32) lr );
}
static inline void set_pc( struct Unwind_Context *ctx, void *pc )
{
set_reg( ctx, R_PC, (__u32) pc );
}
// Pop virtual registers from the stack (using virtual SP)
// pop any subset of the 32 core registers (popping SP is allowed)
static inline void pop_regs( struct Unwind_Context *ctx, __u32 regmask )
{
_Unwind_VRS_Pop( ctx, 0, regmask, 0 );
}
// pop contiguous subset of the 16 or 32 Neon/VFP dword registers
static inline void pop_vfp_dregs( struct Unwind_Context *ctx,
__u32 start, __u32 count )
{
_Unwind_VRS_Pop( ctx, 1, start << 16 | count, 5 );
}
// pop contiguous subset of the 16 WMMX data dword registers
static inline void pop_wmmxd_dregs( struct Unwind_Context *ctx,
__u32 start, __u32 count )
{
_Unwind_VRS_Pop( ctx, 3, start << 16 | count, 5 );
}
// pop any subset of the 4 WMMX control word registers
static inline void pop_wmmxc_regs( struct Unwind_Context *ctx, __u32 regmask )
{
_Unwind_VRS_Pop( ctx, 4, regmask, 0 );
}
#ifdef __cplusplus
} /* extern "C" */
#endif