• 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 <cxxabi.h>
68 #include <unwind.h>
69 #include "dwarf_helper.h"
70 #include "helper_func_internal.h"
71 
72 namespace __cxxabiv1 {
73 
74 #ifdef __arm__
75 extern "C" enum type_match_result {
76   ctm_failed = 0,
77   ctm_succeeded = 1,
78   ctm_succeeded_with_ptr_to_base = 2
79 };
80 
81 
82 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)83 __cxa_type_match(_Unwind_Exception* ucbp,
84                  const __shim_type_info* rttip,
85                  bool is_reference_type,
86                  void** matched_object) {
87 
88   __cxa_exception* header = reinterpret_cast<__cxa_exception*>(ucbp+1)-1;
89   type_match_result result = ctm_succeeded;
90 
91   void* adjustedPtr = header+1;
92   if (dynamic_cast<const __pointer_type_info*>(header->exceptionType)) {
93     adjustedPtr = *reinterpret_cast<void**>(adjustedPtr);
94     result = ctm_succeeded_with_ptr_to_base;
95   }
96 
97   const __shim_type_info* catch_type = rttip;
98   const __shim_type_info* thrown_type =
99       static_cast<const __shim_type_info*>(header->exceptionType);
100   if (!catch_type || !thrown_type) {
101     return ctm_failed;
102   }
103 
104   if (catch_type->can_catch(thrown_type, adjustedPtr)) {
105     *matched_object = adjustedPtr;
106     return result;
107   }
108 
109   return ctm_failed;
110 }
111 #endif  // __arm__
112 
113 namespace {
114 
terminate_helper(std::terminate_handler t_handler)115 void terminate_helper(std::terminate_handler t_handler) {
116   try {
117     t_handler();
118     abort();
119   } catch (...) {
120     abort();
121   }
122 }
123 
unexpected_helper(std::unexpected_handler u_handler)124 void unexpected_helper(std::unexpected_handler u_handler) {
125   u_handler();
126   std::terminate();
127 }
128 
129 }  // namespace
130 
131 #ifdef __arm__
132   extern "C" bool   __attribute__((visibility("default")))
__cxa_begin_cleanup(_Unwind_Exception * exc)133   __cxa_begin_cleanup(_Unwind_Exception* exc) {
134     __cxa_eh_globals *globals = __cxa_get_globals();
135     __cxa_exception *header = reinterpret_cast<__cxa_exception*>(exc+1)-1;
136     bool native = header->unwindHeader.exception_class == __gxx_exception_class;
137 
138     if (native) {
139       header->cleanupCount += 1;
140       if (header->cleanupCount == 1) {  // First time
141         header->nextCleanup = globals->cleanupExceptions;
142         globals->cleanupExceptions = header;
143       }
144     } else {
145       globals->cleanupExceptions = header;
146     }
147 
148     return true;
149   }
150 
helper_end_cleanup()151   extern "C" _Unwind_Exception * helper_end_cleanup() {
152     __cxa_eh_globals *globals = __cxa_get_globals();
153     __cxa_exception* header = globals->cleanupExceptions;
154 
155     if (!header) {
156       std::terminate();
157     }
158 
159     if (header->unwindHeader.exception_class == __gxx_exception_class) {
160       header->cleanupCount -= 1;
161       if (header->cleanupCount == 0) {  // Last one
162         globals->cleanupExceptions = header->nextCleanup;
163         header->nextCleanup = NULL;
164       }
165     } else {
166       globals->cleanupExceptions = NULL;
167     }
168 
169     return &header->unwindHeader;
170   }
171 
172   asm (
173   ".pushsection .text.__cxa_end_cleanup    \n"
174   ".global __cxa_end_cleanup               \n"
175   ".type __cxa_end_cleanup, \"function\"   \n"
176   "__cxa_end_cleanup:                      \n"
177   " push\t{r1, r2, r3, r4}                 \n"
178   " bl helper_end_cleanup                  \n"
179   " pop\t{r1, r2, r3, r4}                  \n"
180   " bl _Unwind_Resume                      \n"
181   " bl abort                               \n"
182   ".popsection                             \n"
183   );
184 
185   extern "C" void __attribute__((visibility("default")))
__cxa_call_unexpected(void * arg)186   __cxa_call_unexpected(void* arg) {
187     _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(arg);
188     __cxa_exception* header = reinterpret_cast<__cxa_exception*>(unwind_exception+1)-1;
189     bool native_exception = unwind_exception->exception_class == __gxx_exception_class;
190 
191     if (!native_exception) {
192       __cxa_begin_catch(unwind_exception);    // unexpected is also a handler
193       try {
194         std::unexpected();
195       } catch (...) {
196         std::terminate();
197       }
198 
199       return;
200     }
201 
202     // Cache previous data first since we will change contents below.
203     uint32_t count = unwind_exception->barrier_cache.bitpattern[1];
204     uint32_t stride = unwind_exception->barrier_cache.bitpattern[3];
205     uint32_t* list = reinterpret_cast<uint32_t*>(
206                             unwind_exception->barrier_cache.bitpattern[4]);
207 
208     __cxa_begin_catch(unwind_exception);    // unexpected is also a handler
209     try {
210       unexpected_helper(header->unexpectedHandler);
211     } catch (...) {
212       // A new exception thrown when calling unexpected.
213       bool allow_bad_exception = false;
214 
215       for (uint32_t i = 0; i != count; ++i) {
216         uint32_t offset = reinterpret_cast<uint32_t>(&list[i * (stride >> 2)]);
217         offset = decodeRelocTarget2(offset);
218         const __shim_type_info* catch_type = reinterpret_cast<const __shim_type_info*>(offset);
219 
220         __cxa_exception* new_header = __cxa_get_globals()->caughtExceptions;
221         void* adjustedPtr = new_header + 1;
222         if (__cxa_type_match(&new_header->unwindHeader,
223                              catch_type,
224                              false/* is_ref_type */,
225                              &adjustedPtr) != ctm_failed) {
226           throw;
227         }
228 
229         void* null_adjustedPtr = NULL;
230         const __shim_type_info* bad_excp =
231             static_cast<const __shim_type_info*>(&typeid(std::bad_exception));
232         if (catch_type->can_catch(bad_excp, null_adjustedPtr)) {
233           allow_bad_exception = true;
234         }
235       }
236 
237       // If no other ones match, throw bad_exception.
238       if (allow_bad_exception) {
239         __cxa_end_catch();
240         __cxa_end_catch();
241         throw std::bad_exception();
242       }
243 
244       terminate_helper(header->terminateHandler);
245     }
246   }
247 #else // ! __arm__
248   extern "C" void __attribute__((visibility("default")))
__cxa_call_unexpected(void * arg)249   __cxa_call_unexpected(void* arg) {
250     _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(arg);
251     if (unwind_exception == 0) {
252       call_terminate(unwind_exception);
253     }
254     __cxa_begin_catch(unwind_exception);    // unexpected is also a handler
255 
256     bool native_old_exception = unwind_exception->exception_class == __gxx_exception_class;
257     std::unexpected_handler u_handler;
258     std::terminate_handler t_handler;
259     __cxa_exception* old_exception_header = 0;
260     int64_t ttypeIndex;
261     const uint8_t* lsda;
262     if (native_old_exception) {
263       old_exception_header = reinterpret_cast<__cxa_exception*>(unwind_exception+1)-1;
264       t_handler = old_exception_header->terminateHandler;
265       u_handler = old_exception_header->unexpectedHandler;
266       // If unexpected_helper(u_handler) rethrows the same exception,
267       //   these values get overwritten by the rethrow.  So save them now:
268       ttypeIndex = old_exception_header->handlerSwitchValue;
269       lsda = old_exception_header->languageSpecificData;
270     } else {
271       t_handler = std::get_terminate();
272       u_handler = std::get_unexpected();
273     }
274 
275     try {
276       unexpected_helper(u_handler);
277     } catch (...) {
278       // A new exception thrown when calling unexpected.
279 
280       if (!native_old_exception) {
281         std::terminate();
282       }
283       uint8_t lpStartEncoding = *lsda++;
284       const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding);
285       uint8_t ttypeEncoding = *lsda++;
286       if (ttypeEncoding == DW_EH_PE_omit) {
287         terminate_helper(t_handler);
288       }
289       uintptr_t classInfoOffset = readULEB128(&lsda);
290       const uint8_t* classInfo = lsda + classInfoOffset;
291       __cxa_eh_globals* globals = __cxa_get_globals_fast();
292       __cxa_exception* new_exception_header = globals->caughtExceptions;
293       if (new_exception_header == 0) {  // This shouldn't be able to happen!
294         terminate_helper(t_handler);
295       }
296       bool native_new_exception =
297         new_exception_header->unwindHeader.exception_class == __gxx_exception_class;
298 
299       if (native_new_exception && (new_exception_header != old_exception_header)) {
300         const std::type_info* excpType = new_exception_header->exceptionType;
301         if (!canExceptionSpecCatch(ttypeIndex, classInfo, ttypeEncoding,
302                                    excpType, new_exception_header+1, unwind_exception)) {
303           // We need to __cxa_end_catch, but for the old exception,
304           //   not the new one.  This is a little tricky ...
305           // Disguise new_exception_header as a rethrown exception, but
306           //   don't actually rethrow it.  This means you can temporarily
307           //   end the catch clause enclosing new_exception_header without
308           //   __cxa_end_catch destroying new_exception_header.
309           new_exception_header->handlerCount = -new_exception_header->handlerCount;
310           globals->uncaughtExceptions += 1;
311           __cxa_end_catch();
312           __cxa_end_catch();
313           __cxa_begin_catch(&new_exception_header->unwindHeader);
314           throw;
315         }
316       }
317 
318       const std::type_info* excpType = &typeid(std::bad_exception);
319       if (!canExceptionSpecCatch(ttypeIndex, classInfo, ttypeEncoding,
320                                  excpType, NULL, unwind_exception)) {
321         __cxa_end_catch();
322         __cxa_end_catch();
323         throw std::bad_exception();
324       }
325     } // catch (...)
326 
327     // Call terminate after unexpected normally done
328     terminate_helper(t_handler);
329   }
330 #endif // __arm__
331 
332 } // namespace __cxxabiv1
333