197403Sobrien// -*- C++ -*- The GNU C++ exception personality routine.
2229551Spfg// Copyright (C) 2001, 2002, 2003, 2006, 2008 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
18169691Skan// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
19169691Skan// Boston, MA 02110-1301, 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#include <bits/c++config.h>
3197403Sobrien#include <cstdlib>
3297403Sobrien#include <exception_defines.h>
3397403Sobrien#include "unwind-cxx.h"
3497403Sobrien
3597403Sobrienusing namespace __cxxabiv1;
3697403Sobrien
37169691Skan#ifdef __ARM_EABI_UNWINDER__
38169691Skan#define NO_SIZE_OF_ENCODED_VALUE
39169691Skan#endif
40169691Skan
4197403Sobrien#include "unwind-pe.h"
4297403Sobrien
4397403Sobrien
4497403Sobrienstruct lsda_header_info
4597403Sobrien{
4697403Sobrien  _Unwind_Ptr Start;
4797403Sobrien  _Unwind_Ptr LPStart;
4897403Sobrien  _Unwind_Ptr ttype_base;
4997403Sobrien  const unsigned char *TType;
5097403Sobrien  const unsigned char *action_table;
5197403Sobrien  unsigned char ttype_encoding;
5297403Sobrien  unsigned char call_site_encoding;
5397403Sobrien};
5497403Sobrien
5597403Sobrienstatic const unsigned char *
5697403Sobrienparse_lsda_header (_Unwind_Context *context, const unsigned char *p,
5797403Sobrien		   lsda_header_info *info)
5897403Sobrien{
5997403Sobrien  _Unwind_Word tmp;
6097403Sobrien  unsigned char lpstart_encoding;
6197403Sobrien
6297403Sobrien  info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
6397403Sobrien
6497403Sobrien  // Find @LPStart, the base to which landing pad offsets are relative.
6597403Sobrien  lpstart_encoding = *p++;
6697403Sobrien  if (lpstart_encoding != DW_EH_PE_omit)
6797403Sobrien    p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
6897403Sobrien  else
6997403Sobrien    info->LPStart = info->Start;
7097403Sobrien
7197403Sobrien  // Find @TType, the base of the handler and exception spec type data.
7297403Sobrien  info->ttype_encoding = *p++;
7397403Sobrien  if (info->ttype_encoding != DW_EH_PE_omit)
7497403Sobrien    {
7597403Sobrien      p = read_uleb128 (p, &tmp);
7697403Sobrien      info->TType = p + tmp;
7797403Sobrien    }
7897403Sobrien  else
7997403Sobrien    info->TType = 0;
8097403Sobrien
8197403Sobrien  // The encoding and length of the call-site table; the action table
8297403Sobrien  // immediately follows.
8397403Sobrien  info->call_site_encoding = *p++;
8497403Sobrien  p = read_uleb128 (p, &tmp);
8597403Sobrien  info->action_table = p + tmp;
8697403Sobrien
8797403Sobrien  return p;
8897403Sobrien}
8997403Sobrien
90169691Skan#ifdef __ARM_EABI_UNWINDER__
91169691Skan
92169691Skan// Return an element from a type table.
93169691Skan
94169691Skanstatic const std::type_info*
95169691Skanget_ttype_entry(lsda_header_info* info, _Unwind_Word i)
96169691Skan{
97169691Skan  _Unwind_Ptr ptr;
98169691Skan
99169691Skan  ptr = (_Unwind_Ptr) (info->TType - (i * 4));
100169691Skan  ptr = _Unwind_decode_target2(ptr);
101169691Skan
102169691Skan  return reinterpret_cast<const std::type_info *>(ptr);
103169691Skan}
104169691Skan
105169691Skan// The ABI provides a routine for matching exception object types.
106169691Skantypedef _Unwind_Control_Block _throw_typet;
107169691Skan#define get_adjusted_ptr(catch_type, throw_type, thrown_ptr_p) \
108169691Skan  (__cxa_type_match (throw_type, catch_type, false, thrown_ptr_p) \
109169691Skan   != ctm_failed)
110169691Skan
111169691Skan// Return true if THROW_TYPE matches one if the filter types.
112169691Skan
113169691Skanstatic bool
114169691Skancheck_exception_spec(lsda_header_info* info, _throw_typet* throw_type,
115169691Skan		     void* thrown_ptr, _Unwind_Sword filter_value)
116169691Skan{
117169691Skan  const _Unwind_Word* e = ((const _Unwind_Word*) info->TType)
118169691Skan			  - filter_value - 1;
119169691Skan
120169691Skan  while (1)
121169691Skan    {
122169691Skan      const std::type_info* catch_type;
123169691Skan      _Unwind_Word tmp;
124169691Skan
125169691Skan      tmp = *e;
126169691Skan
127169691Skan      // Zero signals the end of the list.  If we've not found
128169691Skan      // a match by now, then we've failed the specification.
129169691Skan      if (tmp == 0)
130169691Skan        return false;
131169691Skan
132169691Skan      tmp = _Unwind_decode_target2((_Unwind_Word) e);
133169691Skan
134169691Skan      // Match a ttype entry.
135169691Skan      catch_type = reinterpret_cast<const std::type_info*>(tmp);
136169691Skan
137169691Skan      // ??? There is currently no way to ask the RTTI code about the
138169691Skan      // relationship between two types without reference to a specific
139169691Skan      // object.  There should be; then we wouldn't need to mess with
140169691Skan      // thrown_ptr here.
141169691Skan      if (get_adjusted_ptr(catch_type, throw_type, &thrown_ptr))
142169691Skan	return true;
143169691Skan
144169691Skan      // Advance to the next entry.
145169691Skan      e++;
146169691Skan    }
147169691Skan}
148169691Skan
149169691Skan
150169691Skan// Save stage1 handler information in the exception object
151169691Skan
152169691Skanstatic inline void
153169691Skansave_caught_exception(struct _Unwind_Exception* ue_header,
154169691Skan		      struct _Unwind_Context* context,
155169691Skan		      void* thrown_ptr,
156169691Skan		      int handler_switch_value,
157169691Skan		      const unsigned char* language_specific_data,
158169691Skan		      _Unwind_Ptr landing_pad,
159169691Skan		      const unsigned char* action_record
160169691Skan			__attribute__((__unused__)))
161169691Skan{
162169691Skan    ue_header->barrier_cache.sp = _Unwind_GetGR(context, 13);
163169691Skan    ue_header->barrier_cache.bitpattern[0] = (_uw) thrown_ptr;
164169691Skan    ue_header->barrier_cache.bitpattern[1]
165169691Skan      = (_uw) handler_switch_value;
166169691Skan    ue_header->barrier_cache.bitpattern[2]
167169691Skan      = (_uw) language_specific_data;
168169691Skan    ue_header->barrier_cache.bitpattern[3] = (_uw) landing_pad;
169169691Skan}
170169691Skan
171169691Skan
172169691Skan// Restore the catch handler data saved during phase1.
173169691Skan
174169691Skanstatic inline void
175169691Skanrestore_caught_exception(struct _Unwind_Exception* ue_header,
176169691Skan			 int& handler_switch_value,
177169691Skan			 const unsigned char*& language_specific_data,
178169691Skan			 _Unwind_Ptr& landing_pad)
179169691Skan{
180169691Skan  handler_switch_value = (int) ue_header->barrier_cache.bitpattern[1];
181169691Skan  language_specific_data =
182169691Skan    (const unsigned char*) ue_header->barrier_cache.bitpattern[2];
183169691Skan  landing_pad = (_Unwind_Ptr) ue_header->barrier_cache.bitpattern[3];
184169691Skan}
185169691Skan
186169691Skan#define CONTINUE_UNWINDING \
187169691Skan  do								\
188169691Skan    {								\
189169691Skan      if (__gnu_unwind_frame(ue_header, context) != _URC_OK)	\
190169691Skan	return _URC_FAILURE;					\
191169691Skan      return _URC_CONTINUE_UNWIND;				\
192169691Skan    }								\
193169691Skan  while (0)
194169691Skan
195169691Skan#else
196169691Skantypedef const std::type_info _throw_typet;
197169691Skan
198169691Skan
199169691Skan// Return an element from a type table.
200169691Skan
20197403Sobrienstatic const std::type_info *
20297403Sobrienget_ttype_entry (lsda_header_info *info, _Unwind_Word i)
20397403Sobrien{
20497403Sobrien  _Unwind_Ptr ptr;
20597403Sobrien
20697403Sobrien  i *= size_of_encoded_value (info->ttype_encoding);
20797403Sobrien  read_encoded_value_with_base (info->ttype_encoding, info->ttype_base,
20897403Sobrien				info->TType - i, &ptr);
20997403Sobrien
21097403Sobrien  return reinterpret_cast<const std::type_info *>(ptr);
21197403Sobrien}
21297403Sobrien
21397403Sobrien// Given the thrown type THROW_TYPE, pointer to a variable containing a
21497403Sobrien// pointer to the exception object THROWN_PTR_P and a type CATCH_TYPE to
21597403Sobrien// compare against, return whether or not there is a match and if so,
21697403Sobrien// update *THROWN_PTR_P.
21797403Sobrien
21897403Sobrienstatic bool
21997403Sobrienget_adjusted_ptr (const std::type_info *catch_type,
22097403Sobrien		  const std::type_info *throw_type,
22197403Sobrien		  void **thrown_ptr_p)
22297403Sobrien{
22397403Sobrien  void *thrown_ptr = *thrown_ptr_p;
22497403Sobrien
22597403Sobrien  // Pointer types need to adjust the actual pointer, not
22697403Sobrien  // the pointer to pointer that is the exception object.
22797403Sobrien  // This also has the effect of passing pointer types
22897403Sobrien  // "by value" through the __cxa_begin_catch return value.
22997403Sobrien  if (throw_type->__is_pointer_p ())
23097403Sobrien    thrown_ptr = *(void **) thrown_ptr;
23197403Sobrien
23297403Sobrien  if (catch_type->__do_catch (throw_type, &thrown_ptr, 1))
23397403Sobrien    {
23497403Sobrien      *thrown_ptr_p = thrown_ptr;
23597403Sobrien      return true;
23697403Sobrien    }
23797403Sobrien
23897403Sobrien  return false;
23997403Sobrien}
24097403Sobrien
241117397Skan// Return true if THROW_TYPE matches one if the filter types.
242117397Skan
24397403Sobrienstatic bool
244169691Skancheck_exception_spec(lsda_header_info* info, _throw_typet* throw_type,
245169691Skan		      void* thrown_ptr, _Unwind_Sword filter_value)
24697403Sobrien{
24797403Sobrien  const unsigned char *e = info->TType - filter_value - 1;
24897403Sobrien
24997403Sobrien  while (1)
25097403Sobrien    {
25197403Sobrien      const std::type_info *catch_type;
25297403Sobrien      _Unwind_Word tmp;
25397403Sobrien
25497403Sobrien      e = read_uleb128 (e, &tmp);
25597403Sobrien
25697403Sobrien      // Zero signals the end of the list.  If we've not found
25797403Sobrien      // a match by now, then we've failed the specification.
25897403Sobrien      if (tmp == 0)
25997403Sobrien        return false;
26097403Sobrien
26197403Sobrien      // Match a ttype entry.
26297403Sobrien      catch_type = get_ttype_entry (info, tmp);
26397403Sobrien
26497403Sobrien      // ??? There is currently no way to ask the RTTI code about the
26597403Sobrien      // relationship between two types without reference to a specific
26697403Sobrien      // object.  There should be; then we wouldn't need to mess with
26797403Sobrien      // thrown_ptr here.
26897403Sobrien      if (get_adjusted_ptr (catch_type, throw_type, &thrown_ptr))
26997403Sobrien	return true;
27097403Sobrien    }
27197403Sobrien}
27297403Sobrien
273169691Skan
274169691Skan// Save stage1 handler information in the exception object
275169691Skan
276169691Skanstatic inline void
277169691Skansave_caught_exception(struct _Unwind_Exception* ue_header,
278169691Skan		      struct _Unwind_Context* context
279169691Skan			__attribute__((__unused__)),
280169691Skan		      void* thrown_ptr,
281169691Skan		      int handler_switch_value,
282169691Skan		      const unsigned char* language_specific_data,
283169691Skan		      _Unwind_Ptr landing_pad __attribute__((__unused__)),
284169691Skan		      const unsigned char* action_record)
285169691Skan{
286169691Skan  __cxa_exception* xh = __get_exception_header_from_ue(ue_header);
287169691Skan
288169691Skan  xh->handlerSwitchValue = handler_switch_value;
289169691Skan  xh->actionRecord = action_record;
290169691Skan  xh->languageSpecificData = language_specific_data;
291169691Skan  xh->adjustedPtr = thrown_ptr;
292169691Skan
293169691Skan  // ??? Completely unknown what this field is supposed to be for.
294169691Skan  // ??? Need to cache TType encoding base for call_unexpected.
295169691Skan  xh->catchTemp = landing_pad;
296169691Skan}
297169691Skan
298169691Skan
299169691Skan// Restore the catch handler information saved during phase1.
300169691Skan
301169691Skanstatic inline void
302169691Skanrestore_caught_exception(struct _Unwind_Exception* ue_header,
303169691Skan			 int& handler_switch_value,
304169691Skan			 const unsigned char*& language_specific_data,
305169691Skan			 _Unwind_Ptr& landing_pad)
306169691Skan{
307169691Skan  __cxa_exception* xh = __get_exception_header_from_ue(ue_header);
308169691Skan  handler_switch_value = xh->handlerSwitchValue;
309169691Skan  language_specific_data = xh->languageSpecificData;
310169691Skan  landing_pad = (_Unwind_Ptr) xh->catchTemp;
311169691Skan}
312169691Skan
313169691Skan#define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
314169691Skan
315169691Skan#endif // !__ARM_EABI_UNWINDER__
316169691Skan
317117397Skan// Return true if the filter spec is empty, ie throw().
318117397Skan
319117397Skanstatic bool
320117397Skanempty_exception_spec (lsda_header_info *info, _Unwind_Sword filter_value)
321117397Skan{
322117397Skan  const unsigned char *e = info->TType - filter_value - 1;
323117397Skan  _Unwind_Word tmp;
324117397Skan
325117397Skan  e = read_uleb128 (e, &tmp);
326117397Skan  return tmp == 0;
327117397Skan}
328117397Skan
329169691Skannamespace __cxxabiv1
330169691Skan{
331169691Skan
33297403Sobrien// Using a different personality function name causes link failures
33397403Sobrien// when trying to mix code using different exception handling models.
334132720Skan#ifdef _GLIBCXX_SJLJ_EXCEPTIONS
33597403Sobrien#define PERSONALITY_FUNCTION	__gxx_personality_sj0
33697403Sobrien#define __builtin_eh_return_data_regno(x) x
33797403Sobrien#else
33897403Sobrien#define PERSONALITY_FUNCTION	__gxx_personality_v0
33997403Sobrien#endif
34097403Sobrien
34197403Sobrienextern "C" _Unwind_Reason_Code
342169691Skan#ifdef __ARM_EABI_UNWINDER__
343169691SkanPERSONALITY_FUNCTION (_Unwind_State state,
344169691Skan		      struct _Unwind_Exception* ue_header,
345169691Skan		      struct _Unwind_Context* context)
346169691Skan#else
34797403SobrienPERSONALITY_FUNCTION (int version,
34897403Sobrien		      _Unwind_Action actions,
34997403Sobrien		      _Unwind_Exception_Class exception_class,
35097403Sobrien		      struct _Unwind_Exception *ue_header,
35197403Sobrien		      struct _Unwind_Context *context)
352169691Skan#endif
35397403Sobrien{
35497403Sobrien  enum found_handler_type
35597403Sobrien  {
35697403Sobrien    found_nothing,
35797403Sobrien    found_terminate,
35897403Sobrien    found_cleanup,
35997403Sobrien    found_handler
36097403Sobrien  } found_type;
36197403Sobrien
36297403Sobrien  lsda_header_info info;
36397403Sobrien  const unsigned char *language_specific_data;
36497403Sobrien  const unsigned char *action_record;
36597403Sobrien  const unsigned char *p;
36697403Sobrien  _Unwind_Ptr landing_pad, ip;
36797403Sobrien  int handler_switch_value;
368169691Skan  void* thrown_ptr = ue_header + 1;
369169691Skan  bool foreign_exception;
370169691Skan  int ip_before_insn = 0;
37197403Sobrien
372169691Skan#ifdef __ARM_EABI_UNWINDER__
373169691Skan  _Unwind_Action actions;
374169691Skan
375169691Skan  switch (state & _US_ACTION_MASK)
376169691Skan    {
377169691Skan    case _US_VIRTUAL_UNWIND_FRAME:
378169691Skan      actions = _UA_SEARCH_PHASE;
379169691Skan      break;
380169691Skan
381169691Skan    case _US_UNWIND_FRAME_STARTING:
382169691Skan      actions = _UA_CLEANUP_PHASE;
383169691Skan      if (!(state & _US_FORCE_UNWIND)
384169691Skan	  && ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13))
385169691Skan	actions |= _UA_HANDLER_FRAME;
386169691Skan      break;
387169691Skan
388169691Skan    case _US_UNWIND_FRAME_RESUME:
389169691Skan      CONTINUE_UNWINDING;
390169691Skan      break;
391169691Skan
392169691Skan    default:
393169691Skan      std::abort();
394169691Skan    }
395169691Skan  actions |= state & _US_FORCE_UNWIND;
396169691Skan
397169691Skan  // We don't know which runtime we're working with, so can't check this.
398169691Skan  // However the ABI routines hide this from us, and we don't actually need
399169691Skan  // to know.
400169691Skan  foreign_exception = false;
401169691Skan
402169691Skan  // The dwarf unwinder assumes the context structure holds things like the
403169691Skan  // function and LSDA pointers.  The ARM implementation caches these in
404169691Skan  // the exception header (UCB).  To avoid rewriting everything we make the
405169691Skan  // virtual IP register point at the UCB.
406169691Skan  ip = (_Unwind_Ptr) ue_header;
407169691Skan  _Unwind_SetGR(context, 12, ip);
408169691Skan#else
409169691Skan  __cxa_exception* xh = __get_exception_header_from_ue(ue_header);
410169691Skan
41197403Sobrien  // Interface version check.
41297403Sobrien  if (version != 1)
41397403Sobrien    return _URC_FATAL_PHASE1_ERROR;
414169691Skan  foreign_exception = !__is_gxx_exception_class(exception_class);
415169691Skan#endif
41697403Sobrien
41797403Sobrien  // Shortcut for phase 2 found handler for domestic exception.
41897403Sobrien  if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME)
419169691Skan      && !foreign_exception)
42097403Sobrien    {
421169691Skan      restore_caught_exception(ue_header, handler_switch_value,
422169691Skan			       language_specific_data, landing_pad);
42397403Sobrien      found_type = (landing_pad == 0 ? found_terminate : found_handler);
42497403Sobrien      goto install_context;
42597403Sobrien    }
42697403Sobrien
42797403Sobrien  language_specific_data = (const unsigned char *)
42897403Sobrien    _Unwind_GetLanguageSpecificData (context);
42997403Sobrien
43097403Sobrien  // If no LSDA, then there are no handlers or cleanups.
43197403Sobrien  if (! language_specific_data)
432169691Skan    CONTINUE_UNWINDING;
43397403Sobrien
43497403Sobrien  // Parse the LSDA header.
43597403Sobrien  p = parse_lsda_header (context, language_specific_data, &info);
43697403Sobrien  info.ttype_base = base_of_encoded_value (info.ttype_encoding, context);
437229551Spfg#ifdef _GLIBCXX_HAVE_GETIPINFO
438169691Skan  ip = _Unwind_GetIPInfo (context, &ip_before_insn);
439169691Skan#else
440169691Skan  ip = _Unwind_GetIP (context);
441169691Skan#endif
442169691Skan  if (! ip_before_insn)
443169691Skan    --ip;
44497403Sobrien  landing_pad = 0;
44597403Sobrien  action_record = 0;
44697403Sobrien  handler_switch_value = 0;
44797403Sobrien
448132720Skan#ifdef _GLIBCXX_SJLJ_EXCEPTIONS
44997403Sobrien  // The given "IP" is an index into the call-site table, with two
45097403Sobrien  // exceptions -- -1 means no-action, and 0 means terminate.  But
45197403Sobrien  // since we're using uleb128 values, we've not got random access
45297403Sobrien  // to the array.
45397403Sobrien  if ((int) ip < 0)
45497403Sobrien    return _URC_CONTINUE_UNWIND;
45597403Sobrien  else if (ip == 0)
45697403Sobrien    {
45797403Sobrien      // Fall through to set found_terminate.
45897403Sobrien    }
45997403Sobrien  else
46097403Sobrien    {
46197403Sobrien      _Unwind_Word cs_lp, cs_action;
46297403Sobrien      do
46397403Sobrien	{
46497403Sobrien	  p = read_uleb128 (p, &cs_lp);
46597403Sobrien	  p = read_uleb128 (p, &cs_action);
46697403Sobrien	}
46797403Sobrien      while (--ip);
46897403Sobrien
46997403Sobrien      // Can never have null landing pad for sjlj -- that would have
47097403Sobrien      // been indicated by a -1 call site index.
47197403Sobrien      landing_pad = cs_lp + 1;
47297403Sobrien      if (cs_action)
47397403Sobrien	action_record = info.action_table + cs_action - 1;
47497403Sobrien      goto found_something;
47597403Sobrien    }
47697403Sobrien#else
47797403Sobrien  // Search the call-site table for the action associated with this IP.
47897403Sobrien  while (p < info.action_table)
47997403Sobrien    {
48097403Sobrien      _Unwind_Ptr cs_start, cs_len, cs_lp;
48197403Sobrien      _Unwind_Word cs_action;
48297403Sobrien
48397403Sobrien      // Note that all call-site encodings are "absolute" displacements.
48497403Sobrien      p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
48597403Sobrien      p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
48697403Sobrien      p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
48797403Sobrien      p = read_uleb128 (p, &cs_action);
48897403Sobrien
48997403Sobrien      // The table is sorted, so if we've passed the ip, stop.
49097403Sobrien      if (ip < info.Start + cs_start)
49197403Sobrien	p = info.action_table;
49297403Sobrien      else if (ip < info.Start + cs_start + cs_len)
49397403Sobrien	{
49497403Sobrien	  if (cs_lp)
49597403Sobrien	    landing_pad = info.LPStart + cs_lp;
49697403Sobrien	  if (cs_action)
49797403Sobrien	    action_record = info.action_table + cs_action - 1;
49897403Sobrien	  goto found_something;
49997403Sobrien	}
50097403Sobrien    }
501132720Skan#endif // _GLIBCXX_SJLJ_EXCEPTIONS
50297403Sobrien
50397403Sobrien  // If ip is not present in the table, call terminate.  This is for
50497403Sobrien  // a destructor inside a cleanup, or a library routine the compiler
50597403Sobrien  // was not expecting to throw.
506117397Skan  found_type = found_terminate;
50797403Sobrien  goto do_something;
50897403Sobrien
50997403Sobrien found_something:
51097403Sobrien  if (landing_pad == 0)
51197403Sobrien    {
51297403Sobrien      // If ip is present, and has a null landing pad, there are
51397403Sobrien      // no cleanups or handlers to be run.
51497403Sobrien      found_type = found_nothing;
51597403Sobrien    }
51697403Sobrien  else if (action_record == 0)
51797403Sobrien    {
51897403Sobrien      // If ip is present, has a non-null landing pad, and a null
51997403Sobrien      // action table offset, then there are only cleanups present.
52097403Sobrien      // Cleanups use a zero switch value, as set above.
52197403Sobrien      found_type = found_cleanup;
52297403Sobrien    }
52397403Sobrien  else
52497403Sobrien    {
52597403Sobrien      // Otherwise we have a catch handler or exception specification.
52697403Sobrien
52797403Sobrien      _Unwind_Sword ar_filter, ar_disp;
528169691Skan      const std::type_info* catch_type;
529169691Skan      _throw_typet* throw_type;
53097403Sobrien      bool saw_cleanup = false;
53197403Sobrien      bool saw_handler = false;
53297403Sobrien
53397403Sobrien      // During forced unwinding, we only run cleanups.  With a foreign
53497403Sobrien      // exception class, there's no exception type.
53597403Sobrien      // ??? What to do about GNU Java and GNU Ada exceptions.
53697403Sobrien
53797403Sobrien      if ((actions & _UA_FORCE_UNWIND)
538169691Skan	  || foreign_exception)
53997403Sobrien	throw_type = 0;
54097403Sobrien      else
541169691Skan#ifdef __ARM_EABI_UNWINDER__
542169691Skan	throw_type = ue_header;
543169691Skan#else
54497403Sobrien	throw_type = xh->exceptionType;
545169691Skan#endif
54697403Sobrien
54797403Sobrien      while (1)
54897403Sobrien	{
54997403Sobrien	  p = action_record;
55097403Sobrien	  p = read_sleb128 (p, &ar_filter);
55197403Sobrien	  read_sleb128 (p, &ar_disp);
55297403Sobrien
55397403Sobrien	  if (ar_filter == 0)
55497403Sobrien	    {
55597403Sobrien	      // Zero filter values are cleanups.
55697403Sobrien	      saw_cleanup = true;
55797403Sobrien	    }
55897403Sobrien	  else if (ar_filter > 0)
55997403Sobrien	    {
56097403Sobrien	      // Positive filter values are handlers.
56197403Sobrien	      catch_type = get_ttype_entry (&info, ar_filter);
56297403Sobrien
563117397Skan	      // Null catch type is a catch-all handler; we can catch foreign
564117397Skan	      // exceptions with this.  Otherwise we must match types.
565117397Skan	      if (! catch_type
566117397Skan		  || (throw_type
567117397Skan		      && get_adjusted_ptr (catch_type, throw_type,
568117397Skan					   &thrown_ptr)))
56997403Sobrien		{
570117397Skan		  saw_handler = true;
571117397Skan		  break;
57297403Sobrien		}
57397403Sobrien	    }
57497403Sobrien	  else
57597403Sobrien	    {
57697403Sobrien	      // Negative filter values are exception specifications.
57797403Sobrien	      // ??? How do foreign exceptions fit in?  As far as I can
57897403Sobrien	      // see we can't match because there's no __cxa_exception
57997403Sobrien	      // object to stuff bits in for __cxa_call_unexpected to use.
580117397Skan	      // Allow them iff the exception spec is non-empty.  I.e.
581117397Skan	      // a throw() specification results in __unexpected.
58297403Sobrien	      if (throw_type
583117397Skan		  ? ! check_exception_spec (&info, throw_type, thrown_ptr,
584117397Skan					    ar_filter)
585117397Skan		  : empty_exception_spec (&info, ar_filter))
58697403Sobrien		{
58797403Sobrien		  saw_handler = true;
58897403Sobrien		  break;
58997403Sobrien		}
59097403Sobrien	    }
59197403Sobrien
59297403Sobrien	  if (ar_disp == 0)
59397403Sobrien	    break;
59497403Sobrien	  action_record = p + ar_disp;
59597403Sobrien	}
59697403Sobrien
59797403Sobrien      if (saw_handler)
59897403Sobrien	{
59997403Sobrien	  handler_switch_value = ar_filter;
60097403Sobrien	  found_type = found_handler;
60197403Sobrien	}
60297403Sobrien      else
60397403Sobrien	found_type = (saw_cleanup ? found_cleanup : found_nothing);
60497403Sobrien    }
60597403Sobrien
60697403Sobrien do_something:
60797403Sobrien   if (found_type == found_nothing)
608169691Skan     CONTINUE_UNWINDING;
60997403Sobrien
61097403Sobrien  if (actions & _UA_SEARCH_PHASE)
61197403Sobrien    {
61297403Sobrien      if (found_type == found_cleanup)
613169691Skan	CONTINUE_UNWINDING;
61497403Sobrien
61597403Sobrien      // For domestic exceptions, we cache data from phase 1 for phase 2.
616169691Skan      if (!foreign_exception)
61797403Sobrien        {
618169691Skan	  save_caught_exception(ue_header, context, thrown_ptr,
619169691Skan				handler_switch_value, language_specific_data,
620169691Skan				landing_pad, action_record);
62197403Sobrien	}
62297403Sobrien      return _URC_HANDLER_FOUND;
62397403Sobrien    }
62497403Sobrien
62597403Sobrien install_context:
626169691Skan
627117397Skan  // We can't use any of the cxa routines with foreign exceptions,
628117397Skan  // because they all expect ue_header to be a struct __cxa_exception.
629117397Skan  // So in that case, call terminate or unexpected directly.
630117397Skan  if ((actions & _UA_FORCE_UNWIND)
631169691Skan      || foreign_exception)
63297403Sobrien    {
633117397Skan      if (found_type == found_terminate)
634117397Skan	std::terminate ();
635117397Skan      else if (handler_switch_value < 0)
636117397Skan	{
637117397Skan	  try
638117397Skan	    { std::unexpected (); }
639117397Skan	  catch(...)
640117397Skan	    { std::terminate (); }
641117397Skan	}
64297403Sobrien    }
643117397Skan  else
644117397Skan    {
645117397Skan      if (found_type == found_terminate)
646169691Skan	__cxa_call_terminate(ue_header);
64797403Sobrien
648117397Skan      // Cache the TType base value for __cxa_call_unexpected, as we won't
649117397Skan      // have an _Unwind_Context then.
650117397Skan      if (handler_switch_value < 0)
651117397Skan	{
652117397Skan	  parse_lsda_header (context, language_specific_data, &info);
653169691Skan
654169691Skan#ifdef __ARM_EABI_UNWINDER__
655169691Skan	  const _Unwind_Word* e;
656169691Skan	  _Unwind_Word n;
657169691Skan
658169691Skan	  e = ((const _Unwind_Word*) info.TType) - handler_switch_value - 1;
659169691Skan	  // Count the number of rtti objects.
660169691Skan	  n = 0;
661169691Skan	  while (e[n] != 0)
662169691Skan	    n++;
663169691Skan
664169691Skan	  // Count.
665169691Skan	  ue_header->barrier_cache.bitpattern[1] = n;
666169691Skan	  // Base (obsolete)
667169691Skan	  ue_header->barrier_cache.bitpattern[2] = 0;
668169691Skan	  // Stride.
669169691Skan	  ue_header->barrier_cache.bitpattern[3] = 4;
670169691Skan	  // List head.
671169691Skan	  ue_header->barrier_cache.bitpattern[4] = (_Unwind_Word) e;
672169691Skan#else
673117397Skan	  xh->catchTemp = base_of_encoded_value (info.ttype_encoding, context);
674169691Skan#endif
675117397Skan	}
67697403Sobrien    }
67797403Sobrien
678132720Skan  /* For targets with pointers smaller than the word size, we must extend the
679132720Skan     pointer, and this extension is target dependent.  */
68097403Sobrien  _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
681169691Skan		 __builtin_extend_pointer (ue_header));
68297403Sobrien  _Unwind_SetGR (context, __builtin_eh_return_data_regno (1),
68397403Sobrien		 handler_switch_value);
68497403Sobrien  _Unwind_SetIP (context, landing_pad);
685169691Skan#ifdef __ARM_EABI_UNWINDER__
686169691Skan  if (found_type == found_cleanup)
687169691Skan    __cxa_begin_cleanup(ue_header);
688169691Skan#endif
68997403Sobrien  return _URC_INSTALL_CONTEXT;
69097403Sobrien}
69197403Sobrien
692169691Skan/* The ARM EABI implementation of __cxa_call_unexpected is in a
693169691Skan   different file so that the personality routine (PR) can be used
694169691Skan   standalone.  The generic routine shared datastructures with the PR
695169691Skan   so it is most convenient to implement it here.  */
696169691Skan#ifndef __ARM_EABI_UNWINDER__
69797403Sobrienextern "C" void
69897403Sobrien__cxa_call_unexpected (void *exc_obj_in)
69997403Sobrien{
70097403Sobrien  _Unwind_Exception *exc_obj
70197403Sobrien    = reinterpret_cast <_Unwind_Exception *>(exc_obj_in);
70297403Sobrien
70397403Sobrien  __cxa_begin_catch (exc_obj);
70497403Sobrien
70597403Sobrien  // This function is a handler for our exception argument.  If we exit
70697403Sobrien  // by throwing a different exception, we'll need the original cleaned up.
70797403Sobrien  struct end_catch_protect
70897403Sobrien  {
70997403Sobrien    end_catch_protect() { }
71097403Sobrien    ~end_catch_protect() { __cxa_end_catch(); }
71197403Sobrien  } end_catch_protect_obj;
71297403Sobrien
71397403Sobrien  lsda_header_info info;
71497403Sobrien  __cxa_exception *xh = __get_exception_header_from_ue (exc_obj);
71597403Sobrien  const unsigned char *xh_lsda;
71697403Sobrien  _Unwind_Sword xh_switch_value;
71797403Sobrien  std::terminate_handler xh_terminate_handler;
71897403Sobrien
71997403Sobrien  // If the unexpectedHandler rethrows the exception (e.g. to categorize it),
72097403Sobrien  // it will clobber data about the current handler.  So copy the data out now.
72197403Sobrien  xh_lsda = xh->languageSpecificData;
72297403Sobrien  xh_switch_value = xh->handlerSwitchValue;
72397403Sobrien  xh_terminate_handler = xh->terminateHandler;
72497403Sobrien  info.ttype_base = (_Unwind_Ptr) xh->catchTemp;
72597403Sobrien
72697403Sobrien  try
72797403Sobrien    { __unexpected (xh->unexpectedHandler); }
72897403Sobrien  catch(...)
72997403Sobrien    {
73097403Sobrien      // Get the exception thrown from unexpected.
731117397Skan
73297403Sobrien      __cxa_eh_globals *globals = __cxa_get_globals_fast ();
73397403Sobrien      __cxa_exception *new_xh = globals->caughtExceptions;
73497403Sobrien      void *new_ptr = new_xh + 1;
735117397Skan
73697403Sobrien      // We don't quite have enough stuff cached; re-parse the LSDA.
73797403Sobrien      parse_lsda_header (0, xh_lsda, &info);
738117397Skan
73997403Sobrien      // If this new exception meets the exception spec, allow it.
74097403Sobrien      if (check_exception_spec (&info, new_xh->exceptionType,
74197403Sobrien				new_ptr, xh_switch_value))
74297403Sobrien	__throw_exception_again;
743117397Skan
74497403Sobrien      // If the exception spec allows std::bad_exception, throw that.
74597403Sobrien      // We don't have a thrown object to compare against, but since
74697403Sobrien      // bad_exception doesn't have virtual bases, that's OK; just pass 0.
74797403Sobrien#ifdef __EXCEPTIONS
74897403Sobrien      const std::type_info &bad_exc = typeid (std::bad_exception);
74997403Sobrien      if (check_exception_spec (&info, &bad_exc, 0, xh_switch_value))
75097403Sobrien	throw std::bad_exception();
75197403Sobrien#endif
752117397Skan
75397403Sobrien      // Otherwise, die.
75497403Sobrien      __terminate (xh_terminate_handler);
75597403Sobrien    }
75697403Sobrien}
757169691Skan#endif
758169691Skan
759169691Skan} // namespace __cxxabiv1
760