eh_personality.cc revision 132720
197403Sobrien// -*- C++ -*- The GNU C++ exception personality routine.
2117397Skan// Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
397403Sobrien//
4132720Skan// This file is part of GCC.
597403Sobrien//
6132720Skan// GCC is free software; you can redistribute it and/or modify
797403Sobrien// it under the terms of the GNU General Public License as published by
897403Sobrien// the Free Software Foundation; either version 2, or (at your option)
997403Sobrien// any later version.
1097403Sobrien//
11132720Skan// GCC is distributed in the hope that it will be useful,
1297403Sobrien// but WITHOUT ANY WARRANTY; without even the implied warranty of
1397403Sobrien// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1497403Sobrien// GNU General Public License for more details.
1597403Sobrien//
1697403Sobrien// You should have received a copy of the GNU General Public License
17132720Skan// along with GCC; see the file COPYING.  If not, write to
1897403Sobrien// the Free Software Foundation, 59 Temple Place - Suite 330,
1997403Sobrien// Boston, MA 02111-1307, USA.
2097403Sobrien
2197403Sobrien// As a special exception, you may use this file as part of a free software
2297403Sobrien// library without restriction.  Specifically, if other files instantiate
2397403Sobrien// templates or use macros or inline functions from this file, or you compile
2497403Sobrien// this file and link it with other files to produce an executable, this
2597403Sobrien// file does not by itself cause the resulting executable to be covered by
2697403Sobrien// the GNU General Public License.  This exception does not however
2797403Sobrien// invalidate any other reasons why the executable file might be covered by
2897403Sobrien// the GNU General Public License.
2997403Sobrien
3097403Sobrien
3197403Sobrien#include <bits/c++config.h>
3297403Sobrien#include <cstdlib>
3397403Sobrien#include <exception_defines.h>
3497403Sobrien#include "unwind-cxx.h"
3597403Sobrien
3697403Sobrienusing namespace __cxxabiv1;
3797403Sobrien
3897403Sobrien#include "unwind-pe.h"
3997403Sobrien
4097403Sobrien
4197403Sobrienstruct lsda_header_info
4297403Sobrien{
4397403Sobrien  _Unwind_Ptr Start;
4497403Sobrien  _Unwind_Ptr LPStart;
4597403Sobrien  _Unwind_Ptr ttype_base;
4697403Sobrien  const unsigned char *TType;
4797403Sobrien  const unsigned char *action_table;
4897403Sobrien  unsigned char ttype_encoding;
4997403Sobrien  unsigned char call_site_encoding;
5097403Sobrien};
5197403Sobrien
5297403Sobrienstatic const unsigned char *
5397403Sobrienparse_lsda_header (_Unwind_Context *context, const unsigned char *p,
5497403Sobrien		   lsda_header_info *info)
5597403Sobrien{
5697403Sobrien  _Unwind_Word tmp;
5797403Sobrien  unsigned char lpstart_encoding;
5897403Sobrien
5997403Sobrien  info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
6097403Sobrien
6197403Sobrien  // Find @LPStart, the base to which landing pad offsets are relative.
6297403Sobrien  lpstart_encoding = *p++;
6397403Sobrien  if (lpstart_encoding != DW_EH_PE_omit)
6497403Sobrien    p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
6597403Sobrien  else
6697403Sobrien    info->LPStart = info->Start;
6797403Sobrien
6897403Sobrien  // Find @TType, the base of the handler and exception spec type data.
6997403Sobrien  info->ttype_encoding = *p++;
7097403Sobrien  if (info->ttype_encoding != DW_EH_PE_omit)
7197403Sobrien    {
7297403Sobrien      p = read_uleb128 (p, &tmp);
7397403Sobrien      info->TType = p + tmp;
7497403Sobrien    }
7597403Sobrien  else
7697403Sobrien    info->TType = 0;
7797403Sobrien
7897403Sobrien  // The encoding and length of the call-site table; the action table
7997403Sobrien  // immediately follows.
8097403Sobrien  info->call_site_encoding = *p++;
8197403Sobrien  p = read_uleb128 (p, &tmp);
8297403Sobrien  info->action_table = p + tmp;
8397403Sobrien
8497403Sobrien  return p;
8597403Sobrien}
8697403Sobrien
8797403Sobrienstatic const std::type_info *
8897403Sobrienget_ttype_entry (lsda_header_info *info, _Unwind_Word i)
8997403Sobrien{
9097403Sobrien  _Unwind_Ptr ptr;
9197403Sobrien
9297403Sobrien  i *= size_of_encoded_value (info->ttype_encoding);
9397403Sobrien  read_encoded_value_with_base (info->ttype_encoding, info->ttype_base,
9497403Sobrien				info->TType - i, &ptr);
9597403Sobrien
9697403Sobrien  return reinterpret_cast<const std::type_info *>(ptr);
9797403Sobrien}
9897403Sobrien
9997403Sobrien// Given the thrown type THROW_TYPE, pointer to a variable containing a
10097403Sobrien// pointer to the exception object THROWN_PTR_P and a type CATCH_TYPE to
10197403Sobrien// compare against, return whether or not there is a match and if so,
10297403Sobrien// update *THROWN_PTR_P.
10397403Sobrien
10497403Sobrienstatic bool
10597403Sobrienget_adjusted_ptr (const std::type_info *catch_type,
10697403Sobrien		  const std::type_info *throw_type,
10797403Sobrien		  void **thrown_ptr_p)
10897403Sobrien{
10997403Sobrien  void *thrown_ptr = *thrown_ptr_p;
11097403Sobrien
11197403Sobrien  // Pointer types need to adjust the actual pointer, not
11297403Sobrien  // the pointer to pointer that is the exception object.
11397403Sobrien  // This also has the effect of passing pointer types
11497403Sobrien  // "by value" through the __cxa_begin_catch return value.
11597403Sobrien  if (throw_type->__is_pointer_p ())
11697403Sobrien    thrown_ptr = *(void **) thrown_ptr;
11797403Sobrien
11897403Sobrien  if (catch_type->__do_catch (throw_type, &thrown_ptr, 1))
11997403Sobrien    {
12097403Sobrien      *thrown_ptr_p = thrown_ptr;
12197403Sobrien      return true;
12297403Sobrien    }
12397403Sobrien
12497403Sobrien  return false;
12597403Sobrien}
12697403Sobrien
127117397Skan// Return true if THROW_TYPE matches one if the filter types.
128117397Skan
12997403Sobrienstatic bool
13097403Sobriencheck_exception_spec (lsda_header_info *info, const std::type_info *throw_type,
13197403Sobrien		      void *thrown_ptr, _Unwind_Sword filter_value)
13297403Sobrien{
13397403Sobrien  const unsigned char *e = info->TType - filter_value - 1;
13497403Sobrien
13597403Sobrien  while (1)
13697403Sobrien    {
13797403Sobrien      const std::type_info *catch_type;
13897403Sobrien      _Unwind_Word tmp;
13997403Sobrien
14097403Sobrien      e = read_uleb128 (e, &tmp);
14197403Sobrien
14297403Sobrien      // Zero signals the end of the list.  If we've not found
14397403Sobrien      // a match by now, then we've failed the specification.
14497403Sobrien      if (tmp == 0)
14597403Sobrien        return false;
14697403Sobrien
14797403Sobrien      // Match a ttype entry.
14897403Sobrien      catch_type = get_ttype_entry (info, tmp);
14997403Sobrien
15097403Sobrien      // ??? There is currently no way to ask the RTTI code about the
15197403Sobrien      // relationship between two types without reference to a specific
15297403Sobrien      // object.  There should be; then we wouldn't need to mess with
15397403Sobrien      // thrown_ptr here.
15497403Sobrien      if (get_adjusted_ptr (catch_type, throw_type, &thrown_ptr))
15597403Sobrien	return true;
15697403Sobrien    }
15797403Sobrien}
15897403Sobrien
159117397Skan// Return true if the filter spec is empty, ie throw().
160117397Skan
161117397Skanstatic bool
162117397Skanempty_exception_spec (lsda_header_info *info, _Unwind_Sword filter_value)
163117397Skan{
164117397Skan  const unsigned char *e = info->TType - filter_value - 1;
165117397Skan  _Unwind_Word tmp;
166117397Skan
167117397Skan  e = read_uleb128 (e, &tmp);
168117397Skan  return tmp == 0;
169117397Skan}
170117397Skan
17197403Sobrien// Using a different personality function name causes link failures
17297403Sobrien// when trying to mix code using different exception handling models.
173132720Skan#ifdef _GLIBCXX_SJLJ_EXCEPTIONS
17497403Sobrien#define PERSONALITY_FUNCTION	__gxx_personality_sj0
17597403Sobrien#define __builtin_eh_return_data_regno(x) x
17697403Sobrien#else
17797403Sobrien#define PERSONALITY_FUNCTION	__gxx_personality_v0
17897403Sobrien#endif
17997403Sobrien
18097403Sobrienextern "C" _Unwind_Reason_Code
18197403SobrienPERSONALITY_FUNCTION (int version,
18297403Sobrien		      _Unwind_Action actions,
18397403Sobrien		      _Unwind_Exception_Class exception_class,
18497403Sobrien		      struct _Unwind_Exception *ue_header,
18597403Sobrien		      struct _Unwind_Context *context)
18697403Sobrien{
18797403Sobrien  __cxa_exception *xh = __get_exception_header_from_ue (ue_header);
18897403Sobrien
18997403Sobrien  enum found_handler_type
19097403Sobrien  {
19197403Sobrien    found_nothing,
19297403Sobrien    found_terminate,
19397403Sobrien    found_cleanup,
19497403Sobrien    found_handler
19597403Sobrien  } found_type;
19697403Sobrien
19797403Sobrien  lsda_header_info info;
19897403Sobrien  const unsigned char *language_specific_data;
19997403Sobrien  const unsigned char *action_record;
20097403Sobrien  const unsigned char *p;
20197403Sobrien  _Unwind_Ptr landing_pad, ip;
20297403Sobrien  int handler_switch_value;
20397403Sobrien  void *thrown_ptr = xh + 1;
20497403Sobrien
20597403Sobrien  // Interface version check.
20697403Sobrien  if (version != 1)
20797403Sobrien    return _URC_FATAL_PHASE1_ERROR;
20897403Sobrien
20997403Sobrien  // Shortcut for phase 2 found handler for domestic exception.
21097403Sobrien  if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME)
21197403Sobrien      && exception_class == __gxx_exception_class)
21297403Sobrien    {
21397403Sobrien      handler_switch_value = xh->handlerSwitchValue;
214117397Skan      language_specific_data = xh->languageSpecificData;
21597403Sobrien      landing_pad = (_Unwind_Ptr) xh->catchTemp;
21697403Sobrien      found_type = (landing_pad == 0 ? found_terminate : found_handler);
21797403Sobrien      goto install_context;
21897403Sobrien    }
21997403Sobrien
22097403Sobrien  language_specific_data = (const unsigned char *)
22197403Sobrien    _Unwind_GetLanguageSpecificData (context);
22297403Sobrien
22397403Sobrien  // If no LSDA, then there are no handlers or cleanups.
22497403Sobrien  if (! language_specific_data)
22597403Sobrien    return _URC_CONTINUE_UNWIND;
22697403Sobrien
22797403Sobrien  // Parse the LSDA header.
22897403Sobrien  p = parse_lsda_header (context, language_specific_data, &info);
22997403Sobrien  info.ttype_base = base_of_encoded_value (info.ttype_encoding, context);
23097403Sobrien  ip = _Unwind_GetIP (context) - 1;
23197403Sobrien  landing_pad = 0;
23297403Sobrien  action_record = 0;
23397403Sobrien  handler_switch_value = 0;
23497403Sobrien
235132720Skan#ifdef _GLIBCXX_SJLJ_EXCEPTIONS
23697403Sobrien  // The given "IP" is an index into the call-site table, with two
23797403Sobrien  // exceptions -- -1 means no-action, and 0 means terminate.  But
23897403Sobrien  // since we're using uleb128 values, we've not got random access
23997403Sobrien  // to the array.
24097403Sobrien  if ((int) ip < 0)
24197403Sobrien    return _URC_CONTINUE_UNWIND;
24297403Sobrien  else if (ip == 0)
24397403Sobrien    {
24497403Sobrien      // Fall through to set found_terminate.
24597403Sobrien    }
24697403Sobrien  else
24797403Sobrien    {
24897403Sobrien      _Unwind_Word cs_lp, cs_action;
24997403Sobrien      do
25097403Sobrien	{
25197403Sobrien	  p = read_uleb128 (p, &cs_lp);
25297403Sobrien	  p = read_uleb128 (p, &cs_action);
25397403Sobrien	}
25497403Sobrien      while (--ip);
25597403Sobrien
25697403Sobrien      // Can never have null landing pad for sjlj -- that would have
25797403Sobrien      // been indicated by a -1 call site index.
25897403Sobrien      landing_pad = cs_lp + 1;
25997403Sobrien      if (cs_action)
26097403Sobrien	action_record = info.action_table + cs_action - 1;
26197403Sobrien      goto found_something;
26297403Sobrien    }
26397403Sobrien#else
26497403Sobrien  // Search the call-site table for the action associated with this IP.
26597403Sobrien  while (p < info.action_table)
26697403Sobrien    {
26797403Sobrien      _Unwind_Ptr cs_start, cs_len, cs_lp;
26897403Sobrien      _Unwind_Word cs_action;
26997403Sobrien
27097403Sobrien      // Note that all call-site encodings are "absolute" displacements.
27197403Sobrien      p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
27297403Sobrien      p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
27397403Sobrien      p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
27497403Sobrien      p = read_uleb128 (p, &cs_action);
27597403Sobrien
27697403Sobrien      // The table is sorted, so if we've passed the ip, stop.
27797403Sobrien      if (ip < info.Start + cs_start)
27897403Sobrien	p = info.action_table;
27997403Sobrien      else if (ip < info.Start + cs_start + cs_len)
28097403Sobrien	{
28197403Sobrien	  if (cs_lp)
28297403Sobrien	    landing_pad = info.LPStart + cs_lp;
28397403Sobrien	  if (cs_action)
28497403Sobrien	    action_record = info.action_table + cs_action - 1;
28597403Sobrien	  goto found_something;
28697403Sobrien	}
28797403Sobrien    }
288132720Skan#endif // _GLIBCXX_SJLJ_EXCEPTIONS
28997403Sobrien
29097403Sobrien  // If ip is not present in the table, call terminate.  This is for
29197403Sobrien  // a destructor inside a cleanup, or a library routine the compiler
29297403Sobrien  // was not expecting to throw.
293117397Skan  found_type = found_terminate;
29497403Sobrien  goto do_something;
29597403Sobrien
29697403Sobrien found_something:
29797403Sobrien  if (landing_pad == 0)
29897403Sobrien    {
29997403Sobrien      // If ip is present, and has a null landing pad, there are
30097403Sobrien      // no cleanups or handlers to be run.
30197403Sobrien      found_type = found_nothing;
30297403Sobrien    }
30397403Sobrien  else if (action_record == 0)
30497403Sobrien    {
30597403Sobrien      // If ip is present, has a non-null landing pad, and a null
30697403Sobrien      // action table offset, then there are only cleanups present.
30797403Sobrien      // Cleanups use a zero switch value, as set above.
30897403Sobrien      found_type = found_cleanup;
30997403Sobrien    }
31097403Sobrien  else
31197403Sobrien    {
31297403Sobrien      // Otherwise we have a catch handler or exception specification.
31397403Sobrien
31497403Sobrien      _Unwind_Sword ar_filter, ar_disp;
31597403Sobrien      const std::type_info *throw_type, *catch_type;
31697403Sobrien      bool saw_cleanup = false;
31797403Sobrien      bool saw_handler = false;
31897403Sobrien
31997403Sobrien      // During forced unwinding, we only run cleanups.  With a foreign
32097403Sobrien      // exception class, there's no exception type.
32197403Sobrien      // ??? What to do about GNU Java and GNU Ada exceptions.
32297403Sobrien
32397403Sobrien      if ((actions & _UA_FORCE_UNWIND)
32497403Sobrien	  || exception_class != __gxx_exception_class)
32597403Sobrien	throw_type = 0;
32697403Sobrien      else
32797403Sobrien	throw_type = xh->exceptionType;
32897403Sobrien
32997403Sobrien      while (1)
33097403Sobrien	{
33197403Sobrien	  p = action_record;
33297403Sobrien	  p = read_sleb128 (p, &ar_filter);
33397403Sobrien	  read_sleb128 (p, &ar_disp);
33497403Sobrien
33597403Sobrien	  if (ar_filter == 0)
33697403Sobrien	    {
33797403Sobrien	      // Zero filter values are cleanups.
33897403Sobrien	      saw_cleanup = true;
33997403Sobrien	    }
34097403Sobrien	  else if (ar_filter > 0)
34197403Sobrien	    {
34297403Sobrien	      // Positive filter values are handlers.
34397403Sobrien	      catch_type = get_ttype_entry (&info, ar_filter);
34497403Sobrien
345117397Skan	      // Null catch type is a catch-all handler; we can catch foreign
346117397Skan	      // exceptions with this.  Otherwise we must match types.
347117397Skan	      if (! catch_type
348117397Skan		  || (throw_type
349117397Skan		      && get_adjusted_ptr (catch_type, throw_type,
350117397Skan					   &thrown_ptr)))
35197403Sobrien		{
352117397Skan		  saw_handler = true;
353117397Skan		  break;
35497403Sobrien		}
35597403Sobrien	    }
35697403Sobrien	  else
35797403Sobrien	    {
35897403Sobrien	      // Negative filter values are exception specifications.
35997403Sobrien	      // ??? How do foreign exceptions fit in?  As far as I can
36097403Sobrien	      // see we can't match because there's no __cxa_exception
36197403Sobrien	      // object to stuff bits in for __cxa_call_unexpected to use.
362117397Skan	      // Allow them iff the exception spec is non-empty.  I.e.
363117397Skan	      // a throw() specification results in __unexpected.
36497403Sobrien	      if (throw_type
365117397Skan		  ? ! check_exception_spec (&info, throw_type, thrown_ptr,
366117397Skan					    ar_filter)
367117397Skan		  : empty_exception_spec (&info, ar_filter))
36897403Sobrien		{
36997403Sobrien		  saw_handler = true;
37097403Sobrien		  break;
37197403Sobrien		}
37297403Sobrien	    }
37397403Sobrien
37497403Sobrien	  if (ar_disp == 0)
37597403Sobrien	    break;
37697403Sobrien	  action_record = p + ar_disp;
37797403Sobrien	}
37897403Sobrien
37997403Sobrien      if (saw_handler)
38097403Sobrien	{
38197403Sobrien	  handler_switch_value = ar_filter;
38297403Sobrien	  found_type = found_handler;
38397403Sobrien	}
38497403Sobrien      else
38597403Sobrien	found_type = (saw_cleanup ? found_cleanup : found_nothing);
38697403Sobrien    }
38797403Sobrien
38897403Sobrien do_something:
38997403Sobrien   if (found_type == found_nothing)
39097403Sobrien     return _URC_CONTINUE_UNWIND;
39197403Sobrien
39297403Sobrien  if (actions & _UA_SEARCH_PHASE)
39397403Sobrien    {
39497403Sobrien      if (found_type == found_cleanup)
39597403Sobrien	return _URC_CONTINUE_UNWIND;
39697403Sobrien
39797403Sobrien      // For domestic exceptions, we cache data from phase 1 for phase 2.
39897403Sobrien      if (exception_class == __gxx_exception_class)
39997403Sobrien        {
40097403Sobrien          xh->handlerSwitchValue = handler_switch_value;
40197403Sobrien          xh->actionRecord = action_record;
40297403Sobrien          xh->languageSpecificData = language_specific_data;
40397403Sobrien          xh->adjustedPtr = thrown_ptr;
40497403Sobrien
40597403Sobrien          // ??? Completely unknown what this field is supposed to be for.
40697403Sobrien          // ??? Need to cache TType encoding base for call_unexpected.
407117397Skan          xh->catchTemp = landing_pad;
40897403Sobrien	}
40997403Sobrien      return _URC_HANDLER_FOUND;
41097403Sobrien    }
41197403Sobrien
41297403Sobrien install_context:
413117397Skan  // We can't use any of the cxa routines with foreign exceptions,
414117397Skan  // because they all expect ue_header to be a struct __cxa_exception.
415117397Skan  // So in that case, call terminate or unexpected directly.
416117397Skan  if ((actions & _UA_FORCE_UNWIND)
417117397Skan      || exception_class != __gxx_exception_class)
41897403Sobrien    {
419117397Skan      if (found_type == found_terminate)
420117397Skan	std::terminate ();
421117397Skan      else if (handler_switch_value < 0)
422117397Skan	{
423117397Skan	  try
424117397Skan	    { std::unexpected (); }
425117397Skan	  catch(...)
426117397Skan	    { std::terminate (); }
427117397Skan	}
42897403Sobrien    }
429117397Skan  else
430117397Skan    {
431117397Skan      if (found_type == found_terminate)
432117397Skan	{
433117397Skan	  __cxa_begin_catch (&xh->unwindHeader);
434117397Skan	  __terminate (xh->terminateHandler);
435117397Skan	}
43697403Sobrien
437117397Skan      // Cache the TType base value for __cxa_call_unexpected, as we won't
438117397Skan      // have an _Unwind_Context then.
439117397Skan      if (handler_switch_value < 0)
440117397Skan	{
441117397Skan	  parse_lsda_header (context, language_specific_data, &info);
442117397Skan	  xh->catchTemp = base_of_encoded_value (info.ttype_encoding, context);
443117397Skan	}
44497403Sobrien    }
44597403Sobrien
446132720Skan  /* For targets with pointers smaller than the word size, we must extend the
447132720Skan     pointer, and this extension is target dependent.  */
44897403Sobrien  _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
449132720Skan		 __builtin_extend_pointer (&xh->unwindHeader));
45097403Sobrien  _Unwind_SetGR (context, __builtin_eh_return_data_regno (1),
45197403Sobrien		 handler_switch_value);
45297403Sobrien  _Unwind_SetIP (context, landing_pad);
45397403Sobrien  return _URC_INSTALL_CONTEXT;
45497403Sobrien}
45597403Sobrien
45697403Sobrienextern "C" void
45797403Sobrien__cxa_call_unexpected (void *exc_obj_in)
45897403Sobrien{
45997403Sobrien  _Unwind_Exception *exc_obj
46097403Sobrien    = reinterpret_cast <_Unwind_Exception *>(exc_obj_in);
46197403Sobrien
46297403Sobrien  __cxa_begin_catch (exc_obj);
46397403Sobrien
46497403Sobrien  // This function is a handler for our exception argument.  If we exit
46597403Sobrien  // by throwing a different exception, we'll need the original cleaned up.
46697403Sobrien  struct end_catch_protect
46797403Sobrien  {
46897403Sobrien    end_catch_protect() { }
46997403Sobrien    ~end_catch_protect() { __cxa_end_catch(); }
47097403Sobrien  } end_catch_protect_obj;
47197403Sobrien
47297403Sobrien  lsda_header_info info;
47397403Sobrien  __cxa_exception *xh = __get_exception_header_from_ue (exc_obj);
47497403Sobrien  const unsigned char *xh_lsda;
47597403Sobrien  _Unwind_Sword xh_switch_value;
47697403Sobrien  std::terminate_handler xh_terminate_handler;
47797403Sobrien
47897403Sobrien  // If the unexpectedHandler rethrows the exception (e.g. to categorize it),
47997403Sobrien  // it will clobber data about the current handler.  So copy the data out now.
48097403Sobrien  xh_lsda = xh->languageSpecificData;
48197403Sobrien  xh_switch_value = xh->handlerSwitchValue;
48297403Sobrien  xh_terminate_handler = xh->terminateHandler;
48397403Sobrien  info.ttype_base = (_Unwind_Ptr) xh->catchTemp;
48497403Sobrien
48597403Sobrien  try
48697403Sobrien    { __unexpected (xh->unexpectedHandler); }
48797403Sobrien  catch(...)
48897403Sobrien    {
48997403Sobrien      // Get the exception thrown from unexpected.
490117397Skan
49197403Sobrien      __cxa_eh_globals *globals = __cxa_get_globals_fast ();
49297403Sobrien      __cxa_exception *new_xh = globals->caughtExceptions;
49397403Sobrien      void *new_ptr = new_xh + 1;
494117397Skan
49597403Sobrien      // We don't quite have enough stuff cached; re-parse the LSDA.
49697403Sobrien      parse_lsda_header (0, xh_lsda, &info);
497117397Skan
49897403Sobrien      // If this new exception meets the exception spec, allow it.
49997403Sobrien      if (check_exception_spec (&info, new_xh->exceptionType,
50097403Sobrien				new_ptr, xh_switch_value))
50197403Sobrien	__throw_exception_again;
502117397Skan
50397403Sobrien      // If the exception spec allows std::bad_exception, throw that.
50497403Sobrien      // We don't have a thrown object to compare against, but since
50597403Sobrien      // bad_exception doesn't have virtual bases, that's OK; just pass 0.
50697403Sobrien#ifdef __EXCEPTIONS
50797403Sobrien      const std::type_info &bad_exc = typeid (std::bad_exception);
50897403Sobrien      if (check_exception_spec (&info, &bad_exc, 0, xh_switch_value))
50997403Sobrien	throw std::bad_exception();
51097403Sobrien#endif
511117397Skan
51297403Sobrien      // Otherwise, die.
51397403Sobrien      __terminate (xh_terminate_handler);
51497403Sobrien    }
51597403Sobrien}
516