1117395Skan/* Supporting functions for C exception handling.
2117395Skan   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
3117395Skan   Contributed by Aldy Hernandez <aldy@quesejoda.com>.
4117395Skan   Shamelessly stolen from the Java front end.
5117395Skan
6117395SkanThis file is part of GCC.
7117395Skan
8117395SkanGCC is free software; you can redistribute it and/or modify it under
9117395Skanthe terms of the GNU General Public License as published by the Free
10117395SkanSoftware Foundation; either version 2, or (at your option) any later
11117395Skanversion.
12117395Skan
13132718SkanIn addition to the permissions in the GNU General Public License, the
14132718SkanFree Software Foundation gives you unlimited permission to link the
15132718Skancompiled version of this file into combinations with other programs,
16132718Skanand to distribute those combinations without any restriction coming
17132718Skanfrom the use of this file.  (The General Public License restrictions
18132718Skando apply in other respects; for example, they cover modification of
19132718Skanthe file, and distribution when not linked into a combined
20132718Skanexecutable.)
21132718Skan
22117395SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY
23117395SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or
24117395SkanFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
25117395Skanfor more details.
26117395Skan
27117395SkanYou should have received a copy of the GNU General Public License
28117395Skanalong with GCC; see the file COPYING.  If not, write to the Free
29169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
30169689Skan02110-1301, USA.  */
31117395Skan
32117395Skan#include "tconfig.h"
33117395Skan#include "tsystem.h"
34117395Skan#include "unwind.h"
35132718Skan#define NO_SIZE_OF_ENCODED_VALUE
36117395Skan#include "unwind-pe.h"
37117395Skan
38117395Skantypedef struct
39117395Skan{
40117395Skan  _Unwind_Ptr Start;
41117395Skan  _Unwind_Ptr LPStart;
42117395Skan  _Unwind_Ptr ttype_base;
43117395Skan  const unsigned char *TType;
44117395Skan  const unsigned char *action_table;
45117395Skan  unsigned char ttype_encoding;
46117395Skan  unsigned char call_site_encoding;
47117395Skan} lsda_header_info;
48117395Skan
49117395Skanstatic const unsigned char *
50117395Skanparse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
51117395Skan		   lsda_header_info *info)
52117395Skan{
53117395Skan  _Unwind_Word tmp;
54117395Skan  unsigned char lpstart_encoding;
55117395Skan
56117395Skan  info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
57117395Skan
58117395Skan  /* Find @LPStart, the base to which landing pad offsets are relative.  */
59117395Skan  lpstart_encoding = *p++;
60117395Skan  if (lpstart_encoding != DW_EH_PE_omit)
61117395Skan    p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
62117395Skan  else
63117395Skan    info->LPStart = info->Start;
64117395Skan
65117395Skan  /* Find @TType, the base of the handler and exception spec type data.  */
66117395Skan  info->ttype_encoding = *p++;
67117395Skan  if (info->ttype_encoding != DW_EH_PE_omit)
68117395Skan    {
69117395Skan      p = read_uleb128 (p, &tmp);
70117395Skan      info->TType = p + tmp;
71117395Skan    }
72117395Skan  else
73117395Skan    info->TType = 0;
74117395Skan
75117395Skan  /* The encoding and length of the call-site table; the action table
76117395Skan     immediately follows.  */
77117395Skan  info->call_site_encoding = *p++;
78117395Skan  p = read_uleb128 (p, &tmp);
79117395Skan  info->action_table = p + tmp;
80117395Skan
81117395Skan  return p;
82117395Skan}
83117395Skan
84169689Skan#ifdef __ARM_EABI_UNWINDER__
85169689Skan/* ARM EABI personality routines must also unwind the stack.  */
86169689Skan#define CONTINUE_UNWINDING \
87169689Skan  do								\
88169689Skan    {								\
89169689Skan      if (__gnu_unwind_frame (ue_header, context) != _URC_OK)	\
90169689Skan	return _URC_FAILURE;					\
91169689Skan      return _URC_CONTINUE_UNWIND;				\
92169689Skan    }								\
93169689Skan  while (0)
94169689Skan#else
95169689Skan#define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
96169689Skan#endif
97169689Skan
98117395Skan#ifdef __USING_SJLJ_EXCEPTIONS__
99117395Skan#define PERSONALITY_FUNCTION    __gcc_personality_sj0
100117395Skan#define __builtin_eh_return_data_regno(x) x
101117395Skan#else
102117395Skan#define PERSONALITY_FUNCTION    __gcc_personality_v0
103117395Skan#endif
104117395Skan
105169689Skan#ifdef __ARM_EABI_UNWINDER__
106117395Skan_Unwind_Reason_Code
107169689SkanPERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *,
108169689Skan		      struct _Unwind_Context *);
109169689Skan
110169689Skan_Unwind_Reason_Code
111169689SkanPERSONALITY_FUNCTION (_Unwind_State state,
112169689Skan		      struct _Unwind_Exception * ue_header,
113169689Skan		      struct _Unwind_Context * context)
114169689Skan#else
115169689Skan_Unwind_Reason_Code
116117395SkanPERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class,
117117395Skan		      struct _Unwind_Exception *, struct _Unwind_Context *);
118117395Skan
119117395Skan_Unwind_Reason_Code
120117395SkanPERSONALITY_FUNCTION (int version,
121117395Skan		      _Unwind_Action actions,
122117395Skan		      _Unwind_Exception_Class exception_class ATTRIBUTE_UNUSED,
123117395Skan		      struct _Unwind_Exception *ue_header,
124117395Skan		      struct _Unwind_Context *context)
125169689Skan#endif
126117395Skan{
127117395Skan  lsda_header_info info;
128117395Skan  const unsigned char *language_specific_data, *p, *action_record;
129117395Skan  _Unwind_Ptr landing_pad, ip;
130169689Skan  int ip_before_insn = 0;
131117395Skan
132169689Skan#ifdef __ARM_EABI_UNWINDER__
133169689Skan  if ((state & _US_ACTION_MASK) != _US_UNWIND_FRAME_STARTING)
134169689Skan    CONTINUE_UNWINDING;
135169689Skan
136169689Skan  /* The dwarf unwinder assumes the context structure holds things like the
137169689Skan     function and LSDA pointers.  The ARM implementation caches these in
138169689Skan     the exception header (UCB).  To avoid rewriting everything we make the
139169689Skan     virtual IP register point at the UCB.  */
140169689Skan  ip = (_Unwind_Ptr) ue_header;
141169689Skan  _Unwind_SetGR (context, 12, ip);
142169689Skan#else
143117395Skan  if (version != 1)
144117395Skan    return _URC_FATAL_PHASE1_ERROR;
145117395Skan
146117395Skan  /* Currently we only support cleanups for C.  */
147117395Skan  if ((actions & _UA_CLEANUP_PHASE) == 0)
148169689Skan    CONTINUE_UNWINDING;
149169689Skan#endif
150117395Skan
151117395Skan  language_specific_data = (const unsigned char *)
152117395Skan    _Unwind_GetLanguageSpecificData (context);
153117395Skan
154117395Skan  /* If no LSDA, then there are no handlers or cleanups.  */
155117395Skan  if (! language_specific_data)
156169689Skan    CONTINUE_UNWINDING;
157117395Skan
158117395Skan  /* Parse the LSDA header.  */
159117395Skan  p = parse_lsda_header (context, language_specific_data, &info);
160169689Skan#ifdef HAVE_GETIPINFO
161169689Skan  ip = _Unwind_GetIPInfo (context, &ip_before_insn);
162169689Skan#else
163169689Skan  ip = _Unwind_GetIP (context);
164169689Skan#endif
165169689Skan  if (! ip_before_insn)
166169689Skan    --ip;
167117395Skan  landing_pad = 0;
168117395Skan
169117395Skan#ifdef __USING_SJLJ_EXCEPTIONS__
170117395Skan  /* The given "IP" is an index into the call-site table, with two
171117395Skan     exceptions -- -1 means no-action, and 0 means terminate.  But
172117395Skan     since we're using uleb128 values, we've not got random access
173117395Skan     to the array.  */
174117395Skan  if ((int) ip <= 0)
175117395Skan    return _URC_CONTINUE_UNWIND;
176117395Skan  else
177117395Skan    {
178117395Skan      _Unwind_Word cs_lp, cs_action;
179117395Skan      do
180117395Skan	{
181117395Skan	  p = read_uleb128 (p, &cs_lp);
182117395Skan	  p = read_uleb128 (p, &cs_action);
183117395Skan	}
184117395Skan      while (--ip);
185117395Skan
186117395Skan      /* Can never have null landing pad for sjlj -- that would have
187117395Skan	 been indicated by a -1 call site index.  */
188117395Skan      landing_pad = cs_lp + 1;
189117395Skan      if (cs_action)
190117395Skan	action_record = info.action_table + cs_action - 1;
191117395Skan      goto found_something;
192117395Skan    }
193117395Skan#else
194117395Skan  /* Search the call-site table for the action associated with this IP.  */
195117395Skan  while (p < info.action_table)
196117395Skan    {
197117395Skan      _Unwind_Ptr cs_start, cs_len, cs_lp;
198117395Skan      _Unwind_Word cs_action;
199117395Skan
200117395Skan      /* Note that all call-site encodings are "absolute" displacements.  */
201117395Skan      p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
202117395Skan      p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
203117395Skan      p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
204117395Skan      p = read_uleb128 (p, &cs_action);
205117395Skan
206117395Skan      /* The table is sorted, so if we've passed the ip, stop.  */
207117395Skan      if (ip < info.Start + cs_start)
208117395Skan	p = info.action_table;
209117395Skan      else if (ip < info.Start + cs_start + cs_len)
210117395Skan	{
211117395Skan	  if (cs_lp)
212117395Skan	    landing_pad = info.LPStart + cs_lp;
213117395Skan	  if (cs_action)
214117395Skan	    action_record = info.action_table + cs_action - 1;
215117395Skan	  goto found_something;
216117395Skan	}
217117395Skan    }
218117395Skan#endif
219117395Skan
220117395Skan  /* IP is not in table.  No associated cleanups.  */
221117395Skan  /* ??? This is where C++ calls std::terminate to catch throw
222117395Skan     from a destructor.  */
223169689Skan  CONTINUE_UNWINDING;
224117395Skan
225117395Skan found_something:
226117395Skan  if (landing_pad == 0)
227117395Skan    {
228117395Skan      /* IP is present, but has a null landing pad.
229117395Skan	 No handler to be run.  */
230169689Skan      CONTINUE_UNWINDING;
231117395Skan    }
232117395Skan
233117395Skan  _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
234117395Skan		 (_Unwind_Ptr) ue_header);
235117395Skan  _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0);
236117395Skan  _Unwind_SetIP (context, landing_pad);
237117395Skan  return _URC_INSTALL_CONTEXT;
238117395Skan}
239