1 /*--------------------------------------------------------------------*/
2 /*--- Client-space code for DRD. drd_libstdcxx_intercepts.c ---*/
3 /*--------------------------------------------------------------------*/
4
5 /*
6 This file is part of DRD, a thread error detector.
7
8 Copyright (C) 2014 Bart Van Assche <bvanassche@acm.org>.
9
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2 of the
13 License, or (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
23 02111-1307, USA.
24
25 The GNU General Public License is contained in the file COPYING.
26 */
27
28 /* ---------------------------------------------------------------------
29 ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.
30
31 These functions are not called directly - they're the targets of code
32 redirection or load notifications (see pub_core_redir.h for info).
33 They're named weirdly so that the intercept code can find them when the
34 shared object is initially loaded.
35
36 Note that this filename has the "drd_" prefix because it can appear
37 in stack traces, and the "drd_" makes it a little clearer that it
38 originates from Valgrind.
39 ------------------------------------------------------------------ */
40
41 #include "drd_basics.h" /* DRD_() */
42 #include "drd_clientreq.h"
43 #include "pub_tool_redir.h" /* VG_WRAP_FUNCTION_ZZ() */
44
45 /* From <cxxabi.h> */
46 int __cxa_guard_acquire(void* guard);
47 void __cxa_guard_release(void* guard) __attribute__((__nothrow__));
48 void __cxa_guard_abort(void* guard) __attribute__((__nothrow__));
49
50 #define LIBSTDCXX_FUNC(ret_ty, zf, implf, argl_decl, argl) \
51 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBSTDCXX_SONAME,zf) argl_decl; \
52 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBSTDCXX_SONAME,zf) argl_decl \
53 { return implf argl; }
54
55 /*
56 * Not inlining one of the intercept functions will cause the regression
57 * tests to fail because this would cause an additional stackfram to appear
58 * in the output. The __always_inline macro guarantees that inlining will
59 * happen, even when compiling with optimization disabled.
60 */
61 #undef __always_inline /* since already defined in <cdefs.h> */
62 #if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 2
63 #define __always_inline __inline__ __attribute__((always_inline))
64 #else
65 #define __always_inline __inline__
66 #endif
67
68 static __always_inline
__cxa_guard_acquire_intercept(void * guard)69 int __cxa_guard_acquire_intercept(void *guard)
70 {
71 int ret;
72 OrigFn fn;
73 VALGRIND_GET_ORIG_FN(fn);
74 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
75 guard, mutex_type_cxa_guard, 0, 0, 0);
76 CALL_FN_W_W(ret, fn, guard);
77 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
78 guard, 1, 0, 0, 0);
79 if (ret == 0) {
80 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
81 guard, mutex_type_cxa_guard, 0, 0, 0);
82 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
83 guard, 0, 0, 0, 0);
84 }
85 return ret;
86 }
87
88 LIBSTDCXX_FUNC(int, ZuZucxaZuguardZuacquire, __cxa_guard_acquire_intercept,
89 (void *guard), (guard));
90 LIBSTDCXX_FUNC(int, ZuZucxaZuguardZuacquireZAZACXXABIZu1Zd3,
91 __cxa_guard_acquire_intercept, (void *guard), (guard));
92
93 static __always_inline
__cxa_guard_abort_release_intercept(void * guard)94 void __cxa_guard_abort_release_intercept(void *guard)
95 {
96 int ret;
97 OrigFn fn;
98 VALGRIND_GET_ORIG_FN(fn);
99 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
100 guard, mutex_type_cxa_guard, 0, 0, 0);
101 CALL_FN_W_W(ret, fn, guard);
102 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
103 guard, 0, 0, 0, 0);
104 }
105
106 LIBSTDCXX_FUNC(void, ZuZucxaZuguardZurelease,
107 __cxa_guard_abort_release_intercept, (void *guard), (guard));
108 LIBSTDCXX_FUNC(void, ZuZucxaZuguardZuabort,
109 __cxa_guard_abort_release_intercept, (void *guard), (guard));
110