1 /* Copyright (C) 2009-2016 Free Software Foundation, Inc.
2    Contributed by Richard Henderson <rth@redhat.com>.
3 
4    This file is part of the GNU Transactional Memory Library (libitm).
5 
6    Libitm is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    Libitm is distributed in the hope that it will be useful, but WITHOUT ANY
12    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13    FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14    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 "libitm_i.h"
26 
27 using namespace GTM;
28 
29 /* Exceptions can exist in three phases: (1) after having been allocated by
30    __cxa_allocate_exception but before being handed off to __cxa_throw,
31    (2) when they are in flight, so between __cxa_throw and __cxa_begin_catch,
32    and (3) when they are being handled (between __cxa_begin_catch and
33    __cxa_end_catch).  Note that when an exception is re-thrown in (3), it is
34    not moving back to (2) but handled as a special case of (3) by the EH
35    runtime.
36 
37    We can get aborts in all three phases, for example in (1) during
38    construction of the exception object, or in (2) in destructors called
39    while unwinding the stack.  The transaction that created an exception
40    object can only commit in phase (3) by re-throwing the exception; it cannot
41    commit in other phases because throw expressions and catch clauses are
42    properly nested wrt transactions and because the compiler wraps
43    transaction bodies in a try/catch-all construct.
44 
45    We handle phase (1) by dealing with exception objects similar to how we
46    deal with other (de)allocations, which also ensures that we can have more
47    than one exception object allocated at the same time (e.g., if the
48    throw expression itself throws an exception and thus calls
49    __cxa_allocate_exception).  However, on the call to __cxa_begin_catch
50    we hand off the exception to the special handling of phase (3) and
51    remove the undo log entry of the allocation.  Note that if the allocation
52    happened outside of this transaction, we do not need to do anything.
53 
54    When an exception reaches phase (2) due to a call to __cxa_throw, the count
55    of uncaught exceptions is incremented.  We roll back this effect by saving
56    and restoring this number in the structure returned from __cxa_get_globals.
57    This also takes care of increments of this count when re-throwing an
58    exception.
59 
60    For phase (3), we keep track of the number of times __cxa_begin_catch
61    has been called without a matching call to __cxa_end_catch.  This count
62    is then used by __cxa_tm_cleanup to roll back the exception handling state
63    by calling __cxa_end_catch for the exceptions that have not been finished
64    yet (without running destructors though because we roll back the memory
65    anyway).
66    Once an exception that was allocated in this transaction enters phase (3),
67    it does not need to be deallocated on abort anymore because the calls to
68    __cxa_end_catch will take care of that.
69 
70    We require all code executed by the transaction to be transaction_safe (or
71    transaction_pure, or to have wrappers) if the transaction is to be rolled
72    back.  However, we take care to not require this for transactions that
73    just commit; this way, transactions that enter serial mode and then call
74    uninstrumented code continue to work.
75    */
76 
77 /* Everything from libstdc++ is weak, to avoid requiring that library
78    to be linked into plain C applications using libitm.so.  */
79 
80 #define WEAK  __attribute__((weak))
81 
82 extern "C" {
83 
84 struct __cxa_eh_globals
85 {
86   void *	caughtExceptions;
87   unsigned int	uncaughtExceptions;
88 };
89 
90 extern void *__cxa_allocate_exception (size_t) WEAK;
91 extern void __cxa_free_exception (void *) WEAK;
92 extern void __cxa_throw (void *, void *, void *) WEAK;
93 extern void *__cxa_begin_catch (void *) WEAK;
94 extern void __cxa_end_catch (void) WEAK;
95 extern void __cxa_tm_cleanup (void *, void *, unsigned int) WEAK;
96 extern __cxa_eh_globals *__cxa_get_globals (void) WEAK;
97 
98 #if !defined (HAVE_ELF_STYLE_WEAKREF)
__cxa_allocate_exception(size_t)99 void *__cxa_allocate_exception (size_t) { return NULL; }
__cxa_free_exception(void *)100 void __cxa_free_exception (void *) { return; }
__cxa_throw(void *,void *,void *)101 void __cxa_throw (void *, void *, void *) { return; }
__cxa_begin_catch(void *)102 void *__cxa_begin_catch (void *) { return NULL; }
__cxa_end_catch(void)103 void __cxa_end_catch (void) { return; }
__cxa_tm_cleanup(void *,void *,unsigned int)104 void __cxa_tm_cleanup (void *, void *, unsigned int) { return; }
_Unwind_DeleteException(_Unwind_Exception *)105 void _Unwind_DeleteException (_Unwind_Exception *) { return; }
__cxa_get_globals(void)106 __cxa_eh_globals *__cxa_get_globals (void) { return NULL; }
107 #endif /* HAVE_ELF_STYLE_WEAKREF */
108 
109 }
110 
111 static void
free_any_exception(void * exc_ptr)112 free_any_exception (void *exc_ptr)
113 {
114   // The exception could be in phase (2) and thus calling just
115   // _cxa_free_exception might not be sufficient.
116   __cxa_tm_cleanup (NULL, exc_ptr, 0);
117 }
118 
119 void *
_ITM_cxa_allocate_exception(size_t size)120 _ITM_cxa_allocate_exception (size_t size)
121 {
122   void *r = __cxa_allocate_exception (size);
123   gtm_thr()->record_allocation (r, free_any_exception);
124   return r;
125 }
126 
127 void
_ITM_cxa_free_exception(void * exc_ptr)128 _ITM_cxa_free_exception (void *exc_ptr)
129 {
130   // __cxa_free_exception can be called from user code directly if
131   // construction of an exception object throws another exception, in which
132   // case we need to roll back the initial exception.  We handle this similar
133   // to dead allocations in that we deallocate the exception on both commit
134   // and abort of an outermost transaction.
135   gtm_thr()->forget_allocation (exc_ptr, free_any_exception);
136 }
137 
138 void
_ITM_cxa_throw(void * obj,void * tinfo,void * dest)139 _ITM_cxa_throw (void *obj, void *tinfo, void *dest)
140 {
141   // This used to be instrumented, but does not need to be anymore.
142   __cxa_throw (obj, tinfo, dest);
143 }
144 
145 void *
_ITM_cxa_begin_catch(void * exc_ptr)146 _ITM_cxa_begin_catch (void *exc_ptr)
147 {
148   // If this exception object has been allocated by this transaction, we
149   // discard the undo log entry for the allocation; we are entering phase (3)
150   // now and will handle this exception specially.
151   // Note that this exception cannot have been allocated in a parent
152   // transaction or enclosing nontransactional block because an atomic block
153   // cannot contain just a catch clause but not the associated try clause.
154   // The exception can have been allocated in a nested transaction, in which
155   // case the commit of the nested transaction will have inserted the undo
156   // log entry of the allocation in our undo log.
157   // The exception can also have been allocated in a nested nontransactional
158   // block, but then this transaction cannot abort anymore; functions that
159   // are marked transaction_pure, for example, must not side-step the
160   // transactional exception handling we implement here.
161   gtm_thread *t = gtm_thr ();
162   t->discard_allocation (exc_ptr);
163   // Keep track of the number of unfinished catch handlers.
164   t->cxa_catch_count++;
165   return __cxa_begin_catch (exc_ptr);
166 }
167 
168 void
_ITM_cxa_end_catch(void)169 _ITM_cxa_end_catch (void)
170 {
171   // Keep track of the number of unfinished catch handlers.
172   gtm_thr()->cxa_catch_count--;
173   __cxa_end_catch ();
174 }
175 
176 void
init_cpp_exceptions()177 GTM::gtm_thread::init_cpp_exceptions ()
178 {
179   // Only save and restore the number of uncaught exceptions if this is
180   // actually used in the program.
181   if (__cxa_get_globals != NULL && __cxa_get_globals () != 0)
182     cxa_uncaught_count_ptr = &__cxa_get_globals ()->uncaughtExceptions;
183   else
184     cxa_uncaught_count_ptr = 0;
185 }
186 
187 void
revert_cpp_exceptions(gtm_transaction_cp * cp)188 GTM::gtm_thread::revert_cpp_exceptions (gtm_transaction_cp *cp)
189 {
190   if (cp)
191     {
192       // If rolling back a nested transaction, only clean up incompletely
193       // caught exceptions since the last checkpoint.
194       assert (cxa_catch_count >= cp->cxa_catch_count);
195       uint32_t catch_count = cxa_catch_count - cp->cxa_catch_count;
196       if (catch_count)
197 	{
198 	  __cxa_tm_cleanup (NULL, NULL, catch_count);
199 	  cxa_catch_count = cp->cxa_catch_count;
200 	}
201     }
202   else
203     {
204       // Both cxa_catch_count and cxa_unthrown are maximal because EH regions
205       // and transactions are properly nested.
206       if (cxa_catch_count)
207 	{
208 	  __cxa_tm_cleanup (NULL, NULL, cxa_catch_count);
209 	  cxa_catch_count = 0;
210 	}
211     }
212   // Reset the number of uncaught exceptions.  Any allocations for these
213   // exceptions have been rolled back already, if necessary.
214   if (cxa_uncaught_count_ptr != 0)
215     *cxa_uncaught_count_ptr = cxa_uncaught_count;
216   // Always reset eh_in_flight because it just contains the argument provided
217   // to _ITM_commitTransactionEH.
218   eh_in_flight = NULL;
219 }
220