1// -*- C++ -*- ARM specific Exception handling support routines. 2// Copyright (C) 2004, 2005 Free Software Foundation, Inc. 3// 4// This file is part of GCC. 5// 6// GCC is free software; you can redistribute it and/or modify 7// it under the terms of the GNU General Public License as published by 8// the Free Software Foundation; either version 2, or (at your option) 9// any later version. 10// 11// GCC is distributed in the hope that it will be useful, 12// but WITHOUT ANY WARRANTY; without even the implied warranty of 13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14// GNU General Public License for more details. 15// 16// You should have received a copy of the GNU General Public License 17// along with GCC; see the file COPYING. If not, write to 18// the Free Software Foundation, 51 Franklin Street, Fifth Floor, 19// Boston, MA 02110-1301, USA. 20 21// As a special exception, you may use this file as part of a free software 22// library without restriction. Specifically, if other files instantiate 23// templates or use macros or inline functions from this file, or you compile 24// this file and link it with other files to produce an executable, this 25// file does not by itself cause the resulting executable to be covered by 26// the GNU General Public License. This exception does not however 27// invalidate any other reasons why the executable file might be covered by 28// the GNU General Public License. 29 30#include <cxxabi.h> 31#include "unwind-cxx.h" 32 33#ifdef __ARM_EABI_UNWINDER__ 34 35using namespace __cxxabiv1; 36 37 38// Given the thrown type THROW_TYPE, pointer to a variable containing a 39// pointer to the exception object THROWN_PTR_P and a type CATCH_TYPE to 40// compare against, return whether or not there is a match and if so, 41// update *THROWN_PTR_P. 42 43extern "C" __cxa_type_match_result 44__cxa_type_match(_Unwind_Exception* ue_header, 45 const std::type_info* catch_type, 46 bool is_reference __attribute__((__unused__)), 47 void** thrown_ptr_p) 48{ 49 if (!__is_gxx_exception_class(ue_header->exception_class)) 50 return ctm_failed; 51 52 __cxa_exception* xh = __get_exception_header_from_ue(ue_header); 53 const std::type_info* throw_type = xh->exceptionType; 54 void* thrown_ptr = *thrown_ptr_p; 55 56 // Pointer types need to adjust the actual pointer, not 57 // the pointer to pointer that is the exception object. 58 // This also has the effect of passing pointer types 59 // "by value" through the __cxa_begin_catch return value. 60 if (throw_type->__is_pointer_p()) 61 thrown_ptr = *(void**) thrown_ptr; 62 63 if (catch_type->__do_catch(throw_type, &thrown_ptr, 1)) 64 { 65 *thrown_ptr_p = thrown_ptr; 66 67 if (typeid(*catch_type) == typeid (typeid(void*))) 68 { 69 const __pointer_type_info *catch_pointer_type = 70 static_cast<const __pointer_type_info *> (catch_type); 71 const __pointer_type_info *throw_pointer_type = 72 static_cast<const __pointer_type_info *> (throw_type); 73 74 if (typeid (*catch_pointer_type->__pointee) != typeid (void) 75 && (*catch_pointer_type->__pointee != 76 *throw_pointer_type->__pointee)) 77 return ctm_succeeded_with_ptr_to_base; 78 } 79 80 return ctm_succeeded; 81 } 82 83 return ctm_failed; 84} 85 86// ABI defined routine called at the start of a cleanup handler. 87extern "C" bool 88__cxa_begin_cleanup(_Unwind_Exception* ue_header) 89{ 90 __cxa_eh_globals *globals = __cxa_get_globals(); 91 __cxa_exception *header = __get_exception_header_from_ue(ue_header); 92 bool native = __is_gxx_exception_class(header->unwindHeader.exception_class); 93 94 95 if (native) 96 { 97 header->propagationCount++; 98 // Add it to the chain if this is the first time we've seen this 99 // exception. 100 if (header->propagationCount == 1) 101 { 102 header->nextPropagatingException = globals->propagatingExceptions; 103 globals->propagatingExceptions = header; 104 } 105 } 106 else 107 { 108 // Remember the exception object, so end_cleanup can return it. 109 // These cannot be stacked, so we must abort if we already have 110 // a propagating exception. 111 if (globals->propagatingExceptions) 112 std::terminate (); 113 globals->propagatingExceptions = header; 114 } 115 116 return true; 117} 118 119// Do the work for __cxa_end_cleanup. Returns the currently propagating 120// exception object. 121extern "C" _Unwind_Exception * 122__gnu_end_cleanup(void) 123{ 124 __cxa_exception *header; 125 __cxa_eh_globals *globals = __cxa_get_globals(); 126 127 header = globals->propagatingExceptions; 128 129 // Check something hasn't gone horribly wrong. 130 if (!header) 131 std::terminate(); 132 133 if (__is_gxx_exception_class(header->unwindHeader.exception_class)) 134 { 135 header->propagationCount--; 136 if (header->propagationCount == 0) 137 { 138 // Remove exception from chain. 139 globals->propagatingExceptions = header->nextPropagatingException; 140 header->nextPropagatingException = NULL; 141 } 142 } 143 else 144 globals->propagatingExceptions = NULL; 145 146 return &header->unwindHeader; 147} 148 149// Assembly wrapper to call __gnu_end_cleanup without clobbering r1-r3. 150// Also push r4 to preserve stack alignment. 151#ifdef __thumb__ 152asm (".global __cxa_end_cleanup\n" 153" .type __cxa_end_cleanup, \"function\"\n" 154" .thumb_func\n" 155"__cxa_end_cleanup:\n" 156" push\t{r1, r2, r3, r4}\n" 157" bl\t__gnu_end_cleanup\n" 158" pop\t{r1, r2, r3, r4}\n" 159" bl\t_Unwind_Resume @ Never returns\n"); 160#else 161asm (".global __cxa_end_cleanup\n" 162" .type __cxa_end_cleanup, \"function\"\n" 163"__cxa_end_cleanup:\n" 164" stmfd\tsp!, {r1, r2, r3, r4}\n" 165" bl\t__gnu_end_cleanup\n" 166" ldmfd\tsp!, {r1, r2, r3, r4}\n" 167" bl\t_Unwind_Resume @ Never returns\n"); 168#endif 169 170#endif 171