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-2013 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
59typedef enum { qt_nonrecursive = 0, qt_recursive = 1 } qt_mutex_mode;
60
61
62/** Convert a Qt4 mutex type to a DRD mutex type. */
63static 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 */
79static MutexT mutex_type(void* qt4_mutex)
80{
81   return mutex_type_unknown;
82}
83
84
85// QMutex::QMutex(RecursionMode) -- _ZN6QMutexC1ENS_13RecursionModeE,
86QT4CORE_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
101QT4CORE_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
116QT4CORE_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
130QT4CORE_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
144QT4CORE_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
158QT4CORE_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
173QT4CORE_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
189QT4CORE_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