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> */
46int __cxa_guard_acquire(void* guard);
47void __cxa_guard_release(void* guard) __attribute__((__nothrow__));
48void __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
68static __always_inline
69int __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
88LIBSTDCXX_FUNC(int, ZuZucxaZuguardZuacquire, __cxa_guard_acquire_intercept,
89               (void *guard), (guard));
90LIBSTDCXX_FUNC(int, ZuZucxaZuguardZuacquireZAZACXXABIZu1Zd3,
91               __cxa_guard_acquire_intercept, (void *guard), (guard));
92
93static __always_inline
94void __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
106LIBSTDCXX_FUNC(void, ZuZucxaZuguardZurelease,
107               __cxa_guard_abort_release_intercept, (void *guard), (guard));
108LIBSTDCXX_FUNC(void, ZuZucxaZuguardZuabort,
109               __cxa_guard_abort_release_intercept, (void *guard), (guard));
110