unwind-c.c revision 169689
1193323Sed/* Supporting functions for C exception handling.
2193323Sed   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
3353358Sdim   Contributed by Aldy Hernandez <aldy@quesejoda.com>.
4353358Sdim   Shamelessly stolen from the Java front end.
5353358Sdim
6193323SedThis file is part of GCC.
7193323Sed
8193323SedGCC is free software; you can redistribute it and/or modify it under
9193323Sedthe terms of the GNU General Public License as published by the Free
10193323SedSoftware Foundation; either version 2, or (at your option) any later
11193323Sedversion.
12193323Sed
13193323SedIn addition to the permissions in the GNU General Public License, the
14193323SedFree Software Foundation gives you unlimited permission to link the
15327952Sdimcompiled version of this file into combinations with other programs,
16249423Sdimand to distribute those combinations without any restriction coming
17327952Sdimfrom the use of this file.  (The General Public License restrictions
18327952Sdimdo apply in other respects; for example, they cover modification of
19353358Sdimthe file, and distribution when not linked into a combined
20353358Sdimexecutable.)
21353358Sdim
22327952SdimGCC is distributed in the hope that it will be useful, but WITHOUT ANY
23288943SdimWARRANTY; without even the implied warranty of MERCHANTABILITY or
24353358SdimFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
25249423Sdimfor more details.
26249423Sdim
27327952SdimYou should have received a copy of the GNU General Public License
28249423Sdimalong with GCC; see the file COPYING.  If not, write to the Free
29327952SdimSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
30360784Sdim02110-1301, USA.  */
31193323Sed
32327952Sdim#include "tconfig.h"
33198892Srdivacky#include "tsystem.h"
34193323Sed#include "unwind.h"
35353358Sdim#define NO_SIZE_OF_ENCODED_VALUE
36193323Sed#include "unwind-pe.h"
37341825Sdim
38288943Sdimtypedef struct
39193323Sed{
40327952Sdim  _Unwind_Ptr Start;
41327952Sdim  _Unwind_Ptr LPStart;
42327952Sdim  _Unwind_Ptr ttype_base;
43327952Sdim  const unsigned char *TType;
44327952Sdim  const unsigned char *action_table;
45327952Sdim  unsigned char ttype_encoding;
46193323Sed  unsigned char call_site_encoding;
47193323Sed} lsda_header_info;
48276479Sdim
49276479Sdimstatic const unsigned char *
50193323Sedparse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
51327952Sdim		   lsda_header_info *info)
52288943Sdim{
53288943Sdim  _Unwind_Word tmp;
54288943Sdim  unsigned char lpstart_encoding;
55288943Sdim
56327952Sdim  info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
57288943Sdim
58327952Sdim  /* Find @LPStart, the base to which landing pad offsets are relative.  */
59327952Sdim  lpstart_encoding = *p++;
60327952Sdim  if (lpstart_encoding != DW_EH_PE_omit)
61327952Sdim    p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
62327952Sdim  else
63327952Sdim    info->LPStart = info->Start;
64327952Sdim
65327952Sdim  /* Find @TType, the base of the handler and exception spec type data.  */
66353358Sdim  info->ttype_encoding = *p++;
67353358Sdim  if (info->ttype_encoding != DW_EH_PE_omit)
68327952Sdim    {
69327952Sdim      p = read_uleb128 (p, &tmp);
70327952Sdim      info->TType = p + tmp;
71327952Sdim    }
72327952Sdim  else
73296417Sdim    info->TType = 0;
74198892Srdivacky
75193323Sed  /* The encoding and length of the call-site table; the action table
76327952Sdim     immediately follows.  */
77327952Sdim  info->call_site_encoding = *p++;
78327952Sdim  p = read_uleb128 (p, &tmp);
79218893Sdim  info->action_table = p + tmp;
80218893Sdim
81341825Sdim  return p;
82193323Sed}
83276479Sdim
84276479Sdim#ifdef __ARM_EABI_UNWINDER__
85353358Sdim/* ARM EABI personality routines must also unwind the stack.  */
86353358Sdim#define CONTINUE_UNWINDING \
87353358Sdim  do								\
88353358Sdim    {								\
89193323Sed      if (__gnu_unwind_frame (ue_header, context) != _URC_OK)	\
90288943Sdim	return _URC_FAILURE;					\
91288943Sdim      return _URC_CONTINUE_UNWIND;				\
92193323Sed    }								\
93193323Sed  while (0)
94288943Sdim#else
95288943Sdim#define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
96193323Sed#endif
97193323Sed
98327952Sdim#ifdef __USING_SJLJ_EXCEPTIONS__
99327952Sdim#define PERSONALITY_FUNCTION    __gcc_personality_sj0
100327952Sdim#define __builtin_eh_return_data_regno(x) x
101193323Sed#else
102353358Sdim#define PERSONALITY_FUNCTION    __gcc_personality_v0
103353358Sdim#endif
104353358Sdim
105193323Sed#ifdef __ARM_EABI_UNWINDER__
106276479Sdim_Unwind_Reason_Code
107276479SdimPERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *,
108276479Sdim		      struct _Unwind_Context *);
109288943Sdim
110288943Sdim_Unwind_Reason_Code
111353358SdimPERSONALITY_FUNCTION (_Unwind_State state,
112353358Sdim		      struct _Unwind_Exception * ue_header,
113353358Sdim		      struct _Unwind_Context * context)
114276479Sdim#else
115193323Sed_Unwind_Reason_Code
116261991SdimPERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class,
117261991Sdim		      struct _Unwind_Exception *, struct _Unwind_Context *);
118261991Sdim
119261991Sdim_Unwind_Reason_Code
120327952SdimPERSONALITY_FUNCTION (int version,
121327952Sdim		      _Unwind_Action actions,
122261991Sdim		      _Unwind_Exception_Class exception_class ATTRIBUTE_UNUSED,
123261991Sdim		      struct _Unwind_Exception *ue_header,
124261991Sdim		      struct _Unwind_Context *context)
125261991Sdim#endif
126261991Sdim{
127193323Sed  lsda_header_info info;
128327952Sdim  const unsigned char *language_specific_data, *p, *action_record;
129327952Sdim  _Unwind_Ptr landing_pad, ip;
130193323Sed  int ip_before_insn = 0;
131327952Sdim
132327952Sdim#ifdef __ARM_EABI_UNWINDER__
133327952Sdim  if ((state & _US_ACTION_MASK) != _US_UNWIND_FRAME_STARTING)
134327952Sdim    CONTINUE_UNWINDING;
135353358Sdim
136353358Sdim  /* The dwarf unwinder assumes the context structure holds things like the
137353358Sdim     function and LSDA pointers.  The ARM implementation caches these in
138353358Sdim     the exception header (UCB).  To avoid rewriting everything we make the
139353358Sdim     virtual IP register point at the UCB.  */
140353358Sdim  ip = (_Unwind_Ptr) ue_header;
141193323Sed  _Unwind_SetGR (context, 12, ip);
142193323Sed#else
143193323Sed  if (version != 1)
144193323Sed    return _URC_FATAL_PHASE1_ERROR;
145193323Sed
146193323Sed  /* Currently we only support cleanups for C.  */
147193323Sed  if ((actions & _UA_CLEANUP_PHASE) == 0)
148353358Sdim    CONTINUE_UNWINDING;
149353358Sdim#endif
150353358Sdim
151353358Sdim  language_specific_data = (const unsigned char *)
152353358Sdim    _Unwind_GetLanguageSpecificData (context);
153353358Sdim
154353358Sdim  /* If no LSDA, then there are no handlers or cleanups.  */
155353358Sdim  if (! language_specific_data)
156353358Sdim    CONTINUE_UNWINDING;
157353358Sdim
158353358Sdim  /* Parse the LSDA header.  */
159193323Sed  p = parse_lsda_header (context, language_specific_data, &info);
160296417Sdim#ifdef HAVE_GETIPINFO
161193323Sed  ip = _Unwind_GetIPInfo (context, &ip_before_insn);
162193323Sed#else
163296417Sdim  ip = _Unwind_GetIP (context);
164193323Sed#endif
165296417Sdim  if (! ip_before_insn)
166296417Sdim    --ip;
167296417Sdim  landing_pad = 0;
168296417Sdim
169296417Sdim#ifdef __USING_SJLJ_EXCEPTIONS__
170193323Sed  /* The given "IP" is an index into the call-site table, with two
171193323Sed     exceptions -- -1 means no-action, and 0 means terminate.  But
172353358Sdim     since we're using uleb128 values, we've not got random access
173193323Sed     to the array.  */
174193323Sed  if ((int) ip <= 0)
175193323Sed    return _URC_CONTINUE_UNWIND;
176296417Sdim  else
177353358Sdim    {
178296417Sdim      _Unwind_Word cs_lp, cs_action;
179296417Sdim      do
180296417Sdim	{
181193323Sed	  p = read_uleb128 (p, &cs_lp);
182193323Sed	  p = read_uleb128 (p, &cs_action);
183193323Sed	}
184296417Sdim      while (--ip);
185341825Sdim
186341825Sdim      /* Can never have null landing pad for sjlj -- that would have
187198090Srdivacky	 been indicated by a -1 call site index.  */
188193323Sed      landing_pad = cs_lp + 1;
189193323Sed      if (cs_action)
190353358Sdim	action_record = info.action_table + cs_action - 1;
191353358Sdim      goto found_something;
192353358Sdim    }
193353358Sdim#else
194353358Sdim  /* Search the call-site table for the action associated with this IP.  */
195193323Sed  while (p < info.action_table)
196193323Sed    {
197193323Sed      _Unwind_Ptr cs_start, cs_len, cs_lp;
198193323Sed      _Unwind_Word cs_action;
199193323Sed
200341825Sdim      /* Note that all call-site encodings are "absolute" displacements.  */
201296417Sdim      p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
202296417Sdim      p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
203296417Sdim      p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
204296417Sdim      p = read_uleb128 (p, &cs_action);
205296417Sdim
206296417Sdim      /* The table is sorted, so if we've passed the ip, stop.  */
207296417Sdim      if (ip < info.Start + cs_start)
208296417Sdim	p = info.action_table;
209296417Sdim      else if (ip < info.Start + cs_start + cs_len)
210353358Sdim	{
211353358Sdim	  if (cs_lp)
212353358Sdim	    landing_pad = info.LPStart + cs_lp;
213296417Sdim	  if (cs_action)
214296417Sdim	    action_record = info.action_table + cs_action - 1;
215280031Sdim	  goto found_something;
216276479Sdim	}
217276479Sdim    }
218296417Sdim#endif
219280031Sdim
220280031Sdim  /* IP is not in table.  No associated cleanups.  */
221280031Sdim  /* ??? This is where C++ calls std::terminate to catch throw
222280031Sdim     from a destructor.  */
223280031Sdim  CONTINUE_UNWINDING;
224280031Sdim
225280031Sdim found_something:
226276479Sdim  if (landing_pad == 0)
227280031Sdim    {
228296417Sdim      /* IP is present, but has a null landing pad.
229280031Sdim	 No handler to be run.  */
230288943Sdim      CONTINUE_UNWINDING;
231280031Sdim    }
232280031Sdim
233288943Sdim  _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
234280031Sdim		 (_Unwind_Ptr) ue_header);
235280031Sdim  _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0);
236288943Sdim  _Unwind_SetIP (context, landing_pad);
237288943Sdim  return _URC_INSTALL_CONTEXT;
238327952Sdim}
239309124Sdim