unwind-c.c revision 117395
1180740Sdes/* Supporting functions for C exception handling.
2180740Sdes   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
3180740Sdes   Contributed by Aldy Hernandez <aldy@quesejoda.com>.
4180740Sdes   Shamelessly stolen from the Java front end.
5180740Sdes
6180740SdesThis file is part of GCC.
7189006Sdes
8255670SdesGCC is free software; you can redistribute it and/or modify it under
9255670Sdesthe terms of the GNU General Public License as published by the Free
10255670SdesSoftware Foundation; either version 2, or (at your option) any later
11255670Sdesversion.
12204861Sdes
13180740SdesGCC is distributed in the hope that it will be useful, but WITHOUT ANY
14255670SdesWARRANTY; without even the implied warranty of MERCHANTABILITY or
15180740SdesFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16180740Sdesfor more details.
17180740Sdes
18180740SdesYou should have received a copy of the GNU General Public License
19214979Sdesalong with GCC; see the file COPYING.  If not, write to the Free
20214979SdesSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA
21214979Sdes02111-1307, USA.  */
22180740Sdes
23180740Sdes#include "tconfig.h"
24180740Sdes#include "tsystem.h"
25214979Sdes#include "unwind.h"
26214979Sdes#include "unwind-pe.h"
27180740Sdes
28180740Sdestypedef struct
29180740Sdes{
30180740Sdes  _Unwind_Ptr Start;
31180740Sdes  _Unwind_Ptr LPStart;
32180740Sdes  _Unwind_Ptr ttype_base;
33180740Sdes  const unsigned char *TType;
34180740Sdes  const unsigned char *action_table;
35180740Sdes  unsigned char ttype_encoding;
36180740Sdes  unsigned char call_site_encoding;
37180740Sdes} lsda_header_info;
38180740Sdes
39180740Sdesstatic const unsigned char *
40180740Sdesparse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
41180740Sdes		   lsda_header_info *info)
42180740Sdes{
43180740Sdes  _Unwind_Word tmp;
44180740Sdes  unsigned char lpstart_encoding;
45180740Sdes
46180740Sdes  info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
47204861Sdes
48180740Sdes  /* Find @LPStart, the base to which landing pad offsets are relative.  */
49180740Sdes  lpstart_encoding = *p++;
50180740Sdes  if (lpstart_encoding != DW_EH_PE_omit)
51180740Sdes    p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
52180740Sdes  else
53180740Sdes    info->LPStart = info->Start;
54180740Sdes
55180740Sdes  /* Find @TType, the base of the handler and exception spec type data.  */
56180740Sdes  info->ttype_encoding = *p++;
57214979Sdes  if (info->ttype_encoding != DW_EH_PE_omit)
58214979Sdes    {
59180740Sdes      p = read_uleb128 (p, &tmp);
60180740Sdes      info->TType = p + tmp;
61180740Sdes    }
62180740Sdes  else
63180740Sdes    info->TType = 0;
64180740Sdes
65180740Sdes  /* The encoding and length of the call-site table; the action table
66180740Sdes     immediately follows.  */
67180740Sdes  info->call_site_encoding = *p++;
68180740Sdes  p = read_uleb128 (p, &tmp);
69180740Sdes  info->action_table = p + tmp;
70180740Sdes
71180740Sdes  return p;
72180740Sdes}
73180740Sdes
74214979Sdes#ifdef __USING_SJLJ_EXCEPTIONS__
75214979Sdes#define PERSONALITY_FUNCTION    __gcc_personality_sj0
76180740Sdes#define __builtin_eh_return_data_regno(x) x
77214979Sdes#else
78214979Sdes#define PERSONALITY_FUNCTION    __gcc_personality_v0
79214979Sdes#endif
80214979Sdes#define PERSONALITY_FUNCTION    __gcc_personality_v0
81180740Sdes
82180740Sdes_Unwind_Reason_Code
83197670SdesPERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class,
84214979Sdes		      struct _Unwind_Exception *, struct _Unwind_Context *);
85180740Sdes
86180740Sdes_Unwind_Reason_Code
87180740SdesPERSONALITY_FUNCTION (int version,
88180740Sdes		      _Unwind_Action actions,
89180740Sdes		      _Unwind_Exception_Class exception_class ATTRIBUTE_UNUSED,
90180740Sdes		      struct _Unwind_Exception *ue_header,
91180740Sdes		      struct _Unwind_Context *context)
92180740Sdes{
93180740Sdes  lsda_header_info info;
94214979Sdes  const unsigned char *language_specific_data, *p, *action_record;
95214979Sdes  _Unwind_Ptr landing_pad, ip;
96214979Sdes
97180740Sdes  if (version != 1)
98214979Sdes    return _URC_FATAL_PHASE1_ERROR;
99214979Sdes
100214979Sdes  /* Currently we only support cleanups for C.  */
101214979Sdes  if ((actions & _UA_CLEANUP_PHASE) == 0)
102214979Sdes    return _URC_CONTINUE_UNWIND;
103180740Sdes
104214979Sdes  language_specific_data = (const unsigned char *)
105214979Sdes    _Unwind_GetLanguageSpecificData (context);
106180740Sdes
107255670Sdes  /* If no LSDA, then there are no handlers or cleanups.  */
108255670Sdes  if (! language_specific_data)
109255670Sdes    return _URC_CONTINUE_UNWIND;
110180740Sdes
111180740Sdes  /* Parse the LSDA header.  */
112180740Sdes  p = parse_lsda_header (context, language_specific_data, &info);
113180740Sdes  ip = _Unwind_GetIP (context) - 1;
114180740Sdes  landing_pad = 0;
115180740Sdes
116180740Sdes#ifdef __USING_SJLJ_EXCEPTIONS__
117180740Sdes  /* The given "IP" is an index into the call-site table, with two
118180740Sdes     exceptions -- -1 means no-action, and 0 means terminate.  But
119180740Sdes     since we're using uleb128 values, we've not got random access
120214979Sdes     to the array.  */
121214979Sdes  if ((int) ip <= 0)
122180740Sdes    return _URC_CONTINUE_UNWIND;
123180740Sdes  else
124180740Sdes    {
125180740Sdes      _Unwind_Word cs_lp, cs_action;
126214979Sdes      do
127214979Sdes	{
128214979Sdes	  p = read_uleb128 (p, &cs_lp);
129214979Sdes	  p = read_uleb128 (p, &cs_action);
130180740Sdes	}
131180750Sdes      while (--ip);
132180750Sdes
133214979Sdes      /* Can never have null landing pad for sjlj -- that would have
134214979Sdes	 been indicated by a -1 call site index.  */
135180750Sdes      landing_pad = cs_lp + 1;
136180740Sdes      if (cs_action)
137180740Sdes	action_record = info.action_table + cs_action - 1;
138204861Sdes      goto found_something;
139204861Sdes    }
140204861Sdes#else
141180740Sdes  /* Search the call-site table for the action associated with this IP.  */
142180740Sdes  while (p < info.action_table)
143218767Sdes    {
144218767Sdes      _Unwind_Ptr cs_start, cs_len, cs_lp;
145218767Sdes      _Unwind_Word cs_action;
146218767Sdes
147218767Sdes      /* Note that all call-site encodings are "absolute" displacements.  */
148218767Sdes      p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
149218767Sdes      p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
150218767Sdes      p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
151218767Sdes      p = read_uleb128 (p, &cs_action);
152180740Sdes
153180744Sdes      /* The table is sorted, so if we've passed the ip, stop.  */
154180744Sdes      if (ip < info.Start + cs_start)
155180744Sdes	p = info.action_table;
156180740Sdes      else if (ip < info.Start + cs_start + cs_len)
157180740Sdes	{
158180740Sdes	  if (cs_lp)
159180740Sdes	    landing_pad = info.LPStart + cs_lp;
160180740Sdes	  if (cs_action)
161180740Sdes	    action_record = info.action_table + cs_action - 1;
162180740Sdes	  goto found_something;
163214979Sdes	}
164214979Sdes    }
165180740Sdes
166180740Sdes#endif
167214979Sdes
168214979Sdes  /* IP is not in table.  No associated cleanups.  */
169180740Sdes  /* ??? This is where C++ calls std::terminate to catch throw
170214979Sdes     from a destructor.  */
171214979Sdes  return _URC_CONTINUE_UNWIND;
172214979Sdes
173214979Sdes found_something:
174214979Sdes  if (landing_pad == 0)
175214979Sdes    {
176180740Sdes      /* IP is present, but has a null landing pad.
177180740Sdes	 No handler to be run.  */
178180740Sdes      return _URC_CONTINUE_UNWIND;
179180740Sdes    }
180180740Sdes
181214979Sdes  _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
182214979Sdes		 (_Unwind_Ptr) ue_header);
183214979Sdes  _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0);
184214979Sdes  _Unwind_SetIP (context, landing_pad);
185214979Sdes  return _URC_INSTALL_CONTEXT;
186180740Sdes}
187180740Sdes