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