OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libobjc/] [exception.c] - Blame information for rev 867

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.