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