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