123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- /* Supporting functions for C exception handling.
- Copyright (C) 2002-2015 Free Software Foundation, Inc.
- Contributed by Aldy Hernandez <aldy@quesejoda.com>.
- Shamelessly stolen from the Java front end.
- This file is part of GCC.
- GCC is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 3, or (at your option) any later
- version.
- GCC is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
- Under Section 7 of GPL version 3, you are granted additional
- permissions described in the GCC Runtime Library Exception, version
- 3.1, as published by the Free Software Foundation.
- You should have received a copy of the GNU General Public License and
- a copy of the GCC Runtime Library Exception along with this program;
- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
- <http://www.gnu.org/licenses/>. */
- #include "tconfig.h"
- #include "tsystem.h"
- #include "unwind.h"
- #define NO_SIZE_OF_ENCODED_VALUE
- #include "unwind-pe.h"
- typedef struct
- {
- _Unwind_Ptr Start;
- _Unwind_Ptr LPStart;
- _Unwind_Ptr ttype_base;
- const unsigned char *TType;
- const unsigned char *action_table;
- unsigned char ttype_encoding;
- unsigned char call_site_encoding;
- } lsda_header_info;
- static const unsigned char *
- parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
- lsda_header_info *info)
- {
- _uleb128_t tmp;
- unsigned char lpstart_encoding;
- info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
- /* Find @LPStart, the base to which landing pad offsets are relative. */
- lpstart_encoding = *p++;
- if (lpstart_encoding != DW_EH_PE_omit)
- p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
- else
- info->LPStart = info->Start;
- /* Find @TType, the base of the handler and exception spec type data. */
- info->ttype_encoding = *p++;
- if (info->ttype_encoding != DW_EH_PE_omit)
- {
- p = read_uleb128 (p, &tmp);
- info->TType = p + tmp;
- }
- else
- info->TType = 0;
- /* The encoding and length of the call-site table; the action table
- immediately follows. */
- info->call_site_encoding = *p++;
- p = read_uleb128 (p, &tmp);
- info->action_table = p + tmp;
- return p;
- }
- #ifdef __ARM_EABI_UNWINDER__
- /* ARM EABI personality routines must also unwind the stack. */
- #define CONTINUE_UNWINDING \
- do \
- { \
- if (__gnu_unwind_frame (ue_header, context) != _URC_OK) \
- return _URC_FAILURE; \
- return _URC_CONTINUE_UNWIND; \
- } \
- while (0)
- #else
- #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
- #endif
- #ifdef __USING_SJLJ_EXCEPTIONS__
- #define PERSONALITY_FUNCTION __gcc_personality_sj0
- #define __builtin_eh_return_data_regno(x) x
- #elif defined(__SEH__)
- #define PERSONALITY_FUNCTION __gcc_personality_imp
- #else
- #define PERSONALITY_FUNCTION __gcc_personality_v0
- #endif
- #ifdef __ARM_EABI_UNWINDER__
- _Unwind_Reason_Code
- PERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *,
- struct _Unwind_Context *);
- _Unwind_Reason_Code
- PERSONALITY_FUNCTION (_Unwind_State state,
- struct _Unwind_Exception * ue_header,
- struct _Unwind_Context * context)
- #else
- #if defined (__SEH__) && !defined (__USING_SJLJ_EXCEPTIONS__)
- static
- #endif
- _Unwind_Reason_Code
- PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class,
- struct _Unwind_Exception *, struct _Unwind_Context *);
- _Unwind_Reason_Code
- PERSONALITY_FUNCTION (int version,
- _Unwind_Action actions,
- _Unwind_Exception_Class exception_class ATTRIBUTE_UNUSED,
- struct _Unwind_Exception *ue_header,
- struct _Unwind_Context *context)
- #endif
- {
- lsda_header_info info;
- const unsigned char *language_specific_data, *p;
- _Unwind_Ptr landing_pad, ip;
- int ip_before_insn = 0;
- #ifdef __ARM_EABI_UNWINDER__
- if ((state & _US_ACTION_MASK) != _US_UNWIND_FRAME_STARTING)
- CONTINUE_UNWINDING;
- /* The dwarf unwinder assumes the context structure holds things like the
- function and LSDA pointers. The ARM implementation caches these in
- the exception header (UCB). To avoid rewriting everything we make a
- virtual scratch register point at the UCB. */
- ip = (_Unwind_Ptr) ue_header;
- _Unwind_SetGR (context, UNWIND_POINTER_REG, ip);
- #else
- if (version != 1)
- return _URC_FATAL_PHASE1_ERROR;
- /* Currently we only support cleanups for C. */
- if ((actions & _UA_CLEANUP_PHASE) == 0)
- CONTINUE_UNWINDING;
- #endif
- language_specific_data = (const unsigned char *)
- _Unwind_GetLanguageSpecificData (context);
- /* If no LSDA, then there are no handlers or cleanups. */
- if (! language_specific_data)
- CONTINUE_UNWINDING;
- /* Parse the LSDA header. */
- p = parse_lsda_header (context, language_specific_data, &info);
- #ifdef HAVE_GETIPINFO
- ip = _Unwind_GetIPInfo (context, &ip_before_insn);
- #else
- ip = _Unwind_GetIP (context);
- #endif
- if (! ip_before_insn)
- --ip;
- landing_pad = 0;
- #ifdef __USING_SJLJ_EXCEPTIONS__
- /* The given "IP" is an index into the call-site table, with two
- exceptions -- -1 means no-action, and 0 means terminate. But
- since we're using uleb128 values, we've not got random access
- to the array. */
- if ((int) ip <= 0)
- return _URC_CONTINUE_UNWIND;
- else
- {
- _uleb128_t cs_lp, cs_action;
- do
- {
- p = read_uleb128 (p, &cs_lp);
- p = read_uleb128 (p, &cs_action);
- }
- while (--ip);
- /* Can never have null landing pad for sjlj -- that would have
- been indicated by a -1 call site index. */
- landing_pad = (_Unwind_Ptr)cs_lp + 1;
- goto found_something;
- }
- #else
- /* Search the call-site table for the action associated with this IP. */
- while (p < info.action_table)
- {
- _Unwind_Ptr cs_start, cs_len, cs_lp;
- _uleb128_t cs_action;
- /* Note that all call-site encodings are "absolute" displacements. */
- p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
- p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
- p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
- p = read_uleb128 (p, &cs_action);
- /* The table is sorted, so if we've passed the ip, stop. */
- if (ip < info.Start + cs_start)
- p = info.action_table;
- else if (ip < info.Start + cs_start + cs_len)
- {
- if (cs_lp)
- landing_pad = info.LPStart + cs_lp;
- goto found_something;
- }
- }
- #endif
- /* IP is not in table. No associated cleanups. */
- /* ??? This is where C++ calls std::terminate to catch throw
- from a destructor. */
- CONTINUE_UNWINDING;
- found_something:
- if (landing_pad == 0)
- {
- /* IP is present, but has a null landing pad.
- No handler to be run. */
- CONTINUE_UNWINDING;
- }
- _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
- (_Unwind_Ptr) ue_header);
- _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0);
- _Unwind_SetIP (context, landing_pad);
- return _URC_INSTALL_CONTEXT;
- }
- #if defined (__SEH__) && !defined (__USING_SJLJ_EXCEPTIONS__)
- EXCEPTION_DISPOSITION
- __gcc_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame,
- PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp)
- {
- return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context,
- ms_disp, __gcc_personality_imp);
- }
- #endif /* SEH */
|