eh_personality.cc revision 97403
1// -*- C++ -*- The GNU C++ exception personality routine.
2// Copyright (C) 2001 Free Software Foundation, Inc.
3//
4// This file is part of GNU CC.
5//
6// GNU CC is free software; you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation; either version 2, or (at your option)
9// any later version.
10//
11// GNU CC is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with GNU CC; see the file COPYING.  If not, write to
18// the Free Software Foundation, 59 Temple Place - Suite 330,
19// Boston, MA 02111-1307, USA.
20
21// As a special exception, you may use this file as part of a free software
22// library without restriction.  Specifically, if other files instantiate
23// templates or use macros or inline functions from this file, or you compile
24// this file and link it with other files to produce an executable, this
25// file does not by itself cause the resulting executable to be covered by
26// the GNU General Public License.  This exception does not however
27// invalidate any other reasons why the executable file might be covered by
28// the GNU General Public License.
29
30
31#include <bits/c++config.h>
32#include <cstdlib>
33#include <exception_defines.h>
34#include "unwind-cxx.h"
35
36using namespace __cxxabiv1;
37
38#include "unwind-pe.h"
39
40
41struct lsda_header_info
42{
43  _Unwind_Ptr Start;
44  _Unwind_Ptr LPStart;
45  _Unwind_Ptr ttype_base;
46  const unsigned char *TType;
47  const unsigned char *action_table;
48  unsigned char ttype_encoding;
49  unsigned char call_site_encoding;
50};
51
52static const unsigned char *
53parse_lsda_header (_Unwind_Context *context, const unsigned char *p,
54		   lsda_header_info *info)
55{
56  _Unwind_Word tmp;
57  unsigned char lpstart_encoding;
58
59  info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
60
61  // Find @LPStart, the base to which landing pad offsets are relative.
62  lpstart_encoding = *p++;
63  if (lpstart_encoding != DW_EH_PE_omit)
64    p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
65  else
66    info->LPStart = info->Start;
67
68  // Find @TType, the base of the handler and exception spec type data.
69  info->ttype_encoding = *p++;
70  if (info->ttype_encoding != DW_EH_PE_omit)
71    {
72      p = read_uleb128 (p, &tmp);
73      info->TType = p + tmp;
74    }
75  else
76    info->TType = 0;
77
78  // The encoding and length of the call-site table; the action table
79  // immediately follows.
80  info->call_site_encoding = *p++;
81  p = read_uleb128 (p, &tmp);
82  info->action_table = p + tmp;
83
84  return p;
85}
86
87static const std::type_info *
88get_ttype_entry (lsda_header_info *info, _Unwind_Word i)
89{
90  _Unwind_Ptr ptr;
91
92  i *= size_of_encoded_value (info->ttype_encoding);
93  read_encoded_value_with_base (info->ttype_encoding, info->ttype_base,
94				info->TType - i, &ptr);
95
96  return reinterpret_cast<const std::type_info *>(ptr);
97}
98
99// Given the thrown type THROW_TYPE, pointer to a variable containing a
100// pointer to the exception object THROWN_PTR_P and a type CATCH_TYPE to
101// compare against, return whether or not there is a match and if so,
102// update *THROWN_PTR_P.
103
104static bool
105get_adjusted_ptr (const std::type_info *catch_type,
106		  const std::type_info *throw_type,
107		  void **thrown_ptr_p)
108{
109  void *thrown_ptr = *thrown_ptr_p;
110
111  // Pointer types need to adjust the actual pointer, not
112  // the pointer to pointer that is the exception object.
113  // This also has the effect of passing pointer types
114  // "by value" through the __cxa_begin_catch return value.
115  if (throw_type->__is_pointer_p ())
116    thrown_ptr = *(void **) thrown_ptr;
117
118  if (catch_type->__do_catch (throw_type, &thrown_ptr, 1))
119    {
120      *thrown_ptr_p = thrown_ptr;
121      return true;
122    }
123
124  return false;
125}
126
127static bool
128check_exception_spec (lsda_header_info *info, const std::type_info *throw_type,
129		      void *thrown_ptr, _Unwind_Sword filter_value)
130{
131  const unsigned char *e = info->TType - filter_value - 1;
132
133  while (1)
134    {
135      const std::type_info *catch_type;
136      _Unwind_Word tmp;
137
138      e = read_uleb128 (e, &tmp);
139
140      // Zero signals the end of the list.  If we've not found
141      // a match by now, then we've failed the specification.
142      if (tmp == 0)
143        return false;
144
145      // Match a ttype entry.
146      catch_type = get_ttype_entry (info, tmp);
147
148      // ??? There is currently no way to ask the RTTI code about the
149      // relationship between two types without reference to a specific
150      // object.  There should be; then we wouldn't need to mess with
151      // thrown_ptr here.
152      if (get_adjusted_ptr (catch_type, throw_type, &thrown_ptr))
153	return true;
154    }
155}
156
157// Using a different personality function name causes link failures
158// when trying to mix code using different exception handling models.
159#ifdef _GLIBCPP_SJLJ_EXCEPTIONS
160#define PERSONALITY_FUNCTION	__gxx_personality_sj0
161#define __builtin_eh_return_data_regno(x) x
162#else
163#define PERSONALITY_FUNCTION	__gxx_personality_v0
164#endif
165
166extern "C" _Unwind_Reason_Code
167PERSONALITY_FUNCTION (int version,
168		      _Unwind_Action actions,
169		      _Unwind_Exception_Class exception_class,
170		      struct _Unwind_Exception *ue_header,
171		      struct _Unwind_Context *context)
172{
173  __cxa_exception *xh = __get_exception_header_from_ue (ue_header);
174
175  enum found_handler_type
176  {
177    found_nothing,
178    found_terminate,
179    found_cleanup,
180    found_handler
181  } found_type;
182
183  lsda_header_info info;
184  const unsigned char *language_specific_data;
185  const unsigned char *action_record;
186  const unsigned char *p;
187  _Unwind_Ptr landing_pad, ip;
188  int handler_switch_value;
189  void *thrown_ptr = xh + 1;
190
191  // Interface version check.
192  if (version != 1)
193    return _URC_FATAL_PHASE1_ERROR;
194
195  // Shortcut for phase 2 found handler for domestic exception.
196  if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME)
197      && exception_class == __gxx_exception_class)
198    {
199      handler_switch_value = xh->handlerSwitchValue;
200      landing_pad = (_Unwind_Ptr) xh->catchTemp;
201      found_type = (landing_pad == 0 ? found_terminate : found_handler);
202      goto install_context;
203    }
204
205  language_specific_data = (const unsigned char *)
206    _Unwind_GetLanguageSpecificData (context);
207
208  // If no LSDA, then there are no handlers or cleanups.
209  if (! language_specific_data)
210    return _URC_CONTINUE_UNWIND;
211
212  // Parse the LSDA header.
213  p = parse_lsda_header (context, language_specific_data, &info);
214  info.ttype_base = base_of_encoded_value (info.ttype_encoding, context);
215  ip = _Unwind_GetIP (context) - 1;
216  landing_pad = 0;
217  action_record = 0;
218  handler_switch_value = 0;
219
220#ifdef _GLIBCPP_SJLJ_EXCEPTIONS
221  // The given "IP" is an index into the call-site table, with two
222  // exceptions -- -1 means no-action, and 0 means terminate.  But
223  // since we're using uleb128 values, we've not got random access
224  // to the array.
225  if ((int) ip < 0)
226    return _URC_CONTINUE_UNWIND;
227  else if (ip == 0)
228    {
229      // Fall through to set found_terminate.
230    }
231  else
232    {
233      _Unwind_Word cs_lp, cs_action;
234      do
235	{
236	  p = read_uleb128 (p, &cs_lp);
237	  p = read_uleb128 (p, &cs_action);
238	}
239      while (--ip);
240
241      // Can never have null landing pad for sjlj -- that would have
242      // been indicated by a -1 call site index.
243      landing_pad = cs_lp + 1;
244      if (cs_action)
245	action_record = info.action_table + cs_action - 1;
246      goto found_something;
247    }
248#else
249  // Search the call-site table for the action associated with this IP.
250  while (p < info.action_table)
251    {
252      _Unwind_Ptr cs_start, cs_len, cs_lp;
253      _Unwind_Word cs_action;
254
255      // Note that all call-site encodings are "absolute" displacements.
256      p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
257      p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
258      p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
259      p = read_uleb128 (p, &cs_action);
260
261      // The table is sorted, so if we've passed the ip, stop.
262      if (ip < info.Start + cs_start)
263	p = info.action_table;
264      else if (ip < info.Start + cs_start + cs_len)
265	{
266	  if (cs_lp)
267	    landing_pad = info.LPStart + cs_lp;
268	  if (cs_action)
269	    action_record = info.action_table + cs_action - 1;
270	  goto found_something;
271	}
272    }
273#endif // _GLIBCPP_SJLJ_EXCEPTIONS
274
275  // If ip is not present in the table, call terminate.  This is for
276  // a destructor inside a cleanup, or a library routine the compiler
277  // was not expecting to throw.
278  found_type = (actions & _UA_FORCE_UNWIND ? found_nothing : found_terminate);
279  goto do_something;
280
281 found_something:
282  if (landing_pad == 0)
283    {
284      // If ip is present, and has a null landing pad, there are
285      // no cleanups or handlers to be run.
286      found_type = found_nothing;
287    }
288  else if (action_record == 0)
289    {
290      // If ip is present, has a non-null landing pad, and a null
291      // action table offset, then there are only cleanups present.
292      // Cleanups use a zero switch value, as set above.
293      found_type = found_cleanup;
294    }
295  else
296    {
297      // Otherwise we have a catch handler or exception specification.
298
299      _Unwind_Sword ar_filter, ar_disp;
300      const std::type_info *throw_type, *catch_type;
301      bool saw_cleanup = false;
302      bool saw_handler = false;
303
304      // During forced unwinding, we only run cleanups.  With a foreign
305      // exception class, there's no exception type.
306      // ??? What to do about GNU Java and GNU Ada exceptions.
307
308      if ((actions & _UA_FORCE_UNWIND)
309	  || exception_class != __gxx_exception_class)
310	throw_type = 0;
311      else
312	throw_type = xh->exceptionType;
313
314      while (1)
315	{
316	  p = action_record;
317	  p = read_sleb128 (p, &ar_filter);
318	  read_sleb128 (p, &ar_disp);
319
320	  if (ar_filter == 0)
321	    {
322	      // Zero filter values are cleanups.
323	      saw_cleanup = true;
324	    }
325	  else if (ar_filter > 0)
326	    {
327	      // Positive filter values are handlers.
328	      catch_type = get_ttype_entry (&info, ar_filter);
329
330	      // Null catch type is a catch-all handler.  We can catch
331	      // foreign exceptions with this.
332	      if (! catch_type)
333		{
334		  if (!(actions & _UA_FORCE_UNWIND))
335		    {
336		      saw_handler = true;
337		      break;
338		    }
339		}
340	      else if (throw_type)
341		{
342		  if (get_adjusted_ptr (catch_type, throw_type, &thrown_ptr))
343		    {
344		      saw_handler = true;
345		      break;
346		    }
347		}
348	    }
349	  else
350	    {
351	      // Negative filter values are exception specifications.
352	      // ??? How do foreign exceptions fit in?  As far as I can
353	      // see we can't match because there's no __cxa_exception
354	      // object to stuff bits in for __cxa_call_unexpected to use.
355	      if (throw_type
356		  && ! check_exception_spec (&info, throw_type, thrown_ptr,
357					     ar_filter))
358		{
359		  saw_handler = true;
360		  break;
361		}
362	    }
363
364	  if (ar_disp == 0)
365	    break;
366	  action_record = p + ar_disp;
367	}
368
369      if (saw_handler)
370	{
371	  handler_switch_value = ar_filter;
372	  found_type = found_handler;
373	}
374      else
375	found_type = (saw_cleanup ? found_cleanup : found_nothing);
376    }
377
378 do_something:
379   if (found_type == found_nothing)
380     return _URC_CONTINUE_UNWIND;
381
382  if (actions & _UA_SEARCH_PHASE)
383    {
384      if (found_type == found_cleanup)
385	return _URC_CONTINUE_UNWIND;
386
387      // For domestic exceptions, we cache data from phase 1 for phase 2.
388      if (exception_class == __gxx_exception_class)
389        {
390          xh->handlerSwitchValue = handler_switch_value;
391          xh->actionRecord = action_record;
392          xh->languageSpecificData = language_specific_data;
393          xh->adjustedPtr = thrown_ptr;
394
395          // ??? Completely unknown what this field is supposed to be for.
396          // ??? Need to cache TType encoding base for call_unexpected.
397          xh->catchTemp = (void *) (_Unwind_Ptr) landing_pad;
398	}
399      return _URC_HANDLER_FOUND;
400    }
401
402 install_context:
403  if (found_type == found_terminate)
404    {
405      __cxa_begin_catch (&xh->unwindHeader);
406      __terminate (xh->terminateHandler);
407    }
408
409  // Cache the TType base value for __cxa_call_unexpected, as we won't
410  // have an _Unwind_Context then.
411  if (handler_switch_value < 0)
412    {
413      parse_lsda_header (context, xh->languageSpecificData, &info);
414      xh->catchTemp = (void *) base_of_encoded_value (info.ttype_encoding,
415						      context);
416    }
417
418  _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
419		 (_Unwind_Ptr) &xh->unwindHeader);
420  _Unwind_SetGR (context, __builtin_eh_return_data_regno (1),
421		 handler_switch_value);
422  _Unwind_SetIP (context, landing_pad);
423  return _URC_INSTALL_CONTEXT;
424}
425
426extern "C" void
427__cxa_call_unexpected (void *exc_obj_in)
428{
429  _Unwind_Exception *exc_obj
430    = reinterpret_cast <_Unwind_Exception *>(exc_obj_in);
431
432  __cxa_begin_catch (exc_obj);
433
434  // This function is a handler for our exception argument.  If we exit
435  // by throwing a different exception, we'll need the original cleaned up.
436  struct end_catch_protect
437  {
438    end_catch_protect() { }
439    ~end_catch_protect() { __cxa_end_catch(); }
440  } end_catch_protect_obj;
441
442  lsda_header_info info;
443  __cxa_exception *xh = __get_exception_header_from_ue (exc_obj);
444  const unsigned char *xh_lsda;
445  _Unwind_Sword xh_switch_value;
446  std::terminate_handler xh_terminate_handler;
447
448  // If the unexpectedHandler rethrows the exception (e.g. to categorize it),
449  // it will clobber data about the current handler.  So copy the data out now.
450  xh_lsda = xh->languageSpecificData;
451  xh_switch_value = xh->handlerSwitchValue;
452  xh_terminate_handler = xh->terminateHandler;
453  info.ttype_base = (_Unwind_Ptr) xh->catchTemp;
454
455  try
456    { __unexpected (xh->unexpectedHandler); }
457  catch(...)
458    {
459      // Get the exception thrown from unexpected.
460      // ??? Foreign exceptions can't be stacked this way.
461
462      __cxa_eh_globals *globals = __cxa_get_globals_fast ();
463      __cxa_exception *new_xh = globals->caughtExceptions;
464      void *new_ptr = new_xh + 1;
465
466      // We don't quite have enough stuff cached; re-parse the LSDA.
467      parse_lsda_header (0, xh_lsda, &info);
468
469      // If this new exception meets the exception spec, allow it.
470      if (check_exception_spec (&info, new_xh->exceptionType,
471				new_ptr, xh_switch_value))
472	__throw_exception_again;
473
474      // If the exception spec allows std::bad_exception, throw that.
475      // We don't have a thrown object to compare against, but since
476      // bad_exception doesn't have virtual bases, that's OK; just pass 0.
477#ifdef __EXCEPTIONS
478      const std::type_info &bad_exc = typeid (std::bad_exception);
479      if (check_exception_spec (&info, &bad_exc, 0, xh_switch_value))
480	throw std::bad_exception();
481#endif
482      // Otherwise, die.
483      __terminate (xh_terminate_handler);
484    }
485}
486