unwind-c.c revision 225736
150120Swpaul/* Supporting functions for C exception handling.
250120Swpaul   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
350120Swpaul   Contributed by Aldy Hernandez <aldy@quesejoda.com>.
450120Swpaul   Shamelessly stolen from the Java front end.
550120Swpaul
650120SwpaulThis file is part of GCC.
750120Swpaul
850120SwpaulGCC is free software; you can redistribute it and/or modify it under
950120Swpaulthe terms of the GNU General Public License as published by the Free
1050120SwpaulSoftware Foundation; either version 2, or (at your option) any later
1150120Swpaulversion.
1250120Swpaul
1350120SwpaulIn addition to the permissions in the GNU General Public License, the
1450120SwpaulFree Software Foundation gives you unlimited permission to link the
1550120Swpaulcompiled version of this file into combinations with other programs,
1650120Swpauland to distribute those combinations without any restriction coming
1750120Swpaulfrom the use of this file.  (The General Public License restrictions
1850120Swpauldo apply in other respects; for example, they cover modification of
1950120Swpaulthe file, and distribution when not linked into a combined
2050120Swpaulexecutable.)
2150120Swpaul
2250120SwpaulGCC is distributed in the hope that it will be useful, but WITHOUT ANY
2350120SwpaulWARRANTY; without even the implied warranty of MERCHANTABILITY or
2450120SwpaulFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
2550120Swpaulfor more details.
2650120Swpaul
2750120SwpaulYou should have received a copy of the GNU General Public License
2850120Swpaulalong with GCC; see the file COPYING.  If not, write to the Free
2950120SwpaulSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
3050120Swpaul02110-1301, USA.  */
3150120Swpaul
3250120Swpaul#include "tconfig.h"
33139749Simp#include "tsystem.h"
3450120Swpaul#include "unwind.h"
3550120Swpaul#define NO_SIZE_OF_ENCODED_VALUE
3650120Swpaul#include "unwind-pe.h"
3750120Swpaul
3850120Swpaultypedef struct
3950120Swpaul{
4050120Swpaul  _Unwind_Ptr Start;
4150120Swpaul  _Unwind_Ptr LPStart;
4250120Swpaul  _Unwind_Ptr ttype_base;
4350120Swpaul  const unsigned char *TType;
4450120Swpaul  const unsigned char *action_table;
4550120Swpaul  unsigned char ttype_encoding;
4650120Swpaul  unsigned char call_site_encoding;
4750120Swpaul} lsda_header_info;
4850120Swpaul
4950120Swpaulstatic const unsigned char *
5050120Swpaulparse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
5150120Swpaul		   lsda_header_info *info)
5250120Swpaul{
5350120Swpaul  _Unwind_Word tmp;
5450120Swpaul  unsigned char lpstart_encoding;
5550120Swpaul
5650120Swpaul  info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
57129844Smarius
58129844Smarius  /* Find @LPStart, the base to which landing pad offsets are relative.  */
59129844Smarius  lpstart_encoding = *p++;
6050120Swpaul  if (lpstart_encoding != DW_EH_PE_omit)
6150120Swpaul    p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
6250120Swpaul  else
6350120Swpaul    info->LPStart = info->Start;
6450120Swpaul
6550120Swpaul  /* Find @TType, the base of the handler and exception spec type data.  */
6650120Swpaul  info->ttype_encoding = *p++;
6750120Swpaul  if (info->ttype_encoding != DW_EH_PE_omit)
6850120Swpaul    {
6950120Swpaul      p = read_uleb128 (p, &tmp);
7050120Swpaul      info->TType = p + tmp;
7150120Swpaul    }
7250120Swpaul  else
7350120Swpaul    info->TType = 0;
7450120Swpaul
7550120Swpaul  /* The encoding and length of the call-site table; the action table
7650120Swpaul     immediately follows.  */
7750120Swpaul  info->call_site_encoding = *p++;
78109514Sobrien  p = read_uleb128 (p, &tmp);
7950120Swpaul  info->action_table = p + tmp;
8050120Swpaul
8150120Swpaul  return p;
8250120Swpaul}
8350120Swpaul
84105135Salfred#ifdef __ARM_EABI_UNWINDER__
85105135Salfred/* ARM EABI personality routines must also unwind the stack.  */
8650120Swpaul#define CONTINUE_UNWINDING \
8750120Swpaul  do								\
8850120Swpaul    {								\
8950120Swpaul      if (__gnu_unwind_frame (ue_header, context) != _URC_OK)	\
9050120Swpaul	return _URC_FAILURE;					\
9195722Sphk      return _URC_CONTINUE_UNWIND;				\
9250120Swpaul    }								\
93227908Smarius  while (0)
9450120Swpaul#else
9550120Swpaul#define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
9650120Swpaul#endif
9750120Swpaul
9850120Swpaul#ifdef __USING_SJLJ_EXCEPTIONS__
9950120Swpaul#define PERSONALITY_FUNCTION    __gcc_personality_sj0
10050120Swpaul#define __builtin_eh_return_data_regno(x) x
10150120Swpaul#else
10250120Swpaul#define PERSONALITY_FUNCTION    __gcc_personality_v0
10350120Swpaul#endif
10450120Swpaul
10550120Swpaul#ifdef __ARM_EABI_UNWINDER__
10692739Salfred_Unwind_Reason_Code
10792739SalfredPERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *,
108164708Smarius		      struct _Unwind_Context *);
10950120Swpaul
110164827Smarius_Unwind_Reason_Code
111221407SmariusPERSONALITY_FUNCTION (_Unwind_State state,
112164827Smarius		      struct _Unwind_Exception * ue_header,
113164827Smarius		      struct _Unwind_Context * context)
114164827Smarius#else
115221407Smarius_Unwind_Reason_Code
116221407SmariusPERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class,
117221407Smarius		      struct _Unwind_Exception *, struct _Unwind_Context *);
118221407Smarius
119221407Smarius_Unwind_Reason_Code
120221407SmariusPERSONALITY_FUNCTION (int version,
121105135Salfred		      _Unwind_Action actions,
122150763Simp		      _Unwind_Exception_Class exception_class ATTRIBUTE_UNUSED,
12350120Swpaul		      struct _Unwind_Exception *ue_header,
12450120Swpaul		      struct _Unwind_Context *context)
125164827Smarius#endif
12650120Swpaul{
12750120Swpaul  lsda_header_info info;
128105135Salfred  const unsigned char *language_specific_data, *p, *action_record;
129150763Simp  _Unwind_Ptr landing_pad, ip;
13050120Swpaul  int ip_before_insn = 0;
131164708Smarius
132221407Smarius#ifdef __ARM_EABI_UNWINDER__
13350120Swpaul  if ((state & _US_ACTION_MASK) != _US_UNWIND_FRAME_STARTING)
134221407Smarius    CONTINUE_UNWINDING;
135221407Smarius
13650120Swpaul  /* The dwarf unwinder assumes the context structure holds things like the
137213893Smarius     function and LSDA pointers.  The ARM implementation caches these in
13850120Swpaul     the exception header (UCB).  To avoid rewriting everything we make the
139213893Smarius     virtual IP register point at the UCB.  */
140221407Smarius  ip = (_Unwind_Ptr) ue_header;
141221407Smarius  _Unwind_SetGR (context, 12, ip);
142164708Smarius#else
14350120Swpaul  if (version != 1)
14450120Swpaul    return _URC_FATAL_PHASE1_ERROR;
14584145Sjlemon
146150763Simp  /* Currently we only support cleanups for C.  */
14750120Swpaul  if ((actions & _UA_CLEANUP_PHASE) == 0)
14850120Swpaul    CONTINUE_UNWINDING;
14950120Swpaul#endif
15050120Swpaul
15150120Swpaul  language_specific_data = (const unsigned char *)
15250120Swpaul    _Unwind_GetLanguageSpecificData (context);
15350120Swpaul
15450120Swpaul  /* If no LSDA, then there are no handlers or cleanups.  */
15550120Swpaul  if (! language_specific_data)
15650120Swpaul    CONTINUE_UNWINDING;
15750120Swpaul
15850120Swpaul  /* Parse the LSDA header.  */
15950120Swpaul  p = parse_lsda_header (context, language_specific_data, &info);
16050120Swpaul#ifdef HAVE_GETIPINFO
16150120Swpaul  ip = _Unwind_GetIPInfo (context, &ip_before_insn);
16250120Swpaul#else
16350120Swpaul  ip = _Unwind_GetIP (context);
16450120Swpaul#endif
16550120Swpaul  if (! ip_before_insn)
16650120Swpaul    --ip;
16750120Swpaul  landing_pad = 0;
16850120Swpaul
16950120Swpaul#ifdef __USING_SJLJ_EXCEPTIONS__
170129842Smarius  /* The given "IP" is an index into the call-site table, with two
17150120Swpaul     exceptions -- -1 means no-action, and 0 means terminate.  But
17250120Swpaul     since we're using uleb128 values, we've not got random access
17350120Swpaul     to the array.  */
17450120Swpaul  if ((int) ip <= 0)
17550120Swpaul    return _URC_CONTINUE_UNWIND;
17650120Swpaul  else
17750120Swpaul    {
17850120Swpaul      _Unwind_Word cs_lp, cs_action;
17950120Swpaul      do
18050120Swpaul	{
18150120Swpaul	  p = read_uleb128 (p, &cs_lp);
18250120Swpaul	  p = read_uleb128 (p, &cs_action);
18350120Swpaul	}
18450120Swpaul      while (--ip);
18574353Sjlemon
18674353Sjlemon      /* Can never have null landing pad for sjlj -- that would have
18774353Sjlemon	 been indicated by a -1 call site index.  */
18874353Sjlemon      landing_pad = cs_lp + 1;
18974353Sjlemon      if (cs_action)
19074353Sjlemon	action_record = info.action_table + cs_action - 1;
19150120Swpaul      goto found_something;
19250120Swpaul    }
19374353Sjlemon#else
194164708Smarius  /* Search the call-site table for the action associated with this IP.  */
19577634Sjlemon  while (p < info.action_table)
19674353Sjlemon    {
197164708Smarius      _Unwind_Ptr cs_start, cs_len, cs_lp;
19850120Swpaul      _Unwind_Word cs_action;
19950120Swpaul
20050120Swpaul      /* Note that all call-site encodings are "absolute" displacements.  */
20184145Sjlemon      p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
20250120Swpaul      p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
20350120Swpaul      p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
20450120Swpaul      p = read_uleb128 (p, &cs_action);
20550120Swpaul
20650120Swpaul      /* The table is sorted, so if we've passed the ip, stop.  */
207221407Smarius      if (ip < info.Start + cs_start)
20850120Swpaul	p = info.action_table;
20950120Swpaul      else if (ip < info.Start + cs_start + cs_len)
21084145Sjlemon	{
21150120Swpaul	  if (cs_lp)
21250120Swpaul	    landing_pad = info.LPStart + cs_lp;
21350120Swpaul	  if (cs_action)
21484145Sjlemon	    action_record = info.action_table + cs_action - 1;
215150763Simp	  goto found_something;
21650120Swpaul	}
21750120Swpaul    }
218164708Smarius#endif
21950120Swpaul
22050120Swpaul  /* IP is not in table.  No associated cleanups.  */
22150120Swpaul  /* ??? This is where C++ calls std::terminate to catch throw
22250120Swpaul     from a destructor.  */
22350120Swpaul  CONTINUE_UNWINDING;
22450120Swpaul
22550120Swpaul found_something:
22650120Swpaul  if (landing_pad == 0)
22750120Swpaul    {
22850120Swpaul      /* IP is present, but has a null landing pad.
22950120Swpaul	 No handler to be run.  */
23050120Swpaul      CONTINUE_UNWINDING;
23150120Swpaul    }
23250120Swpaul
23350120Swpaul  _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
23450120Swpaul		 (_Unwind_Ptr) ue_header);
23550120Swpaul  _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0);
23650120Swpaul  _Unwind_SetIP (context, landing_pad);
23750120Swpaul  return _URC_INSTALL_CONTEXT;
23850120Swpaul}
23950120Swpaul