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