1169691Skan// -*- C++ -*- ARM specific Exception handling support routines. 2169691Skan// Copyright (C) 2004, 2005 Free Software Foundation, Inc. 3169691Skan// 4169691Skan// This file is part of GCC. 5169691Skan// 6169691Skan// GCC is free software; you can redistribute it and/or modify 7169691Skan// it under the terms of the GNU General Public License as published by 8169691Skan// the Free Software Foundation; either version 2, or (at your option) 9169691Skan// any later version. 10169691Skan// 11169691Skan// GCC is distributed in the hope that it will be useful, 12169691Skan// but WITHOUT ANY WARRANTY; without even the implied warranty of 13169691Skan// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14169691Skan// GNU General Public License for more details. 15169691Skan// 16169691Skan// You should have received a copy of the GNU General Public License 17169691Skan// along with GCC; see the file COPYING. If not, write to 18169691Skan// the Free Software Foundation, 51 Franklin Street, Fifth Floor, 19169691Skan// Boston, MA 02110-1301, USA. 20169691Skan 21169691Skan// As a special exception, you may use this file as part of a free software 22169691Skan// library without restriction. Specifically, if other files instantiate 23169691Skan// templates or use macros or inline functions from this file, or you compile 24169691Skan// this file and link it with other files to produce an executable, this 25169691Skan// file does not by itself cause the resulting executable to be covered by 26169691Skan// the GNU General Public License. This exception does not however 27169691Skan// invalidate any other reasons why the executable file might be covered by 28169691Skan// the GNU General Public License. 29169691Skan 30169691Skan#include <cxxabi.h> 31169691Skan#include "unwind-cxx.h" 32169691Skan 33169691Skan#ifdef __ARM_EABI_UNWINDER__ 34169691Skan 35169691Skanusing namespace __cxxabiv1; 36169691Skan 37169691Skan 38169691Skan// Given the thrown type THROW_TYPE, pointer to a variable containing a 39169691Skan// pointer to the exception object THROWN_PTR_P and a type CATCH_TYPE to 40169691Skan// compare against, return whether or not there is a match and if so, 41169691Skan// update *THROWN_PTR_P. 42169691Skan 43169691Skanextern "C" __cxa_type_match_result 44169691Skan__cxa_type_match(_Unwind_Exception* ue_header, 45169691Skan const std::type_info* catch_type, 46169691Skan bool is_reference __attribute__((__unused__)), 47169691Skan void** thrown_ptr_p) 48169691Skan{ 49169691Skan if (!__is_gxx_exception_class(ue_header->exception_class)) 50169691Skan return ctm_failed; 51169691Skan 52169691Skan __cxa_exception* xh = __get_exception_header_from_ue(ue_header); 53169691Skan const std::type_info* throw_type = xh->exceptionType; 54169691Skan void* thrown_ptr = *thrown_ptr_p; 55169691Skan 56169691Skan // Pointer types need to adjust the actual pointer, not 57169691Skan // the pointer to pointer that is the exception object. 58169691Skan // This also has the effect of passing pointer types 59169691Skan // "by value" through the __cxa_begin_catch return value. 60169691Skan if (throw_type->__is_pointer_p()) 61169691Skan thrown_ptr = *(void**) thrown_ptr; 62169691Skan 63169691Skan if (catch_type->__do_catch(throw_type, &thrown_ptr, 1)) 64169691Skan { 65169691Skan *thrown_ptr_p = thrown_ptr; 66169691Skan 67169691Skan if (typeid(*catch_type) == typeid (typeid(void*))) 68169691Skan { 69169691Skan const __pointer_type_info *catch_pointer_type = 70169691Skan static_cast<const __pointer_type_info *> (catch_type); 71169691Skan const __pointer_type_info *throw_pointer_type = 72169691Skan static_cast<const __pointer_type_info *> (throw_type); 73169691Skan 74169691Skan if (typeid (*catch_pointer_type->__pointee) != typeid (void) 75169691Skan && (*catch_pointer_type->__pointee != 76169691Skan *throw_pointer_type->__pointee)) 77169691Skan return ctm_succeeded_with_ptr_to_base; 78169691Skan } 79169691Skan 80169691Skan return ctm_succeeded; 81169691Skan } 82169691Skan 83169691Skan return ctm_failed; 84169691Skan} 85169691Skan 86169691Skan// ABI defined routine called at the start of a cleanup handler. 87169691Skanextern "C" bool 88169691Skan__cxa_begin_cleanup(_Unwind_Exception* ue_header) 89169691Skan{ 90169691Skan __cxa_eh_globals *globals = __cxa_get_globals(); 91169691Skan __cxa_exception *header = __get_exception_header_from_ue(ue_header); 92169691Skan bool native = __is_gxx_exception_class(header->unwindHeader.exception_class); 93169691Skan 94169691Skan 95169691Skan if (native) 96169691Skan { 97169691Skan header->propagationCount++; 98169691Skan // Add it to the chain if this is the first time we've seen this 99169691Skan // exception. 100169691Skan if (header->propagationCount == 1) 101169691Skan { 102169691Skan header->nextPropagatingException = globals->propagatingExceptions; 103169691Skan globals->propagatingExceptions = header; 104169691Skan } 105169691Skan } 106169691Skan else 107169691Skan { 108169691Skan // Remember the exception object, so end_cleanup can return it. 109169691Skan // These cannot be stacked, so we must abort if we already have 110169691Skan // a propagating exception. 111169691Skan if (globals->propagatingExceptions) 112169691Skan std::terminate (); 113169691Skan globals->propagatingExceptions = header; 114169691Skan } 115169691Skan 116169691Skan return true; 117169691Skan} 118169691Skan 119169691Skan// Do the work for __cxa_end_cleanup. Returns the currently propagating 120169691Skan// exception object. 121169691Skanextern "C" _Unwind_Exception * 122169691Skan__gnu_end_cleanup(void) 123169691Skan{ 124169691Skan __cxa_exception *header; 125169691Skan __cxa_eh_globals *globals = __cxa_get_globals(); 126169691Skan 127169691Skan header = globals->propagatingExceptions; 128169691Skan 129169691Skan // Check something hasn't gone horribly wrong. 130169691Skan if (!header) 131169691Skan std::terminate(); 132169691Skan 133169691Skan if (__is_gxx_exception_class(header->unwindHeader.exception_class)) 134169691Skan { 135169691Skan header->propagationCount--; 136169691Skan if (header->propagationCount == 0) 137169691Skan { 138169691Skan // Remove exception from chain. 139169691Skan globals->propagatingExceptions = header->nextPropagatingException; 140169691Skan header->nextPropagatingException = NULL; 141169691Skan } 142169691Skan } 143169691Skan else 144169691Skan globals->propagatingExceptions = NULL; 145169691Skan 146169691Skan return &header->unwindHeader; 147169691Skan} 148169691Skan 149169691Skan// Assembly wrapper to call __gnu_end_cleanup without clobbering r1-r3. 150169691Skan// Also push r4 to preserve stack alignment. 151169691Skan#ifdef __thumb__ 152169691Skanasm (".global __cxa_end_cleanup\n" 153169691Skan" .type __cxa_end_cleanup, \"function\"\n" 154169691Skan" .thumb_func\n" 155169691Skan"__cxa_end_cleanup:\n" 156169691Skan" push\t{r1, r2, r3, r4}\n" 157169691Skan" bl\t__gnu_end_cleanup\n" 158169691Skan" pop\t{r1, r2, r3, r4}\n" 159169691Skan" bl\t_Unwind_Resume @ Never returns\n"); 160169691Skan#else 161169691Skanasm (".global __cxa_end_cleanup\n" 162169691Skan" .type __cxa_end_cleanup, \"function\"\n" 163169691Skan"__cxa_end_cleanup:\n" 164169691Skan" stmfd\tsp!, {r1, r2, r3, r4}\n" 165169691Skan" bl\t__gnu_end_cleanup\n" 166169691Skan" ldmfd\tsp!, {r1, r2, r3, r4}\n" 167169691Skan" bl\t_Unwind_Resume @ Never returns\n"); 168169691Skan#endif 169169691Skan 170169691Skan#endif 171