198524Sfenner// -*- C++ -*- The GNU C++ exception personality routine.
298524Sfenner// Copyright (C) 2001, 2002, 2003, 2006, 2008 Free Software Foundation, Inc.
398524Sfenner//
498524Sfenner// This file is part of GCC.
598524Sfenner//
698524Sfenner// GCC is free software; you can redistribute it and/or modify
798524Sfenner// it under the terms of the GNU General Public License as published by
898524Sfenner// the Free Software Foundation; either version 2, or (at your option)
998524Sfenner// any later version.
1098524Sfenner//
1198524Sfenner// GCC is distributed in the hope that it will be useful,
1298524Sfenner// but WITHOUT ANY WARRANTY; without even the implied warranty of
1398524Sfenner// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1498524Sfenner// GNU General Public License for more details.
1598524Sfenner//
1698524Sfenner// You should have received a copy of the GNU General Public License
1798524Sfenner// along with GCC; see the file COPYING.  If not, write to
1898524Sfenner// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
1998524Sfenner// Boston, MA 02110-1301, USA.
2098524Sfenner
2198524Sfenner// As a special exception, you may use this file as part of a free software
2298524Sfenner// library without restriction.  Specifically, if other files instantiate
2398524Sfenner// templates or use macros or inline functions from this file, or you compile
2498524Sfenner// this file and link it with other files to produce an executable, this
2598524Sfenner// file does not by itself cause the resulting executable to be covered by
26127668Sbms// the GNU General Public License.  This exception does not however
27190207Srpaulo// invalidate any other reasons why the executable file might be covered by
2898524Sfenner// the GNU General Public License.
2998524Sfenner
3098524Sfenner#include <bits/c++config.h>
3198524Sfenner#include <cstdlib>
3298524Sfenner#include <exception_defines.h>
3398524Sfenner#include "unwind-cxx.h"
34127668Sbms
35127668Sbmsusing namespace __cxxabiv1;
3698524Sfenner
3798524Sfenner#ifdef __ARM_EABI_UNWINDER__
3898524Sfenner#define NO_SIZE_OF_ENCODED_VALUE
39127668Sbms#endif
4098524Sfenner
4198524Sfenner#include "unwind-pe.h"
4298524Sfenner
4398524Sfenner
4498524Sfennerstruct lsda_header_info
4598524Sfenner{
4698524Sfenner  _Unwind_Ptr Start;
4798524Sfenner  _Unwind_Ptr LPStart;
4898524Sfenner  _Unwind_Ptr ttype_base;
49127668Sbms  const unsigned char *TType;
5098524Sfenner  const unsigned char *action_table;
5198524Sfenner  unsigned char ttype_encoding;
5298524Sfenner  unsigned char call_site_encoding;
5398524Sfenner};
5498524Sfenner
5598524Sfennerstatic const unsigned char *
5698524Sfennerparse_lsda_header (_Unwind_Context *context, const unsigned char *p,
5798524Sfenner		   lsda_header_info *info)
5898524Sfenner{
5998524Sfenner  _Unwind_Word tmp;
6098524Sfenner  unsigned char lpstart_encoding;
6198524Sfenner
6298524Sfenner  info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
6398524Sfenner
6498524Sfenner  // Find @LPStart, the base to which landing pad offsets are relative.
6598524Sfenner  lpstart_encoding = *p++;
6698524Sfenner  if (lpstart_encoding != DW_EH_PE_omit)
6798524Sfenner    p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
6898524Sfenner  else
69127668Sbms    info->LPStart = info->Start;
7098524Sfenner
7198524Sfenner  // Find @TType, the base of the handler and exception spec type data.
7298524Sfenner  info->ttype_encoding = *p++;
7398524Sfenner  if (info->ttype_encoding != DW_EH_PE_omit)
7498524Sfenner    {
7598524Sfenner      p = read_uleb128 (p, &tmp);
7698524Sfenner      info->TType = p + tmp;
7798524Sfenner    }
7898524Sfenner  else
7998524Sfenner    info->TType = 0;
8098524Sfenner
8198524Sfenner  // The encoding and length of the call-site table; the action table
8298524Sfenner  // immediately follows.
8398524Sfenner  info->call_site_encoding = *p++;
8498524Sfenner  p = read_uleb128 (p, &tmp);
8598524Sfenner  info->action_table = p + tmp;
8698524Sfenner
8798524Sfenner  return p;
8898524Sfenner}
8998524Sfenner
9098524Sfenner#ifdef __ARM_EABI_UNWINDER__
9198524Sfenner
9298524Sfenner// Return an element from a type table.
9398524Sfenner
9498524Sfennerstatic const std::type_info*
9598524Sfennerget_ttype_entry(lsda_header_info* info, _Unwind_Word i)
9698524Sfenner{
9798524Sfenner  _Unwind_Ptr ptr;
9898524Sfenner
9998524Sfenner  ptr = (_Unwind_Ptr) (info->TType - (i * 4));
10098524Sfenner  ptr = _Unwind_decode_target2(ptr);
10198524Sfenner
10298524Sfenner  return reinterpret_cast<const std::type_info *>(ptr);
10398524Sfenner}
10498524Sfenner
10598524Sfenner// The ABI provides a routine for matching exception object types.
10698524Sfennertypedef _Unwind_Control_Block _throw_typet;
10798524Sfenner#define get_adjusted_ptr(catch_type, throw_type, thrown_ptr_p) \
10898524Sfenner  (__cxa_type_match (throw_type, catch_type, false, thrown_ptr_p) \
10998524Sfenner   != ctm_failed)
11098524Sfenner
11198524Sfenner// Return true if THROW_TYPE matches one if the filter types.
11298524Sfenner
11398524Sfennerstatic bool
11498524Sfennercheck_exception_spec(lsda_header_info* info, _throw_typet* throw_type,
11598524Sfenner		     void* thrown_ptr, _Unwind_Sword filter_value)
11698524Sfenner{
11798524Sfenner  const _Unwind_Word* e = ((const _Unwind_Word*) info->TType)
11898524Sfenner			  - filter_value - 1;
11998524Sfenner
12098524Sfenner  while (1)
12198524Sfenner    {
12298524Sfenner      const std::type_info* catch_type;
12398524Sfenner      _Unwind_Word tmp;
12498524Sfenner
12598524Sfenner      tmp = *e;
12698524Sfenner
12798524Sfenner      // Zero signals the end of the list.  If we've not found
12898524Sfenner      // a match by now, then we've failed the specification.
12998524Sfenner      if (tmp == 0)
13098524Sfenner        return false;
13198524Sfenner
13298524Sfenner      tmp = _Unwind_decode_target2((_Unwind_Word) e);
13398524Sfenner
13498524Sfenner      // Match a ttype entry.
13598524Sfenner      catch_type = reinterpret_cast<const std::type_info*>(tmp);
13698524Sfenner
13798524Sfenner      // ??? There is currently no way to ask the RTTI code about the
13898524Sfenner      // relationship between two types without reference to a specific
13998524Sfenner      // object.  There should be; then we wouldn't need to mess with
14098524Sfenner      // thrown_ptr here.
14198524Sfenner      if (get_adjusted_ptr(catch_type, throw_type, &thrown_ptr))
14298524Sfenner	return true;
14398524Sfenner
14498524Sfenner      // Advance to the next entry.
14598524Sfenner      e++;
14698524Sfenner    }
14798524Sfenner}
14898524Sfenner
14998524Sfenner
15098524Sfenner// Save stage1 handler information in the exception object
15198524Sfenner
15298524Sfennerstatic inline void
15398524Sfennersave_caught_exception(struct _Unwind_Exception* ue_header,
15498524Sfenner		      struct _Unwind_Context* context,
15598524Sfenner		      void* thrown_ptr,
15698524Sfenner		      int handler_switch_value,
15798524Sfenner		      const unsigned char* language_specific_data,
15898524Sfenner		      _Unwind_Ptr landing_pad,
15998524Sfenner		      const unsigned char* action_record
16098524Sfenner			__attribute__((__unused__)))
16198524Sfenner{
16298524Sfenner    ue_header->barrier_cache.sp = _Unwind_GetGR(context, 13);
16398524Sfenner    ue_header->barrier_cache.bitpattern[0] = (_uw) thrown_ptr;
16498524Sfenner    ue_header->barrier_cache.bitpattern[1]
16598524Sfenner      = (_uw) handler_switch_value;
16698524Sfenner    ue_header->barrier_cache.bitpattern[2]
16798524Sfenner      = (_uw) language_specific_data;
16898524Sfenner    ue_header->barrier_cache.bitpattern[3] = (_uw) landing_pad;
16998524Sfenner}
17098524Sfenner
17198524Sfenner
17298524Sfenner// Restore the catch handler data saved during phase1.
17398524Sfenner
17498524Sfennerstatic inline void
17598524Sfennerrestore_caught_exception(struct _Unwind_Exception* ue_header,
17698524Sfenner			 int& handler_switch_value,
17798524Sfenner			 const unsigned char*& language_specific_data,
17898524Sfenner			 _Unwind_Ptr& landing_pad)
179127668Sbms{
180127668Sbms  handler_switch_value = (int) ue_header->barrier_cache.bitpattern[1];
18198524Sfenner  language_specific_data =
18298524Sfenner    (const unsigned char*) ue_header->barrier_cache.bitpattern[2];
18398524Sfenner  landing_pad = (_Unwind_Ptr) ue_header->barrier_cache.bitpattern[3];
18498524Sfenner}
18598524Sfenner
18698524Sfenner#define CONTINUE_UNWINDING \
18798524Sfenner  do								\
18898524Sfenner    {								\
18998524Sfenner      if (__gnu_unwind_frame(ue_header, context) != _URC_OK)	\
19098524Sfenner	return _URC_FAILURE;					\
19198524Sfenner      return _URC_CONTINUE_UNWIND;				\
19298524Sfenner    }								\
19398524Sfenner  while (0)
19498524Sfenner
19598524Sfenner#else
19698524Sfennertypedef const std::type_info _throw_typet;
19798524Sfenner
19898524Sfenner
19998524Sfenner// Return an element from a type table.
20098524Sfenner
20198524Sfennerstatic const std::type_info *
20298524Sfennerget_ttype_entry (lsda_header_info *info, _Unwind_Word i)
20398524Sfenner{
20498524Sfenner  _Unwind_Ptr ptr;
20598524Sfenner
20698524Sfenner  i *= size_of_encoded_value (info->ttype_encoding);
20798524Sfenner  read_encoded_value_with_base (info->ttype_encoding, info->ttype_base,
20898524Sfenner				info->TType - i, &ptr);
20998524Sfenner
21098524Sfenner  return reinterpret_cast<const std::type_info *>(ptr);
21198524Sfenner}
21298524Sfenner
21398524Sfenner// Given the thrown type THROW_TYPE, pointer to a variable containing a
21498524Sfenner// pointer to the exception object THROWN_PTR_P and a type CATCH_TYPE to
21598524Sfenner// compare against, return whether or not there is a match and if so,
21698524Sfenner// update *THROWN_PTR_P.
21798524Sfenner
21898524Sfennerstatic bool
21998524Sfennerget_adjusted_ptr (const std::type_info *catch_type,
22098524Sfenner		  const std::type_info *throw_type,
22198524Sfenner		  void **thrown_ptr_p)
22298524Sfenner{
22398524Sfenner  void *thrown_ptr = *thrown_ptr_p;
22498524Sfenner
22598524Sfenner  // Pointer types need to adjust the actual pointer, not
22698524Sfenner  // the pointer to pointer that is the exception object.
22798524Sfenner  // This also has the effect of passing pointer types
22898524Sfenner  // "by value" through the __cxa_begin_catch return value.
22998524Sfenner  if (throw_type->__is_pointer_p ())
23098524Sfenner    thrown_ptr = *(void **) thrown_ptr;
23198524Sfenner
23298524Sfenner  if (catch_type->__do_catch (throw_type, &thrown_ptr, 1))
23398524Sfenner    {
23498524Sfenner      *thrown_ptr_p = thrown_ptr;
23598524Sfenner      return true;
23698524Sfenner    }
23798524Sfenner
23898524Sfenner  return false;
239127668Sbms}
24098524Sfenner
24198524Sfenner// Return true if THROW_TYPE matches one if the filter types.
24298524Sfenner
24398524Sfennerstatic bool
24498524Sfennercheck_exception_spec(lsda_header_info* info, _throw_typet* throw_type,
24598524Sfenner		      void* thrown_ptr, _Unwind_Sword filter_value)
24698524Sfenner{
24798524Sfenner  const unsigned char *e = info->TType - filter_value - 1;
24898524Sfenner
24998524Sfenner  while (1)
25098524Sfenner    {
25198524Sfenner      const std::type_info *catch_type;
25298524Sfenner      _Unwind_Word tmp;
25398524Sfenner
25498524Sfenner      e = read_uleb128 (e, &tmp);
25598524Sfenner
25698524Sfenner      // Zero signals the end of the list.  If we've not found
25798524Sfenner      // a match by now, then we've failed the specification.
25898524Sfenner      if (tmp == 0)
25998524Sfenner        return false;
26098524Sfenner
26198524Sfenner      // Match a ttype entry.
26298524Sfenner      catch_type = get_ttype_entry (info, tmp);
26398524Sfenner
26498524Sfenner      // ??? There is currently no way to ask the RTTI code about the
26598524Sfenner      // relationship between two types without reference to a specific
266127668Sbms      // object.  There should be; then we wouldn't need to mess with
26798524Sfenner      // thrown_ptr here.
26898524Sfenner      if (get_adjusted_ptr (catch_type, throw_type, &thrown_ptr))
26998524Sfenner	return true;
27098524Sfenner    }
27198524Sfenner}
27298524Sfenner
27398524Sfenner
27498524Sfenner// Save stage1 handler information in the exception object
27598524Sfenner
27698524Sfennerstatic inline void
27798524Sfennersave_caught_exception(struct _Unwind_Exception* ue_header,
27898524Sfenner		      struct _Unwind_Context* context
27998524Sfenner			__attribute__((__unused__)),
28098524Sfenner		      void* thrown_ptr,
28198524Sfenner		      int handler_switch_value,
282127668Sbms		      const unsigned char* language_specific_data,
28398524Sfenner		      _Unwind_Ptr landing_pad __attribute__((__unused__)),
28498524Sfenner		      const unsigned char* action_record)
285127668Sbms{
28698524Sfenner  __cxa_exception* xh = __get_exception_header_from_ue(ue_header);
28798524Sfenner
28898524Sfenner  xh->handlerSwitchValue = handler_switch_value;
28998524Sfenner  xh->actionRecord = action_record;
29098524Sfenner  xh->languageSpecificData = language_specific_data;
29198524Sfenner  xh->adjustedPtr = thrown_ptr;
29298524Sfenner
29398524Sfenner  // ??? Completely unknown what this field is supposed to be for.
29498524Sfenner  // ??? Need to cache TType encoding base for call_unexpected.
295127668Sbms  xh->catchTemp = landing_pad;
29698524Sfenner}
29798524Sfenner
29898524Sfenner
29998524Sfenner// Restore the catch handler information saved during phase1.
30098524Sfenner
30198524Sfennerstatic inline void
302127668Sbmsrestore_caught_exception(struct _Unwind_Exception* ue_header,
30398524Sfenner			 int& handler_switch_value,
30498524Sfenner			 const unsigned char*& language_specific_data,
30598524Sfenner			 _Unwind_Ptr& landing_pad)
30698524Sfenner{
30798524Sfenner  __cxa_exception* xh = __get_exception_header_from_ue(ue_header);
30898524Sfenner  handler_switch_value = xh->handlerSwitchValue;
30998524Sfenner  language_specific_data = xh->languageSpecificData;
31098524Sfenner  landing_pad = (_Unwind_Ptr) xh->catchTemp;
31198524Sfenner}
31298524Sfenner
31398524Sfenner#define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
31498524Sfenner
315127668Sbms#endif // !__ARM_EABI_UNWINDER__
31698524Sfenner
31798524Sfenner// Return true if the filter spec is empty, ie throw().
31898524Sfenner
31998524Sfennerstatic bool
32098524Sfennerempty_exception_spec (lsda_header_info *info, _Unwind_Sword filter_value)
321127668Sbms{
32298524Sfenner  const unsigned char *e = info->TType - filter_value - 1;
32398524Sfenner  _Unwind_Word tmp;
32498524Sfenner
32598524Sfenner  e = read_uleb128 (e, &tmp);
32698524Sfenner  return tmp == 0;
327127668Sbms}
32898524Sfenner
32998524Sfennernamespace __cxxabiv1
33098524Sfenner{
33198524Sfenner
33298524Sfenner// Using a different personality function name causes link failures
333127668Sbms// when trying to mix code using different exception handling models.
33498524Sfenner#ifdef _GLIBCXX_SJLJ_EXCEPTIONS
33598524Sfenner#define PERSONALITY_FUNCTION	__gxx_personality_sj0
33698524Sfenner#define __builtin_eh_return_data_regno(x) x
33798524Sfenner#else
33898524Sfenner#define PERSONALITY_FUNCTION	__gxx_personality_v0
33998524Sfenner#endif
34098524Sfenner
34198524Sfennerextern "C" _Unwind_Reason_Code
34298524Sfenner#ifdef __ARM_EABI_UNWINDER__
34398524SfennerPERSONALITY_FUNCTION (_Unwind_State state,
34498524Sfenner		      struct _Unwind_Exception* ue_header,
34598524Sfenner		      struct _Unwind_Context* context)
34698524Sfenner#else
34798524SfennerPERSONALITY_FUNCTION (int version,
34898524Sfenner		      _Unwind_Action actions,
34998524Sfenner		      _Unwind_Exception_Class exception_class,
35098524Sfenner		      struct _Unwind_Exception *ue_header,
35198524Sfenner		      struct _Unwind_Context *context)
35298524Sfenner#endif
35398524Sfenner{
35498524Sfenner  enum found_handler_type
35598524Sfenner  {
35698524Sfenner    found_nothing,
35798524Sfenner    found_terminate,
35898524Sfenner    found_cleanup,
35998524Sfenner    found_handler
36098524Sfenner  } found_type;
36198524Sfenner
36298524Sfenner  lsda_header_info info;
36398524Sfenner  const unsigned char *language_specific_data;
36498524Sfenner  const unsigned char *action_record;
36598524Sfenner  const unsigned char *p;
36698524Sfenner  _Unwind_Ptr landing_pad, ip;
36798524Sfenner  int handler_switch_value;
36898524Sfenner  void* thrown_ptr = ue_header + 1;
36998524Sfenner  bool foreign_exception;
37098524Sfenner  int ip_before_insn = 0;
37198524Sfenner
37298524Sfenner#ifdef __ARM_EABI_UNWINDER__
37398524Sfenner  _Unwind_Action actions;
374127668Sbms
37598524Sfenner  switch (state & _US_ACTION_MASK)
37698524Sfenner    {
37798524Sfenner    case _US_VIRTUAL_UNWIND_FRAME:
37898524Sfenner      actions = _UA_SEARCH_PHASE;
37998524Sfenner      break;
38098524Sfenner
381127668Sbms    case _US_UNWIND_FRAME_STARTING:
38298524Sfenner      actions = _UA_CLEANUP_PHASE;
38398524Sfenner      if (!(state & _US_FORCE_UNWIND)
384127668Sbms	  && ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13))
38598524Sfenner	actions |= _UA_HANDLER_FRAME;
38698524Sfenner      break;
38798524Sfenner
38898524Sfenner    case _US_UNWIND_FRAME_RESUME:
38998524Sfenner      CONTINUE_UNWINDING;
39098524Sfenner      break;
39198524Sfenner
39298524Sfenner    default:
39398524Sfenner      std::abort();
394127668Sbms    }
39598524Sfenner  actions |= state & _US_FORCE_UNWIND;
39698524Sfenner
39798524Sfenner  // We don't know which runtime we're working with, so can't check this.
39898524Sfenner  // However the ABI routines hide this from us, and we don't actually need
39998524Sfenner  // to know.
40098524Sfenner  foreign_exception = false;
40198524Sfenner
40298524Sfenner  // The dwarf unwinder assumes the context structure holds things like the
40398524Sfenner  // function and LSDA pointers.  The ARM implementation caches these in
40498524Sfenner  // the exception header (UCB).  To avoid rewriting everything we make the
40598524Sfenner  // virtual IP register point at the UCB.
40698524Sfenner  ip = (_Unwind_Ptr) ue_header;
40798524Sfenner  _Unwind_SetGR(context, 12, ip);
40898524Sfenner#else
40998524Sfenner  __cxa_exception* xh = __get_exception_header_from_ue(ue_header);
41098524Sfenner
41198524Sfenner  // Interface version check.
41298524Sfenner  if (version != 1)
41398524Sfenner    return _URC_FATAL_PHASE1_ERROR;
41498524Sfenner  foreign_exception = !__is_gxx_exception_class(exception_class);
41598524Sfenner#endif
41698524Sfenner
41798524Sfenner  // Shortcut for phase 2 found handler for domestic exception.
41898524Sfenner  if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME)
41998524Sfenner      && !foreign_exception)
420127668Sbms    {
42198524Sfenner      restore_caught_exception(ue_header, handler_switch_value,
42298524Sfenner			       language_specific_data, landing_pad);
42398524Sfenner      found_type = (landing_pad == 0 ? found_terminate : found_handler);
42498524Sfenner      goto install_context;
42598524Sfenner    }
426127668Sbms
42798524Sfenner  language_specific_data = (const unsigned char *)
42898524Sfenner    _Unwind_GetLanguageSpecificData (context);
42998524Sfenner
43098524Sfenner  // If no LSDA, then there are no handlers or cleanups.
43198524Sfenner  if (! language_specific_data)
432127668Sbms    CONTINUE_UNWINDING;
43398524Sfenner
43498524Sfenner  // Parse the LSDA header.
43598524Sfenner  p = parse_lsda_header (context, language_specific_data, &info);
43698524Sfenner  info.ttype_base = base_of_encoded_value (info.ttype_encoding, context);
43798524Sfenner#ifdef _GLIBCXX_HAVE_GETIPINFO
438127668Sbms  ip = _Unwind_GetIPInfo (context, &ip_before_insn);
43998524Sfenner#else
44098524Sfenner  ip = _Unwind_GetIP (context);
44198524Sfenner#endif
44298524Sfenner  if (! ip_before_insn)
44398524Sfenner    --ip;
444127668Sbms  landing_pad = 0;
44598524Sfenner  action_record = 0;
44698524Sfenner  handler_switch_value = 0;
44798524Sfenner
44898524Sfenner#ifdef _GLIBCXX_SJLJ_EXCEPTIONS
44998524Sfenner  // The given "IP" is an index into the call-site table, with two
45098524Sfenner  // exceptions -- -1 means no-action, and 0 means terminate.  But
451127668Sbms  // since we're using uleb128 values, we've not got random access
452127668Sbms  // to the array.
45398524Sfenner  if ((int) ip < 0)
45498524Sfenner    return _URC_CONTINUE_UNWIND;
45598524Sfenner  else if (ip == 0)
45698524Sfenner    {
45798524Sfenner      // Fall through to set found_terminate.
458127668Sbms    }
45998524Sfenner  else
46098524Sfenner    {
46198524Sfenner      _Unwind_Word cs_lp, cs_action;
46298524Sfenner      do
46398524Sfenner	{
46498524Sfenner	  p = read_uleb128 (p, &cs_lp);
46598524Sfenner	  p = read_uleb128 (p, &cs_action);
46698524Sfenner	}
46798524Sfenner      while (--ip);
46898524Sfenner
46998524Sfenner      // Can never have null landing pad for sjlj -- that would have
47098524Sfenner      // been indicated by a -1 call site index.
47198524Sfenner      landing_pad = cs_lp + 1;
47298524Sfenner      if (cs_action)
47398524Sfenner	action_record = info.action_table + cs_action - 1;
47498524Sfenner      goto found_something;
47598524Sfenner    }
47698524Sfenner#else
47798524Sfenner  // Search the call-site table for the action associated with this IP.
47898524Sfenner  while (p < info.action_table)
47998524Sfenner    {
48098524Sfenner      _Unwind_Ptr cs_start, cs_len, cs_lp;
48198524Sfenner      _Unwind_Word cs_action;
48298524Sfenner
48398524Sfenner      // Note that all call-site encodings are "absolute" displacements.
48498524Sfenner      p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
48598524Sfenner      p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
48698524Sfenner      p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
48798524Sfenner      p = read_uleb128 (p, &cs_action);
48898524Sfenner
48998524Sfenner      // The table is sorted, so if we've passed the ip, stop.
49098524Sfenner      if (ip < info.Start + cs_start)
49198524Sfenner	p = info.action_table;
49298524Sfenner      else if (ip < info.Start + cs_start + cs_len)
49398524Sfenner	{
49498524Sfenner	  if (cs_lp)
49598524Sfenner	    landing_pad = info.LPStart + cs_lp;
49698524Sfenner	  if (cs_action)
49798524Sfenner	    action_record = info.action_table + cs_action - 1;
49898524Sfenner	  goto found_something;
49998524Sfenner	}
50098524Sfenner    }
50198524Sfenner#endif // _GLIBCXX_SJLJ_EXCEPTIONS
50298524Sfenner
50398524Sfenner  // If ip is not present in the table, call terminate.  This is for
50498524Sfenner  // a destructor inside a cleanup, or a library routine the compiler
50598524Sfenner  // was not expecting to throw.
50698524Sfenner  found_type = found_terminate;
50798524Sfenner  goto do_something;
50898524Sfenner
50998524Sfenner found_something:
51098524Sfenner  if (landing_pad == 0)
51198524Sfenner    {
51298524Sfenner      // If ip is present, and has a null landing pad, there are
51398524Sfenner      // no cleanups or handlers to be run.
51498524Sfenner      found_type = found_nothing;
51598524Sfenner    }
51698524Sfenner  else if (action_record == 0)
51798524Sfenner    {
51898524Sfenner      // If ip is present, has a non-null landing pad, and a null
51998524Sfenner      // action table offset, then there are only cleanups present.
52098524Sfenner      // Cleanups use a zero switch value, as set above.
52198524Sfenner      found_type = found_cleanup;
52298524Sfenner    }
52398524Sfenner  else
52498524Sfenner    {
52598524Sfenner      // Otherwise we have a catch handler or exception specification.
52698524Sfenner
52798524Sfenner      _Unwind_Sword ar_filter, ar_disp;
52898524Sfenner      const std::type_info* catch_type;
52998524Sfenner      _throw_typet* throw_type;
53098524Sfenner      bool saw_cleanup = false;
53198524Sfenner      bool saw_handler = false;
53298524Sfenner
53398524Sfenner      // During forced unwinding, we only run cleanups.  With a foreign
53498524Sfenner      // exception class, there's no exception type.
53598524Sfenner      // ??? What to do about GNU Java and GNU Ada exceptions.
53698524Sfenner
53798524Sfenner      if ((actions & _UA_FORCE_UNWIND)
53898524Sfenner	  || foreign_exception)
53998524Sfenner	throw_type = 0;
54098524Sfenner      else
54198524Sfenner#ifdef __ARM_EABI_UNWINDER__
54298524Sfenner	throw_type = ue_header;
54398524Sfenner#else
54498524Sfenner	throw_type = xh->exceptionType;
54598524Sfenner#endif
54698524Sfenner
54798524Sfenner      while (1)
54898524Sfenner	{
54998524Sfenner	  p = action_record;
55098524Sfenner	  p = read_sleb128 (p, &ar_filter);
55198524Sfenner	  read_sleb128 (p, &ar_disp);
55298524Sfenner
55398524Sfenner	  if (ar_filter == 0)
55498524Sfenner	    {
55598524Sfenner	      // Zero filter values are cleanups.
55698524Sfenner	      saw_cleanup = true;
55798524Sfenner	    }
55898524Sfenner	  else if (ar_filter > 0)
55998524Sfenner	    {
56098524Sfenner	      // Positive filter values are handlers.
56198524Sfenner	      catch_type = get_ttype_entry (&info, ar_filter);
56298524Sfenner
56398524Sfenner	      // Null catch type is a catch-all handler; we can catch foreign
56498524Sfenner	      // exceptions with this.  Otherwise we must match types.
56598524Sfenner	      if (! catch_type
56698524Sfenner		  || (throw_type
56798524Sfenner		      && get_adjusted_ptr (catch_type, throw_type,
56898524Sfenner					   &thrown_ptr)))
56998524Sfenner		{
57098524Sfenner		  saw_handler = true;
57198524Sfenner		  break;
57298524Sfenner		}
57398524Sfenner	    }
57498524Sfenner	  else
57598524Sfenner	    {
57698524Sfenner	      // Negative filter values are exception specifications.
57798524Sfenner	      // ??? How do foreign exceptions fit in?  As far as I can
57898524Sfenner	      // see we can't match because there's no __cxa_exception
57998524Sfenner	      // object to stuff bits in for __cxa_call_unexpected to use.
58098524Sfenner	      // Allow them iff the exception spec is non-empty.  I.e.
58198524Sfenner	      // a throw() specification results in __unexpected.
58298524Sfenner	      if (throw_type
58398524Sfenner		  ? ! check_exception_spec (&info, throw_type, thrown_ptr,
58498524Sfenner					    ar_filter)
58598524Sfenner		  : empty_exception_spec (&info, ar_filter))
58698524Sfenner		{
58798524Sfenner		  saw_handler = true;
58898524Sfenner		  break;
58998524Sfenner		}
59098524Sfenner	    }
59198524Sfenner
59298524Sfenner	  if (ar_disp == 0)
59398524Sfenner	    break;
59498524Sfenner	  action_record = p + ar_disp;
59598524Sfenner	}
59698524Sfenner
59798524Sfenner      if (saw_handler)
59898524Sfenner	{
59998524Sfenner	  handler_switch_value = ar_filter;
60098524Sfenner	  found_type = found_handler;
60198524Sfenner	}
60298524Sfenner      else
60398524Sfenner	found_type = (saw_cleanup ? found_cleanup : found_nothing);
60498524Sfenner    }
60598524Sfenner
60698524Sfenner do_something:
60798524Sfenner   if (found_type == found_nothing)
60898524Sfenner     CONTINUE_UNWINDING;
60998524Sfenner
61098524Sfenner  if (actions & _UA_SEARCH_PHASE)
61198524Sfenner    {
61298524Sfenner      if (found_type == found_cleanup)
61398524Sfenner	CONTINUE_UNWINDING;
61498524Sfenner
61598524Sfenner      // For domestic exceptions, we cache data from phase 1 for phase 2.
61698524Sfenner      if (!foreign_exception)
61798524Sfenner        {
61898524Sfenner	  save_caught_exception(ue_header, context, thrown_ptr,
61998524Sfenner				handler_switch_value, language_specific_data,
62098524Sfenner				landing_pad, action_record);
62198524Sfenner	}
62298524Sfenner      return _URC_HANDLER_FOUND;
62398524Sfenner    }
62498524Sfenner
62598524Sfenner install_context:
62698524Sfenner
62798524Sfenner  // We can't use any of the cxa routines with foreign exceptions,
62898524Sfenner  // because they all expect ue_header to be a struct __cxa_exception.
62998524Sfenner  // So in that case, call terminate or unexpected directly.
63098524Sfenner  if ((actions & _UA_FORCE_UNWIND)
63198524Sfenner      || foreign_exception)
63298524Sfenner    {
63398524Sfenner      if (found_type == found_terminate)
63498524Sfenner	std::terminate ();
63598524Sfenner      else if (handler_switch_value < 0)
63698524Sfenner	{
63798524Sfenner	  try
63898524Sfenner	    { std::unexpected (); }
63998524Sfenner	  catch(...)
64098524Sfenner	    { std::terminate (); }
64198524Sfenner	}
64298524Sfenner    }
64398524Sfenner  else
64498524Sfenner    {
64598524Sfenner      if (found_type == found_terminate)
64698524Sfenner	__cxa_call_terminate(ue_header);
64798524Sfenner
64898524Sfenner      // Cache the TType base value for __cxa_call_unexpected, as we won't
64998524Sfenner      // have an _Unwind_Context then.
65098524Sfenner      if (handler_switch_value < 0)
65198524Sfenner	{
65298524Sfenner	  parse_lsda_header (context, language_specific_data, &info);
65398524Sfenner
65498524Sfenner#ifdef __ARM_EABI_UNWINDER__
65598524Sfenner	  const _Unwind_Word* e;
65698524Sfenner	  _Unwind_Word n;
65798524Sfenner
65898524Sfenner	  e = ((const _Unwind_Word*) info.TType) - handler_switch_value - 1;
65998524Sfenner	  // Count the number of rtti objects.
66098524Sfenner	  n = 0;
66198524Sfenner	  while (e[n] != 0)
66298524Sfenner	    n++;
66398524Sfenner
66498524Sfenner	  // Count.
66598524Sfenner	  ue_header->barrier_cache.bitpattern[1] = n;
66698524Sfenner	  // Base (obsolete)
66798524Sfenner	  ue_header->barrier_cache.bitpattern[2] = 0;
66898524Sfenner	  // Stride.
66998524Sfenner	  ue_header->barrier_cache.bitpattern[3] = 4;
67098524Sfenner	  // List head.
67198524Sfenner	  ue_header->barrier_cache.bitpattern[4] = (_Unwind_Word) e;
67298524Sfenner#else
67398524Sfenner	  xh->catchTemp = base_of_encoded_value (info.ttype_encoding, context);
67498524Sfenner#endif
67598524Sfenner	}
67698524Sfenner    }
67798524Sfenner
67898524Sfenner  /* For targets with pointers smaller than the word size, we must extend the
67998524Sfenner     pointer, and this extension is target dependent.  */
68098524Sfenner  _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
68198524Sfenner		 __builtin_extend_pointer (ue_header));
68298524Sfenner  _Unwind_SetGR (context, __builtin_eh_return_data_regno (1),
68398524Sfenner		 handler_switch_value);
68498524Sfenner  _Unwind_SetIP (context, landing_pad);
68598524Sfenner#ifdef __ARM_EABI_UNWINDER__
68698524Sfenner  if (found_type == found_cleanup)
68798524Sfenner    __cxa_begin_cleanup(ue_header);
68898524Sfenner#endif
68998524Sfenner  return _URC_INSTALL_CONTEXT;
69098524Sfenner}
69198524Sfenner
69298524Sfenner/* The ARM EABI implementation of __cxa_call_unexpected is in a
69398524Sfenner   different file so that the personality routine (PR) can be used
69498524Sfenner   standalone.  The generic routine shared datastructures with the PR
69598524Sfenner   so it is most convenient to implement it here.  */
69698524Sfenner#ifndef __ARM_EABI_UNWINDER__
69798524Sfennerextern "C" void
69898524Sfenner__cxa_call_unexpected (void *exc_obj_in)
69998524Sfenner{
70098524Sfenner  _Unwind_Exception *exc_obj
70198524Sfenner    = reinterpret_cast <_Unwind_Exception *>(exc_obj_in);
702127668Sbms
70398524Sfenner  __cxa_begin_catch (exc_obj);
70498524Sfenner
70598524Sfenner  // This function is a handler for our exception argument.  If we exit
70698524Sfenner  // by throwing a different exception, we'll need the original cleaned up.
70798524Sfenner  struct end_catch_protect
70898524Sfenner  {
70998524Sfenner    end_catch_protect() { }
71098524Sfenner    ~end_catch_protect() { __cxa_end_catch(); }
71198524Sfenner  } end_catch_protect_obj;
71298524Sfenner
71398524Sfenner  lsda_header_info info;
71498524Sfenner  __cxa_exception *xh = __get_exception_header_from_ue (exc_obj);
71598524Sfenner  const unsigned char *xh_lsda;
71698524Sfenner  _Unwind_Sword xh_switch_value;
71798524Sfenner  std::terminate_handler xh_terminate_handler;
71898524Sfenner
71998524Sfenner  // If the unexpectedHandler rethrows the exception (e.g. to categorize it),
72098524Sfenner  // it will clobber data about the current handler.  So copy the data out now.
721127668Sbms  xh_lsda = xh->languageSpecificData;
72298524Sfenner  xh_switch_value = xh->handlerSwitchValue;
72398524Sfenner  xh_terminate_handler = xh->terminateHandler;
72498524Sfenner  info.ttype_base = (_Unwind_Ptr) xh->catchTemp;
72598524Sfenner
72698524Sfenner  try
72798524Sfenner    { __unexpected (xh->unexpectedHandler); }
72898524Sfenner  catch(...)
72998524Sfenner    {
73098524Sfenner      // Get the exception thrown from unexpected.
73198524Sfenner
73298524Sfenner      __cxa_eh_globals *globals = __cxa_get_globals_fast ();
73398524Sfenner      __cxa_exception *new_xh = globals->caughtExceptions;
73498524Sfenner      void *new_ptr = new_xh + 1;
73598524Sfenner
73698524Sfenner      // We don't quite have enough stuff cached; re-parse the LSDA.
73798524Sfenner      parse_lsda_header (0, xh_lsda, &info);
738127668Sbms
73998524Sfenner      // If this new exception meets the exception spec, allow it.
740127668Sbms      if (check_exception_spec (&info, new_xh->exceptionType,
74198524Sfenner				new_ptr, xh_switch_value))
74298524Sfenner	__throw_exception_again;
74398524Sfenner
74498524Sfenner      // If the exception spec allows std::bad_exception, throw that.
74598524Sfenner      // We don't have a thrown object to compare against, but since
74698524Sfenner      // bad_exception doesn't have virtual bases, that's OK; just pass 0.
74798524Sfenner#ifdef __EXCEPTIONS
74898524Sfenner      const std::type_info &bad_exc = typeid (std::bad_exception);
74998524Sfenner      if (check_exception_spec (&info, &bad_exc, 0, xh_switch_value))
750127668Sbms	throw std::bad_exception();
75198524Sfenner#endif
75298524Sfenner
75398524Sfenner      // Otherwise, die.
75498524Sfenner      __terminate (xh_terminate_handler);
75598524Sfenner    }
75698524Sfenner}
75798524Sfenner#endif
75898524Sfenner
75998524Sfenner} // namespace __cxxabiv1
76098524Sfenner