]>
Commit | Line | Data |
---|---|---|
0bfa5f65 | 1 | /* Supporting functions for C exception handling. |
83ffe9cd | 2 | Copyright (C) 2002-2023 Free Software Foundation, Inc. |
0bfa5f65 RH |
3 | Contributed by Aldy Hernandez <aldy@quesejoda.com>. |
4 | Shamelessly stolen from the Java front end. | |
5 | ||
6 | This file is part of GCC. | |
7 | ||
8 | GCC is free software; you can redistribute it and/or modify it under | |
9 | the terms of the GNU General Public License as published by the Free | |
748086b7 | 10 | Software Foundation; either version 3, or (at your option) any later |
0bfa5f65 RH |
11 | version. |
12 | ||
13 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 | for more details. | |
17 | ||
748086b7 JJ |
18 | Under Section 7 of GPL version 3, you are granted additional |
19 | permissions described in the GCC Runtime Library Exception, version | |
20 | 3.1, as published by the Free Software Foundation. | |
21 | ||
22 | You should have received a copy of the GNU General Public License and | |
23 | a copy of the GCC Runtime Library Exception along with this program; | |
24 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
25 | <http://www.gnu.org/licenses/>. */ | |
0bfa5f65 RH |
26 | |
27 | #include "tconfig.h" | |
28 | #include "tsystem.h" | |
33107571 | 29 | #include "auto-target.h" |
0bfa5f65 | 30 | #include "unwind.h" |
333991cf | 31 | #define NO_SIZE_OF_ENCODED_VALUE |
0bfa5f65 RH |
32 | #include "unwind-pe.h" |
33 | ||
34 | typedef struct | |
35 | { | |
36 | _Unwind_Ptr Start; | |
37 | _Unwind_Ptr LPStart; | |
38 | _Unwind_Ptr ttype_base; | |
39 | const unsigned char *TType; | |
40 | const unsigned char *action_table; | |
41 | unsigned char ttype_encoding; | |
42 | unsigned char call_site_encoding; | |
43 | } lsda_header_info; | |
44 | ||
45 | static const unsigned char * | |
46 | parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p, | |
47 | lsda_header_info *info) | |
48 | { | |
f767122b | 49 | _uleb128_t tmp; |
0bfa5f65 RH |
50 | unsigned char lpstart_encoding; |
51 | ||
52 | info->Start = (context ? _Unwind_GetRegionStart (context) : 0); | |
53 | ||
54 | /* Find @LPStart, the base to which landing pad offsets are relative. */ | |
55 | lpstart_encoding = *p++; | |
56 | if (lpstart_encoding != DW_EH_PE_omit) | |
57 | p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart); | |
58 | else | |
59 | info->LPStart = info->Start; | |
60 | ||
61 | /* Find @TType, the base of the handler and exception spec type data. */ | |
62 | info->ttype_encoding = *p++; | |
63 | if (info->ttype_encoding != DW_EH_PE_omit) | |
64 | { | |
65 | p = read_uleb128 (p, &tmp); | |
66 | info->TType = p + tmp; | |
67 | } | |
68 | else | |
69 | info->TType = 0; | |
70 | ||
71 | /* The encoding and length of the call-site table; the action table | |
72 | immediately follows. */ | |
73 | info->call_site_encoding = *p++; | |
74 | p = read_uleb128 (p, &tmp); | |
75 | info->action_table = p + tmp; | |
76 | ||
77 | return p; | |
78 | } | |
79 | ||
617a1b71 PB |
80 | #ifdef __ARM_EABI_UNWINDER__ |
81 | /* ARM EABI personality routines must also unwind the stack. */ | |
82 | #define CONTINUE_UNWINDING \ | |
83 | do \ | |
84 | { \ | |
85 | if (__gnu_unwind_frame (ue_header, context) != _URC_OK) \ | |
86 | return _URC_FAILURE; \ | |
87 | return _URC_CONTINUE_UNWIND; \ | |
88 | } \ | |
89 | while (0) | |
90 | #else | |
91 | #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND | |
92 | #endif | |
93 | ||
0bfa5f65 RH |
94 | #ifdef __USING_SJLJ_EXCEPTIONS__ |
95 | #define PERSONALITY_FUNCTION __gcc_personality_sj0 | |
96 | #define __builtin_eh_return_data_regno(x) x | |
bf1431e3 TG |
97 | #elif defined(__SEH__) |
98 | #define PERSONALITY_FUNCTION __gcc_personality_imp | |
0bfa5f65 RH |
99 | #else |
100 | #define PERSONALITY_FUNCTION __gcc_personality_v0 | |
101 | #endif | |
0bfa5f65 | 102 | |
617a1b71 PB |
103 | #ifdef __ARM_EABI_UNWINDER__ |
104 | _Unwind_Reason_Code | |
105 | PERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *, | |
106 | struct _Unwind_Context *); | |
107 | ||
108 | _Unwind_Reason_Code | |
48528842 | 109 | __attribute__((target ("general-regs-only"))) |
617a1b71 PB |
110 | PERSONALITY_FUNCTION (_Unwind_State state, |
111 | struct _Unwind_Exception * ue_header, | |
112 | struct _Unwind_Context * context) | |
113 | #else | |
e5a81c8e | 114 | #if defined (__SEH__) && !defined (__USING_SJLJ_EXCEPTIONS__) |
bf1431e3 TG |
115 | static |
116 | #endif | |
0bfa5f65 RH |
117 | _Unwind_Reason_Code |
118 | PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class, | |
119 | struct _Unwind_Exception *, struct _Unwind_Context *); | |
120 | ||
121 | _Unwind_Reason_Code | |
122 | PERSONALITY_FUNCTION (int version, | |
123 | _Unwind_Action actions, | |
124 | _Unwind_Exception_Class exception_class ATTRIBUTE_UNUSED, | |
125 | struct _Unwind_Exception *ue_header, | |
126 | struct _Unwind_Context *context) | |
617a1b71 | 127 | #endif |
0bfa5f65 RH |
128 | { |
129 | lsda_header_info info; | |
f1ed99cd | 130 | const unsigned char *language_specific_data, *p; |
0bfa5f65 | 131 | _Unwind_Ptr landing_pad, ip; |
754e45a8 | 132 | int ip_before_insn = 0; |
0bfa5f65 | 133 | |
617a1b71 | 134 | #ifdef __ARM_EABI_UNWINDER__ |
74d9c39f | 135 | if ((state & _US_ACTION_MASK) != _US_UNWIND_FRAME_STARTING) |
617a1b71 PB |
136 | CONTINUE_UNWINDING; |
137 | ||
138 | /* The dwarf unwinder assumes the context structure holds things like the | |
139 | function and LSDA pointers. The ARM implementation caches these in | |
1e874273 PB |
140 | the exception header (UCB). To avoid rewriting everything we make a |
141 | virtual scratch register point at the UCB. */ | |
617a1b71 | 142 | ip = (_Unwind_Ptr) ue_header; |
1e874273 | 143 | _Unwind_SetGR (context, UNWIND_POINTER_REG, ip); |
617a1b71 | 144 | #else |
0bfa5f65 RH |
145 | if (version != 1) |
146 | return _URC_FATAL_PHASE1_ERROR; | |
147 | ||
148 | /* Currently we only support cleanups for C. */ | |
149 | if ((actions & _UA_CLEANUP_PHASE) == 0) | |
617a1b71 PB |
150 | CONTINUE_UNWINDING; |
151 | #endif | |
0bfa5f65 RH |
152 | |
153 | language_specific_data = (const unsigned char *) | |
154 | _Unwind_GetLanguageSpecificData (context); | |
155 | ||
156 | /* If no LSDA, then there are no handlers or cleanups. */ | |
157 | if (! language_specific_data) | |
617a1b71 | 158 | CONTINUE_UNWINDING; |
0bfa5f65 RH |
159 | |
160 | /* Parse the LSDA header. */ | |
161 | p = parse_lsda_header (context, language_specific_data, &info); | |
e64f5acf | 162 | #ifdef HAVE_GETIPINFO |
754e45a8 | 163 | ip = _Unwind_GetIPInfo (context, &ip_before_insn); |
e64f5acf SE |
164 | #else |
165 | ip = _Unwind_GetIP (context); | |
166 | #endif | |
754e45a8 JJ |
167 | if (! ip_before_insn) |
168 | --ip; | |
0bfa5f65 RH |
169 | landing_pad = 0; |
170 | ||
171 | #ifdef __USING_SJLJ_EXCEPTIONS__ | |
172 | /* The given "IP" is an index into the call-site table, with two | |
173 | exceptions -- -1 means no-action, and 0 means terminate. But | |
174 | since we're using uleb128 values, we've not got random access | |
175 | to the array. */ | |
176 | if ((int) ip <= 0) | |
177 | return _URC_CONTINUE_UNWIND; | |
178 | else | |
179 | { | |
f767122b | 180 | _uleb128_t cs_lp, cs_action; |
0bfa5f65 RH |
181 | do |
182 | { | |
183 | p = read_uleb128 (p, &cs_lp); | |
184 | p = read_uleb128 (p, &cs_action); | |
185 | } | |
186 | while (--ip); | |
187 | ||
188 | /* Can never have null landing pad for sjlj -- that would have | |
189 | been indicated by a -1 call site index. */ | |
f767122b | 190 | landing_pad = (_Unwind_Ptr)cs_lp + 1; |
0bfa5f65 RH |
191 | goto found_something; |
192 | } | |
193 | #else | |
194 | /* Search the call-site table for the action associated with this IP. */ | |
195 | while (p < info.action_table) | |
196 | { | |
197 | _Unwind_Ptr cs_start, cs_len, cs_lp; | |
f767122b | 198 | _uleb128_t cs_action; |
0bfa5f65 RH |
199 | |
200 | /* Note that all call-site encodings are "absolute" displacements. */ | |
201 | p = read_encoded_value (0, info.call_site_encoding, p, &cs_start); | |
202 | p = read_encoded_value (0, info.call_site_encoding, p, &cs_len); | |
203 | p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp); | |
204 | p = read_uleb128 (p, &cs_action); | |
205 | ||
206 | /* The table is sorted, so if we've passed the ip, stop. */ | |
207 | if (ip < info.Start + cs_start) | |
208 | p = info.action_table; | |
209 | else if (ip < info.Start + cs_start + cs_len) | |
210 | { | |
211 | if (cs_lp) | |
212 | landing_pad = info.LPStart + cs_lp; | |
0bfa5f65 RH |
213 | goto found_something; |
214 | } | |
215 | } | |
0bfa5f65 RH |
216 | #endif |
217 | ||
218 | /* IP is not in table. No associated cleanups. */ | |
219 | /* ??? This is where C++ calls std::terminate to catch throw | |
220 | from a destructor. */ | |
617a1b71 | 221 | CONTINUE_UNWINDING; |
0bfa5f65 RH |
222 | |
223 | found_something: | |
224 | if (landing_pad == 0) | |
225 | { | |
226 | /* IP is present, but has a null landing pad. | |
227 | No handler to be run. */ | |
617a1b71 | 228 | CONTINUE_UNWINDING; |
0bfa5f65 RH |
229 | } |
230 | ||
231 | _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), | |
232 | (_Unwind_Ptr) ue_header); | |
233 | _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0); | |
234 | _Unwind_SetIP (context, landing_pad); | |
235 | return _URC_INSTALL_CONTEXT; | |
236 | } | |
bf1431e3 | 237 | |
e5a81c8e | 238 | #if defined (__SEH__) && !defined (__USING_SJLJ_EXCEPTIONS__) |
bf1431e3 TG |
239 | EXCEPTION_DISPOSITION |
240 | __gcc_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame, | |
241 | PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp) | |
242 | { | |
243 | return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context, | |
244 | ms_disp, __gcc_personality_imp); | |
245 | } | |
246 | #endif /* SEH */ |