unwind-c.c revision 132718
1/* Supporting functions for C exception handling.
2   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
3   Contributed by Aldy Hernandez <aldy@quesejoda.com>.
4   Shamelessly stolen from the Java front end.
5
6This file is part of GCC.
7
8GCC is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
10Software Foundation; either version 2, or (at your option) any later
11version.
12
13In addition to the permissions in the GNU General Public License, the
14Free Software Foundation gives you unlimited permission to link the
15compiled version of this file into combinations with other programs,
16and to distribute those combinations without any restriction coming
17from the use of this file.  (The General Public License restrictions
18do apply in other respects; for example, they cover modification of
19the file, and distribution when not linked into a combined
20executable.)
21
22GCC is distributed in the hope that it will be useful, but WITHOUT ANY
23WARRANTY; without even the implied warranty of MERCHANTABILITY or
24FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
25for more details.
26
27You should have received a copy of the GNU General Public License
28along with GCC; see the file COPYING.  If not, write to the Free
29Software Foundation, 59 Temple Place - Suite 330, Boston, MA
3002111-1307, USA.  */
31
32#include "tconfig.h"
33#include "tsystem.h"
34#include "unwind.h"
35#define NO_SIZE_OF_ENCODED_VALUE
36#include "unwind-pe.h"
37
38typedef struct
39{
40  _Unwind_Ptr Start;
41  _Unwind_Ptr LPStart;
42  _Unwind_Ptr ttype_base;
43  const unsigned char *TType;
44  const unsigned char *action_table;
45  unsigned char ttype_encoding;
46  unsigned char call_site_encoding;
47} lsda_header_info;
48
49static const unsigned char *
50parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
51		   lsda_header_info *info)
52{
53  _Unwind_Word tmp;
54  unsigned char lpstart_encoding;
55
56  info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
57
58  /* Find @LPStart, the base to which landing pad offsets are relative.  */
59  lpstart_encoding = *p++;
60  if (lpstart_encoding != DW_EH_PE_omit)
61    p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
62  else
63    info->LPStart = info->Start;
64
65  /* Find @TType, the base of the handler and exception spec type data.  */
66  info->ttype_encoding = *p++;
67  if (info->ttype_encoding != DW_EH_PE_omit)
68    {
69      p = read_uleb128 (p, &tmp);
70      info->TType = p + tmp;
71    }
72  else
73    info->TType = 0;
74
75  /* The encoding and length of the call-site table; the action table
76     immediately follows.  */
77  info->call_site_encoding = *p++;
78  p = read_uleb128 (p, &tmp);
79  info->action_table = p + tmp;
80
81  return p;
82}
83
84#ifdef __USING_SJLJ_EXCEPTIONS__
85#define PERSONALITY_FUNCTION    __gcc_personality_sj0
86#define __builtin_eh_return_data_regno(x) x
87#else
88#define PERSONALITY_FUNCTION    __gcc_personality_v0
89#endif
90
91_Unwind_Reason_Code
92PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class,
93		      struct _Unwind_Exception *, struct _Unwind_Context *);
94
95_Unwind_Reason_Code
96PERSONALITY_FUNCTION (int version,
97		      _Unwind_Action actions,
98		      _Unwind_Exception_Class exception_class ATTRIBUTE_UNUSED,
99		      struct _Unwind_Exception *ue_header,
100		      struct _Unwind_Context *context)
101{
102  lsda_header_info info;
103  const unsigned char *language_specific_data, *p, *action_record;
104  _Unwind_Ptr landing_pad, ip;
105
106  if (version != 1)
107    return _URC_FATAL_PHASE1_ERROR;
108
109  /* Currently we only support cleanups for C.  */
110  if ((actions & _UA_CLEANUP_PHASE) == 0)
111    return _URC_CONTINUE_UNWIND;
112
113  language_specific_data = (const unsigned char *)
114    _Unwind_GetLanguageSpecificData (context);
115
116  /* If no LSDA, then there are no handlers or cleanups.  */
117  if (! language_specific_data)
118    return _URC_CONTINUE_UNWIND;
119
120  /* Parse the LSDA header.  */
121  p = parse_lsda_header (context, language_specific_data, &info);
122  ip = _Unwind_GetIP (context) - 1;
123  landing_pad = 0;
124
125#ifdef __USING_SJLJ_EXCEPTIONS__
126  /* The given "IP" is an index into the call-site table, with two
127     exceptions -- -1 means no-action, and 0 means terminate.  But
128     since we're using uleb128 values, we've not got random access
129     to the array.  */
130  if ((int) ip <= 0)
131    return _URC_CONTINUE_UNWIND;
132  else
133    {
134      _Unwind_Word cs_lp, cs_action;
135      do
136	{
137	  p = read_uleb128 (p, &cs_lp);
138	  p = read_uleb128 (p, &cs_action);
139	}
140      while (--ip);
141
142      /* Can never have null landing pad for sjlj -- that would have
143	 been indicated by a -1 call site index.  */
144      landing_pad = cs_lp + 1;
145      if (cs_action)
146	action_record = info.action_table + cs_action - 1;
147      goto found_something;
148    }
149#else
150  /* Search the call-site table for the action associated with this IP.  */
151  while (p < info.action_table)
152    {
153      _Unwind_Ptr cs_start, cs_len, cs_lp;
154      _Unwind_Word cs_action;
155
156      /* Note that all call-site encodings are "absolute" displacements.  */
157      p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
158      p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
159      p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
160      p = read_uleb128 (p, &cs_action);
161
162      /* The table is sorted, so if we've passed the ip, stop.  */
163      if (ip < info.Start + cs_start)
164	p = info.action_table;
165      else if (ip < info.Start + cs_start + cs_len)
166	{
167	  if (cs_lp)
168	    landing_pad = info.LPStart + cs_lp;
169	  if (cs_action)
170	    action_record = info.action_table + cs_action - 1;
171	  goto found_something;
172	}
173    }
174
175#endif
176
177  /* IP is not in table.  No associated cleanups.  */
178  /* ??? This is where C++ calls std::terminate to catch throw
179     from a destructor.  */
180  return _URC_CONTINUE_UNWIND;
181
182 found_something:
183  if (landing_pad == 0)
184    {
185      /* IP is present, but has a null landing pad.
186	 No handler to be run.  */
187      return _URC_CONTINUE_UNWIND;
188    }
189
190  _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
191		 (_Unwind_Ptr) ue_header);
192  _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0);
193  _Unwind_SetIP (context, landing_pad);
194  return _URC_INSTALL_CONTEXT;
195}
196