1117395Skan/* Supporting functions for C exception handling. 2117395Skan Copyright (C) 2002, 2003 Free Software Foundation, Inc. 3117395Skan Contributed by Aldy Hernandez <aldy@quesejoda.com>. 4117395Skan Shamelessly stolen from the Java front end. 5117395Skan 6117395SkanThis file is part of GCC. 7117395Skan 8117395SkanGCC is free software; you can redistribute it and/or modify it under 9117395Skanthe terms of the GNU General Public License as published by the Free 10117395SkanSoftware Foundation; either version 2, or (at your option) any later 11117395Skanversion. 12117395Skan 13132718SkanIn addition to the permissions in the GNU General Public License, the 14132718SkanFree Software Foundation gives you unlimited permission to link the 15132718Skancompiled version of this file into combinations with other programs, 16132718Skanand to distribute those combinations without any restriction coming 17132718Skanfrom the use of this file. (The General Public License restrictions 18132718Skando apply in other respects; for example, they cover modification of 19132718Skanthe file, and distribution when not linked into a combined 20132718Skanexecutable.) 21132718Skan 22117395SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY 23117395SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or 24117395SkanFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 25117395Skanfor more details. 26117395Skan 27117395SkanYou should have received a copy of the GNU General Public License 28117395Skanalong with GCC; see the file COPYING. If not, write to the Free 29169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 30169689Skan02110-1301, USA. */ 31117395Skan 32117395Skan#include "tconfig.h" 33117395Skan#include "tsystem.h" 34117395Skan#include "unwind.h" 35132718Skan#define NO_SIZE_OF_ENCODED_VALUE 36117395Skan#include "unwind-pe.h" 37117395Skan 38117395Skantypedef struct 39117395Skan{ 40117395Skan _Unwind_Ptr Start; 41117395Skan _Unwind_Ptr LPStart; 42117395Skan _Unwind_Ptr ttype_base; 43117395Skan const unsigned char *TType; 44117395Skan const unsigned char *action_table; 45117395Skan unsigned char ttype_encoding; 46117395Skan unsigned char call_site_encoding; 47117395Skan} lsda_header_info; 48117395Skan 49117395Skanstatic const unsigned char * 50117395Skanparse_lsda_header (struct _Unwind_Context *context, const unsigned char *p, 51117395Skan lsda_header_info *info) 52117395Skan{ 53117395Skan _Unwind_Word tmp; 54117395Skan unsigned char lpstart_encoding; 55117395Skan 56117395Skan info->Start = (context ? _Unwind_GetRegionStart (context) : 0); 57117395Skan 58117395Skan /* Find @LPStart, the base to which landing pad offsets are relative. */ 59117395Skan lpstart_encoding = *p++; 60117395Skan if (lpstart_encoding != DW_EH_PE_omit) 61117395Skan p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart); 62117395Skan else 63117395Skan info->LPStart = info->Start; 64117395Skan 65117395Skan /* Find @TType, the base of the handler and exception spec type data. */ 66117395Skan info->ttype_encoding = *p++; 67117395Skan if (info->ttype_encoding != DW_EH_PE_omit) 68117395Skan { 69117395Skan p = read_uleb128 (p, &tmp); 70117395Skan info->TType = p + tmp; 71117395Skan } 72117395Skan else 73117395Skan info->TType = 0; 74117395Skan 75117395Skan /* The encoding and length of the call-site table; the action table 76117395Skan immediately follows. */ 77117395Skan info->call_site_encoding = *p++; 78117395Skan p = read_uleb128 (p, &tmp); 79117395Skan info->action_table = p + tmp; 80117395Skan 81117395Skan return p; 82117395Skan} 83117395Skan 84169689Skan#ifdef __ARM_EABI_UNWINDER__ 85169689Skan/* ARM EABI personality routines must also unwind the stack. */ 86169689Skan#define CONTINUE_UNWINDING \ 87169689Skan do \ 88169689Skan { \ 89169689Skan if (__gnu_unwind_frame (ue_header, context) != _URC_OK) \ 90169689Skan return _URC_FAILURE; \ 91169689Skan return _URC_CONTINUE_UNWIND; \ 92169689Skan } \ 93169689Skan while (0) 94169689Skan#else 95169689Skan#define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND 96169689Skan#endif 97169689Skan 98117395Skan#ifdef __USING_SJLJ_EXCEPTIONS__ 99117395Skan#define PERSONALITY_FUNCTION __gcc_personality_sj0 100117395Skan#define __builtin_eh_return_data_regno(x) x 101117395Skan#else 102117395Skan#define PERSONALITY_FUNCTION __gcc_personality_v0 103117395Skan#endif 104117395Skan 105169689Skan#ifdef __ARM_EABI_UNWINDER__ 106117395Skan_Unwind_Reason_Code 107169689SkanPERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *, 108169689Skan struct _Unwind_Context *); 109169689Skan 110169689Skan_Unwind_Reason_Code 111169689SkanPERSONALITY_FUNCTION (_Unwind_State state, 112169689Skan struct _Unwind_Exception * ue_header, 113169689Skan struct _Unwind_Context * context) 114169689Skan#else 115169689Skan_Unwind_Reason_Code 116117395SkanPERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class, 117117395Skan struct _Unwind_Exception *, struct _Unwind_Context *); 118117395Skan 119117395Skan_Unwind_Reason_Code 120117395SkanPERSONALITY_FUNCTION (int version, 121117395Skan _Unwind_Action actions, 122117395Skan _Unwind_Exception_Class exception_class ATTRIBUTE_UNUSED, 123117395Skan struct _Unwind_Exception *ue_header, 124117395Skan struct _Unwind_Context *context) 125169689Skan#endif 126117395Skan{ 127117395Skan lsda_header_info info; 128117395Skan const unsigned char *language_specific_data, *p, *action_record; 129117395Skan _Unwind_Ptr landing_pad, ip; 130169689Skan int ip_before_insn = 0; 131117395Skan 132169689Skan#ifdef __ARM_EABI_UNWINDER__ 133169689Skan if ((state & _US_ACTION_MASK) != _US_UNWIND_FRAME_STARTING) 134169689Skan CONTINUE_UNWINDING; 135169689Skan 136169689Skan /* The dwarf unwinder assumes the context structure holds things like the 137169689Skan function and LSDA pointers. The ARM implementation caches these in 138169689Skan the exception header (UCB). To avoid rewriting everything we make the 139169689Skan virtual IP register point at the UCB. */ 140169689Skan ip = (_Unwind_Ptr) ue_header; 141169689Skan _Unwind_SetGR (context, 12, ip); 142169689Skan#else 143117395Skan if (version != 1) 144117395Skan return _URC_FATAL_PHASE1_ERROR; 145117395Skan 146117395Skan /* Currently we only support cleanups for C. */ 147117395Skan if ((actions & _UA_CLEANUP_PHASE) == 0) 148169689Skan CONTINUE_UNWINDING; 149169689Skan#endif 150117395Skan 151117395Skan language_specific_data = (const unsigned char *) 152117395Skan _Unwind_GetLanguageSpecificData (context); 153117395Skan 154117395Skan /* If no LSDA, then there are no handlers or cleanups. */ 155117395Skan if (! language_specific_data) 156169689Skan CONTINUE_UNWINDING; 157117395Skan 158117395Skan /* Parse the LSDA header. */ 159117395Skan p = parse_lsda_header (context, language_specific_data, &info); 160169689Skan#ifdef HAVE_GETIPINFO 161169689Skan ip = _Unwind_GetIPInfo (context, &ip_before_insn); 162169689Skan#else 163169689Skan ip = _Unwind_GetIP (context); 164169689Skan#endif 165169689Skan if (! ip_before_insn) 166169689Skan --ip; 167117395Skan landing_pad = 0; 168117395Skan 169117395Skan#ifdef __USING_SJLJ_EXCEPTIONS__ 170117395Skan /* The given "IP" is an index into the call-site table, with two 171117395Skan exceptions -- -1 means no-action, and 0 means terminate. But 172117395Skan since we're using uleb128 values, we've not got random access 173117395Skan to the array. */ 174117395Skan if ((int) ip <= 0) 175117395Skan return _URC_CONTINUE_UNWIND; 176117395Skan else 177117395Skan { 178117395Skan _Unwind_Word cs_lp, cs_action; 179117395Skan do 180117395Skan { 181117395Skan p = read_uleb128 (p, &cs_lp); 182117395Skan p = read_uleb128 (p, &cs_action); 183117395Skan } 184117395Skan while (--ip); 185117395Skan 186117395Skan /* Can never have null landing pad for sjlj -- that would have 187117395Skan been indicated by a -1 call site index. */ 188117395Skan landing_pad = cs_lp + 1; 189117395Skan if (cs_action) 190117395Skan action_record = info.action_table + cs_action - 1; 191117395Skan goto found_something; 192117395Skan } 193117395Skan#else 194117395Skan /* Search the call-site table for the action associated with this IP. */ 195117395Skan while (p < info.action_table) 196117395Skan { 197117395Skan _Unwind_Ptr cs_start, cs_len, cs_lp; 198117395Skan _Unwind_Word cs_action; 199117395Skan 200117395Skan /* Note that all call-site encodings are "absolute" displacements. */ 201117395Skan p = read_encoded_value (0, info.call_site_encoding, p, &cs_start); 202117395Skan p = read_encoded_value (0, info.call_site_encoding, p, &cs_len); 203117395Skan p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp); 204117395Skan p = read_uleb128 (p, &cs_action); 205117395Skan 206117395Skan /* The table is sorted, so if we've passed the ip, stop. */ 207117395Skan if (ip < info.Start + cs_start) 208117395Skan p = info.action_table; 209117395Skan else if (ip < info.Start + cs_start + cs_len) 210117395Skan { 211117395Skan if (cs_lp) 212117395Skan landing_pad = info.LPStart + cs_lp; 213117395Skan if (cs_action) 214117395Skan action_record = info.action_table + cs_action - 1; 215117395Skan goto found_something; 216117395Skan } 217117395Skan } 218117395Skan#endif 219117395Skan 220117395Skan /* IP is not in table. No associated cleanups. */ 221117395Skan /* ??? This is where C++ calls std::terminate to catch throw 222117395Skan from a destructor. */ 223169689Skan CONTINUE_UNWINDING; 224117395Skan 225117395Skan found_something: 226117395Skan if (landing_pad == 0) 227117395Skan { 228117395Skan /* IP is present, but has a null landing pad. 229117395Skan No handler to be run. */ 230169689Skan CONTINUE_UNWINDING; 231117395Skan } 232117395Skan 233117395Skan _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), 234117395Skan (_Unwind_Ptr) ue_header); 235117395Skan _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0); 236117395Skan _Unwind_SetIP (context, landing_pad); 237117395Skan return _URC_INSTALL_CONTEXT; 238117395Skan} 239