unwind-c.c revision 225736
150120Swpaul/* Supporting functions for C exception handling. 250120Swpaul Copyright (C) 2002, 2003 Free Software Foundation, Inc. 350120Swpaul Contributed by Aldy Hernandez <aldy@quesejoda.com>. 450120Swpaul Shamelessly stolen from the Java front end. 550120Swpaul 650120SwpaulThis file is part of GCC. 750120Swpaul 850120SwpaulGCC is free software; you can redistribute it and/or modify it under 950120Swpaulthe terms of the GNU General Public License as published by the Free 1050120SwpaulSoftware Foundation; either version 2, or (at your option) any later 1150120Swpaulversion. 1250120Swpaul 1350120SwpaulIn addition to the permissions in the GNU General Public License, the 1450120SwpaulFree Software Foundation gives you unlimited permission to link the 1550120Swpaulcompiled version of this file into combinations with other programs, 1650120Swpauland to distribute those combinations without any restriction coming 1750120Swpaulfrom the use of this file. (The General Public License restrictions 1850120Swpauldo apply in other respects; for example, they cover modification of 1950120Swpaulthe file, and distribution when not linked into a combined 2050120Swpaulexecutable.) 2150120Swpaul 2250120SwpaulGCC is distributed in the hope that it will be useful, but WITHOUT ANY 2350120SwpaulWARRANTY; without even the implied warranty of MERCHANTABILITY or 2450120SwpaulFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 2550120Swpaulfor more details. 2650120Swpaul 2750120SwpaulYou should have received a copy of the GNU General Public License 2850120Swpaulalong with GCC; see the file COPYING. If not, write to the Free 2950120SwpaulSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 3050120Swpaul02110-1301, USA. */ 3150120Swpaul 3250120Swpaul#include "tconfig.h" 33139749Simp#include "tsystem.h" 3450120Swpaul#include "unwind.h" 3550120Swpaul#define NO_SIZE_OF_ENCODED_VALUE 3650120Swpaul#include "unwind-pe.h" 3750120Swpaul 3850120Swpaultypedef struct 3950120Swpaul{ 4050120Swpaul _Unwind_Ptr Start; 4150120Swpaul _Unwind_Ptr LPStart; 4250120Swpaul _Unwind_Ptr ttype_base; 4350120Swpaul const unsigned char *TType; 4450120Swpaul const unsigned char *action_table; 4550120Swpaul unsigned char ttype_encoding; 4650120Swpaul unsigned char call_site_encoding; 4750120Swpaul} lsda_header_info; 4850120Swpaul 4950120Swpaulstatic const unsigned char * 5050120Swpaulparse_lsda_header (struct _Unwind_Context *context, const unsigned char *p, 5150120Swpaul lsda_header_info *info) 5250120Swpaul{ 5350120Swpaul _Unwind_Word tmp; 5450120Swpaul unsigned char lpstart_encoding; 5550120Swpaul 5650120Swpaul info->Start = (context ? _Unwind_GetRegionStart (context) : 0); 57129844Smarius 58129844Smarius /* Find @LPStart, the base to which landing pad offsets are relative. */ 59129844Smarius lpstart_encoding = *p++; 6050120Swpaul if (lpstart_encoding != DW_EH_PE_omit) 6150120Swpaul p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart); 6250120Swpaul else 6350120Swpaul info->LPStart = info->Start; 6450120Swpaul 6550120Swpaul /* Find @TType, the base of the handler and exception spec type data. */ 6650120Swpaul info->ttype_encoding = *p++; 6750120Swpaul if (info->ttype_encoding != DW_EH_PE_omit) 6850120Swpaul { 6950120Swpaul p = read_uleb128 (p, &tmp); 7050120Swpaul info->TType = p + tmp; 7150120Swpaul } 7250120Swpaul else 7350120Swpaul info->TType = 0; 7450120Swpaul 7550120Swpaul /* The encoding and length of the call-site table; the action table 7650120Swpaul immediately follows. */ 7750120Swpaul info->call_site_encoding = *p++; 78109514Sobrien p = read_uleb128 (p, &tmp); 7950120Swpaul info->action_table = p + tmp; 8050120Swpaul 8150120Swpaul return p; 8250120Swpaul} 8350120Swpaul 84105135Salfred#ifdef __ARM_EABI_UNWINDER__ 85105135Salfred/* ARM EABI personality routines must also unwind the stack. */ 8650120Swpaul#define CONTINUE_UNWINDING \ 8750120Swpaul do \ 8850120Swpaul { \ 8950120Swpaul if (__gnu_unwind_frame (ue_header, context) != _URC_OK) \ 9050120Swpaul return _URC_FAILURE; \ 9195722Sphk return _URC_CONTINUE_UNWIND; \ 9250120Swpaul } \ 93227908Smarius while (0) 9450120Swpaul#else 9550120Swpaul#define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND 9650120Swpaul#endif 9750120Swpaul 9850120Swpaul#ifdef __USING_SJLJ_EXCEPTIONS__ 9950120Swpaul#define PERSONALITY_FUNCTION __gcc_personality_sj0 10050120Swpaul#define __builtin_eh_return_data_regno(x) x 10150120Swpaul#else 10250120Swpaul#define PERSONALITY_FUNCTION __gcc_personality_v0 10350120Swpaul#endif 10450120Swpaul 10550120Swpaul#ifdef __ARM_EABI_UNWINDER__ 10692739Salfred_Unwind_Reason_Code 10792739SalfredPERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *, 108164708Smarius struct _Unwind_Context *); 10950120Swpaul 110164827Smarius_Unwind_Reason_Code 111221407SmariusPERSONALITY_FUNCTION (_Unwind_State state, 112164827Smarius struct _Unwind_Exception * ue_header, 113164827Smarius struct _Unwind_Context * context) 114164827Smarius#else 115221407Smarius_Unwind_Reason_Code 116221407SmariusPERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class, 117221407Smarius struct _Unwind_Exception *, struct _Unwind_Context *); 118221407Smarius 119221407Smarius_Unwind_Reason_Code 120221407SmariusPERSONALITY_FUNCTION (int version, 121105135Salfred _Unwind_Action actions, 122150763Simp _Unwind_Exception_Class exception_class ATTRIBUTE_UNUSED, 12350120Swpaul struct _Unwind_Exception *ue_header, 12450120Swpaul struct _Unwind_Context *context) 125164827Smarius#endif 12650120Swpaul{ 12750120Swpaul lsda_header_info info; 128105135Salfred const unsigned char *language_specific_data, *p, *action_record; 129150763Simp _Unwind_Ptr landing_pad, ip; 13050120Swpaul int ip_before_insn = 0; 131164708Smarius 132221407Smarius#ifdef __ARM_EABI_UNWINDER__ 13350120Swpaul if ((state & _US_ACTION_MASK) != _US_UNWIND_FRAME_STARTING) 134221407Smarius CONTINUE_UNWINDING; 135221407Smarius 13650120Swpaul /* The dwarf unwinder assumes the context structure holds things like the 137213893Smarius function and LSDA pointers. The ARM implementation caches these in 13850120Swpaul the exception header (UCB). To avoid rewriting everything we make the 139213893Smarius virtual IP register point at the UCB. */ 140221407Smarius ip = (_Unwind_Ptr) ue_header; 141221407Smarius _Unwind_SetGR (context, 12, ip); 142164708Smarius#else 14350120Swpaul if (version != 1) 14450120Swpaul return _URC_FATAL_PHASE1_ERROR; 14584145Sjlemon 146150763Simp /* Currently we only support cleanups for C. */ 14750120Swpaul if ((actions & _UA_CLEANUP_PHASE) == 0) 14850120Swpaul CONTINUE_UNWINDING; 14950120Swpaul#endif 15050120Swpaul 15150120Swpaul language_specific_data = (const unsigned char *) 15250120Swpaul _Unwind_GetLanguageSpecificData (context); 15350120Swpaul 15450120Swpaul /* If no LSDA, then there are no handlers or cleanups. */ 15550120Swpaul if (! language_specific_data) 15650120Swpaul CONTINUE_UNWINDING; 15750120Swpaul 15850120Swpaul /* Parse the LSDA header. */ 15950120Swpaul p = parse_lsda_header (context, language_specific_data, &info); 16050120Swpaul#ifdef HAVE_GETIPINFO 16150120Swpaul ip = _Unwind_GetIPInfo (context, &ip_before_insn); 16250120Swpaul#else 16350120Swpaul ip = _Unwind_GetIP (context); 16450120Swpaul#endif 16550120Swpaul if (! ip_before_insn) 16650120Swpaul --ip; 16750120Swpaul landing_pad = 0; 16850120Swpaul 16950120Swpaul#ifdef __USING_SJLJ_EXCEPTIONS__ 170129842Smarius /* The given "IP" is an index into the call-site table, with two 17150120Swpaul exceptions -- -1 means no-action, and 0 means terminate. But 17250120Swpaul since we're using uleb128 values, we've not got random access 17350120Swpaul to the array. */ 17450120Swpaul if ((int) ip <= 0) 17550120Swpaul return _URC_CONTINUE_UNWIND; 17650120Swpaul else 17750120Swpaul { 17850120Swpaul _Unwind_Word cs_lp, cs_action; 17950120Swpaul do 18050120Swpaul { 18150120Swpaul p = read_uleb128 (p, &cs_lp); 18250120Swpaul p = read_uleb128 (p, &cs_action); 18350120Swpaul } 18450120Swpaul while (--ip); 18574353Sjlemon 18674353Sjlemon /* Can never have null landing pad for sjlj -- that would have 18774353Sjlemon been indicated by a -1 call site index. */ 18874353Sjlemon landing_pad = cs_lp + 1; 18974353Sjlemon if (cs_action) 19074353Sjlemon action_record = info.action_table + cs_action - 1; 19150120Swpaul goto found_something; 19250120Swpaul } 19374353Sjlemon#else 194164708Smarius /* Search the call-site table for the action associated with this IP. */ 19577634Sjlemon while (p < info.action_table) 19674353Sjlemon { 197164708Smarius _Unwind_Ptr cs_start, cs_len, cs_lp; 19850120Swpaul _Unwind_Word cs_action; 19950120Swpaul 20050120Swpaul /* Note that all call-site encodings are "absolute" displacements. */ 20184145Sjlemon p = read_encoded_value (0, info.call_site_encoding, p, &cs_start); 20250120Swpaul p = read_encoded_value (0, info.call_site_encoding, p, &cs_len); 20350120Swpaul p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp); 20450120Swpaul p = read_uleb128 (p, &cs_action); 20550120Swpaul 20650120Swpaul /* The table is sorted, so if we've passed the ip, stop. */ 207221407Smarius if (ip < info.Start + cs_start) 20850120Swpaul p = info.action_table; 20950120Swpaul else if (ip < info.Start + cs_start + cs_len) 21084145Sjlemon { 21150120Swpaul if (cs_lp) 21250120Swpaul landing_pad = info.LPStart + cs_lp; 21350120Swpaul if (cs_action) 21484145Sjlemon action_record = info.action_table + cs_action - 1; 215150763Simp goto found_something; 21650120Swpaul } 21750120Swpaul } 218164708Smarius#endif 21950120Swpaul 22050120Swpaul /* IP is not in table. No associated cleanups. */ 22150120Swpaul /* ??? This is where C++ calls std::terminate to catch throw 22250120Swpaul from a destructor. */ 22350120Swpaul CONTINUE_UNWINDING; 22450120Swpaul 22550120Swpaul found_something: 22650120Swpaul if (landing_pad == 0) 22750120Swpaul { 22850120Swpaul /* IP is present, but has a null landing pad. 22950120Swpaul No handler to be run. */ 23050120Swpaul CONTINUE_UNWINDING; 23150120Swpaul } 23250120Swpaul 23350120Swpaul _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), 23450120Swpaul (_Unwind_Ptr) ue_header); 23550120Swpaul _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0); 23650120Swpaul _Unwind_SetIP (context, landing_pad); 23750120Swpaul return _URC_INSTALL_CONTEXT; 23850120Swpaul} 23950120Swpaul