unwind-c.c revision 169689
1193323Sed/* Supporting functions for C exception handling. 2193323Sed Copyright (C) 2002, 2003 Free Software Foundation, Inc. 3353358Sdim Contributed by Aldy Hernandez <aldy@quesejoda.com>. 4353358Sdim Shamelessly stolen from the Java front end. 5353358Sdim 6193323SedThis file is part of GCC. 7193323Sed 8193323SedGCC is free software; you can redistribute it and/or modify it under 9193323Sedthe terms of the GNU General Public License as published by the Free 10193323SedSoftware Foundation; either version 2, or (at your option) any later 11193323Sedversion. 12193323Sed 13193323SedIn addition to the permissions in the GNU General Public License, the 14193323SedFree Software Foundation gives you unlimited permission to link the 15327952Sdimcompiled version of this file into combinations with other programs, 16249423Sdimand to distribute those combinations without any restriction coming 17327952Sdimfrom the use of this file. (The General Public License restrictions 18327952Sdimdo apply in other respects; for example, they cover modification of 19353358Sdimthe file, and distribution when not linked into a combined 20353358Sdimexecutable.) 21353358Sdim 22327952SdimGCC is distributed in the hope that it will be useful, but WITHOUT ANY 23288943SdimWARRANTY; without even the implied warranty of MERCHANTABILITY or 24353358SdimFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 25249423Sdimfor more details. 26249423Sdim 27327952SdimYou should have received a copy of the GNU General Public License 28249423Sdimalong with GCC; see the file COPYING. If not, write to the Free 29327952SdimSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 30360784Sdim02110-1301, USA. */ 31193323Sed 32327952Sdim#include "tconfig.h" 33198892Srdivacky#include "tsystem.h" 34193323Sed#include "unwind.h" 35353358Sdim#define NO_SIZE_OF_ENCODED_VALUE 36193323Sed#include "unwind-pe.h" 37341825Sdim 38288943Sdimtypedef struct 39193323Sed{ 40327952Sdim _Unwind_Ptr Start; 41327952Sdim _Unwind_Ptr LPStart; 42327952Sdim _Unwind_Ptr ttype_base; 43327952Sdim const unsigned char *TType; 44327952Sdim const unsigned char *action_table; 45327952Sdim unsigned char ttype_encoding; 46193323Sed unsigned char call_site_encoding; 47193323Sed} lsda_header_info; 48276479Sdim 49276479Sdimstatic const unsigned char * 50193323Sedparse_lsda_header (struct _Unwind_Context *context, const unsigned char *p, 51327952Sdim lsda_header_info *info) 52288943Sdim{ 53288943Sdim _Unwind_Word tmp; 54288943Sdim unsigned char lpstart_encoding; 55288943Sdim 56327952Sdim info->Start = (context ? _Unwind_GetRegionStart (context) : 0); 57288943Sdim 58327952Sdim /* Find @LPStart, the base to which landing pad offsets are relative. */ 59327952Sdim lpstart_encoding = *p++; 60327952Sdim if (lpstart_encoding != DW_EH_PE_omit) 61327952Sdim p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart); 62327952Sdim else 63327952Sdim info->LPStart = info->Start; 64327952Sdim 65327952Sdim /* Find @TType, the base of the handler and exception spec type data. */ 66353358Sdim info->ttype_encoding = *p++; 67353358Sdim if (info->ttype_encoding != DW_EH_PE_omit) 68327952Sdim { 69327952Sdim p = read_uleb128 (p, &tmp); 70327952Sdim info->TType = p + tmp; 71327952Sdim } 72327952Sdim else 73296417Sdim info->TType = 0; 74198892Srdivacky 75193323Sed /* The encoding and length of the call-site table; the action table 76327952Sdim immediately follows. */ 77327952Sdim info->call_site_encoding = *p++; 78327952Sdim p = read_uleb128 (p, &tmp); 79218893Sdim info->action_table = p + tmp; 80218893Sdim 81341825Sdim return p; 82193323Sed} 83276479Sdim 84276479Sdim#ifdef __ARM_EABI_UNWINDER__ 85353358Sdim/* ARM EABI personality routines must also unwind the stack. */ 86353358Sdim#define CONTINUE_UNWINDING \ 87353358Sdim do \ 88353358Sdim { \ 89193323Sed if (__gnu_unwind_frame (ue_header, context) != _URC_OK) \ 90288943Sdim return _URC_FAILURE; \ 91288943Sdim return _URC_CONTINUE_UNWIND; \ 92193323Sed } \ 93193323Sed while (0) 94288943Sdim#else 95288943Sdim#define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND 96193323Sed#endif 97193323Sed 98327952Sdim#ifdef __USING_SJLJ_EXCEPTIONS__ 99327952Sdim#define PERSONALITY_FUNCTION __gcc_personality_sj0 100327952Sdim#define __builtin_eh_return_data_regno(x) x 101193323Sed#else 102353358Sdim#define PERSONALITY_FUNCTION __gcc_personality_v0 103353358Sdim#endif 104353358Sdim 105193323Sed#ifdef __ARM_EABI_UNWINDER__ 106276479Sdim_Unwind_Reason_Code 107276479SdimPERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *, 108276479Sdim struct _Unwind_Context *); 109288943Sdim 110288943Sdim_Unwind_Reason_Code 111353358SdimPERSONALITY_FUNCTION (_Unwind_State state, 112353358Sdim struct _Unwind_Exception * ue_header, 113353358Sdim struct _Unwind_Context * context) 114276479Sdim#else 115193323Sed_Unwind_Reason_Code 116261991SdimPERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class, 117261991Sdim struct _Unwind_Exception *, struct _Unwind_Context *); 118261991Sdim 119261991Sdim_Unwind_Reason_Code 120327952SdimPERSONALITY_FUNCTION (int version, 121327952Sdim _Unwind_Action actions, 122261991Sdim _Unwind_Exception_Class exception_class ATTRIBUTE_UNUSED, 123261991Sdim struct _Unwind_Exception *ue_header, 124261991Sdim struct _Unwind_Context *context) 125261991Sdim#endif 126261991Sdim{ 127193323Sed lsda_header_info info; 128327952Sdim const unsigned char *language_specific_data, *p, *action_record; 129327952Sdim _Unwind_Ptr landing_pad, ip; 130193323Sed int ip_before_insn = 0; 131327952Sdim 132327952Sdim#ifdef __ARM_EABI_UNWINDER__ 133327952Sdim if ((state & _US_ACTION_MASK) != _US_UNWIND_FRAME_STARTING) 134327952Sdim CONTINUE_UNWINDING; 135353358Sdim 136353358Sdim /* The dwarf unwinder assumes the context structure holds things like the 137353358Sdim function and LSDA pointers. The ARM implementation caches these in 138353358Sdim the exception header (UCB). To avoid rewriting everything we make the 139353358Sdim virtual IP register point at the UCB. */ 140353358Sdim ip = (_Unwind_Ptr) ue_header; 141193323Sed _Unwind_SetGR (context, 12, ip); 142193323Sed#else 143193323Sed if (version != 1) 144193323Sed return _URC_FATAL_PHASE1_ERROR; 145193323Sed 146193323Sed /* Currently we only support cleanups for C. */ 147193323Sed if ((actions & _UA_CLEANUP_PHASE) == 0) 148353358Sdim CONTINUE_UNWINDING; 149353358Sdim#endif 150353358Sdim 151353358Sdim language_specific_data = (const unsigned char *) 152353358Sdim _Unwind_GetLanguageSpecificData (context); 153353358Sdim 154353358Sdim /* If no LSDA, then there are no handlers or cleanups. */ 155353358Sdim if (! language_specific_data) 156353358Sdim CONTINUE_UNWINDING; 157353358Sdim 158353358Sdim /* Parse the LSDA header. */ 159193323Sed p = parse_lsda_header (context, language_specific_data, &info); 160296417Sdim#ifdef HAVE_GETIPINFO 161193323Sed ip = _Unwind_GetIPInfo (context, &ip_before_insn); 162193323Sed#else 163296417Sdim ip = _Unwind_GetIP (context); 164193323Sed#endif 165296417Sdim if (! ip_before_insn) 166296417Sdim --ip; 167296417Sdim landing_pad = 0; 168296417Sdim 169296417Sdim#ifdef __USING_SJLJ_EXCEPTIONS__ 170193323Sed /* The given "IP" is an index into the call-site table, with two 171193323Sed exceptions -- -1 means no-action, and 0 means terminate. But 172353358Sdim since we're using uleb128 values, we've not got random access 173193323Sed to the array. */ 174193323Sed if ((int) ip <= 0) 175193323Sed return _URC_CONTINUE_UNWIND; 176296417Sdim else 177353358Sdim { 178296417Sdim _Unwind_Word cs_lp, cs_action; 179296417Sdim do 180296417Sdim { 181193323Sed p = read_uleb128 (p, &cs_lp); 182193323Sed p = read_uleb128 (p, &cs_action); 183193323Sed } 184296417Sdim while (--ip); 185341825Sdim 186341825Sdim /* Can never have null landing pad for sjlj -- that would have 187198090Srdivacky been indicated by a -1 call site index. */ 188193323Sed landing_pad = cs_lp + 1; 189193323Sed if (cs_action) 190353358Sdim action_record = info.action_table + cs_action - 1; 191353358Sdim goto found_something; 192353358Sdim } 193353358Sdim#else 194353358Sdim /* Search the call-site table for the action associated with this IP. */ 195193323Sed while (p < info.action_table) 196193323Sed { 197193323Sed _Unwind_Ptr cs_start, cs_len, cs_lp; 198193323Sed _Unwind_Word cs_action; 199193323Sed 200341825Sdim /* Note that all call-site encodings are "absolute" displacements. */ 201296417Sdim p = read_encoded_value (0, info.call_site_encoding, p, &cs_start); 202296417Sdim p = read_encoded_value (0, info.call_site_encoding, p, &cs_len); 203296417Sdim p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp); 204296417Sdim p = read_uleb128 (p, &cs_action); 205296417Sdim 206296417Sdim /* The table is sorted, so if we've passed the ip, stop. */ 207296417Sdim if (ip < info.Start + cs_start) 208296417Sdim p = info.action_table; 209296417Sdim else if (ip < info.Start + cs_start + cs_len) 210353358Sdim { 211353358Sdim if (cs_lp) 212353358Sdim landing_pad = info.LPStart + cs_lp; 213296417Sdim if (cs_action) 214296417Sdim action_record = info.action_table + cs_action - 1; 215280031Sdim goto found_something; 216276479Sdim } 217276479Sdim } 218296417Sdim#endif 219280031Sdim 220280031Sdim /* IP is not in table. No associated cleanups. */ 221280031Sdim /* ??? This is where C++ calls std::terminate to catch throw 222280031Sdim from a destructor. */ 223280031Sdim CONTINUE_UNWINDING; 224280031Sdim 225280031Sdim found_something: 226276479Sdim if (landing_pad == 0) 227280031Sdim { 228296417Sdim /* IP is present, but has a null landing pad. 229280031Sdim No handler to be run. */ 230288943Sdim CONTINUE_UNWINDING; 231280031Sdim } 232280031Sdim 233288943Sdim _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), 234280031Sdim (_Unwind_Ptr) ue_header); 235280031Sdim _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0); 236288943Sdim _Unwind_SetIP (context, landing_pad); 237288943Sdim return _URC_INSTALL_CONTEXT; 238327952Sdim} 239309124Sdim