exception.cc 13.8 KB
Newer Older
Tom Tromey committed
1 2
// Functions for Exception Support for Java.

3
/* Copyright (C) 1998, 1999, 2001, 2002, 2006  Free Software Foundation
Tom Tromey committed
4 5 6 7 8 9 10 11 12 13

   This file is part of libgcj.

This software is copyrighted work licensed under the terms of the
Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
details.  */

#include <config.h>

#include <stddef.h>
14
#include <stdlib.h>
Tom Tromey committed
15 16 17

#include <java/lang/Class.h>
#include <java/lang/NullPointerException.h>
Andrew Haley committed
18
#include <gnu/gcj/RawData.h> 
Tom Tromey committed
19
#include <gcj/cni.h>
Tom Tromey committed
20 21
#include <jvm.h>

22 23 24 25 26 27 28 29 30 31 32
// unwind-pe.h uses std::abort(), but sometimes we compile libjava
// without libstdc++-v3. The following hack forces it to use
// stdlib.h's abort().
namespace std
{
  static __attribute__ ((__noreturn__)) void
  abort ()
  {
    ::abort ();
  }
}
33
#include "unwind.h"
Tom Tromey committed
34

35 36 37 38 39
struct alignment_test_struct
{
  char space;
  char end[0] __attribute__((aligned));
};
Tom Tromey committed
40

41
struct java_exception_header
Tom Tromey committed
42
{
43 44 45
  /* Cache handler details between Phase 1 and Phase 2.  */
  _Unwind_Ptr landingPad;
  int handlerSwitchValue;
Tom Tromey committed
46

47 48 49 50 51 52 53 54 55
  /* The object being thrown.  Compiled code expects this to be immediately
     before the generic exception header.  Which is complicated by the fact
     that _Unwind_Exception is ((aligned)).  */

  char pad[sizeof(jthrowable) < sizeof(alignment_test_struct)
	   ? sizeof(alignment_test_struct) - sizeof(jthrowable) : 0]
    __attribute__((aligned));

  jthrowable value;
Tom Tromey committed
56

57 58 59 60
  /* The generic exception header.  */
  _Unwind_Exception unwindHeader;
};

Andrew Haley committed
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
#ifdef __ARM_EABI_UNWINDER__
// This is the exception class we report -- "GNUCJAVA".

const _Unwind_Exception_Class __gcj_exception_class
  = {'G', 'N', 'U', 'C', 'J', 'A', 'V', 'A'};

static inline java_exception_header *
get_exception_header_from_ue (_Unwind_Exception *exc)
{
  return reinterpret_cast<java_exception_header *>(exc + 1) - 1;
}

extern "C" void __cxa_begin_cleanup (_Unwind_Exception*);

#else // !__ARM_EABI_UNWINDER__
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
// This is the exception class we report -- "GNUCJAVA".
const _Unwind_Exception_Class __gcj_exception_class
= ((((((((_Unwind_Exception_Class) 'G' 
         << 8 | (_Unwind_Exception_Class) 'N')
        << 8 | (_Unwind_Exception_Class) 'U')
       << 8 | (_Unwind_Exception_Class) 'C')
      << 8 | (_Unwind_Exception_Class) 'J')
     << 8 | (_Unwind_Exception_Class) 'A')
    << 8 | (_Unwind_Exception_Class) 'V')
   << 8 | (_Unwind_Exception_Class) 'A');


static inline java_exception_header *
get_exception_header_from_ue (_Unwind_Exception *exc)
{
  return reinterpret_cast<java_exception_header *>(exc + 1) - 1;
Tom Tromey committed
92
}
Andrew Haley committed
93
#endif // !__ARM_EABI_UNWINDER__
Tom Tromey committed
94

95 96
/* Perform a throw, Java style. Throw will unwind through this call,
   so there better not be any handlers or exception thrown here. */
Tom Tromey committed
97

98 99
extern "C" void
_Jv_Throw (jthrowable value)
Tom Tromey committed
100
{
101
  java_exception_header *xh
102
    = static_cast<java_exception_header *>(_Jv_AllocRawObj (sizeof (*xh)));
103 104 105 106

  if (value == NULL)
    value = new java::lang::NullPointerException ();
  xh->value = value;
Tom Tromey committed
107

Andrew Haley committed
108 109
  memcpy (&xh->unwindHeader.exception_class, &__gcj_exception_class,
	  sizeof xh->unwindHeader.exception_class);
110
  xh->unwindHeader.exception_cleanup = NULL;
Tom Tromey committed
111

112 113 114 115 116 117 118 119
  /* We're happy with setjmp/longjmp exceptions or region-based
     exception handlers: entry points are provided here for both.  */
  _Unwind_Reason_Code code;
#ifdef SJLJ_EXCEPTIONS
  code = _Unwind_SjLj_RaiseException (&xh->unwindHeader);
#else
  code = _Unwind_RaiseException (&xh->unwindHeader);
#endif
Tom Tromey committed
120

121 122 123 124 125 126 127
  /* If code == _URC_END_OF_STACK, then we reached top of stack without
     finding a handler for the exception.  Since each thread is run in
     a try/catch, this oughtn't happen.  If code is something else, we
     encountered some sort of heinous lossage from which we could not
     recover.  As is the way of such things, almost certainly we will have
     crashed before now, rather than actually being able to diagnose the
     problem.  */
128
  abort();
Tom Tromey committed
129 130
}

131

132
#include "unwind-pe.h"
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147

struct lsda_header_info
{
  _Unwind_Ptr Start;
  _Unwind_Ptr LPStart;
  const unsigned char *TType;
  const unsigned char *action_table;
  unsigned char ttype_encoding;
  unsigned char call_site_encoding;
};

static const unsigned char *
parse_lsda_header (_Unwind_Context *context, const unsigned char *p,
		   lsda_header_info *info)
{
148
  _uleb128_t tmp;
149 150 151
  unsigned char lpstart_encoding;

  info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
Tom Tromey committed
152

153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
  // Find @LPStart, the base to which landing pad offsets are relative.
  lpstart_encoding = *p++;
  if (lpstart_encoding != DW_EH_PE_omit)
    p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
  else
    info->LPStart = info->Start;

  // Find @TType, the base of the handler and exception spec type data.
  info->ttype_encoding = *p++;
  if (info->ttype_encoding != DW_EH_PE_omit)
    {
      p = read_uleb128 (p, &tmp);
      info->TType = p + tmp;
    }
  else
    info->TType = 0;

  // The encoding and length of the call-site table; the action table
  // immediately follows.
  info->call_site_encoding = *p++;
  p = read_uleb128 (p, &tmp);
  info->action_table = p + tmp;

  return p;
}

Andrew Haley committed
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
#ifdef __ARM_EABI_UNWINDER__

static void **
get_ttype_entry(_Unwind_Context *, lsda_header_info* info, _uleb128_t i)
{
  _Unwind_Ptr ptr;

  ptr = (_Unwind_Ptr) (info->TType - (i * 4));
  ptr = _Unwind_decode_target2(ptr);
  
  return reinterpret_cast<void **>(ptr);
}

#else

194
static void **
195
get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i)
Tom Tromey committed
196
{
197 198 199 200 201
  _Unwind_Ptr ptr;

  i *= size_of_encoded_value (info->ttype_encoding);
  read_encoded_value (context, info->ttype_encoding, info->TType - i, &ptr);

202
  return reinterpret_cast<void **>(ptr);
Tom Tromey committed
203 204
}

Andrew Haley committed
205
#endif
Tom Tromey committed
206

207 208
// Using a different personality function name causes link failures
// when trying to mix code using different exception handling models.
209
#ifdef SJLJ_EXCEPTIONS
210 211 212 213
#define PERSONALITY_FUNCTION	__gcj_personality_sj0
#define __builtin_eh_return_data_regno(x) x
#else
#define PERSONALITY_FUNCTION	__gcj_personality_v0
214 215
#endif

Andrew Haley committed
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
#ifdef __ARM_EABI_UNWINDER__

#define CONTINUE_UNWINDING \
  do								\
    {								\
      if (__gnu_unwind_frame(ue_header, context) != _URC_OK)	\
	return _URC_FAILURE;					\
      return _URC_CONTINUE_UNWIND;				\
    }								\
  while (0)

extern "C" _Unwind_Reason_Code
PERSONALITY_FUNCTION (_Unwind_State state,
		      struct _Unwind_Exception* ue_header,
		      struct _Unwind_Context* context)
#else

#define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND

235 236 237 238 239 240
extern "C" _Unwind_Reason_Code
PERSONALITY_FUNCTION (int version,
		      _Unwind_Action actions,
		      _Unwind_Exception_Class exception_class,
		      struct _Unwind_Exception *ue_header,
		      struct _Unwind_Context *context)
Andrew Haley committed
241 242

#endif
Tom Tromey committed
243
{
244 245 246 247 248 249 250 251 252 253
  java_exception_header *xh = get_exception_header_from_ue (ue_header);

  lsda_header_info info;
  const unsigned char *language_specific_data;
  const unsigned char *action_record;
  const unsigned char *p;
  _Unwind_Ptr landing_pad, ip;
  int handler_switch_value;
  bool saw_cleanup;
  bool saw_handler;
Andrew Haley committed
254
  bool foreign_exception;
255
  int ip_before_insn = 0;
256

Andrew Haley committed
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
#ifdef __ARM_EABI_UNWINDER__
  _Unwind_Action actions;

  switch (state & _US_ACTION_MASK)
    {
    case _US_VIRTUAL_UNWIND_FRAME:
      actions = _UA_SEARCH_PHASE;
      break;

    case _US_UNWIND_FRAME_STARTING:
      actions = _UA_CLEANUP_PHASE;
      if (!(state & _US_FORCE_UNWIND)
	  && ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13))
	actions |= _UA_HANDLER_FRAME;
      break;

    case _US_UNWIND_FRAME_RESUME:
      CONTINUE_UNWINDING;
      break;

    default:
      std::abort();
    }
  actions |= state & _US_FORCE_UNWIND;

  // We don't know which runtime we're working with, so can't check this.
  // However the ABI routines hide this from us, and we don't actually need
  // to know.
  foreign_exception = false;

  // The dwarf unwinder assumes the context structure holds things like the
  // function and LSDA pointers.  The ARM implementation caches these in
  // the exception header (UCB).  To avoid rewriting everything we make the
  // virtual IP register point at the UCB.
  ip = (_Unwind_Ptr) ue_header;
  _Unwind_SetGR(context, 12, ip);
293

Andrew Haley committed
294
#else
295 296 297
  // Interface version check.
  if (version != 1)
    return _URC_FATAL_PHASE1_ERROR;
Andrew Haley committed
298 299
  foreign_exception = exception_class != __gcj_exception_class;
#endif
300 301 302

  // Shortcut for phase 2 found handler for domestic exception.
  if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME)
Andrew Haley committed
303
      && !foreign_exception)
Tom Tromey committed
304
    {
305 306 307
      handler_switch_value = xh->handlerSwitchValue;
      landing_pad = xh->landingPad;
      goto install_context;
Tom Tromey committed
308
    }
Tom Tromey committed
309

310
  // FIXME: In Phase 1, record _Unwind_GetIPInfo in xh->obj as a part of
311 312
  // the stack trace for this exception.  This will only collect Java
  // frames, but perhaps that is acceptable.
313
  // FIXME2: _Unwind_GetIPInfo is nonsensical for SJLJ, being a call-site
314 315 316 317 318 319 320 321 322 323
  // index instead of a PC value.  We could perhaps arrange for
  // _Unwind_GetRegionStart to return context->fc->jbuf[1], which
  // is the address of the handler label for __builtin_longjmp, but
  // there is no solution for DONT_USE_BUILTIN_SETJMP.

  language_specific_data = (const unsigned char *)
    _Unwind_GetLanguageSpecificData (context);

  // If no LSDA, then there are no handlers or cleanups.
  if (! language_specific_data)
Andrew Haley committed
324
    CONTINUE_UNWINDING;
325 326 327

  // Parse the LSDA header.
  p = parse_lsda_header (context, language_specific_data, &info);
328
#ifdef HAVE_GETIPINFO
329
  ip = _Unwind_GetIPInfo (context, &ip_before_insn);
330 331 332
#else
  ip = _Unwind_GetIP (context) - 1;
#endif
Andrew Haley committed
333 334
  if (! ip_before_insn)
    --ip;
335 336 337 338
  landing_pad = 0;
  action_record = 0;
  handler_switch_value = 0;

Tom Tromey committed
339
#ifdef SJLJ_EXCEPTIONS
340 341 342 343 344 345 346 347
  // The given "IP" is an index into the call-site table, with two
  // exceptions -- -1 means no-action, and 0 means terminate.  But
  // since we're using uleb128 values, we've not got random access
  // to the array.
  if ((int) ip <= 0)
    return _URC_CONTINUE_UNWIND;
  else
    {
348
      _uleb128_t cs_lp, cs_action;
349 350 351 352 353 354 355 356 357 358 359 360 361 362
      do
	{
	  p = read_uleb128 (p, &cs_lp);
	  p = read_uleb128 (p, &cs_action);
	}
      while (--ip);

      // Can never have null landing pad for sjlj -- that would have
      // been indicated by a -1 call site index.
      landing_pad = cs_lp + 1;
      if (cs_action)
	action_record = info.action_table + cs_action - 1;
      goto found_something;
    }
Tom Tromey committed
363
#else
364 365 366
  // Search the call-site table for the action associated with this IP.
  while (p < info.action_table)
    {
367
      _Unwind_Ptr cs_start, cs_len, cs_lp;
368
      _uleb128_t cs_action;
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388

      // Note that all call-site encodings are "absolute" displacements.
      p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
      p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
      p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
      p = read_uleb128 (p, &cs_action);

      // The table is sorted, so if we've passed the ip, stop.
      if (ip < info.Start + cs_start)
	p = info.action_table;
      else if (ip < info.Start + cs_start + cs_len)
	{
	  if (cs_lp)
	    landing_pad = info.LPStart + cs_lp;
	  if (cs_action)
	    action_record = info.action_table + cs_action - 1;
	  goto found_something;
	}
    }
#endif // SJLJ_EXCEPTIONS
Tom Tromey committed
389

390 391 392
  // If ip is not present in the table, C++ would call terminate.
  // ??? It is perhaps better to tweek the LSDA so that no-action
  // is mapped to no-entry for Java.
Andrew Haley committed
393
  CONTINUE_UNWINDING;
Tom Tromey committed
394

395 396 397
 found_something:
  saw_cleanup = false;
  saw_handler = false;
Tom Tromey committed
398

399
  if (landing_pad == 0)
Tom Tromey committed
400
    {
401 402 403 404 405 406 407 408 409 410 411 412 413
      // If ip is present, and has a null landing pad, there are
      // no cleanups or handlers to be run.
    }
  else if (action_record == 0)
    {
      // If ip is present, has a non-null landing pad, and a null
      // action table offset, then there are only cleanups present.
      // Cleanups use a zero switch value, as set above.
      saw_cleanup = true;
    }
  else
    {
      // Otherwise we have a catch handler.
414
      _sleb128_t ar_filter, ar_disp;
415 416 417 418

      while (1)
	{
	  p = action_record;
419 420
	  p = read_sleb128 (p, &ar_filter);
	  read_sleb128 (p, &ar_disp);
421 422 423 424 425 426 427 428 429 430

	  if (ar_filter == 0)
	    {
	      // Zero filter values are cleanups.
	      saw_cleanup = true;
	    }

	  // During forced unwinding, we only run cleanups.  With a
	  // foreign exception class, we have no class info to match.
	  else if ((actions & _UA_FORCE_UNWIND)
Andrew Haley committed
431
		   || foreign_exception)
432 433 434 435 436 437
	    ;

	  else if (ar_filter > 0)
	    {
	      // Positive filter values are handlers.

438 439 440 441 442 443 444 445
	      void **catch_word = get_ttype_entry (context, &info, ar_filter);
	      jclass catch_type = (jclass)*catch_word;

	      // FIXME: This line is a kludge to work around exception
	      // handlers written in C++, which don't yet use indirect
	      // dispatch.
	      if (catch_type == *(void **)&java::lang::Class::class$)
		catch_type = (jclass)catch_word;
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460

	      if (_Jv_IsInstanceOf (xh->value, catch_type))
		{
		  handler_switch_value = ar_filter;
		  saw_handler = true;
		  break;
		}
	    }
	  else
	    {
	      // Negative filter values are exception specifications,
	      // which Java does not use.
	      // ??? Perhaps better to make them an index into a table
	      // of null-terminated strings instead of playing games
	      // with Utf8Const+1 as above.
461
	      abort ();
462 463 464 465 466 467
	    }

	  if (ar_disp == 0)
	    break;
	  action_record = p + ar_disp;
	}
Tom Tromey committed
468 469
    }

470
  if (! saw_handler && ! saw_cleanup)
Andrew Haley committed
471
	CONTINUE_UNWINDING;
Tom Tromey committed
472

473 474 475
  if (actions & _UA_SEARCH_PHASE)
    {
      if (! saw_handler)
Andrew Haley committed
476
	CONTINUE_UNWINDING;
477 478

      // For domestic exceptions, we cache data from phase 1 for phase 2.
Andrew Haley committed
479
      if (! foreign_exception)
480 481 482 483 484 485
        {
          xh->handlerSwitchValue = handler_switch_value;
          xh->landingPad = landing_pad;
	}
      return _URC_HANDLER_FOUND;
    }
Tom Tromey committed
486

487 488 489 490 491 492
 install_context:
  _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
		 (_Unwind_Ptr) &xh->unwindHeader);
  _Unwind_SetGR (context, __builtin_eh_return_data_regno (1),
		 handler_switch_value);
  _Unwind_SetIP (context, landing_pad);
Andrew Haley committed
493 494 495 496
#ifdef __ARM_EABI_UNWINDER__
  if (saw_cleanup)
    __cxa_begin_cleanup(ue_header);
#endif
497
  return _URC_INSTALL_CONTEXT;
Tom Tromey committed
498
}