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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [runtime/] [go-unwind.c] - Blame information for rev 747

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
/* go-unwind.c -- unwind the stack for panic/recover.
2
 
3
   Copyright 2010 The Go Authors. All rights reserved.
4
   Use of this source code is governed by a BSD-style
5
   license that can be found in the LICENSE file.  */
6
 
7
#include "config.h"
8
 
9
#include <stdlib.h>
10
#include <unistd.h>
11
 
12
#include "unwind.h"
13
#define NO_SIZE_OF_ENCODED_VALUE
14
#include "unwind-pe.h"
15
 
16
#include "runtime.h"
17
#include "go-alloc.h"
18
#include "go-defer.h"
19
#include "go-panic.h"
20
 
21
/* The code for a Go exception.  */
22
 
23
#ifdef __ARM_EABI_UNWINDER__
24
static const _Unwind_Exception_Class __go_exception_class =
25
  { 'G', 'N', 'U', 'C', 'G', 'O', '\0', '\0' };
26
#else
27
static const _Unwind_Exception_Class __go_exception_class =
28
  ((((((((_Unwind_Exception_Class) 'G'
29
         << 8 | (_Unwind_Exception_Class) 'N')
30
        << 8 | (_Unwind_Exception_Class) 'U')
31
       << 8 | (_Unwind_Exception_Class) 'C')
32
      << 8 | (_Unwind_Exception_Class) 'G')
33
     << 8 | (_Unwind_Exception_Class) 'O')
34
    << 8 | (_Unwind_Exception_Class) '\0')
35
   << 8 | (_Unwind_Exception_Class) '\0');
36
#endif
37
 
38
 
39
/* This function is called by exception handlers used when unwinding
40
   the stack after a recovered panic.  The exception handler looks
41
   like this:
42
     __go_check_defer (frame);
43
     return;
44
   If we have not yet reached the frame we are looking for, we
45
   continue unwinding.  */
46
 
47
void
48
__go_check_defer (_Bool *frame)
49
{
50
  G *g;
51
  struct _Unwind_Exception *hdr;
52
 
53
  g = runtime_g ();
54
 
55
  if (g == NULL)
56
    {
57
      /* Some other language has thrown an exception.  We know there
58
         are no defer handlers, so there is nothing to do.  */
59
    }
60
  else if (g->is_foreign)
61
    {
62
      struct __go_panic_stack *n;
63
      _Bool was_recovered;
64
 
65
      /* Some other language has thrown an exception.  We need to run
66
         the local defer handlers.  If they call recover, we stop
67
         unwinding the stack here.  */
68
 
69
      n = ((struct __go_panic_stack *)
70
           __go_alloc (sizeof (struct __go_panic_stack)));
71
 
72
      n->__arg.__type_descriptor = NULL;
73
      n->__arg.__object = NULL;
74
      n->__was_recovered = 0;
75
      n->__is_foreign = 1;
76
      n->__next = g->panic;
77
      g->panic = n;
78
 
79
      while (1)
80
        {
81
          struct __go_defer_stack *d;
82
          void (*pfn) (void *);
83
 
84
          d = g->defer;
85
          if (d == NULL || d->__frame != frame || d->__pfn == NULL)
86
            break;
87
 
88
          pfn = d->__pfn;
89
          g->defer = d->__next;
90
 
91
          (*pfn) (d->__arg);
92
 
93
          __go_free (d);
94
 
95
          if (n->__was_recovered)
96
            {
97
              /* The recover function caught the panic thrown by some
98
                 other language.  */
99
              break;
100
            }
101
        }
102
 
103
      was_recovered = n->__was_recovered;
104
      g->panic = n->__next;
105
      __go_free (n);
106
 
107
      if (was_recovered)
108
        {
109
          /* Just return and continue executing Go code.  */
110
          *frame = 1;
111
          return;
112
        }
113
 
114
      /* We are panicing through this function.  */
115
      *frame = 0;
116
    }
117
  else if (g->defer != NULL
118
           && g->defer->__pfn == NULL
119
           && g->defer->__frame == frame)
120
    {
121
      struct __go_defer_stack *d;
122
 
123
      /* This is the defer function which called recover.  Simply
124
         return to stop the stack unwind, and let the Go code continue
125
         to execute.  */
126
      d = g->defer;
127
      g->defer = d->__next;
128
      __go_free (d);
129
 
130
      /* We are returning from this function.  */
131
      *frame = 1;
132
 
133
      return;
134
    }
135
 
136
  /* This is some other defer function.  It was already run by the
137
     call to panic, or just above.  Rethrow the exception.  */
138
 
139
  hdr = (struct _Unwind_Exception *) g->exception;
140
 
141
#ifdef LIBGO_SJLJ_EXCEPTIONS
142
  _Unwind_SjLj_Resume_or_Rethrow (hdr);
143
#else
144
#if defined(_LIBUNWIND_STD_ABI)
145
  _Unwind_RaiseException (hdr);
146
#else
147
  _Unwind_Resume_or_Rethrow (hdr);
148
#endif
149
#endif
150
 
151
  /* Rethrowing the exception should not return.  */
152
  abort();
153
}
154
 
155
/* Unwind function calls until we reach the one which used a defer
156
   function which called recover.  Each function which uses a defer
157
   statement will have an exception handler, as shown above.  */
158
 
159
void
160
__go_unwind_stack ()
161
{
162
  struct _Unwind_Exception *hdr;
163
 
164
  hdr = ((struct _Unwind_Exception *)
165
         __go_alloc (sizeof (struct _Unwind_Exception)));
166
  __builtin_memcpy (&hdr->exception_class, &__go_exception_class,
167
                    sizeof hdr->exception_class);
168
  hdr->exception_cleanup = NULL;
169
 
170
  runtime_g ()->exception = hdr;
171
 
172
#ifdef __USING_SJLJ_EXCEPTIONS__
173
  _Unwind_SjLj_RaiseException (hdr);
174
#else
175
  _Unwind_RaiseException (hdr);
176
#endif
177
 
178
  /* Raising an exception should not return.  */
179
  abort ();
180
}
181
 
182
/* The rest of this code is really similar to gcc/unwind-c.c and
183
   libjava/exception.cc.  */
184
 
185
typedef struct
186
{
187
  _Unwind_Ptr Start;
188
  _Unwind_Ptr LPStart;
189
  _Unwind_Ptr ttype_base;
190
  const unsigned char *TType;
191
  const unsigned char *action_table;
192
  unsigned char ttype_encoding;
193
  unsigned char call_site_encoding;
194
} lsda_header_info;
195
 
196
static const unsigned char *
197
parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
198
                   lsda_header_info *info)
199
{
200
  _uleb128_t tmp;
201
  unsigned char lpstart_encoding;
202
 
203
  info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
204
 
205
  /* Find @LPStart, the base to which landing pad offsets are relative.  */
206
  lpstart_encoding = *p++;
207
  if (lpstart_encoding != DW_EH_PE_omit)
208
    p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
209
  else
210
    info->LPStart = info->Start;
211
 
212
  /* Find @TType, the base of the handler and exception spec type data.  */
213
  info->ttype_encoding = *p++;
214
  if (info->ttype_encoding != DW_EH_PE_omit)
215
    {
216
      p = read_uleb128 (p, &tmp);
217
      info->TType = p + tmp;
218
    }
219
  else
220
    info->TType = 0;
221
 
222
  /* The encoding and length of the call-site table; the action table
223
     immediately follows.  */
224
  info->call_site_encoding = *p++;
225
  p = read_uleb128 (p, &tmp);
226
  info->action_table = p + tmp;
227
 
228
  return p;
229
}
230
 
231
/* The personality function is invoked when unwinding the stack due to
232
   a panic.  Its job is to find the cleanup and exception handlers to
233
   run.  We can't split the stack here, because we won't be able to
234
   unwind from that split.  */
235
 
236
#ifdef __ARM_EABI_UNWINDER__
237
/* ARM EABI personality routines must also unwind the stack.  */
238
#define CONTINUE_UNWINDING \
239
  do                                                            \
240
    {                                                           \
241
      if (__gnu_unwind_frame (ue_header, context) != _URC_OK)   \
242
        return _URC_FAILURE;                                    \
243
      return _URC_CONTINUE_UNWIND;                              \
244
    }                                                           \
245
  while (0)
246
#else
247
#define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
248
#endif
249
 
250
#ifdef __USING_SJLJ_EXCEPTIONS__
251
#define PERSONALITY_FUNCTION    __gccgo_personality_sj0
252
#define __builtin_eh_return_data_regno(x) x
253
#else
254
#define PERSONALITY_FUNCTION    __gccgo_personality_v0
255
#endif
256
 
257
#ifdef __ARM_EABI_UNWINDER__
258
_Unwind_Reason_Code
259
PERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *,
260
                      struct _Unwind_Context *)
261
  __attribute__ ((no_split_stack, flatten));
262
 
263
_Unwind_Reason_Code
264
PERSONALITY_FUNCTION (_Unwind_State state,
265
                      struct _Unwind_Exception * ue_header,
266
                      struct _Unwind_Context * context)
267
#else
268
_Unwind_Reason_Code
269
PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class,
270
                      struct _Unwind_Exception *, struct _Unwind_Context *)
271
  __attribute__ ((no_split_stack, flatten));
272
 
273
_Unwind_Reason_Code
274
PERSONALITY_FUNCTION (int version,
275
                      _Unwind_Action actions,
276
                      _Unwind_Exception_Class exception_class,
277
                      struct _Unwind_Exception *ue_header,
278
                      struct _Unwind_Context *context)
279
#endif
280
{
281
  lsda_header_info info;
282
  const unsigned char *language_specific_data, *p, *action_record;
283
  _Unwind_Ptr landing_pad, ip;
284
  int ip_before_insn = 0;
285
  _Bool is_foreign;
286
  G *g;
287
 
288
#ifdef __ARM_EABI_UNWINDER__
289
  _Unwind_Action actions;
290
 
291
  switch (state & _US_ACTION_MASK)
292
    {
293
    case _US_VIRTUAL_UNWIND_FRAME:
294
      actions = _UA_SEARCH_PHASE;
295
      break;
296
 
297
    case _US_UNWIND_FRAME_STARTING:
298
      actions = _UA_CLEANUP_PHASE;
299
      if (!(state & _US_FORCE_UNWIND)
300
          && ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13))
301
        actions |= _UA_HANDLER_FRAME;
302
      break;
303
 
304
    case _US_UNWIND_FRAME_RESUME:
305
      CONTINUE_UNWINDING;
306
      break;
307
 
308
    default:
309
      abort();
310
    }
311
  actions |= state & _US_FORCE_UNWIND;
312
 
313
  is_foreign = 0;
314
 
315
  /* The dwarf unwinder assumes the context structure holds things like the
316
     function and LSDA pointers.  The ARM implementation caches these in
317
     the exception header (UCB).  To avoid rewriting everything we make the
318
     virtual IP register point at the UCB.  */
319
  ip = (_Unwind_Ptr) ue_header;
320
  _Unwind_SetGR (context, 12, ip);
321
#else
322
  if (version != 1)
323
    return _URC_FATAL_PHASE1_ERROR;
324
 
325
  is_foreign = exception_class != __go_exception_class;
326
#endif
327
 
328
  language_specific_data = (const unsigned char *)
329
    _Unwind_GetLanguageSpecificData (context);
330
 
331
  /* If no LSDA, then there are no handlers or cleanups.  */
332
  if (! language_specific_data)
333
    CONTINUE_UNWINDING;
334
 
335
  /* Parse the LSDA header.  */
336
  p = parse_lsda_header (context, language_specific_data, &info);
337
#ifdef HAVE_GETIPINFO
338
  ip = _Unwind_GetIPInfo (context, &ip_before_insn);
339
#else
340
  ip = _Unwind_GetIP (context);
341
#endif
342
  if (! ip_before_insn)
343
    --ip;
344
  landing_pad = 0;
345
  action_record = NULL;
346
 
347
#ifdef __USING_SJLJ_EXCEPTIONS__
348
  /* The given "IP" is an index into the call-site table, with two
349
     exceptions -- -1 means no-action, and 0 means terminate.  But
350
     since we're using uleb128 values, we've not got random access
351
     to the array.  */
352
  if ((int) ip <= 0)
353
    return _URC_CONTINUE_UNWIND;
354
  else
355
    {
356
      _uleb128_t cs_lp, cs_action;
357
      do
358
        {
359
          p = read_uleb128 (p, &cs_lp);
360
          p = read_uleb128 (p, &cs_action);
361
        }
362
      while (--ip);
363
 
364
      /* Can never have null landing pad for sjlj -- that would have
365
         been indicated by a -1 call site index.  */
366
      landing_pad = (_Unwind_Ptr)cs_lp + 1;
367
      if (cs_action)
368
        action_record = info.action_table + cs_action - 1;
369
      goto found_something;
370
    }
371
#else
372
  /* Search the call-site table for the action associated with this IP.  */
373
  while (p < info.action_table)
374
    {
375
      _Unwind_Ptr cs_start, cs_len, cs_lp;
376
      _uleb128_t cs_action;
377
 
378
      /* Note that all call-site encodings are "absolute" displacements.  */
379
      p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
380
      p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
381
      p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
382
      p = read_uleb128 (p, &cs_action);
383
 
384
      /* The table is sorted, so if we've passed the ip, stop.  */
385
      if (ip < info.Start + cs_start)
386
        p = info.action_table;
387
      else if (ip < info.Start + cs_start + cs_len)
388
        {
389
          if (cs_lp)
390
            landing_pad = info.LPStart + cs_lp;
391
          if (cs_action)
392
            action_record = info.action_table + cs_action - 1;
393
          goto found_something;
394
        }
395
    }
396
#endif
397
 
398
  /* IP is not in table.  No associated cleanups.  */
399
  CONTINUE_UNWINDING;
400
 
401
 found_something:
402
  if (landing_pad == 0)
403
    {
404
      /* IP is present, but has a null landing pad.
405
         No handler to be run.  */
406
      CONTINUE_UNWINDING;
407
    }
408
 
409
  if (actions & _UA_SEARCH_PHASE)
410
    {
411
      if (action_record == 0)
412
        {
413
          /* This indicates a cleanup rather than an exception
414
             handler.  */
415
          CONTINUE_UNWINDING;
416
        }
417
 
418
      return _URC_HANDLER_FOUND;
419
    }
420
 
421
  /* It's possible for g to be NULL here for an exception thrown by a
422
     language other than Go.  */
423
  g = runtime_g ();
424
  if (g == NULL)
425
    {
426
      if (!is_foreign)
427
        abort ();
428
    }
429
  else
430
    {
431
      g->exception = ue_header;
432
      g->is_foreign = is_foreign;
433
    }
434
 
435
  _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
436
                 (_Unwind_Ptr) ue_header);
437
  _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0);
438
  _Unwind_SetIP (context, landing_pad);
439
  return _URC_INSTALL_CONTEXT;
440
}

powered by: WebSVN 2.1.0

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