1/* -*- mode: C; c-basic-offset: 3; indent-tabs-mode: nil; -*- */
2
3/*--------------------------------------------------------------------*/
4/*--- Client-space code for drd.           drd_qtcore_intercepts.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
8  This file is part of drd, a thread error detector.
9
10  Copyright (C) 2006-2011 Bart Van Assche <bvanassche@acm.org>.
11
12  This program is free software; you can redistribute it and/or
13  modify it under the terms of the GNU General Public License as
14  published by the Free Software Foundation; either version 2 of the
15  License, or (at your option) any later version.
16
17  This program is distributed in the hope that it will be useful, but
18  WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  General Public License for more details.
21
22  You should have received a copy of the GNU General Public License
23  along with this program; if not, write to the Free Software
24  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25  02111-1307, USA.
26
27  The GNU General Public License is contained in the file COPYING.
28*/
29
30/* ---------------------------------------------------------------------
31   ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.
32
33   These functions are not called directly - they're the targets of code
34   redirection or load notifications (see pub_core_redir.h for info).
35   They're named weirdly so that the intercept code can find them when the
36   shared object is initially loaded.
37
38   Note that this filename has the "drd_" prefix because it can appear
39   in stack traces, and the "drd_" makes it a little clearer that it
40   originates from Valgrind.
41   ------------------------------------------------------------------ */
42
43#include <assert.h>
44#include "drd_clientreq.h"
45#include "pub_tool_redir.h"
46
47
48// Defines.
49
50#define QT4CORE_FUNC(ret_ty, f, args...)                        \
51   ret_ty VG_WRAP_FUNCTION_ZU(libQtCoreZdsoZd4,f)(args);        \
52   ret_ty VG_WRAP_FUNCTION_ZU(libQtCoreZdsoZd4,f)(args)
53
54
55
56//////////////////////////////////////////////////////////////////
57// QMutex intercepts.
58//////////////////////////////////////////////////////////////////
59
60
61typedef enum { qt_nonrecursive = 0, qt_recursive = 1 } qt_mutex_mode;
62
63
64/** Convert a Qt4 mutex type to a DRD mutex type. */
65static MutexT qt_to_drd_mutex_type(qt_mutex_mode mode)
66{
67   switch (mode)
68   {
69   case qt_nonrecursive:
70      return mutex_type_default_mutex;
71   case qt_recursive:
72      return mutex_type_recursive_mutex;
73   }
74   return mutex_type_invalid_mutex;
75}
76
77/** Find out the type of a Qt4 mutex (recursive or not).
78 *  Since it's not possible to do this in a portable way, return
79 *  mutex_type_unknown and let drd_mutex.c look up the real mutex type.
80 */
81static MutexT mutex_type(void* qt4_mutex)
82{
83   return mutex_type_unknown;
84}
85
86
87// QMutex::QMutex(RecursionMode) -- _ZN6QMutexC1ENS_13RecursionModeE,
88QT4CORE_FUNC(void, _ZN6QMutexC1ENS_13RecursionModeE,
89             void* mutex,
90             qt_mutex_mode mode)
91{
92   int    ret;
93   OrigFn fn;
94   VALGRIND_GET_ORIG_FN(fn);
95   VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_MUTEX_INIT,
96                                   mutex, qt_to_drd_mutex_type(mode), 0, 0, 0);
97   CALL_FN_W_WW(ret, fn, mutex, mode);
98   VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_INIT,
99                                   mutex, 0, 0, 0, 0);
100}
101
102// QMutex::QMutex(RecursionMode) -- _ZN6QMutexC2ENS_13RecursionModeE
103QT4CORE_FUNC(void, _ZN6QMutexC2ENS_13RecursionModeE,
104             void* mutex,
105             qt_mutex_mode mode)
106{
107   int    ret;
108   OrigFn fn;
109   VALGRIND_GET_ORIG_FN(fn);
110   VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_MUTEX_INIT,
111                                   mutex, qt_to_drd_mutex_type(mode), 0, 0, 0);
112   CALL_FN_W_WW(ret, fn, mutex, mode);
113   VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_INIT,
114                                   mutex, 0, 0, 0, 0);
115}
116
117// QMutex::~QMutex() -- _ZN6QMutexD1Ev
118QT4CORE_FUNC(void, _ZN6QMutexD1Ev,
119             void* mutex)
120{
121   int    ret;
122   OrigFn fn;
123   VALGRIND_GET_ORIG_FN(fn);
124   VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_MUTEX_DESTROY,
125                                   mutex, 0, 0, 0, 0);
126   CALL_FN_W_W(ret, fn, mutex);
127   VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_DESTROY,
128                                   mutex, mutex_type(mutex), 0, 0, 0);
129}
130
131// QMutex::~QMutex() -- _ZN6QMutexD2Ev
132QT4CORE_FUNC(void, _ZN6QMutexD2Ev,
133             void** mutex)
134{
135   int    ret;
136   OrigFn fn;
137   VALGRIND_GET_ORIG_FN(fn);
138   VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_MUTEX_DESTROY,
139                                   mutex, 0, 0, 0, 0);
140   CALL_FN_W_W(ret, fn, mutex);
141   VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_DESTROY,
142                                   mutex, mutex_type(mutex), 0, 0, 0);
143}
144
145// QMutex::lock() -- _ZN6QMutex4lockEv
146QT4CORE_FUNC(void, _ZN6QMutex4lockEv,
147             void* mutex)
148{
149   int   ret;
150   OrigFn fn;
151   VALGRIND_GET_ORIG_FN(fn);
152   VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRE_MUTEX_LOCK,
153                                   mutex, mutex_type(mutex), 0, 0, 0);
154   CALL_FN_W_W(ret, fn, mutex);
155   VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__POST_MUTEX_LOCK,
156                                   mutex, 1, 0, 0, 0);
157}
158
159// QMutex::tryLock() -- _ZN6QMutex7tryLockEv
160QT4CORE_FUNC(int, _ZN6QMutex7tryLockEv,
161             void* mutex)
162{
163   int    ret;
164   OrigFn fn;
165   VALGRIND_GET_ORIG_FN(fn);
166   VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRE_MUTEX_LOCK,
167                                   mutex, mutex_type(mutex), 1, 0, 0);
168   CALL_FN_W_W(ret, fn, mutex);
169   VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_LOCK,
170                                   mutex, ret, 0, 0, 0);
171   return ret;
172}
173
174// QMutex::tryLock(int) -- _ZN6QMutex7tryLockEi
175QT4CORE_FUNC(int, _ZN6QMutex7tryLockEi,
176             void* mutex,
177             int timeout_ms)
178{
179   int    ret;
180   OrigFn fn;
181   VALGRIND_GET_ORIG_FN(fn);
182   VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRE_MUTEX_LOCK,
183                                   mutex, mutex_type(mutex), 1, 0, 0);
184   CALL_FN_W_WW(ret, fn, mutex, timeout_ms);
185   VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_LOCK,
186                                   mutex, ret, 0, 0, 0);
187   return ret;
188}
189
190// QMutex::unlock() -- _ZN6QMutex6unlockEv
191QT4CORE_FUNC(void, _ZN6QMutex6unlockEv,
192             void* mutex)
193{
194   int    ret;
195   OrigFn fn;
196   VALGRIND_GET_ORIG_FN(fn);
197   VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_MUTEX_UNLOCK,
198                                   mutex, mutex_type(mutex), 0, 0, 0);
199   CALL_FN_W_W(ret, fn, mutex);
200   VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_UNLOCK,
201                                   mutex, 0, 0, 0, 0);
202}
203