]>
Commit | Line | Data |
---|---|---|
0bfa5f65 RH |
1 | /* Supporting functions for C exception handling. |
2 | Copyright (C) 2002, 2003 Free Software Foundation, Inc. | |
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 | |
10 | Software Foundation; either version 2, or (at your option) any later | |
11 | version. | |
12 | ||
1ee93c1b DJ |
13 | In addition to the permissions in the GNU General Public License, the |
14 | Free Software Foundation gives you unlimited permission to link the | |
15 | compiled version of this file into combinations with other programs, | |
16 | and to distribute those combinations without any restriction coming | |
17 | from the use of this file. (The General Public License restrictions | |
18 | do apply in other respects; for example, they cover modification of | |
19 | the file, and distribution when not linked into a combined | |
20 | executable.) | |
21 | ||
0bfa5f65 RH |
22 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
23 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
24 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
25 | for more details. | |
26 | ||
27 | You should have received a copy of the GNU General Public License | |
28 | along with GCC; see the file COPYING. If not, write to the Free | |
366ccddb KC |
29 | Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA |
30 | 02110-1301, USA. */ | |
0bfa5f65 RH |
31 | |
32 | #include "tconfig.h" | |
33 | #include "tsystem.h" | |
34 | #include "unwind.h" | |
333991cf | 35 | #define NO_SIZE_OF_ENCODED_VALUE |
0bfa5f65 RH |
36 | #include "unwind-pe.h" |
37 | ||
38 | typedef struct | |
39 | { | |
40 | _Unwind_Ptr Start; | |
41 | _Unwind_Ptr LPStart; | |
42 | _Unwind_Ptr ttype_base; | |
43 | const unsigned char *TType; | |
44 | const unsigned char *action_table; | |
45 | unsigned char ttype_encoding; | |
46 | unsigned char call_site_encoding; | |
47 | } lsda_header_info; | |
48 | ||
49 | static const unsigned char * | |
50 | parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p, | |
51 | lsda_header_info *info) | |
52 | { | |
53 | _Unwind_Word tmp; | |
54 | unsigned char lpstart_encoding; | |
55 | ||
56 | info->Start = (context ? _Unwind_GetRegionStart (context) : 0); | |
57 | ||
58 | /* Find @LPStart, the base to which landing pad offsets are relative. */ | |
59 | lpstart_encoding = *p++; | |
60 | if (lpstart_encoding != DW_EH_PE_omit) | |
61 | p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart); | |
62 | else | |
63 | info->LPStart = info->Start; | |
64 | ||
65 | /* Find @TType, the base of the handler and exception spec type data. */ | |
66 | info->ttype_encoding = *p++; | |
67 | if (info->ttype_encoding != DW_EH_PE_omit) | |
68 | { | |
69 | p = read_uleb128 (p, &tmp); | |
70 | info->TType = p + tmp; | |
71 | } | |
72 | else | |
73 | info->TType = 0; | |
74 | ||
75 | /* The encoding and length of the call-site table; the action table | |
76 | immediately follows. */ | |
77 | info->call_site_encoding = *p++; | |
78 | p = read_uleb128 (p, &tmp); | |
79 | info->action_table = p + tmp; | |
80 | ||
81 | return p; | |
82 | } | |
83 | ||
617a1b71 PB |
84 | #ifdef __ARM_EABI_UNWINDER__ |
85 | /* ARM EABI personality routines must also unwind the stack. */ | |
86 | #define CONTINUE_UNWINDING \ | |
87 | do \ | |
88 | { \ | |
89 | if (__gnu_unwind_frame (ue_header, context) != _URC_OK) \ | |
90 | return _URC_FAILURE; \ | |
91 | return _URC_CONTINUE_UNWIND; \ | |
92 | } \ | |
93 | while (0) | |
94 | #else | |
95 | #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND | |
96 | #endif | |
97 | ||
0bfa5f65 RH |
98 | #ifdef __USING_SJLJ_EXCEPTIONS__ |
99 | #define PERSONALITY_FUNCTION __gcc_personality_sj0 | |
100 | #define __builtin_eh_return_data_regno(x) x | |
101 | #else | |
102 | #define PERSONALITY_FUNCTION __gcc_personality_v0 | |
103 | #endif | |
0bfa5f65 | 104 | |
617a1b71 PB |
105 | #ifdef __ARM_EABI_UNWINDER__ |
106 | _Unwind_Reason_Code | |
107 | PERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *, | |
108 | struct _Unwind_Context *); | |
109 | ||
110 | _Unwind_Reason_Code | |
111 | PERSONALITY_FUNCTION (_Unwind_State state, | |
112 | struct _Unwind_Exception * ue_header, | |
113 | struct _Unwind_Context * context) | |
114 | #else | |
0bfa5f65 RH |
115 | _Unwind_Reason_Code |
116 | PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class, | |
117 | struct _Unwind_Exception *, struct _Unwind_Context *); | |
118 | ||
119 | _Unwind_Reason_Code | |
120 | PERSONALITY_FUNCTION (int version, | |
121 | _Unwind_Action actions, | |
122 | _Unwind_Exception_Class exception_class ATTRIBUTE_UNUSED, | |
123 | struct _Unwind_Exception *ue_header, | |
124 | struct _Unwind_Context *context) | |
617a1b71 | 125 | #endif |
0bfa5f65 RH |
126 | { |
127 | lsda_header_info info; | |
128 | const unsigned char *language_specific_data, *p, *action_record; | |
129 | _Unwind_Ptr landing_pad, ip; | |
130 | ||
617a1b71 PB |
131 | #ifdef __ARM_EABI_UNWINDER__ |
132 | if (state != _US_UNWIND_FRAME_STARTING) | |
133 | CONTINUE_UNWINDING; | |
134 | ||
135 | /* The dwarf unwinder assumes the context structure holds things like the | |
136 | function and LSDA pointers. The ARM implementation caches these in | |
137 | the exception header (UCB). To avoid rewriting everything we make the | |
138 | virtual IP register point at the UCB. */ | |
139 | ip = (_Unwind_Ptr) ue_header; | |
140 | _Unwind_SetGR (context, 12, ip); | |
141 | #else | |
0bfa5f65 RH |
142 | if (version != 1) |
143 | return _URC_FATAL_PHASE1_ERROR; | |
144 | ||
145 | /* Currently we only support cleanups for C. */ | |
146 | if ((actions & _UA_CLEANUP_PHASE) == 0) | |
617a1b71 PB |
147 | CONTINUE_UNWINDING; |
148 | #endif | |
0bfa5f65 RH |
149 | |
150 | language_specific_data = (const unsigned char *) | |
151 | _Unwind_GetLanguageSpecificData (context); | |
152 | ||
153 | /* If no LSDA, then there are no handlers or cleanups. */ | |
154 | if (! language_specific_data) | |
617a1b71 | 155 | CONTINUE_UNWINDING; |
0bfa5f65 RH |
156 | |
157 | /* Parse the LSDA header. */ | |
158 | p = parse_lsda_header (context, language_specific_data, &info); | |
159 | ip = _Unwind_GetIP (context) - 1; | |
160 | landing_pad = 0; | |
161 | ||
162 | #ifdef __USING_SJLJ_EXCEPTIONS__ | |
163 | /* The given "IP" is an index into the call-site table, with two | |
164 | exceptions -- -1 means no-action, and 0 means terminate. But | |
165 | since we're using uleb128 values, we've not got random access | |
166 | to the array. */ | |
167 | if ((int) ip <= 0) | |
168 | return _URC_CONTINUE_UNWIND; | |
169 | else | |
170 | { | |
171 | _Unwind_Word cs_lp, cs_action; | |
172 | do | |
173 | { | |
174 | p = read_uleb128 (p, &cs_lp); | |
175 | p = read_uleb128 (p, &cs_action); | |
176 | } | |
177 | while (--ip); | |
178 | ||
179 | /* Can never have null landing pad for sjlj -- that would have | |
180 | been indicated by a -1 call site index. */ | |
181 | landing_pad = cs_lp + 1; | |
182 | if (cs_action) | |
183 | action_record = info.action_table + cs_action - 1; | |
184 | goto found_something; | |
185 | } | |
186 | #else | |
187 | /* Search the call-site table for the action associated with this IP. */ | |
188 | while (p < info.action_table) | |
189 | { | |
190 | _Unwind_Ptr cs_start, cs_len, cs_lp; | |
191 | _Unwind_Word cs_action; | |
192 | ||
193 | /* Note that all call-site encodings are "absolute" displacements. */ | |
194 | p = read_encoded_value (0, info.call_site_encoding, p, &cs_start); | |
195 | p = read_encoded_value (0, info.call_site_encoding, p, &cs_len); | |
196 | p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp); | |
197 | p = read_uleb128 (p, &cs_action); | |
198 | ||
199 | /* The table is sorted, so if we've passed the ip, stop. */ | |
200 | if (ip < info.Start + cs_start) | |
201 | p = info.action_table; | |
202 | else if (ip < info.Start + cs_start + cs_len) | |
203 | { | |
204 | if (cs_lp) | |
205 | landing_pad = info.LPStart + cs_lp; | |
206 | if (cs_action) | |
207 | action_record = info.action_table + cs_action - 1; | |
208 | goto found_something; | |
209 | } | |
210 | } | |
0bfa5f65 RH |
211 | #endif |
212 | ||
213 | /* IP is not in table. No associated cleanups. */ | |
214 | /* ??? This is where C++ calls std::terminate to catch throw | |
215 | from a destructor. */ | |
617a1b71 | 216 | CONTINUE_UNWINDING; |
0bfa5f65 RH |
217 | |
218 | found_something: | |
219 | if (landing_pad == 0) | |
220 | { | |
221 | /* IP is present, but has a null landing pad. | |
222 | No handler to be run. */ | |
617a1b71 | 223 | CONTINUE_UNWINDING; |
0bfa5f65 RH |
224 | } |
225 | ||
226 | _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), | |
227 | (_Unwind_Ptr) ue_header); | |
228 | _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0); | |
229 | _Unwind_SetIP (context, landing_pad); | |
230 | return _URC_INSTALL_CONTEXT; | |
231 | } |