1/* -*- mode: C; c-basic-offset: 3; -*- */
2/*
3  This file is part of drd, a thread error detector.
4
5  Copyright (C) 2006-2010 Bart Van Assche <bvanassche@acm.org>.
6
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of the
10  License, or (at your option) any later version.
11
12  This program is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  General Public License for more details.
16
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20  02111-1307, USA.
21
22  The GNU General Public License is contained in the file COPYING.
23*/
24
25
26#include "drd_barrier.h"
27#include "drd_clientreq.h"
28#include "drd_cond.h"
29#include "drd_error.h"
30#include "drd_hb.h"
31#include "drd_load_store.h"
32#include "drd_malloc_wrappers.h"
33#include "drd_mutex.h"
34#include "drd_rwlock.h"
35#include "drd_semaphore.h"
36#include "drd_suppression.h"      // drd_start_suppression()
37#include "drd_thread.h"
38#include "pub_tool_basics.h"      // Bool
39#include "pub_tool_debuginfo.h"   // VG_(describe_IP)()
40#include "pub_tool_libcassert.h"
41#include "pub_tool_libcassert.h"  // tl_assert()
42#include "pub_tool_libcprint.h"   // VG_(message)()
43#include "pub_tool_machine.h"     // VG_(get_SP)()
44#include "pub_tool_threadstate.h"
45#include "pub_tool_tooliface.h"   // VG_(needs_...)()
46
47
48/* Local function declarations. */
49
50static Bool handle_client_request(ThreadId vg_tid, UWord* arg, UWord* ret);
51
52
53/* Function definitions. */
54
55/**
56 * Tell the Valgrind core the address of the DRD function that processes
57 * client requests. Must be called before any client code is run.
58 */
59void DRD_(clientreq_init)(void)
60{
61   VG_(needs_client_requests)(handle_client_request);
62}
63
64/**
65 * DRD's handler for Valgrind client requests. The code below handles both
66 * DRD's public and tool-internal client requests.
67 */
68static Bool handle_client_request(ThreadId vg_tid, UWord* arg, UWord* ret)
69{
70   UWord result = 0;
71   const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
72
73   tl_assert(vg_tid == VG_(get_running_tid()));
74   tl_assert(DRD_(VgThreadIdToDrdThreadId)(vg_tid) == drd_tid);
75
76   switch (arg[0])
77   {
78   case VG_USERREQ__MALLOCLIKE_BLOCK:
79      if (arg[1])
80         DRD_(malloclike_block)(vg_tid, arg[1]/*addr*/, arg[2]/*size*/);
81      break;
82
83   case VG_USERREQ__FREELIKE_BLOCK:
84      if (arg[1] && ! DRD_(freelike_block)(vg_tid, arg[1]/*addr*/))
85      {
86         GenericErrInfo GEI = {
87	    .tid = DRD_(thread_get_running_tid)(),
88	    .addr = 0,
89	 };
90         VG_(maybe_record_error)(vg_tid,
91                                 GenericErr,
92                                 VG_(get_IP)(vg_tid),
93                                 "Invalid VG_USERREQ__FREELIKE_BLOCK request",
94                                 &GEI);
95      }
96      break;
97
98   case VG_USERREQ__DRD_GET_VALGRIND_THREAD_ID:
99      result = vg_tid;
100      break;
101
102   case VG_USERREQ__DRD_GET_DRD_THREAD_ID:
103      result = drd_tid;
104      break;
105
106   case VG_USERREQ__DRD_SET_THREAD_NAME:
107      DRD_(thread_set_name)(drd_tid, (const char*)arg[1]);
108      break;
109
110   case VG_USERREQ__DRD_START_SUPPRESSION:
111      /*_VG_USERREQ__HG_ARANGE_MAKE_UNTRACKED*/
112   case VG_USERREQ_TOOL_BASE('H','G') + 256 + 39:
113      DRD_(start_suppression)(arg[1], arg[1] + arg[2], "client");
114      break;
115
116   case VG_USERREQ__DRD_FINISH_SUPPRESSION:
117      /*_VG_USERREQ__HG_ARANGE_MAKE_TRACKED*/
118   case VG_USERREQ_TOOL_BASE('H','G') + 256 + 40:
119      DRD_(finish_suppression)(arg[1], arg[1] + arg[2]);
120      break;
121
122   case VG_USERREQ__DRD_ANNOTATE_HAPPENS_BEFORE:
123      DRD_(hb_happens_before)(drd_tid, arg[1]);
124      break;
125
126   case VG_USERREQ__DRD_ANNOTATE_HAPPENS_AFTER:
127      DRD_(hb_happens_after)(drd_tid, arg[1]);
128      break;
129
130   case VG_USERREQ__DRD_ANNOTATE_RWLOCK_CREATE:
131      if (arg[1])
132      {
133         struct mutex_info* const mutex_p = DRD_(mutex_get)(arg[1]);
134         if (mutex_p && mutex_p->mutex_type == mutex_type_spinlock)
135            break;
136      }
137      DRD_(rwlock_pre_init)(arg[1], user_rwlock);
138      break;
139
140   case VG_USERREQ__DRD_ANNOTATE_RWLOCK_DESTROY:
141      if (arg[1])
142      {
143         struct mutex_info* const mutex_p = DRD_(mutex_get)(arg[1]);
144         if (mutex_p && mutex_p->mutex_type == mutex_type_spinlock)
145            break;
146      }
147      DRD_(rwlock_post_destroy)(arg[1], user_rwlock);
148      break;
149
150   case VG_USERREQ__DRD_ANNOTATE_RWLOCK_ACQUIRED:
151      if (arg[1])
152      {
153         struct mutex_info* const mutex_p = DRD_(mutex_get)(arg[1]);
154         if (mutex_p && mutex_p->mutex_type == mutex_type_spinlock)
155            break;
156      }
157      tl_assert(arg[2] == !! arg[2]);
158      if (arg[2])
159      {
160         DRD_(rwlock_pre_wrlock)(arg[1], user_rwlock);
161         DRD_(rwlock_post_wrlock)(arg[1], user_rwlock, True);
162      }
163      else
164      {
165         DRD_(rwlock_pre_rdlock)(arg[1], user_rwlock);
166         DRD_(rwlock_post_rdlock)(arg[1], user_rwlock, True);
167      }
168      break;
169
170   case VG_USERREQ__DRD_ANNOTATE_RWLOCK_RELEASED:
171      if (arg[1])
172      {
173         struct mutex_info* const mutex_p = DRD_(mutex_get)(arg[1]);
174         if (mutex_p && mutex_p->mutex_type == mutex_type_spinlock)
175            break;
176      }
177      tl_assert(arg[2] == !! arg[2]);
178      DRD_(rwlock_pre_unlock)(arg[1], user_rwlock);
179      break;
180
181   case VG_USERREQ__SET_PTHREAD_COND_INITIALIZER:
182      DRD_(pthread_cond_initializer) = (Addr)arg[1];
183      DRD_(pthread_cond_initializer_size) = arg[2];
184      break;
185
186   case VG_USERREQ__DRD_START_NEW_SEGMENT:
187      DRD_(thread_new_segment)(DRD_(PtThreadIdToDrdThreadId)(arg[1]));
188      break;
189
190   case VG_USERREQ__DRD_START_TRACE_ADDR:
191      DRD_(start_tracing_address_range)(arg[1], arg[1] + arg[2]);
192      break;
193
194   case VG_USERREQ__DRD_STOP_TRACE_ADDR:
195      DRD_(stop_tracing_address_range)(arg[1], arg[1] + arg[2]);
196      break;
197
198   case VG_USERREQ__DRD_RECORD_LOADS:
199      DRD_(thread_set_record_loads)(drd_tid, arg[1]);
200      break;
201
202   case VG_USERREQ__DRD_RECORD_STORES:
203      DRD_(thread_set_record_stores)(drd_tid, arg[1]);
204      break;
205
206   case VG_USERREQ__SET_PTHREADID:
207      // pthread_self() returns 0 for programs not linked with libpthread.so.
208      if (arg[1] != INVALID_POSIX_THREADID)
209         DRD_(thread_set_pthreadid)(drd_tid, arg[1]);
210      break;
211
212   case VG_USERREQ__SET_JOINABLE:
213      DRD_(thread_set_joinable)(DRD_(PtThreadIdToDrdThreadId)(arg[1]),
214                                (Bool)arg[2]);
215      break;
216
217   case VG_USERREQ__ENTERING_PTHREAD_CREATE:
218      DRD_(thread_entering_pthread_create)(drd_tid);
219      break;
220
221   case VG_USERREQ__LEFT_PTHREAD_CREATE:
222      DRD_(thread_left_pthread_create)(drd_tid);
223      break;
224
225   case VG_USERREQ__POST_THREAD_JOIN:
226   {
227      const DrdThreadId thread_to_join = DRD_(PtThreadIdToDrdThreadId)(arg[1]);
228      if (thread_to_join == DRD_INVALID_THREADID)
229      {
230         InvalidThreadIdInfo ITI = { DRD_(thread_get_running_tid)(), arg[1] };
231         VG_(maybe_record_error)(vg_tid,
232                                 InvalidThreadId,
233                                 VG_(get_IP)(vg_tid),
234                                 "pthread_join(): invalid thread ID",
235                                 &ITI);
236      }
237      else
238      {
239         DRD_(thread_post_join)(drd_tid, thread_to_join);
240      }
241      break;
242   }
243
244   case VG_USERREQ__PRE_THREAD_CANCEL:
245   {
246      const DrdThreadId thread_to_cancel =DRD_(PtThreadIdToDrdThreadId)(arg[1]);
247      if (thread_to_cancel == DRD_INVALID_THREADID)
248      {
249         InvalidThreadIdInfo ITI = { DRD_(thread_get_running_tid)(), arg[1] };
250         VG_(maybe_record_error)(vg_tid,
251                                 InvalidThreadId,
252                                 VG_(get_IP)(vg_tid),
253                                 "pthread_cancel(): invalid thread ID",
254                                 &ITI);
255      }
256      else
257      {
258         DRD_(thread_pre_cancel)(thread_to_cancel);
259      }
260      break;
261   }
262
263   case VG_USERREQ__POST_THREAD_CANCEL:
264      break;
265
266   case VG_USERREQ__PRE_MUTEX_INIT:
267      if (DRD_(thread_enter_synchr)(drd_tid) == 0)
268         DRD_(mutex_init)(arg[1], arg[2]);
269      break;
270
271   case VG_USERREQ__POST_MUTEX_INIT:
272      DRD_(thread_leave_synchr)(drd_tid);
273      break;
274
275   case VG_USERREQ__PRE_MUTEX_DESTROY:
276      DRD_(thread_enter_synchr)(drd_tid);
277      break;
278
279   case VG_USERREQ__POST_MUTEX_DESTROY:
280      if (DRD_(thread_leave_synchr)(drd_tid) == 0)
281         DRD_(mutex_post_destroy)(arg[1]);
282      break;
283
284   case VG_USERREQ__PRE_MUTEX_LOCK:
285      if (DRD_(thread_enter_synchr)(drd_tid) == 0)
286         DRD_(mutex_pre_lock)(arg[1], arg[2], arg[3]);
287      break;
288
289   case VG_USERREQ__POST_MUTEX_LOCK:
290      if (DRD_(thread_leave_synchr)(drd_tid) == 0)
291         DRD_(mutex_post_lock)(arg[1], arg[2], False/*post_cond_wait*/);
292      break;
293
294   case VG_USERREQ__PRE_MUTEX_UNLOCK:
295      if (DRD_(thread_enter_synchr)(drd_tid) == 0)
296         DRD_(mutex_unlock)(arg[1], arg[2]);
297      break;
298
299   case VG_USERREQ__POST_MUTEX_UNLOCK:
300      DRD_(thread_leave_synchr)(drd_tid);
301      break;
302
303   case VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK:
304      if (DRD_(thread_enter_synchr)(drd_tid) == 0)
305         DRD_(spinlock_init_or_unlock)(arg[1]);
306      break;
307
308   case VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK:
309      DRD_(thread_leave_synchr)(drd_tid);
310      break;
311
312   case VG_USERREQ__PRE_COND_INIT:
313      if (DRD_(thread_enter_synchr)(drd_tid) == 0)
314         DRD_(cond_pre_init)(arg[1]);
315      break;
316
317   case VG_USERREQ__POST_COND_INIT:
318      DRD_(thread_leave_synchr)(drd_tid);
319      break;
320
321   case VG_USERREQ__PRE_COND_DESTROY:
322      DRD_(thread_enter_synchr)(drd_tid);
323      break;
324
325   case VG_USERREQ__POST_COND_DESTROY:
326      if (DRD_(thread_leave_synchr)(drd_tid) == 0)
327         DRD_(cond_post_destroy)(arg[1]);
328      break;
329
330   case VG_USERREQ__PRE_COND_WAIT:
331      if (DRD_(thread_enter_synchr)(drd_tid) == 0)
332      {
333         const Addr cond = arg[1];
334         const Addr mutex = arg[2];
335         const MutexT mutex_type = arg[3];
336         DRD_(mutex_unlock)(mutex, mutex_type);
337         DRD_(cond_pre_wait)(cond, mutex);
338      }
339      break;
340
341   case VG_USERREQ__POST_COND_WAIT:
342      if (DRD_(thread_leave_synchr)(drd_tid) == 0)
343      {
344         const Addr cond = arg[1];
345         const Addr mutex = arg[2];
346         const Bool took_lock = arg[3];
347         DRD_(cond_post_wait)(cond);
348         DRD_(mutex_post_lock)(mutex, took_lock, True);
349      }
350      break;
351
352   case VG_USERREQ__PRE_COND_SIGNAL:
353      if (DRD_(thread_enter_synchr)(drd_tid) == 0)
354         DRD_(cond_pre_signal)(arg[1]);
355      break;
356
357   case VG_USERREQ__POST_COND_SIGNAL:
358      DRD_(thread_leave_synchr)(drd_tid);
359      break;
360
361   case VG_USERREQ__PRE_COND_BROADCAST:
362      if (DRD_(thread_enter_synchr)(drd_tid) == 0)
363         DRD_(cond_pre_broadcast)(arg[1]);
364      break;
365
366   case VG_USERREQ__POST_COND_BROADCAST:
367      DRD_(thread_leave_synchr)(drd_tid);
368      break;
369
370   case VG_USERREQ__PRE_SEM_INIT:
371      if (DRD_(thread_enter_synchr)(drd_tid) == 0)
372         DRD_(semaphore_init)(arg[1], arg[2], arg[3]);
373      break;
374
375   case VG_USERREQ__POST_SEM_INIT:
376      DRD_(thread_leave_synchr)(drd_tid);
377      break;
378
379   case VG_USERREQ__PRE_SEM_DESTROY:
380      DRD_(thread_enter_synchr)(drd_tid);
381      break;
382
383   case VG_USERREQ__POST_SEM_DESTROY:
384      if (DRD_(thread_leave_synchr)(drd_tid) == 0)
385         DRD_(semaphore_destroy)(arg[1]);
386      break;
387
388   case VG_USERREQ__PRE_SEM_OPEN:
389      DRD_(thread_enter_synchr)(drd_tid);
390      break;
391
392   case VG_USERREQ__POST_SEM_OPEN:
393      if (DRD_(thread_leave_synchr)(drd_tid) == 0)
394         DRD_(semaphore_open)(arg[1], (Char*)arg[2], arg[3], arg[4], arg[5]);
395      break;
396
397   case VG_USERREQ__PRE_SEM_CLOSE:
398      if (DRD_(thread_enter_synchr)(drd_tid) == 0)
399         DRD_(semaphore_close)(arg[1]);
400      break;
401
402   case VG_USERREQ__POST_SEM_CLOSE:
403      DRD_(thread_leave_synchr)(drd_tid);
404      break;
405
406   case VG_USERREQ__PRE_SEM_WAIT:
407      if (DRD_(thread_enter_synchr)(drd_tid) == 0)
408         DRD_(semaphore_pre_wait)(arg[1]);
409      break;
410
411   case VG_USERREQ__POST_SEM_WAIT:
412      if (DRD_(thread_leave_synchr)(drd_tid) == 0)
413         DRD_(semaphore_post_wait)(drd_tid, arg[1], arg[2]);
414      break;
415
416   case VG_USERREQ__PRE_SEM_POST:
417      if (DRD_(thread_enter_synchr)(drd_tid) == 0)
418         DRD_(semaphore_pre_post)(drd_tid, arg[1]);
419      break;
420
421   case VG_USERREQ__POST_SEM_POST:
422      if (DRD_(thread_leave_synchr)(drd_tid) == 0)
423         DRD_(semaphore_post_post)(drd_tid, arg[1], arg[2]);
424      break;
425
426   case VG_USERREQ__PRE_BARRIER_INIT:
427      if (DRD_(thread_enter_synchr)(drd_tid) == 0)
428         DRD_(barrier_init)(arg[1], arg[2], arg[3], arg[4]);
429      break;
430
431   case VG_USERREQ__POST_BARRIER_INIT:
432      DRD_(thread_leave_synchr)(drd_tid);
433      break;
434
435   case VG_USERREQ__PRE_BARRIER_DESTROY:
436      DRD_(thread_enter_synchr)(drd_tid);
437      break;
438
439   case VG_USERREQ__POST_BARRIER_DESTROY:
440      if (DRD_(thread_leave_synchr)(drd_tid) == 0)
441         DRD_(barrier_destroy)(arg[1], arg[2]);
442      break;
443
444   case VG_USERREQ__PRE_BARRIER_WAIT:
445      if (DRD_(thread_enter_synchr)(drd_tid) == 0)
446         DRD_(barrier_pre_wait)(drd_tid, arg[1], arg[2]);
447      break;
448
449   case VG_USERREQ__POST_BARRIER_WAIT:
450      if (DRD_(thread_leave_synchr)(drd_tid) == 0)
451         DRD_(barrier_post_wait)(drd_tid, arg[1], arg[2], arg[3], arg[4]);
452      break;
453
454   case VG_USERREQ__PRE_RWLOCK_INIT:
455      DRD_(rwlock_pre_init)(arg[1], pthread_rwlock);
456      break;
457
458   case VG_USERREQ__POST_RWLOCK_DESTROY:
459      DRD_(rwlock_post_destroy)(arg[1], pthread_rwlock);
460      break;
461
462   case VG_USERREQ__PRE_RWLOCK_RDLOCK:
463      if (DRD_(thread_enter_synchr)(drd_tid) == 0)
464         DRD_(rwlock_pre_rdlock)(arg[1], pthread_rwlock);
465      break;
466
467   case VG_USERREQ__POST_RWLOCK_RDLOCK:
468      if (DRD_(thread_leave_synchr)(drd_tid) == 0)
469         DRD_(rwlock_post_rdlock)(arg[1], pthread_rwlock, arg[2]);
470      break;
471
472   case VG_USERREQ__PRE_RWLOCK_WRLOCK:
473      if (DRD_(thread_enter_synchr)(drd_tid) == 0)
474         DRD_(rwlock_pre_wrlock)(arg[1], pthread_rwlock);
475      break;
476
477   case VG_USERREQ__POST_RWLOCK_WRLOCK:
478      if (DRD_(thread_leave_synchr)(drd_tid) == 0)
479         DRD_(rwlock_post_wrlock)(arg[1], pthread_rwlock, arg[2]);
480      break;
481
482   case VG_USERREQ__PRE_RWLOCK_UNLOCK:
483      if (DRD_(thread_enter_synchr)(drd_tid) == 0)
484         DRD_(rwlock_pre_unlock)(arg[1], pthread_rwlock);
485      break;
486
487   case VG_USERREQ__POST_RWLOCK_UNLOCK:
488      DRD_(thread_leave_synchr)(drd_tid);
489      break;
490
491   case VG_USERREQ__DRD_CLEAN_MEMORY:
492      if (arg[2] > 0)
493         DRD_(clean_memory)(arg[1], arg[2]);
494      break;
495
496   case VG_USERREQ__HELGRIND_ANNOTATION_UNIMP:
497      {
498         /* Note: it is assumed below that the text arg[1] points to is never
499          * freed, e.g. because it points to static data.
500          */
501         UnimpClReqInfo UICR =
502            { DRD_(thread_get_running_tid)(), (Char*)arg[1] };
503         VG_(maybe_record_error)(vg_tid,
504                                 UnimpHgClReq,
505                                 VG_(get_IP)(vg_tid),
506                                 "",
507                                 &UICR);
508      }
509      break;
510
511   case VG_USERREQ__DRD_ANNOTATION_UNIMP:
512      {
513         /* Note: it is assumed below that the text arg[1] points to is never
514          * freed, e.g. because it points to static data.
515          */
516         UnimpClReqInfo UICR =
517            { DRD_(thread_get_running_tid)(), (Char*)arg[1] };
518         VG_(maybe_record_error)(vg_tid,
519                                 UnimpDrdClReq,
520                                 VG_(get_IP)(vg_tid),
521                                 "",
522                                 &UICR);
523      }
524      break;
525
526   default:
527#if 0
528      VG_(message)(Vg_DebugMsg, "Unrecognized client request 0x%lx 0x%lx",
529                   arg[0], arg[1]);
530      tl_assert(0);
531#endif
532      return False;
533   }
534
535   *ret = result;
536   return True;
537}
538