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