1 /*--------------------------------------------------------------------*/
2 /*--- Client-space code for drd.           drd_qtcore_intercepts.c ---*/
3 /*--------------------------------------------------------------------*/
4 
5 /*
6   This file is part of drd, a thread error detector.
7 
8   Copyright (C) 2006-2017 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 <assert.h>
42 #include "drd_clientreq.h"
43 #include "pub_tool_redir.h"
44 
45 
46 // Defines.
47 
48 #define QT4CORE_FUNC(ret_ty, f, args...)                        \
49    ret_ty VG_WRAP_FUNCTION_ZU(libQtCoreZdsoZd4,f)(args);        \
50    ret_ty VG_WRAP_FUNCTION_ZU(libQtCoreZdsoZd4,f)(args)
51 
52 
53 
54 //////////////////////////////////////////////////////////////////
55 // QMutex intercepts.
56 //////////////////////////////////////////////////////////////////
57 
58 
59 typedef enum { qt_nonrecursive = 0, qt_recursive = 1 } qt_mutex_mode;
60 
61 
62 /** Convert a Qt4 mutex type to a DRD mutex type. */
63 static MutexT qt_to_drd_mutex_type(qt_mutex_mode mode)
64 {
65    switch (mode)
66    {
67    case qt_nonrecursive:
68       return mutex_type_default_mutex;
69    case qt_recursive:
70       return mutex_type_recursive_mutex;
71    }
72    return mutex_type_invalid_mutex;
73 }
74 
75 /** Find out the type of a Qt4 mutex (recursive or not).
76  *  Since it's not possible to do this in a portable way, return
77  *  mutex_type_unknown and let drd_mutex.c look up the real mutex type.
78  */
79 static MutexT mutex_type(void* qt4_mutex)
80 {
81    return mutex_type_unknown;
82 }
83 
84 
85 // QMutex::QMutex(RecursionMode) -- _ZN6QMutexC1ENS_13RecursionModeE,
86 QT4CORE_FUNC(void, _ZN6QMutexC1ENS_13RecursionModeE,
87              void* mutex,
88              qt_mutex_mode mode)
89 {
90    int    ret;
91    OrigFn fn;
92    VALGRIND_GET_ORIG_FN(fn);
93    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
94                                    mutex, qt_to_drd_mutex_type(mode), 0, 0, 0);
95    CALL_FN_W_WW(ret, fn, mutex, mode);
96    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
97                                    mutex, 0, 0, 0, 0);
98 }
99 
100 // QMutex::QMutex(RecursionMode) -- _ZN6QMutexC2ENS_13RecursionModeE
101 QT4CORE_FUNC(void, _ZN6QMutexC2ENS_13RecursionModeE,
102              void* mutex,
103              qt_mutex_mode mode)
104 {
105    int    ret;
106    OrigFn fn;
107    VALGRIND_GET_ORIG_FN(fn);
108    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
109                                    mutex, qt_to_drd_mutex_type(mode), 0, 0, 0);
110    CALL_FN_W_WW(ret, fn, mutex, mode);
111    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
112                                    mutex, 0, 0, 0, 0);
113 }
114 
115 // QMutex::~QMutex() -- _ZN6QMutexD1Ev
116 QT4CORE_FUNC(void, _ZN6QMutexD1Ev,
117              void* mutex)
118 {
119    int    ret;
120    OrigFn fn;
121    VALGRIND_GET_ORIG_FN(fn);
122    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
123                                    mutex, 0, 0, 0, 0);
124    CALL_FN_W_W(ret, fn, mutex);
125    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
126                                    mutex, mutex_type(mutex), 0, 0, 0);
127 }
128 
129 // QMutex::~QMutex() -- _ZN6QMutexD2Ev
130 QT4CORE_FUNC(void, _ZN6QMutexD2Ev,
131              void** mutex)
132 {
133    int    ret;
134    OrigFn fn;
135    VALGRIND_GET_ORIG_FN(fn);
136    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
137                                    mutex, 0, 0, 0, 0);
138    CALL_FN_W_W(ret, fn, mutex);
139    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
140                                    mutex, mutex_type(mutex), 0, 0, 0);
141 }
142 
143 // QMutex::lock() -- _ZN6QMutex4lockEv
144 QT4CORE_FUNC(void, _ZN6QMutex4lockEv,
145              void* mutex)
146 {
147    int   ret;
148    OrigFn fn;
149    VALGRIND_GET_ORIG_FN(fn);
150    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
151                                    mutex, mutex_type(mutex), 0, 0, 0);
152    CALL_FN_W_W(ret, fn, mutex);
153    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
154                                    mutex, 1, 0, 0, 0);
155 }
156 
157 // QMutex::tryLock() -- _ZN6QMutex7tryLockEv
158 QT4CORE_FUNC(int, _ZN6QMutex7tryLockEv,
159              void* mutex)
160 {
161    int    ret;
162    OrigFn fn;
163    VALGRIND_GET_ORIG_FN(fn);
164    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
165                                    mutex, mutex_type(mutex), 1, 0, 0);
166    CALL_FN_W_W(ret, fn, mutex);
167    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
168                                    mutex, ret, 0, 0, 0);
169    return ret;
170 }
171 
172 // QMutex::tryLock(int) -- _ZN6QMutex7tryLockEi
173 QT4CORE_FUNC(int, _ZN6QMutex7tryLockEi,
174              void* mutex,
175              int timeout_ms)
176 {
177    int    ret;
178    OrigFn fn;
179    VALGRIND_GET_ORIG_FN(fn);
180    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
181                                    mutex, mutex_type(mutex), 1, 0, 0);
182    CALL_FN_W_WW(ret, fn, mutex, timeout_ms);
183    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
184                                    mutex, ret, 0, 0, 0);
185    return ret;
186 }
187 
188 // QMutex::unlock() -- _ZN6QMutex6unlockEv
189 QT4CORE_FUNC(void, _ZN6QMutex6unlockEv,
190              void* mutex)
191 {
192    int    ret;
193    OrigFn fn;
194    VALGRIND_GET_ORIG_FN(fn);
195    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
196                                    mutex, mutex_type(mutex), 0, 0, 0);
197    CALL_FN_W_W(ret, fn, mutex);
198    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
199                                    mutex, 0, 0, 0, 0);
200 }
201