Home | History | Annotate | Download | only in drd
      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 (at) 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
     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
     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