]> git.ipfire.org Git - thirdparty/gcc.git/blame - libobjc/exception.c
re PR testsuite/39696 (gcc.dg/tree-ssa/ssa-ccp-25.c scan-tree-dump doesn't work on...
[thirdparty/gcc.git] / libobjc / exception.c
CommitLineData
a776161b 1/* The implementation of exception handling primitives for Objective-C.
faef499b 2 Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
a776161b
RH
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT
12ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GCC; see the file COPYING. If not, write to
f9d09c43
KC
18the Free Software Foundation, 51 Franklin Street, Fifth Floor,
19Boston, MA 02110-1301, USA. */
a776161b
RH
20
21/* As a special exception, if you link this library with files compiled
22 with GCC to produce an executable, this does not cause the resulting
23 executable to be covered by the GNU General Public License. This
24 exception does not however invalidate any other reasons why the
25 executable file might be covered by the GNU General Public License. */
26
27#include <stdlib.h>
049bc404 28#include "config.h"
a776161b
RH
29#include "objc/objc-api.h"
30#include "unwind.h"
31#include "unwind-pe.h"
32
33\f
3f6383d3
JB
34#ifdef __ARM_EABI_UNWINDER__
35
36const _Unwind_Exception_Class __objc_exception_class
37 = {'G', 'N', 'U', 'C', 'O', 'B', 'J', 'C'};
38
39#else
40
a776161b 41/* This is the exception class we report -- "GNUCOBJC". */
3f6383d3
JB
42static const _Unwind_Exception_Class __objc_exception_class
43 = ((((((((_Unwind_Exception_Class) 'G'
44 << 8 | (_Unwind_Exception_Class) 'N')
45 << 8 | (_Unwind_Exception_Class) 'U')
46 << 8 | (_Unwind_Exception_Class) 'C')
47 << 8 | (_Unwind_Exception_Class) 'O')
48 << 8 | (_Unwind_Exception_Class) 'B')
49 << 8 | (_Unwind_Exception_Class) 'J')
50 << 8 | (_Unwind_Exception_Class) 'C');
51
52#endif
a776161b
RH
53
54/* This is the object that is passed around by the Objective C runtime
55 to represent the exception in flight. */
56
57struct ObjcException
58{
59 /* This bit is needed in order to interact with the unwind runtime. */
60 struct _Unwind_Exception base;
61
3f6383d3
JB
62 /* The actual object we want to throw. Note: must come immediately after
63 unwind header. */
a776161b
RH
64 id value;
65
3f6383d3
JB
66#ifdef __ARM_EABI_UNWINDER__
67 /* Note: we use the barrier cache defined in the unwind control block for
68 ARM EABI. */
69#else
a776161b
RH
70 /* Cache some internal unwind data between phase 1 and phase 2. */
71 _Unwind_Ptr landingPad;
72 int handlerSwitchValue;
3f6383d3 73#endif
a776161b
RH
74};
75
76\f
77
78struct lsda_header_info
79{
80 _Unwind_Ptr Start;
81 _Unwind_Ptr LPStart;
82 _Unwind_Ptr ttype_base;
83 const unsigned char *TType;
84 const unsigned char *action_table;
85 unsigned char ttype_encoding;
86 unsigned char call_site_encoding;
87};
88
faef499b
DA
89/* This hook allows libraries to sepecify special actions when an
90 exception is thrown without a handler in place.
91 */
92void (*_objc_unexpected_exception) (id exception); /* !T:SAFE */
93
a776161b
RH
94static const unsigned char *
95parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
96 struct lsda_header_info *info)
97{
30cad60d 98 _uleb128_t tmp;
a776161b
RH
99 unsigned char lpstart_encoding;
100
101 info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
102
103 /* Find @LPStart, the base to which landing pad offsets are relative. */
104 lpstart_encoding = *p++;
105 if (lpstart_encoding != DW_EH_PE_omit)
106 p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
107 else
108 info->LPStart = info->Start;
109
110 /* Find @TType, the base of the handler and exception spec type data. */
111 info->ttype_encoding = *p++;
112 if (info->ttype_encoding != DW_EH_PE_omit)
113 {
114 p = read_uleb128 (p, &tmp);
115 info->TType = p + tmp;
116 }
117 else
118 info->TType = 0;
119
120 /* The encoding and length of the call-site table; the action table
121 immediately follows. */
122 info->call_site_encoding = *p++;
123 p = read_uleb128 (p, &tmp);
124 info->action_table = p + tmp;
125
126 return p;
127}
128
3f6383d3
JB
129#ifdef __ARM_EABI_UNWINDER__
130
131static Class
132get_ttype_entry (struct lsda_header_info *info, _uleb128_t i)
133{
134 _Unwind_Ptr ptr;
135
136 ptr = (_Unwind_Ptr) (info->TType - (i * 4));
137 ptr = _Unwind_decode_target2 (ptr);
138
139 if (ptr)
140 return objc_get_class ((const char *) ptr);
141 else
142 return 0;
143}
144
145#else
146
a776161b
RH
147static Class
148get_ttype_entry (struct lsda_header_info *info, _Unwind_Word i)
149{
150 _Unwind_Ptr ptr;
151
152 i *= size_of_encoded_value (info->ttype_encoding);
153 read_encoded_value_with_base (info->ttype_encoding, info->ttype_base,
154 info->TType - i, &ptr);
155
156 /* NULL ptr means catch-all. */
157 if (ptr)
158 return objc_get_class ((const char *) ptr);
159 else
160 return 0;
161}
162
3f6383d3
JB
163#endif
164
a776161b
RH
165/* Like unto the method of the same name on Object, but takes an id. */
166/* ??? Does this bork the meta-type system? Can/should we look up an
167 isKindOf method on the id? */
168
169static int
170isKindOf (id value, Class target)
171{
172 Class c;
173
174 /* NULL target is catch-all. */
175 if (target == 0)
176 return 1;
177
178 for (c = value->class_pointer; c; c = class_get_super_class (c))
179 if (c == target)
180 return 1;
181 return 0;
182}
183
184/* Using a different personality function name causes link failures
185 when trying to mix code using different exception handling models. */
186#ifdef SJLJ_EXCEPTIONS
187#define PERSONALITY_FUNCTION __gnu_objc_personality_sj0
188#define __builtin_eh_return_data_regno(x) x
189#else
190#define PERSONALITY_FUNCTION __gnu_objc_personality_v0
191#endif
192
3f6383d3
JB
193#ifdef __ARM_EABI_UNWINDER__
194
195#define CONTINUE_UNWINDING \
196 do \
197 { \
198 if (__gnu_unwind_frame(ue_header, context) != _URC_OK) \
199 return _URC_FAILURE; \
200 return _URC_CONTINUE_UNWIND; \
201 } \
202 while (0)
203
204_Unwind_Reason_Code
205PERSONALITY_FUNCTION (_Unwind_State state,
206 struct _Unwind_Exception *ue_header,
207 struct _Unwind_Context *context)
208#else
209
210#define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
211
a776161b
RH
212_Unwind_Reason_Code
213PERSONALITY_FUNCTION (int version,
214 _Unwind_Action actions,
215 _Unwind_Exception_Class exception_class,
216 struct _Unwind_Exception *ue_header,
217 struct _Unwind_Context *context)
3f6383d3 218#endif
a776161b
RH
219{
220 struct ObjcException *xh = (struct ObjcException *) ue_header;
221
222 struct lsda_header_info info;
223 const unsigned char *language_specific_data;
224 const unsigned char *action_record;
225 const unsigned char *p;
226 _Unwind_Ptr landing_pad, ip;
227 int handler_switch_value;
3f6383d3 228 int saw_cleanup = 0, saw_handler, foreign_exception;
ee1658f3 229 void *return_object;
3f6383d3
JB
230 int ip_before_insn = 0;
231
232#ifdef __ARM_EABI_UNWINDER__
233 _Unwind_Action actions;
234
235 switch (state & _US_ACTION_MASK)
236 {
237 case _US_VIRTUAL_UNWIND_FRAME:
238 actions = _UA_SEARCH_PHASE;
239 break;
240
241 case _US_UNWIND_FRAME_STARTING:
242 actions = _UA_CLEANUP_PHASE;
243 if (!(state & _US_FORCE_UNWIND)
244 && ue_header->barrier_cache.sp == _Unwind_GetGR (context, 13))
245 actions |= _UA_HANDLER_FRAME;
246 break;
247
248 case _US_UNWIND_FRAME_RESUME:
249 CONTINUE_UNWINDING;
250 break;
251
252 default:
253 abort();
254 }
255 actions |= state & _US_FORCE_UNWIND;
256
257 /* TODO: Foreign exceptions need some attention (e.g. rethrowing doesn't
258 work). */
259 foreign_exception = 0;
a776161b 260
3f6383d3
JB
261 /* The dwarf unwinder assumes the context structure holds things like the
262 function and LSDA pointers. The ARM implementation caches these in
263 the exception header (UCB). To avoid rewriting everything we make the
264 virtual IP register point at the UCB. */
265 ip = (_Unwind_Ptr) ue_header;
266 _Unwind_SetGR (context, 12, ip);
267
268#else /* !__ARM_EABI_UNWINDER. */
a776161b
RH
269 /* Interface version check. */
270 if (version != 1)
271 return _URC_FATAL_PHASE1_ERROR;
3f6383d3
JB
272
273 foreign_exception = (exception_class != __objc_exception_class);
274#endif
a776161b
RH
275
276 /* Shortcut for phase 2 found handler for domestic exception. */
277 if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME)
3f6383d3 278 && !foreign_exception)
a776161b 279 {
3f6383d3
JB
280#ifdef __ARM_EABI_UNWINDER__
281 handler_switch_value = (int) ue_header->barrier_cache.bitpattern[1];
282 landing_pad = (_Unwind_Ptr) ue_header->barrier_cache.bitpattern[3];
283#else
a776161b
RH
284 handler_switch_value = xh->handlerSwitchValue;
285 landing_pad = xh->landingPad;
3f6383d3 286#endif
a776161b
RH
287 goto install_context;
288 }
289
290 language_specific_data = (const unsigned char *)
291 _Unwind_GetLanguageSpecificData (context);
292
293 /* If no LSDA, then there are no handlers or cleanups. */
294 if (! language_specific_data)
3f6383d3 295 CONTINUE_UNWINDING;
a776161b
RH
296
297 /* Parse the LSDA header. */
298 p = parse_lsda_header (context, language_specific_data, &info);
299 info.ttype_base = base_of_encoded_value (info.ttype_encoding, context);
3f6383d3
JB
300#ifdef HAVE_GETIPINFO
301 ip = _Unwind_GetIPInfo (context, &ip_before_insn);
302#else
b01bd5fe 303 ip = _Unwind_GetIP (context);
3f6383d3
JB
304#endif
305 if (!ip_before_insn)
306 --ip;
a776161b
RH
307 landing_pad = 0;
308 action_record = 0;
309 handler_switch_value = 0;
310
311#ifdef SJLJ_EXCEPTIONS
312 /* The given "IP" is an index into the call-site table, with two
313 exceptions -- -1 means no-action, and 0 means terminate. But
314 since we're using uleb128 values, we've not got random access
315 to the array. */
316 if ((int) ip < 0)
317 return _URC_CONTINUE_UNWIND;
318 else
319 {
30cad60d 320 _uleb128_t cs_lp, cs_action;
a776161b
RH
321 do
322 {
323 p = read_uleb128 (p, &cs_lp);
324 p = read_uleb128 (p, &cs_action);
325 }
326 while (--ip);
327
328 /* Can never have null landing pad for sjlj -- that would have
329 been indicated by a -1 call site index. */
330 landing_pad = cs_lp + 1;
331 if (cs_action)
332 action_record = info.action_table + cs_action - 1;
333 goto found_something;
334 }
335#else
336 /* Search the call-site table for the action associated with this IP. */
337 while (p < info.action_table)
338 {
339 _Unwind_Ptr cs_start, cs_len, cs_lp;
30cad60d 340 _uleb128_t cs_action;
a776161b
RH
341
342 /* Note that all call-site encodings are "absolute" displacements. */
343 p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
344 p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
345 p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
346 p = read_uleb128 (p, &cs_action);
347
348 /* The table is sorted, so if we've passed the ip, stop. */
349 if (ip < info.Start + cs_start)
350 p = info.action_table;
351 else if (ip < info.Start + cs_start + cs_len)
352 {
353 if (cs_lp)
354 landing_pad = info.LPStart + cs_lp;
355 if (cs_action)
356 action_record = info.action_table + cs_action - 1;
357 goto found_something;
358 }
359 }
360#endif /* SJLJ_EXCEPTIONS */
361
362 /* If ip is not present in the table, C++ would call terminate. */
363 /* ??? As with Java, it's perhaps better to tweek the LSDA to
364 that no-action is mapped to no-entry. */
3f6383d3 365 CONTINUE_UNWINDING;
a776161b
RH
366
367 found_something:
368 saw_cleanup = 0;
369 saw_handler = 0;
370
371 if (landing_pad == 0)
372 {
373 /* If ip is present, and has a null landing pad, there are
374 no cleanups or handlers to be run. */
375 }
376 else if (action_record == 0)
377 {
378 /* If ip is present, has a non-null landing pad, and a null
379 action table offset, then there are only cleanups present.
380 Cleanups use a zero switch value, as set above. */
381 saw_cleanup = 1;
382 }
383 else
384 {
385 /* Otherwise we have a catch handler. */
30cad60d 386 _sleb128_t ar_filter, ar_disp;
a776161b
RH
387
388 while (1)
389 {
390 p = action_record;
391 p = read_sleb128 (p, &ar_filter);
392 read_sleb128 (p, &ar_disp);
393
394 if (ar_filter == 0)
395 {
396 /* Zero filter values are cleanups. */
397 saw_cleanup = 1;
398 }
399
400 /* During forced unwinding, we only run cleanups. With a
401 foreign exception class, we have no class info to match. */
3f6383d3 402 else if ((actions & _UA_FORCE_UNWIND) || foreign_exception)
a776161b
RH
403 ;
404
405 else if (ar_filter > 0)
406 {
407 /* Positive filter values are handlers. */
408
409 Class catch_type = get_ttype_entry (&info, ar_filter);
410
411 if (isKindOf (xh->value, catch_type))
412 {
413 handler_switch_value = ar_filter;
414 saw_handler = 1;
415 break;
416 }
417 }
418 else
419 {
420 /* Negative filter values are exception specifications,
421 which Objective-C does not use. */
422 abort ();
423 }
424
425 if (ar_disp == 0)
426 break;
427 action_record = p + ar_disp;
428 }
429 }
430
431 if (! saw_handler && ! saw_cleanup)
3f6383d3 432 CONTINUE_UNWINDING;
a776161b
RH
433
434 if (actions & _UA_SEARCH_PHASE)
435 {
436 if (!saw_handler)
3f6383d3 437 CONTINUE_UNWINDING;
a776161b
RH
438
439 /* For domestic exceptions, we cache data from phase 1 for phase 2. */
3f6383d3 440 if (!foreign_exception)
a776161b 441 {
3f6383d3
JB
442#ifdef __ARM_EABI_UNWINDER__
443 ue_header->barrier_cache.sp = _Unwind_GetGR (context, 13);
444 ue_header->barrier_cache.bitpattern[1] = (_uw) handler_switch_value;
445 ue_header->barrier_cache.bitpattern[3] = (_uw) landing_pad;
446#else
a776161b
RH
447 xh->handlerSwitchValue = handler_switch_value;
448 xh->landingPad = landing_pad;
3f6383d3 449#endif
a776161b
RH
450 }
451 return _URC_HANDLER_FOUND;
452 }
453
454 install_context:
ee1658f3
MK
455 if (saw_cleanup == 0)
456 {
457 return_object = xh->value;
458 if (!(actions & _UA_SEARCH_PHASE))
459 _Unwind_DeleteException(&xh->base);
460 }
461
a776161b 462 _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
ee1658f3 463 __builtin_extend_pointer (saw_cleanup ? xh : return_object));
a776161b
RH
464 _Unwind_SetGR (context, __builtin_eh_return_data_regno (1),
465 handler_switch_value);
466 _Unwind_SetIP (context, landing_pad);
467 return _URC_INSTALL_CONTEXT;
468}
469
470static void
471__objc_exception_cleanup (_Unwind_Reason_Code code __attribute__((unused)),
472 struct _Unwind_Exception *exc)
473{
474 free (exc);
475}
476
477void
478objc_exception_throw (id value)
479{
480 struct ObjcException *header = calloc (1, sizeof (*header));
3f6383d3
JB
481
482 memcpy (&header->base.exception_class, &__objc_exception_class,
483 sizeof (__objc_exception_class));
a776161b
RH
484 header->base.exception_cleanup = __objc_exception_cleanup;
485 header->value = value;
486
049bc404 487#ifdef SJLJ_EXCEPTIONS
a776161b
RH
488 _Unwind_SjLj_RaiseException (&header->base);
489#else
490 _Unwind_RaiseException (&header->base);
491#endif
492
493 /* Some sort of unwinding error. */
faef499b
DA
494 if (_objc_unexpected_exception != 0)
495 {
496 (*_objc_unexpected_exception) (value);
497 }
a776161b
RH
498 abort ();
499}