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 6This file is part of GCC. 7 8GCC is free software; you can redistribute it and/or modify it under 9the terms of the GNU General Public License as published by the Free 10Software Foundation; either version 2, or (at your option) any later 11version. 12 13In addition to the permissions in the GNU General Public License, the 14Free Software Foundation gives you unlimited permission to link the 15compiled version of this file into combinations with other programs, 16and to distribute those combinations without any restriction coming 17from the use of this file. (The General Public License restrictions 18do apply in other respects; for example, they cover modification of 19the file, and distribution when not linked into a combined 20executable.) 21 22GCC is distributed in the hope that it will be useful, but WITHOUT ANY 23WARRANTY; without even the implied warranty of MERCHANTABILITY or 24FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 25for more details. 26 27You should have received a copy of the GNU General Public License 28along with GCC; see the file COPYING. If not, write to the Free 29Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 3002110-1301, USA. */ 31 32#include "tconfig.h" 33#include "tsystem.h" 34#include "unwind.h" 35#define NO_SIZE_OF_ENCODED_VALUE 36#include "unwind-pe.h" 37 38typedef struct 39{ 40 _Unwind_Ptr Start; 41 _Unwind_Ptr LPStart; 42 _Unwind_Ptr ttype_base; 43 const unsigned char *TType; 44 const unsigned char *action_table; 45 unsigned char ttype_encoding; 46 unsigned char call_site_encoding; 47} lsda_header_info; 48 49static const unsigned char * 50parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p, 51 lsda_header_info *info) 52{ 53 _Unwind_Word tmp; 54 unsigned char lpstart_encoding; 55 56 info->Start = (context ? _Unwind_GetRegionStart (context) : 0); 57 58 /* Find @LPStart, the base to which landing pad offsets are relative. */ 59 lpstart_encoding = *p++; 60 if (lpstart_encoding != DW_EH_PE_omit) 61 p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart); 62 else 63 info->LPStart = info->Start; 64 65 /* Find @TType, the base of the handler and exception spec type data. */ 66 info->ttype_encoding = *p++; 67 if (info->ttype_encoding != DW_EH_PE_omit) 68 { 69 p = read_uleb128 (p, &tmp); 70 info->TType = p + tmp; 71 } 72 else 73 info->TType = 0; 74 75 /* The encoding and length of the call-site table; the action table 76 immediately follows. */ 77 info->call_site_encoding = *p++; 78 p = read_uleb128 (p, &tmp); 79 info->action_table = p + tmp; 80 81 return p; 82} 83 84#ifdef __ARM_EABI_UNWINDER__ 85/* ARM EABI personality routines must also unwind the stack. */ 86#define CONTINUE_UNWINDING \ 87 do \ 88 { \ 89 if (__gnu_unwind_frame (ue_header, context) != _URC_OK) \ 90 return _URC_FAILURE; \ 91 return _URC_CONTINUE_UNWIND; \ 92 } \ 93 while (0) 94#else 95#define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND 96#endif 97 98#ifdef __USING_SJLJ_EXCEPTIONS__ 99#define PERSONALITY_FUNCTION __gcc_personality_sj0 100#define __builtin_eh_return_data_regno(x) x 101#else 102#define PERSONALITY_FUNCTION __gcc_personality_v0 103#endif 104 105#ifdef __ARM_EABI_UNWINDER__ 106_Unwind_Reason_Code 107PERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *, 108 struct _Unwind_Context *); 109 110_Unwind_Reason_Code 111PERSONALITY_FUNCTION (_Unwind_State state, 112 struct _Unwind_Exception * ue_header, 113 struct _Unwind_Context * context) 114#else 115_Unwind_Reason_Code 116PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class, 117 struct _Unwind_Exception *, struct _Unwind_Context *); 118 119_Unwind_Reason_Code 120PERSONALITY_FUNCTION (int version, 121 _Unwind_Action actions, 122 _Unwind_Exception_Class exception_class ATTRIBUTE_UNUSED, 123 struct _Unwind_Exception *ue_header, 124 struct _Unwind_Context *context) 125#endif 126{ 127 lsda_header_info info; 128 const unsigned char *language_specific_data, *p, *action_record; 129 _Unwind_Ptr landing_pad, ip; 130 int ip_before_insn = 0; 131 132#ifdef __ARM_EABI_UNWINDER__ 133 if ((state & _US_ACTION_MASK) != _US_UNWIND_FRAME_STARTING) 134 CONTINUE_UNWINDING; 135 136 /* The dwarf unwinder assumes the context structure holds things like the 137 function and LSDA pointers. The ARM implementation caches these in 138 the exception header (UCB). To avoid rewriting everything we make the 139 virtual IP register point at the UCB. */ 140 ip = (_Unwind_Ptr) ue_header; 141 _Unwind_SetGR (context, 12, ip); 142#else 143 if (version != 1) 144 return _URC_FATAL_PHASE1_ERROR; 145 146 /* Currently we only support cleanups for C. */ 147 if ((actions & _UA_CLEANUP_PHASE) == 0) 148 CONTINUE_UNWINDING; 149#endif 150 151 language_specific_data = (const unsigned char *) 152 _Unwind_GetLanguageSpecificData (context); 153 154 /* If no LSDA, then there are no handlers or cleanups. */ 155 if (! language_specific_data) 156 CONTINUE_UNWINDING; 157 158 /* Parse the LSDA header. */ 159 p = parse_lsda_header (context, language_specific_data, &info); 160#ifdef HAVE_GETIPINFO 161 ip = _Unwind_GetIPInfo (context, &ip_before_insn); 162#else 163 ip = _Unwind_GetIP (context); 164#endif 165 if (! ip_before_insn) 166 --ip; 167 landing_pad = 0; 168 169#ifdef __USING_SJLJ_EXCEPTIONS__ 170 /* The given "IP" is an index into the call-site table, with two 171 exceptions -- -1 means no-action, and 0 means terminate. But 172 since we're using uleb128 values, we've not got random access 173 to the array. */ 174 if ((int) ip <= 0) 175 return _URC_CONTINUE_UNWIND; 176 else 177 { 178 _Unwind_Word cs_lp, cs_action; 179 do 180 { 181 p = read_uleb128 (p, &cs_lp); 182 p = read_uleb128 (p, &cs_action); 183 } 184 while (--ip); 185 186 /* Can never have null landing pad for sjlj -- that would have 187 been indicated by a -1 call site index. */ 188 landing_pad = cs_lp + 1; 189 if (cs_action) 190 action_record = info.action_table + cs_action - 1; 191 goto found_something; 192 } 193#else 194 /* Search the call-site table for the action associated with this IP. */ 195 while (p < info.action_table) 196 { 197 _Unwind_Ptr cs_start, cs_len, cs_lp; 198 _Unwind_Word cs_action; 199 200 /* Note that all call-site encodings are "absolute" displacements. */ 201 p = read_encoded_value (0, info.call_site_encoding, p, &cs_start); 202 p = read_encoded_value (0, info.call_site_encoding, p, &cs_len); 203 p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp); 204 p = read_uleb128 (p, &cs_action); 205 206 /* The table is sorted, so if we've passed the ip, stop. */ 207 if (ip < info.Start + cs_start) 208 p = info.action_table; 209 else if (ip < info.Start + cs_start + cs_len) 210 { 211 if (cs_lp) 212 landing_pad = info.LPStart + cs_lp; 213 if (cs_action) 214 action_record = info.action_table + cs_action - 1; 215 goto found_something; 216 } 217 } 218#endif 219 220 /* IP is not in table. No associated cleanups. */ 221 /* ??? This is where C++ calls std::terminate to catch throw 222 from a destructor. */ 223 CONTINUE_UNWINDING; 224 225 found_something: 226 if (landing_pad == 0) 227 { 228 /* IP is present, but has a null landing pad. 229 No handler to be run. */ 230 CONTINUE_UNWINDING; 231 } 232 233 _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), 234 (_Unwind_Ptr) ue_header); 235 _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0); 236 _Unwind_SetIP (context, landing_pad); 237 return _URC_INSTALL_CONTEXT; 238} 239