1 // -*- C++ -*- ARM specific Exception handling support routines. 2 // Copyright (C) 2004, 2005, 2008, 2009, 2010 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 3, 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 // Under Section 7 of GPL version 3, you are granted additional 17 // permissions described in the GCC Runtime Library Exception, version 18 // 3.1, as published by the Free Software Foundation. 19 // 20 // You should have received a copy of the GNU General Public License and 21 // a copy of the GCC Runtime Library Exception along with this program; 22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 // <http://www.gnu.org/licenses/>. 24 25 #include <cxxabi.h> 26 #include "unwind-cxx.h" 27 28 #ifdef __ARM_EABI_UNWINDER__ 29 30 using namespace __cxxabiv1; 31 32 33 // Given the thrown type THROW_TYPE, exception object UE_HEADER and a 34 // type CATCH_TYPE to compare against, return whether or not there is 35 // a match and if so, update *THROWN_PTR_P to point to either the 36 // type-matched object, or in the case of a pointer type, the object 37 // pointed to by the pointer. 38 39 extern "C" __cxa_type_match_result 40 __cxa_type_match(_Unwind_Exception* ue_header, 41 const std::type_info* catch_type, 42 bool is_reference __attribute__((__unused__)), 43 void** thrown_ptr_p) 44 { 45 bool forced_unwind 46 = __is_gxx_forced_unwind_class(ue_header->exception_class); 47 bool foreign_exception 48 = !forced_unwind && !__is_gxx_exception_class(ue_header->exception_class); 49 bool dependent_exception 50 = __is_dependent_exception(ue_header->exception_class); 51 __cxa_exception* xh = __get_exception_header_from_ue(ue_header); 52 __cxa_dependent_exception *dx = __get_dependent_exception_from_ue(ue_header); 53 const std::type_info* throw_type; 54 void *thrown_ptr = 0; 55 56 if (forced_unwind) 57 throw_type = &typeid(abi::__forced_unwind); 58 else if (foreign_exception) 59 throw_type = &typeid(abi::__foreign_exception); 60 else 61 { 62 if (dependent_exception) 63 xh = __get_exception_header_from_obj (dx->primaryException); 64 throw_type = xh->exceptionType; 65 // We used to require the caller set the target of thrown_ptr_p, 66 // but that's incorrect -- the EHABI makes no such requirement 67 // -- and not all callers will set it. Fortunately callers that 68 // do initialize will always pass us the value we calculate 69 // here, so there's no backwards compatibility problem. 70 thrown_ptr = __get_object_from_ue (ue_header); 71 } 72 73 __cxa_type_match_result result = ctm_succeeded; 74 75 // Pointer types need to adjust the actual pointer, not 76 // the pointer to pointer that is the exception object. 77 // This also has the effect of passing pointer types 78 // "by value" through the __cxa_begin_catch return value. 79 if (throw_type->__is_pointer_p()) 80 { 81 thrown_ptr = *(void**) thrown_ptr; 82 // We need to indicate the indirection to our caller. 83 result = ctm_succeeded_with_ptr_to_base; 84 } 85 86 if (catch_type->__do_catch(throw_type, &thrown_ptr, 1)) 87 { 88 *thrown_ptr_p = thrown_ptr; 89 return result; 90 } 91 92 return ctm_failed; 93 } 94 95 // ABI defined routine called at the start of a cleanup handler. 96 extern "C" bool 97 __cxa_begin_cleanup(_Unwind_Exception* ue_header) 98 { 99 __cxa_eh_globals *globals = __cxa_get_globals(); 100 __cxa_exception *header = __get_exception_header_from_ue(ue_header); 101 bool native = __is_gxx_exception_class(header->unwindHeader.exception_class); 102 103 104 if (native) 105 { 106 header->propagationCount++; 107 // Add it to the chain if this is the first time we've seen this 108 // exception. 109 if (header->propagationCount == 1) 110 { 111 header->nextPropagatingException = globals->propagatingExceptions; 112 globals->propagatingExceptions = header; 113 } 114 } 115 else 116 { 117 // Remember the exception object, so end_cleanup can return it. 118 // These cannot be stacked, so we must abort if we already have 119 // a propagating exception. 120 if (globals->propagatingExceptions) 121 std::terminate (); 122 globals->propagatingExceptions = header; 123 } 124 125 return true; 126 } 127 128 // Do the work for __cxa_end_cleanup. Returns the currently propagating 129 // exception object. 130 extern "C" _Unwind_Exception * 131 __gnu_end_cleanup(void) 132 { 133 __cxa_exception *header; 134 __cxa_eh_globals *globals = __cxa_get_globals(); 135 136 header = globals->propagatingExceptions; 137 138 // Check something hasn't gone horribly wrong. 139 if (!header) 140 std::terminate(); 141 142 if (__is_gxx_exception_class(header->unwindHeader.exception_class)) 143 { 144 header->propagationCount--; 145 if (header->propagationCount == 0) 146 { 147 // Remove exception from chain. 148 globals->propagatingExceptions = header->nextPropagatingException; 149 header->nextPropagatingException = NULL; 150 } 151 } 152 else 153 globals->propagatingExceptions = NULL; 154 155 return &header->unwindHeader; 156 } 157 158 #ifdef __TMS320C6X__ 159 // Assembly wrapper to call __gnu_end_cleanup without clobbering 160 // function arguments to _Unwind_Resume. 161 asm (".global __cxa_end_cleanup\n" 162 " .type __cxa_end_cleanup, \"function\"\n" 163 "__cxa_end_cleanup:\n" 164 " stw .d2t2 B9, *B15--[10]\n" 165 " stw .d2t2 B8, *+B15[9]\n" 166 " stw .d2t2 B7, *+B15[8]\n" 167 " stw .d2t2 B6, *+B15[7]\n" 168 " stw .d2t2 B5, *+B15[6]\n" 169 " stw .d2t2 B4, *+B15[5]\n" 170 " stw .d2t1 A9, *+B15[4]\n" 171 " stw .d2t1 A8, *+B15[3]\n" 172 " stw .d2t1 A7, *+B15[2]\n" 173 " stw .d2t1 A6, *+B15[1]\n" 174 #ifdef _TMS320C6400_PLUS 175 " callp .s2 (__gnu_end_cleanup), B3\n" 176 #elif defined(_TMS320C6400) 177 " call .s2 (__gnu_end_cleanup)\n" 178 " addkpc .s2 1f, B3, 0\n" 179 " nop 4\n" 180 "1:\n" 181 #else 182 " call .s2 (__gnu_end_cleanup)\n" 183 " mvkl .s2 1f, B3\n" 184 " mvkh .s2 1f, B3\n" 185 " nop 3\n" 186 "1:\n" 187 #endif 188 " ldw .d2t1 *+B15[1], A6\n" 189 " ldw .d2t1 *+B15[2], A7\n" 190 " ldw .d2t1 *+B15[3], A8\n" 191 " ldw .d2t1 *+B15[4], A9\n" 192 " ldw .d2t2 *+B15[5], B4\n" 193 " ldw .d2t2 *+B15[6], B5\n" 194 " ldw .d2t2 *+B15[7], B6\n" 195 " ldw .d2t2 *+B15[8], B7\n" 196 " ldw .d2t2 *+B15[9], B8\n" 197 " ldw .d2t2 *++B15[10], B9\n" 198 " b .s2 _Unwind_Resume\n" 199 " nop 5\n"); 200 #else 201 // Assembly wrapper to call __gnu_end_cleanup without clobbering r1-r3. 202 // Also push r4 to preserve stack alignment. 203 #ifdef __thumb__ 204 asm (" .pushsection .text.__cxa_end_cleanup\n" 205 " .global __cxa_end_cleanup\n" 206 " .type __cxa_end_cleanup, \"function\"\n" 207 " .thumb_func\n" 208 "__cxa_end_cleanup:\n" 209 " push\t{r1, r2, r3, r4}\n" 210 " bl\t__gnu_end_cleanup\n" 211 " pop\t{r1, r2, r3, r4}\n" 212 " bl\t_Unwind_Resume @ Never returns\n" 213 " .popsection\n"); 214 #else 215 asm (" .pushsection .text.__cxa_end_cleanup\n" 216 " .global __cxa_end_cleanup\n" 217 " .type __cxa_end_cleanup, \"function\"\n" 218 "__cxa_end_cleanup:\n" 219 " stmfd\tsp!, {r1, r2, r3, r4}\n" 220 " bl\t__gnu_end_cleanup\n" 221 " ldmfd\tsp!, {r1, r2, r3, r4}\n" 222 " bl\t_Unwind_Resume @ Never returns\n" 223 " .popsection\n"); 224 #endif 225 #endif 226 227 #endif 228