Example #1
0
_Unwind_Reason_Code
PERSONALITY_FUNCTION (int version,
		      _Unwind_Action actions,
		      _Unwind_Exception_Class exception_class ATTRIBUTE_UNUSED,
		      struct _Unwind_Exception *ue_header,
		      struct _Unwind_Context *context)
/* APPLE LOCAL begin LLVM */
#endif
/* APPLE LOCAL end LLVM */
{
  lsda_header_info info;
  const unsigned char *language_specific_data, *p, *action_record;
  _Unwind_Ptr landing_pad, ip;

/* APPLE LOCAL begin LLVM */
#ifdef __ARM_EABI_UNWINDER__
  if (state != _US_UNWIND_FRAME_STARTING)
    CONTINUE_UNWINDING;

  /* 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);
#else
/* APPLE LOCAL end LLVM */
  if (version != 1)
    return _URC_FATAL_PHASE1_ERROR;

  /* Currently we only support cleanups for C.  */
  if ((actions & _UA_CLEANUP_PHASE) == 0)
/* APPLE LOCAL begin LLVM */
    CONTINUE_UNWINDING;
#endif
/* APPLE LOCAL end LLVM */

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

  /* If no LSDA, then there are no handlers or cleanups.  */
  if (! language_specific_data)
/* APPLE LOCAL begin LLVM */
    CONTINUE_UNWINDING;
/* APPLE LOCAL end LLVM */

  /* Parse the LSDA header.  */
  p = parse_lsda_header (context, language_specific_data, &info);
  ip = _Unwind_GetIP (context) - 1;
  landing_pad = 0;

#ifdef __USING_SJLJ_EXCEPTIONS__
  /* 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
    {
      _Unwind_Word cs_lp, cs_action;
      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;
    }
#else
  /* Search the call-site table for the action associated with this IP.  */
  while (p < info.action_table)
    {
      _Unwind_Ptr cs_start, cs_len, cs_lp;
      _Unwind_Word cs_action;

      /* 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

  /* IP is not in table.  No associated cleanups.  */
  /* ??? This is where C++ calls std::terminate to catch throw
     from a destructor.  */
/* APPLE LOCAL begin LLVM */
  CONTINUE_UNWINDING;
/* APPLE LOCAL end LLVM */

 found_something:
  if (landing_pad == 0)
    {
      /* IP is present, but has a null landing pad.
	 No handler to be run.  */
/* APPLE LOCAL begin LLVM */
      CONTINUE_UNWINDING;
/* APPLE LOCAL end LLVM */
    }

  _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
		 (_Unwind_Ptr) ue_header);
  _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0);
  _Unwind_SetIP (context, landing_pad);
  return _URC_INSTALL_CONTEXT;
}
Example #2
0
PERSONALITY_FUNCTION (int version,
		      _Unwind_Action actions,
		      _Unwind_Exception_Class exception_class,
		      struct _Unwind_Exception *ue_header,
		      struct _Unwind_Context *context)
#endif
{
  struct ObjcException *xh = (struct ObjcException *) ue_header;

  struct 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;
  int saw_cleanup = 0, saw_handler;
  void *return_object;
  int foreign_exception;
  int ip_before_insn = 0;

#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:
      abort();
    }
  actions |= state & _US_FORCE_UNWIND;

  foreign_exception = 0;

  ip = (_Unwind_Ptr) ue_header;
  _Unwind_SetGR(context, 12, ip);
#else
  /* Interface version check.  */
  if (version != 1)
    return _URC_FATAL_PHASE1_ERROR;
  foreign_exception = !(exception_class == __objc_exception_class);
#endif

  /* Shortcut for phase 2 found handler for domestic exception.  */
  if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME)
      && !foreign_exception)
    {
#ifdef __ARM_EABI_UNWINDER__
      handler_switch_value = (int) ue_header->barrier_cache.bitpattern[1];
      landing_pad = (_Unwind_Ptr) ue_header->barrier_cache.bitpattern[3];
#else
      handler_switch_value = xh->handlerSwitchValue;
      landing_pad = xh->landingPad;
#endif
      goto install_context;
    }

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

  /* If no LSDA, then there are no handlers or cleanups.  */
  if (! language_specific_data)
    CONTINUE_UNWINDING;

  /* Parse the LSDA header.  */
  p = parse_lsda_header (context, language_specific_data, &info);
  info.ttype_base = base_of_encoded_value (info.ttype_encoding, context);
#ifdef HAVE_GETIPINFO
  ip = _Unwind_GetIPInfo (context, &ip_before_insn);
#else
  ip = _Unwind_GetIP (context);
#endif
  if (! ip_before_insn)
    --ip;
  landing_pad = 0;
  action_record = 0;
  handler_switch_value = 0;

#ifdef SJLJ_EXCEPTIONS
  /* 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
    {
      _Unwind_Word cs_lp, cs_action;
      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;
    }
#else
  /* Search the call-site table for the action associated with this IP.  */
  while (p < info.action_table)
    {
      _Unwind_Ptr cs_start, cs_len, cs_lp;
      _Unwind_Word cs_action;

      /* 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  */

  /* If ip is not present in the table, C++ would call terminate.  */
  /* ??? As with Java, it's perhaps better to tweek the LSDA to
     that no-action is mapped to no-entry.  */
  return _URC_CONTINUE_UNWIND;

 found_something:
  saw_cleanup = 0;
  saw_handler = 0;

  if (landing_pad == 0)
    {
      /* 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 = 1;
    }
  else
    {
      /* Otherwise we have a catch handler.  */
      _Unwind_Sword ar_filter, ar_disp;

      while (1)
	{
	  p = action_record;
	  p = read_sleb128 (p, &ar_filter);
	  read_sleb128 (p, &ar_disp);

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

	  /* 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)
		   || foreign_exception)
	    ;

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

	      Class catch_type = get_ttype_entry (&info, ar_filter);

	      if (isKindOf (xh->value, catch_type))
		{
		  handler_switch_value = ar_filter;
		  saw_handler = 1;
		  break;
		}
	    }
	  else
	    {
	      /* Negative filter values are exception specifications,
	         which Objective-C does not use.  */
	      abort ();
	    }

	  if (ar_disp == 0)
	    break;
	  action_record = p + ar_disp;
	}
    }

  if (! saw_handler && ! saw_cleanup)
    CONTINUE_UNWINDING;

  if (actions & _UA_SEARCH_PHASE)
    {
      if (!saw_handler)
	CONTINUE_UNWINDING;

      /* For domestic exceptions, we cache data from phase 1 for phase 2.  */
      if (!foreign_exception)
        {
#ifdef __ARM_EABI_UNWIDER__
	  ue_header->barrier_cache.sp = _Unwind_GetGR(context, 13);
	  ue_header->barrier_cache.bitpattern[1]
	    = (_uw) handler_switch_value;
	  ue_header->barrier_cache.bitpattern[3] = (_uw) landing_pad;
#else
          xh->handlerSwitchValue = handler_switch_value;
          xh->landingPad = landing_pad;
#endif
	}
      return _URC_HANDLER_FOUND;
    }

 install_context:
  if (saw_cleanup == 0)
    {
      return_object = xh->value;
      if (!(actions & _UA_SEARCH_PHASE))
	_Unwind_DeleteException(&xh->base);
    }
  
  _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
		 __builtin_extend_pointer (saw_cleanup ? xh : return_object));
  _Unwind_SetGR (context, __builtin_eh_return_data_regno (1),
		 handler_switch_value);
  _Unwind_SetIP (context, landing_pad);
  return _URC_INSTALL_CONTEXT;
}
Example #3
0
// The stack-unwinding loop.
static inline void unwind_loop(ExcInfo* exc_data) {
    // NB. https://monoinfinito.wordpress.com/series/exception-handling-in-c/ is a very useful resource
    // as are http://www.airs.com/blog/archives/460 and http://www.airs.com/blog/archives/464
    unw_cursor_t cursor;
    unw_context_t uc; // exists only to initialize cursor
#ifndef NDEBUG
    // poison stack memory. have had problems with these structures being insufficiently initialized.
    memset(&uc, 0xef, sizeof uc);
    memset(&cursor, 0xef, sizeof cursor);
#endif
    unw_getcontext(&uc);
    unw_init_local(&cursor, &uc);

    auto unwind_session = getActivePythonUnwindSession();

    while (unw_step(&cursor) > 0) {
        unw_proc_info_t pip;

        static StatCounter frames_unwound("num_frames_unwound_cxx");
        frames_unwound.log();

        // NB. unw_get_proc_info is slow; a significant chunk of all time spent unwinding is spent here.
        check(unw_get_proc_info(&cursor, &pip));

        assert((pip.lsda == 0) == (pip.handler == 0));
        assert(pip.flags == 0);

        if (VERBOSITY("cxx_unwind") >= 4) {
            print_frame(&cursor, &pip);
        }

        // let the PythonUnwindSession know that we're in a new frame,
        // giving it a chance to possibly add a traceback entry for
        // it.
        unwindingThroughFrame(unwind_session, &cursor);

        // Skip frames without handlers
        if (pip.handler == 0) {
            continue;
        }

        RELEASE_ASSERT(pip.handler == (uintptr_t)__gxx_personality_v0,
                       "personality function other than __gxx_personality_v0; "
                       "don't know how to unwind through non-C++ functions");

        // Don't call __gxx_personality_v0; we perform dispatch ourselves.
        // 1. parse LSDA header
        lsda_info_t info;
        parse_lsda_header(&pip, &info);

        call_site_entry_t entry;
        {
            // 2. Find our current IP in the call site table.
            unw_word_t ip;
            unw_get_reg(&cursor, UNW_REG_IP, &ip);
            // ip points to the instruction *after* the instruction that caused the error - which is generally (always?)
            // a call instruction - UNLESS we're in a signal frame, in which case it points at the instruction that
            // caused the error. For now, we assume we're never in a signal frame. So, we decrement it by one.
            //
            // TODO: double-check that we never hit a signal frame.
            --ip;

            bool found = find_call_site_entry(&info, (const uint8_t*)ip, &entry);
            // If we didn't find an entry, an exception happened somewhere exceptions should never happen; terminate
            // immediately.
            if (!found) {
                panic();
            }
        }

        // 3. Figure out what to do based on the call site entry.
        if (!entry.landing_pad) {
            // No landing pad means no exception handling or cleanup; keep unwinding!
            continue;
        }
        // After this point we are guaranteed to resume something rather than unwinding further.

        if (VERBOSITY("cxx_unwind") >= 4) {
            print_lsda(&info);
        }

        int64_t switch_value = determine_action(&info, &entry);
        if (switch_value != CLEANUP_ACTION) {
            // we're transfering control to a non-cleanup landing pad.
            // i.e. a catch block.  thus ends our unwind session.
            endPythonUnwindSession(unwind_session);
#if STAT_TIMERS
            pyston::StatTimer::finishOverride();
#endif
        }
        static_assert(THREADING_USE_GIL, "have to make the unwind session usage in this file thread safe!");
        // there is a python unwinding implementation detail leaked
        // here - that the unwind session can be ended but its
        // exception storage is still around.
        //
        // this manifests itself as this short window here where we've
        // (possibly) ended the unwind session above but we still need
        // to pass exc_data (which is the exceptionStorage for this
        // unwind session) to resume().
        //
        // the only way this could bite us is if we somehow clobber
        // the PythonUnwindSession's storage, or cause a GC to occur, before
        // transfering control to the landing pad in resume().
        //
        resume(&cursor, entry.landing_pad, switch_value, exc_data);
    }

    // Hit end of stack! return & let unwindException determine what to do.
}
Example #4
0
_Unwind_Reason_Code
PERSONALITY_FUNCTION (int version,
		      _Unwind_Action actions,
		      _Unwind_Exception_Class exception_class,
		      struct _Unwind_Exception *ue_header,
		      struct _Unwind_Context *context)
#endif
{
  lsda_header_info info;
  const unsigned char *language_specific_data, *p, *action_record;
  _Unwind_Ptr landing_pad, ip;
  int ip_before_insn = 0;
  _Bool is_foreign;
  G *g;

#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:
      abort();
    }
  actions |= state & _US_FORCE_UNWIND;

  is_foreign = 0;

  /* 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);
#else
  if (version != 1)
    return _URC_FATAL_PHASE1_ERROR;

  is_foreign = exception_class != __go_exception_class;
#endif

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

  /* If no LSDA, then there are no handlers or cleanups.  */
  if (! language_specific_data)
    CONTINUE_UNWINDING;

  /* Parse the LSDA header.  */
  p = parse_lsda_header (context, language_specific_data, &info);
#ifdef HAVE_GETIPINFO
  ip = _Unwind_GetIPInfo (context, &ip_before_insn);
#else
  ip = _Unwind_GetIP (context);
#endif
  if (! ip_before_insn)
    --ip;
  landing_pad = 0;
  action_record = NULL;

#ifdef __USING_SJLJ_EXCEPTIONS__
  /* 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
    {
      _uleb128_t cs_lp, cs_action;
      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 = (_Unwind_Ptr)cs_lp + 1;
      if (cs_action)
	action_record = info.action_table + cs_action - 1;
      goto found_something;
    }
#else
  /* Search the call-site table for the action associated with this IP.  */
  while (p < info.action_table)
    {
      _Unwind_Ptr cs_start, cs_len, cs_lp;
      _uleb128_t cs_action;

      /* 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

  /* IP is not in table.  No associated cleanups.  */
  CONTINUE_UNWINDING;

 found_something:
  if (landing_pad == 0)
    {
      /* IP is present, but has a null landing pad.
	 No handler to be run.  */
      CONTINUE_UNWINDING;
    }

  if (actions & _UA_SEARCH_PHASE)
    {
      if (action_record == 0)
	{
	  /* This indicates a cleanup rather than an exception
	     handler.  */
	  CONTINUE_UNWINDING;
	}

      return _URC_HANDLER_FOUND;
    }

  /* It's possible for g to be NULL here for an exception thrown by a
     language other than Go.  */
  g = runtime_g ();
  if (g == NULL)
    {
      if (!is_foreign)
	abort ();
    }
  else
    {
      g->exception = ue_header;
      g->isforeign = is_foreign;
    }

  _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
		 (_Unwind_Ptr) ue_header);
  _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0);
  _Unwind_SetIP (context, landing_pad);
  return _URC_INSTALL_CONTEXT;
}
Example #5
0
_Unwind_Reason_Code __runa_personality(int version,
  _Unwind_Action actions, _Unwind_Exception_Class exception_class,
  struct _Unwind_Exception *ue_header, struct _Unwind_Context *context) {

  enum found_handler_type {
    found_nothing, found_terminate, found_cleanup, found_handler
  } found_type;

  struct 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;
  void* thrown_ptr = 0;
  bool foreign_exception;
  int ip_before_insn = 0;

  //__cxa_exception* xh = __get_exception_header_from_ue(ue_header);

  // Interface version check.
  if (version != 1)
    return _URC_FATAL_PHASE1_ERROR;

  foreign_exception = exception_class != RUNA_CLASS;

  // Shortcut for phase 2 found handler for domestic exception.
  if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME) && !foreign_exception) {
    restore_caught_exception(ue_header, &handler_switch_value,
                             &language_specific_data, &landing_pad);
    found_type = (landing_pad == 0 ? found_terminate : found_handler);
    goto install_context;
  }

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

  // If no LSDA, then there are no handlers or cleanups.
  if (!language_specific_data)
    return _URC_CONTINUE_UNWIND;

  // Parse the LSDA header.
  p = parse_lsda_header(context, language_specific_data, &info);
  info.ttype_base = base_of_encoded_value(info.ttype_encoding, context);
  ip = _Unwind_GetIPInfo(context, &ip_before_insn);
  //ip = _Unwind_GetIP(context);
  if (!ip_before_insn)
    --ip;

  landing_pad = 0;
  action_record = 0;
  handler_switch_value = 0;

  // Search the call-site table for the action associated with this IP.
  while (p < info.action_table) {

    _Unwind_Ptr cs_start, cs_len, cs_lp;
    _uleb128_t cs_action;

    // 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;
    }

  }

  // If ip is not present in the table, call terminate. This is for
  // a destructor inside a cleanup, or a library routine the compiler
  // was not expecting to throw.
  found_type = found_terminate;
  goto do_something;

 found_something:
  if (landing_pad == 0) {
    // If ip is present, and has a null landing pad, there are
    // no cleanups or handlers to be run.
    found_type = found_nothing;
  } 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.
    found_type = found_cleanup;
  } else {

    // Otherwise we have a catch handler or exception specification.
    _sleb128_t ar_filter, ar_disp;
    //const std::type_info* catch_type;
    //_throw_typet* throw_type;
    bool saw_cleanup = false;
    bool saw_handler = false;

    {
      //thrown_ptr = __get_object_from_ue(ue_header);
      //throw_type = __get_exception_header_from_obj(thrown_ptr)->exceptionType;
    }

    while (1) {

      p = action_record;
      p = read_sleb128(p, &ar_filter);
      read_sleb128(p, &ar_disp);

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

        // Positive filter values are handlers.
        //catch_type = get_ttype_entry(&info, ar_filter);
        //printf("positive filter value -- handler found\n");
        saw_handler = true;
        break;

        // Null catch type is a catch-all handler; we can catch foreign
        // exceptions with this. Otherwise we must match types.

        //if (!catch_type || (throw_type &&
        //                    get_adjusted_ptr(catch_type, throw_type, &thrown_ptr))) {
        //  saw_handler = true;
        //  break;
        //}

      } else {

        printf("negative filter value -- exception spec\n");
        // Negative filter values are exception specifications.
        // ??? How do foreign exceptions fit in?  As far as I can
        // see we can't match because there's no __cxa_exception
        // object to stuff bits in for __cxa_call_unexpected to use.
        // Allow them iff the exception spec is non-empty.  I.e.
        // a throw() specification results in __unexpected.

        //if ((throw_type && !(actions & _UA_FORCE_UNWIND) && !foreign_exception) ?
        //    !check_exception_spec(&info, throw_type, thrown_ptr, ar_filter) :
        //    empty_exception_spec(&info, ar_filter)) {
        //  saw_handler = true;
        //  break;
        //}

      }

      if (ar_disp == 0)
        break;
      action_record = p + ar_disp;

    }

    if (saw_handler) {
      handler_switch_value = ar_filter;
      found_type = found_handler;
    } else {
      found_type = (saw_cleanup ? found_cleanup : found_nothing);
    }

  }

 do_something:

   if (found_type == found_nothing)
     return _URC_CONTINUE_UNWIND;

  if (actions & _UA_SEARCH_PHASE) {

    if (found_type == found_cleanup)
      return _URC_CONTINUE_UNWIND;

    // For domestic exceptions, we cache data from phase 1 for phase 2.
    if (!foreign_exception) {
      save_caught_exception(ue_header, handler_switch_value,
                            language_specific_data, landing_pad);
    }

    return _URC_HANDLER_FOUND;
  }

 install_context:

  // We can't use any of the cxa routines with foreign exceptions,
  // because they all expect ue_header to be a struct __cxa_exception.
  // So in that case, call terminate or unexpected directly.
  if ((actions & _UA_FORCE_UNWIND) || foreign_exception) {

    if (found_type == found_terminate)
      abort(); // std::terminate();
    else if (handler_switch_value < 0) {
      printf("WTF\n");
      //__try
      //  { std::unexpected (); }
      //__catch(...)
      //  { std::terminate (); }
    }

  } else {

    if (found_type == found_terminate)
      abort(); //__cxa_call_terminate(ue_header);

    // Cache the TType base value for __cxa_call_unexpected, as we won't
    // have an _Unwind_Context then.
    if (handler_switch_value < 0) {
      parse_lsda_header(context, language_specific_data, &info);
      info.ttype_base = base_of_encoded_value(info.ttype_encoding, context);
      //xh->catchTemp = base_of_encoded_value (info.ttype_encoding, context);
    }

  }

  /* For targets with pointers smaller than the word size, we must extend the
     pointer, and this extension is target dependent.  */
  _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), __builtin_extend_pointer(ue_header));
  _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), handler_switch_value);
  _Unwind_SetIP(context, landing_pad);
  return _URC_INSTALL_CONTEXT;

}