• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2012 The Android Open Source Project
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 //    notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 //    notice, this list of conditions and the following disclaimer in the
11 //    documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the project nor the names of its contributors
13 //    may be used to endorse or promote products derived from this software
14 //    without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 // SUCH DAMAGE.
27 //===----------------------------------------------------------------------===//
28 //                     The LLVM Compiler Infrastructure
29 //
30 // This file is dual licensed under the MIT and the University of Illinois Open
31 // Source Licenses. See LICENSE.TXT for details.
32 //
33 //
34 //  This file implements the "Exception Handling APIs"
35 //  http://www.codesourcery.com/public/cxx-abi/abi-eh.html
36 //  http://www.intel.com/design/itanium/downloads/245358.htm
37 //
38 //===----------------------------------------------------------------------===//
39 /*
40  * Copyright 2010-2011 PathScale, Inc. All rights reserved.
41  *
42  * Redistribution and use in source and binary forms, with or without
43  * modification, are permitted provided that the following conditions are met:
44  *
45  * 1. Redistributions of source code must retain the above copyright notice,
46  *    this list of conditions and the following disclaimer.
47  *
48  * 2. Redistributions in binary form must reproduce the above copyright notice,
49  *    this list of conditions and the following disclaimer in the documentation
50  *    and/or other materials provided with the distribution.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
53  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
54  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
55  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
56  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
57  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
58  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
59  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
60  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
61  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
62  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
63  */
64 
65 
66 #include <cstdlib>
67 #include <unwind.h>
68 
69 #include "cxxabi_defines.h"
70 #include "dwarf_helper.h"
71 #include "helper_func_internal.h"
72 
73 namespace __cxxabiv1 {
74 
75 #ifdef __arm__
76 extern "C" enum type_match_result {
77   ctm_failed = 0,
78   ctm_succeeded = 1,
79   ctm_succeeded_with_ptr_to_base = 2
80 };
81 
82 
83 extern "C" type_match_result __attribute__((visibility("default")))
__cxa_type_match(_Unwind_Exception * ucbp,const __shim_type_info * rttip,bool is_reference_type,void ** matched_object)84 __cxa_type_match(_Unwind_Exception* ucbp,
85                  const __shim_type_info* rttip,
86                  bool is_reference_type,
87                  void** matched_object) {
88 
89   __cxa_exception* header = reinterpret_cast<__cxa_exception*>(ucbp+1)-1;
90   type_match_result result = ctm_succeeded;
91 
92   void* adjustedPtr = header+1;
93   if (dynamic_cast<const __pointer_type_info*>(header->exceptionType)) {
94     adjustedPtr = *reinterpret_cast<void**>(adjustedPtr);
95     result = ctm_succeeded_with_ptr_to_base;
96   }
97 
98   const __shim_type_info* catch_type = rttip;
99   const __shim_type_info* thrown_type =
100       static_cast<const __shim_type_info*>(header->exceptionType);
101   if (!catch_type || !thrown_type) {
102     return ctm_failed;
103   }
104 
105   if (catch_type->can_catch(thrown_type, adjustedPtr)) {
106     *matched_object = adjustedPtr;
107     return result;
108   }
109 
110   return ctm_failed;
111 }
112 #endif  // __arm__
113 
114 namespace {
115 
terminate_helper(std::terminate_handler t_handler)116 void terminate_helper(std::terminate_handler t_handler) {
117   try {
118     t_handler();
119     abort();
120   } catch (...) {
121     abort();
122   }
123 }
124 
unexpected_helper(std::unexpected_handler u_handler)125 void unexpected_helper(std::unexpected_handler u_handler) {
126   u_handler();
127   std::terminate();
128 }
129 
130 }  // namespace
131 
132 #ifdef __arm__
133   extern "C" bool   __attribute__((visibility("default")))
__cxa_begin_cleanup(_Unwind_Exception * exc)134   __cxa_begin_cleanup(_Unwind_Exception* exc) {
135     __cxa_eh_globals *globals = __cxa_get_globals();
136     __cxa_exception *header = reinterpret_cast<__cxa_exception*>(exc+1)-1;
137     bool native = header->unwindHeader.exception_class == __gxx_exception_class;
138 
139     if (native) {
140       header->cleanupCount += 1;
141       if (header->cleanupCount == 1) {  // First time
142         header->nextCleanup = globals->cleanupExceptions;
143         globals->cleanupExceptions = header;
144       }
145     } else {
146       globals->cleanupExceptions = header;
147     }
148 
149     return true;
150   }
151 
helper_end_cleanup()152   extern "C" _Unwind_Exception * helper_end_cleanup() {
153     __cxa_eh_globals *globals = __cxa_get_globals();
154     __cxa_exception* header = globals->cleanupExceptions;
155 
156     if (!header) {
157       std::terminate();
158     }
159 
160     if (header->unwindHeader.exception_class == __gxx_exception_class) {
161       header->cleanupCount -= 1;
162       if (header->cleanupCount == 0) {  // Last one
163         globals->cleanupExceptions = header->nextCleanup;
164         header->nextCleanup = NULL;
165       }
166     } else {
167       globals->cleanupExceptions = NULL;
168     }
169 
170     return &header->unwindHeader;
171   }
172 
173   asm (
174   ".pushsection .text.__cxa_end_cleanup    \n"
175   ".global __cxa_end_cleanup               \n"
176   ".type __cxa_end_cleanup, \"function\"   \n"
177   "__cxa_end_cleanup:                      \n"
178   " push\t{r1, r2, r3, r4}                 \n"
179   " bl helper_end_cleanup                  \n"
180   " pop\t{r1, r2, r3, r4}                  \n"
181   " bl _Unwind_Resume                      \n"
182   " bl abort                               \n"
183   ".popsection                             \n"
184   );
185 
186   extern "C" void __attribute__((visibility("default")))
__cxa_call_unexpected(void * arg)187   __cxa_call_unexpected(void* arg) {
188     _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(arg);
189     __cxa_exception* header = reinterpret_cast<__cxa_exception*>(unwind_exception+1)-1;
190     bool native_exception = unwind_exception->exception_class == __gxx_exception_class;
191 
192     if (!native_exception) {
193       __cxa_begin_catch(unwind_exception);    // unexpected is also a handler
194       try {
195         std::unexpected();
196       } catch (...) {
197         std::terminate();
198       }
199 
200       return;
201     }
202 
203     // Cache previous data first since we will change contents below.
204     uint32_t count = unwind_exception->barrier_cache.bitpattern[1];
205     uint32_t stride = unwind_exception->barrier_cache.bitpattern[3];
206     uint32_t* list = reinterpret_cast<uint32_t*>(
207                             unwind_exception->barrier_cache.bitpattern[4]);
208 
209     __cxa_begin_catch(unwind_exception);    // unexpected is also a handler
210     try {
211       unexpected_helper(header->unexpectedHandler);
212     } catch (...) {
213       // A new exception thrown when calling unexpected.
214       bool allow_bad_exception = false;
215 
216       for (uint32_t i = 0; i != count; ++i) {
217         uint32_t offset = reinterpret_cast<uint32_t>(&list[i * (stride >> 2)]);
218         offset = decodeRelocTarget2(offset);
219         const __shim_type_info* catch_type = reinterpret_cast<const __shim_type_info*>(offset);
220 
221         __cxa_exception* new_header = __cxa_get_globals()->caughtExceptions;
222         void* adjustedPtr = new_header + 1;
223         if (__cxa_type_match(&new_header->unwindHeader,
224                              catch_type,
225                              false/* is_ref_type */,
226                              &adjustedPtr) != ctm_failed) {
227           throw;
228         }
229 
230         void* null_adjustedPtr = NULL;
231         const __shim_type_info* bad_excp =
232             static_cast<const __shim_type_info*>(&typeid(std::bad_exception));
233         if (catch_type->can_catch(bad_excp, null_adjustedPtr)) {
234           allow_bad_exception = true;
235         }
236       }
237 
238       // If no other ones match, throw bad_exception.
239       if (allow_bad_exception) {
240         __cxa_end_catch();
241         __cxa_end_catch();
242         throw std::bad_exception();
243       }
244 
245       terminate_helper(header->terminateHandler);
246     }
247   }
248 #else // ! __arm__
249   extern "C" void __attribute__((visibility("default")))
__cxa_call_unexpected(void * arg)250   __cxa_call_unexpected(void* arg) {
251     _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(arg);
252     if (unwind_exception == 0) {
253       call_terminate(unwind_exception);
254     }
255     __cxa_begin_catch(unwind_exception);    // unexpected is also a handler
256 
257     bool native_old_exception = unwind_exception->exception_class == __gxx_exception_class;
258     std::unexpected_handler u_handler;
259     std::terminate_handler t_handler;
260     __cxa_exception* old_exception_header = 0;
261     int64_t ttypeIndex;
262     const uint8_t* lsda;
263     if (native_old_exception) {
264       old_exception_header = reinterpret_cast<__cxa_exception*>(unwind_exception+1)-1;
265       t_handler = old_exception_header->terminateHandler;
266       u_handler = old_exception_header->unexpectedHandler;
267       // If unexpected_helper(u_handler) rethrows the same exception,
268       //   these values get overwritten by the rethrow.  So save them now:
269       ttypeIndex = old_exception_header->handlerSwitchValue;
270       lsda = old_exception_header->languageSpecificData;
271     } else {
272       t_handler = std::get_terminate();
273       u_handler = std::get_unexpected();
274     }
275 
276     try {
277       unexpected_helper(u_handler);
278     } catch (...) {
279       // A new exception thrown when calling unexpected.
280 
281       if (!native_old_exception) {
282         std::terminate();
283       }
284       uint8_t lpStartEncoding = *lsda++;
285       readEncodedPointer(&lsda, lpStartEncoding);
286       uint8_t ttypeEncoding = *lsda++;
287       if (ttypeEncoding == DW_EH_PE_omit) {
288         terminate_helper(t_handler);
289       }
290       uintptr_t classInfoOffset = readULEB128(&lsda);
291       const uint8_t* classInfo = lsda + classInfoOffset;
292       __cxa_eh_globals* globals = __cxa_get_globals_fast();
293       __cxa_exception* new_exception_header = globals->caughtExceptions;
294       if (new_exception_header == 0) {  // This shouldn't be able to happen!
295         terminate_helper(t_handler);
296       }
297       bool native_new_exception =
298         new_exception_header->unwindHeader.exception_class == __gxx_exception_class;
299 
300       if (native_new_exception && (new_exception_header != old_exception_header)) {
301         const std::type_info* excpType = new_exception_header->exceptionType;
302         if (!canExceptionSpecCatch(ttypeIndex, classInfo, ttypeEncoding,
303                                    excpType, new_exception_header+1, unwind_exception)) {
304           // We need to __cxa_end_catch, but for the old exception,
305           //   not the new one.  This is a little tricky ...
306           // Disguise new_exception_header as a rethrown exception, but
307           //   don't actually rethrow it.  This means you can temporarily
308           //   end the catch clause enclosing new_exception_header without
309           //   __cxa_end_catch destroying new_exception_header.
310           new_exception_header->handlerCount = -new_exception_header->handlerCount;
311           globals->uncaughtExceptions += 1;
312           __cxa_end_catch();
313           __cxa_end_catch();
314           __cxa_begin_catch(&new_exception_header->unwindHeader);
315           throw;
316         }
317       }
318 
319       const std::type_info* excpType = &typeid(std::bad_exception);
320       if (!canExceptionSpecCatch(ttypeIndex, classInfo, ttypeEncoding,
321                                  excpType, NULL, unwind_exception)) {
322         __cxa_end_catch();
323         __cxa_end_catch();
324         throw std::bad_exception();
325       }
326     } // catch (...)
327 
328     // Call terminate after unexpected normally done
329     terminate_helper(t_handler);
330   }
331 #endif // __arm__
332 
333 } // namespace __cxxabiv1
334