blob: 7ddb900c8c9e2e826e2b72a3662ce683f38bd95a [file] [log] [blame]
sewardjaf44c822007-11-25 14:01:38 +00001/*
2 This file is part of drd, a data race detector.
3
4 Copyright (C) 2006-2007 Bart Van Assche
5 bart.vanassche@gmail.com
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 "pub_drd_bitmap.h"
27#include "drd_clientreq.h"
28#include "drd_cond.h"
29#include "drd_error.h"
30#include "drd_malloc_wrappers.h"
31#include "drd_mutex.h"
32#include "drd_segment.h"
33#include "drd_suppression.h"
34#include "drd_thread.h"
35#include "drd_track.h"
36#include "drd_vc.h"
37#include "pthread_object_size.h"
38#include "pub_core_mallocfree.h"
39#include "pub_core_options.h"
40#include "pub_tool_vki.h"
41#include "pub_tool_basics.h"
42#include "pub_tool_debuginfo.h" // VG_(describe_IP)()
43#include "pub_tool_libcassert.h" // tl_assert()
44#include "pub_tool_libcbase.h" // VG_(strcmp)
45#include "pub_tool_libcprint.h" // VG_(printf)
46#include "pub_tool_libcproc.h"
47#include "pub_tool_machine.h"
48#include "pub_tool_options.h" // command line options
49#include "pub_tool_threadstate.h" // VG_(get_running_tid)
50#include "pub_tool_tooliface.h"
51
52
53// Type definitions.
54
55#if 0
56typedef struct
57{
58 const Char* const soname;
59 const Char* const symbol;
60} SuppressedSymbol;
61#endif
62
63
64// Function declarations.
65
66static void drd_start_client_code(const ThreadId tid, const ULong bbs_done);
67static void drd_set_running_tid(const ThreadId tid);
68
69
70
71// Local variables.
72
73static Bool drd_print_stats = False;
74static Bool drd_trace_mem = False;
75static Bool drd_trace_fork_join = False;
76static Addr drd_trace_address = 0;
77#if 0
78// Note: using the information below for suppressing data races is only
79// possible when the client and the shared libraries it uses contain
80// debug information. Not every Linux distribution includes debug information
81// in shared libraries.
82static const SuppressedSymbol s_suppressed_symbols[] =
83 {
84 { "ld-linux.so.2", "_rtld_local" },
85 { "libpthread.so.0", "__nptl_nthreads" },
86 { "libpthread.so.0", "stack_cache" },
87 { "libpthread.so.0", "stack_cache_actsize" },
88 { "libpthread.so.0", "stack_cache_lock" },
89 { "libpthread.so.0", "stack_used" },
90 { "libpthread.so.0", "libgcc_s_forcedunwind" },
91 { "libpthread.so.0", "libgcc_s_getcfa" },
92 };
93#endif
94
95
96//
97// Implement the needs_command_line_options for drd.
98//
99
100static Bool drd_process_cmd_line_option(Char* arg)
101{
102 Bool trace_cond = False;
103 Bool trace_mutex = False;
104 Bool trace_segment = False;
105 Bool trace_suppression = False;
106 Char* trace_address = 0;
107
108 VG_BOOL_CLO (arg, "--drd-stats", drd_print_stats)
109 else VG_BOOL_CLO(arg, "--trace-cond", trace_cond)
110 else VG_BOOL_CLO(arg, "--trace-fork-join", drd_trace_fork_join)
111 else VG_BOOL_CLO(arg, "--trace-mem", drd_trace_mem)
112 else VG_BOOL_CLO(arg, "--trace-mutex", trace_mutex)
113 else VG_BOOL_CLO(arg, "--trace-segment", trace_segment)
114 else VG_BOOL_CLO(arg, "--trace-suppression", trace_suppression)
115 else VG_STR_CLO (arg, "--trace-address", trace_address)
116 else
117 return False;
118
119 if (trace_address)
120 drd_trace_address = VG_(strtoll16)(trace_address, 0);
121 if (trace_cond)
122 cond_set_trace(trace_cond);
123 if (trace_mutex)
124 mutex_set_trace(trace_mutex);
125 if (trace_segment)
126 sg_set_trace(trace_segment);
127 if (trace_suppression)
128 suppression_set_trace(trace_suppression);
129
130 return True;
131}
132
133static void drd_print_usage(void)
134{
135 VG_(printf)(" --trace-mem=no|yes Trace all memory accesses to stdout[no]"
136 "\n"
137 " --trace-fork-join=no|yes Trace all thread creation and join"
138 " activity\n"
139 " --trace-mutex=no|yes Trace all mutex activity\n"
140 " --trace-segment=no|yes Trace segment actions\n"
141 );
142}
143
144static void drd_print_debug_usage(void)
145{
146}
147
148
149//
150// Implements the thread-related core callbacks.
151//
152
153static
154VG_REGPARM(2) void drd_trace_load(Addr addr, SizeT size)
155{
156 Segment* sg;
157
158 if (! thread_is_recording(thread_get_running_tid()))
159 return;
160
161#if 1
162 if (drd_trace_mem || (addr == drd_trace_address))
163 {
164 VG_(message)(Vg_UserMsg, "load 0x%lx size %ld %s (vg %d / drd %d)",
165 addr,
166 size,
167 thread_get_name(thread_get_running_tid()),
168 VG_(get_running_tid)(),
169 thread_get_running_tid());
170 VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(),
171 VG_(clo_backtrace_size));
172 tl_assert(DrdThreadIdToVgThreadId(thread_get_running_tid())
173 == VG_(get_running_tid)());
174 }
175#endif
176 sg = thread_get_segment(thread_get_running_tid());
177 bm_access_range(sg->bm, addr, size, eLoad);
178 if (thread_conflicting_access(addr, size, eLoad))
179 {
180 DataRaceErrInfo drei;
181 drei.tid = VG_(get_running_tid)();
182 drei.addr = addr;
183 drei.size = size;
184 drei.access_type = eLoad;
185 VG_(maybe_record_error)(VG_(get_running_tid)(),
186 DataRaceErr,
187 VG_(get_IP)(VG_(get_running_tid)()),
188 "Conflicting accesses",
189 &drei);
190 }
191}
192
193static
194VG_REGPARM(2) void drd_trace_store(Addr addr, SizeT size)
195{
196 Segment* sg;
197
198 if (! thread_is_recording(thread_get_running_tid()))
199 return;
200
201#if 1
202 if (drd_trace_mem || (addr == drd_trace_address))
203 {
204 VG_(message)(Vg_UserMsg, "store 0x%lx size %ld %s (vg %d / drd %d / off %d)",
205 addr,
206 size,
207 thread_get_name(thread_get_running_tid()),
208 VG_(get_running_tid)(),
209 thread_get_running_tid(),
210 addr - thread_get_stack_min(thread_get_running_tid()));
211 VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(),
212 VG_(clo_backtrace_size));
213 tl_assert(DrdThreadIdToVgThreadId(thread_get_running_tid())
214 == VG_(get_running_tid)());
215 }
216#endif
217 sg = thread_get_segment(thread_get_running_tid());
218 bm_access_range(sg->bm, addr, size, eStore);
219 if (thread_conflicting_access(addr, size, eStore))
220 {
221 DataRaceErrInfo drei;
222 drei.tid = VG_(get_running_tid)();
223 drei.addr = addr;
224 drei.size = size;
225 drei.access_type = eStore;
226 VG_(maybe_record_error)(VG_(get_running_tid)(),
227 DataRaceErr,
228 VG_(get_IP)(VG_(get_running_tid)()),
229 "Conflicting accesses",
230 &drei);
231 }
232}
233
234static void drd_pre_mem_read(const CorePart part,
235 const ThreadId tid,
236 Char* const s,
237 const Addr a,
238 const SizeT size)
239{
240 const ThreadId running_tid = VG_(get_running_tid)();
241
242 if (size == 0)
243 return;
244
245 if (tid != running_tid)
246 {
247 if (VgThreadIdToDrdThreadId(tid) != DRD_INVALID_THREADID)
248 {
249 drd_set_running_tid(tid);
250 drd_trace_load(a, size);
251 drd_set_running_tid(running_tid);
252 }
253 else
254 {
255 VG_(message)(Vg_DebugMsg,
256 "drd_pre_mem_read() was called before"
257 " drd_post_thread_create() for thread ID %d",
258 tid);
259 tl_assert(0);
260 }
261 }
262 else
263 {
264 drd_trace_load(a, size);
265 }
266}
267
268static void drd_post_mem_write(const CorePart part,
269 const ThreadId tid,
270 const Addr a,
271 const SizeT size)
272{
273 const ThreadId running_tid = VG_(get_running_tid)();
274
275 if (size == 0)
276 return;
277
278 if (tid != running_tid)
279 {
280 if (VgThreadIdToDrdThreadId(tid) != DRD_INVALID_THREADID)
281 {
282 drd_set_running_tid(tid);
283 drd_trace_store(a, size);
284 drd_set_running_tid(running_tid);
285 }
286 else
287 {
288#if 1
289 VG_(message)(Vg_DebugMsg,
290 "drd_pre_mem_write() was called before"
291 " drd_post_thread_create() for thread ID %d",
292 tid);
293 tl_assert(0);
294#endif
295 }
296 }
297 else
298 {
299 drd_trace_store(a, size);
300 }
301}
302
303static void drd_start_using_mem(const Addr a1, const Addr a2)
304{
305 if (a1 <= drd_trace_address && drd_trace_address < a2
306 && thread_is_recording(thread_get_running_tid()))
307 {
308 VG_(message)(Vg_UserMsg, "start 0x%lx size %ld %s (tracing 0x%lx)",
309 a1, a2 - a1, thread_get_name(thread_get_running_tid()),
310 drd_trace_address);
311 VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(),
312 VG_(clo_backtrace_size));
313 }
314}
315
316static void drd_stop_using_mem(const Addr a1, const Addr a2)
317{
318 if (a1 <= drd_trace_address && drd_trace_address < a2
319 && thread_is_recording(thread_get_running_tid()))
320 {
321 VG_(message)(Vg_UserMsg, "end 0x%lx size %ld %s (tracing 0x%lx)",
322 a1, a2 - a1, thread_get_name(thread_get_running_tid()),
323 drd_trace_address);
324 VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(),
325 VG_(clo_backtrace_size));
326 }
327 thread_stop_using_mem(a1, a2);
328 mutex_stop_using_mem(a1, a2);
329 cond_stop_using_mem(a1, a2);
330 drd_suppression_stop_using_mem(a1, a2);
331}
332
333static VG_REGPARM(2)
334 void drd_make_stack_uninit(const Addr base, const UWord len)
335{
336#if 0
337 VG_(message)(Vg_DebugMsg, "make_stack_uninit(0x%lx, %ld)", base, len);
338#endif
339 drd_stop_using_mem(base, base + len);
340}
341
342/* Called by the core when the stack of a thread grows, to indicate that */
343/* the addresses in range [ a, a + len [ may now be used by the client. */
344/* Assumption: stacks grow downward. */
345static void drd_start_using_mem_stack(const Addr a, const SizeT len)
346{
347 thread_set_stack_min(thread_get_running_tid(), a - VG_STACK_REDZONE_SZB);
348 drd_start_using_mem(a - VG_STACK_REDZONE_SZB,
349 a - VG_STACK_REDZONE_SZB + len);
350}
351
352/* Called by the core when the stack of a thread shrinks, to indicate that */
353/* the addresses [ a, a + len [ are no longer accessible for the client. */
354/* Assumption: stacks grow downward. */
355static void drd_stop_using_mem_stack(const Addr a, const SizeT len)
356{
357#if 0
358 VG_(message)(Vg_DebugMsg, "stop_using_mem_stack(0x%lx, %ld)", a, len);
359#endif
360 thread_set_stack_min(thread_get_running_tid(),
361 a + len - VG_STACK_REDZONE_SZB);
362 drd_stop_using_mem(a - VG_STACK_REDZONE_SZB,
363 a + len - VG_STACK_REDZONE_SZB);
364}
365
366static void drd_start_using_mem_mmap(Addr a, SizeT len,
367 Bool rr, Bool ww, Bool xx)
368{
369 drd_start_using_mem(a, a + len);
370}
371
372static void drd_stop_using_mem_munmap(Addr a, SizeT len)
373{
374 drd_stop_using_mem(a, a + len);
375}
376
377static
378void drd_pre_thread_create(const ThreadId creator, const ThreadId created)
379{
380 const DrdThreadId drd_creator = VgThreadIdToDrdThreadId(creator);
381 tl_assert(created != VG_INVALID_THREADID);
382 thread_pre_create(drd_creator, created);
383#if 1
384 // Hack: compensation for code missing in coregrind/m_main.c.
385 if (created == 1)
386 {
387 extern ThreadId VG_(running_tid);
388 tl_assert(VG_(running_tid) == VG_INVALID_THREADID);
389 VG_(running_tid) = 1;
390 drd_start_client_code(VG_(running_tid), 0);
391 VG_(running_tid) = VG_INVALID_THREADID;
392 }
393#endif
394 if (IsValidDrdThreadId(drd_creator))
395 {
396 thread_new_segment(drd_creator);
397 }
398 if (drd_trace_fork_join)
399 {
400 VG_(message)(Vg_DebugMsg,
401 "drd_pre_thread_create creator = %d/%d, created = %d",
402 creator, drd_creator, created);
403 }
404}
405
406/* Called by Valgrind's core before any loads or stores are performed on */
407/* the context of thread "created". At startup, this function is called */
408/* with arguments (0,1). */
409static
410void drd_post_thread_create(const ThreadId created)
411{
412 const DrdThreadId drd_created = thread_post_create(created);
413 tl_assert(created != VG_INVALID_THREADID);
414 if (drd_trace_fork_join)
415 {
416 VG_(message)(Vg_DebugMsg,
417 "drd_post_thread_create created = %d/%d",
418 created, drd_created);
419 }
420}
421
422/* Process VG_USERREQ__POST_THREAD_JOIN. This client request is invoked just */
423/* after thread drd_joiner joined thread drd_joinee. */
424void drd_post_thread_join(DrdThreadId drd_joiner, DrdThreadId drd_joinee)
425{
426 tl_assert(IsValidDrdThreadId(drd_joiner));
427 tl_assert(IsValidDrdThreadId(drd_joinee));
428 thread_new_segment(drd_joinee);
429 thread_combine_vc(drd_joiner, drd_joinee);
430 thread_new_segment(drd_joiner);
431
432 if (drd_trace_fork_join)
433 {
434 char msg[256];
435 const ThreadId joiner = DrdThreadIdToVgThreadId(drd_joiner);
436 const ThreadId joinee = DrdThreadIdToVgThreadId(drd_joinee);
437 VG_(snprintf)(msg, sizeof(msg),
438 "drd_post_thread_join joiner = %d/%d, joinee = %d/%d",
439 joiner, drd_joiner, joinee, drd_joinee);
440 if (joiner)
441 {
442 VG_(snprintf)(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
443 ", new vc: ");
444 vc_snprint(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
445 thread_get_vc(drd_joiner));
446 }
447 VG_(message)(Vg_DebugMsg, msg);
448 }
449
450 thread_delete(drd_joinee);
451 mutex_thread_delete(drd_joinee);
452}
453
454/* Called after a thread has performed its last memory access. */
455static void drd_thread_finished(ThreadId tid)
456{
457 const DrdThreadId drd_tid = VgThreadIdToDrdThreadId(tid);
458 if (drd_trace_fork_join)
459 {
460 VG_(message)(Vg_DebugMsg,
461 "drd_thread_finished tid = %d/%d%s",
462 tid,
463 drd_tid,
464 thread_get_joinable(drd_tid)
465 ? ""
466 : " (which is a detached thread)");
467
468 }
469 thread_finished(drd_tid);
470}
471
472void drd_pre_mutex_init(Addr mutex, SizeT size)
473{
474 mutex_init(mutex, size);
475}
476
477void drd_post_mutex_destroy(Addr mutex, SizeT size)
478{
479 struct mutex_info* p;
480
481 p = mutex_get(mutex);
482 if (p)
483 {
484 // TO DO: report an error in case the recursion count is not zero
485 // before asserting.
486 tl_assert(mutex_get_recursion_count(mutex) == 0);
487 mutex_destroy(p);
488 }
489}
490
491void drd_pre_mutex_lock(const DrdThreadId drd_tid,
492 const Addr mutex,
493 const SizeT size)
494{
495 if (mutex_get(mutex) == 0)
496 {
497 mutex_init(mutex, size);
498 }
499}
500
501void drd_post_mutex_lock(const DrdThreadId drd_tid,
502 const Addr mutex,
503 const SizeT size)
504{
505 mutex_lock(mutex, size);
506}
507
508void drd_pre_mutex_unlock(const DrdThreadId drd_tid, Addr mutex)
509{
510 mutex_unlock(mutex);
511}
512
513void drd_post_cond_init(Addr cond, SizeT s)
514{
515 tl_assert(s == PTHREAD_COND_SIZE);
516 if (cond_get(cond))
517 {
518 CondErrInfo cei = { .cond = cond };
519 VG_(maybe_record_error)(VG_(get_running_tid)(),
520 CondErr,
521 VG_(get_IP)(VG_(get_running_tid)()),
522 "initialized twice",
523 &cei);
524 }
525 cond_init(cond);
526}
527
528void drd_pre_cond_destroy(Addr cond, SizeT s)
529{
530 struct cond_info* cond_p;
531
532 tl_assert(s == PTHREAD_COND_SIZE);
533 cond_p = cond_get(cond);
534 if (cond_p)
535 {
536 cond_destroy(cond_p);
537 }
538 else
539 {
540 CondErrInfo cei = { .cond = cond };
541 VG_(maybe_record_error)(VG_(get_running_tid)(),
542 CondErr,
543 VG_(get_IP)(VG_(get_running_tid)()),
544 "destroy requested but not initialized",
545 &cei);
546 }
547}
548
549
550//
551// Implementation of the tool interface.
552//
553
554static
555void drd_post_clo_init(void)
sewardjdcbb8d32007-11-26 21:34:30 +0000556{
557# if defined(VGP_x86_linux) || defined(VGP_amd64_linux)
558 /* fine */
559# else
560 VG_(printf)("\nDRD currently only works on x86-linux and amd64-linux.\n");
561 VG_(printf)("At the very least you need to set PTHREAD_{MUTEX,COND}_SIZE\n");
562 VG_(printf)("in pthread_object_size.h to correct values. Sorry.\n\n");
563 VG_(exit)(0);
564# endif
565}
sewardjaf44c822007-11-25 14:01:38 +0000566
567static
568IRSB* drd_instrument(VgCallbackClosure* const closure,
569 IRSB* const bb_in,
570 VexGuestLayout* const layout,
571 VexGuestExtents* const vge,
572 IRType const gWordTy,
573 IRType const hWordTy)
574{
575 IRDirty* di;
576 Int i;
577 IRSB* bb;
578 IRExpr** argv;
579 IRExpr* addr_expr;
580 IRExpr* size_expr;
581 Bool instrument = True;
582
583 /* Set up BB */
584 bb = emptyIRSB();
585 bb->tyenv = deepCopyIRTypeEnv(bb_in->tyenv);
586 bb->next = deepCopyIRExpr(bb_in->next);
587 bb->jumpkind = bb_in->jumpkind;
588
589 for (i = 0; i < bb_in->stmts_used; i++)
590 {
591 IRStmt* const st = bb_in->stmts[i];
592 if (!st || st->tag == Ist_NoOp)
593 continue;
594
595 switch (st->tag)
596 {
597 case Ist_IMark:
598 instrument = VG_(seginfo_sect_kind)(st->Ist.IMark.addr) != Vg_SectPLT;
599 break;
600
601 case Ist_AbiHint:
602 addStmtToIRSB(bb,
603 IRStmt_Dirty(
604 unsafeIRDirty_0_N(
605 /*regparms*/2,
606 "drd_make_stack_uninit",
607 VG_(fnptr_to_fnentry)(drd_make_stack_uninit),
608 mkIRExprVec_2(st->Ist.AbiHint.base,
609 mkIRExpr_HWord((UInt)st->Ist.AbiHint.len))
610 )
611 )
612 );
613 break;
614
615 case Ist_Store:
616 if (instrument)
617 {
618 addr_expr = st->Ist.Store.addr;
619 size_expr = mkIRExpr_HWord(
620 sizeofIRType(typeOfIRExpr(bb->tyenv, st->Ist.Store.data)));
621 argv = mkIRExprVec_2(addr_expr, size_expr);
622 di = unsafeIRDirty_0_N(/*regparms*/2,
623 "drd_trace_store",
624 VG_(fnptr_to_fnentry)(drd_trace_store),
625 argv);
626 addStmtToIRSB(bb, IRStmt_Dirty(di));
627 }
628 addStmtToIRSB(bb, st);
629 break;
630
631 case Ist_WrTmp:
632 if (instrument)
633 {
634 const IRExpr* const data = st->Ist.WrTmp.data;
635 if (data->tag == Iex_Load)
636 {
637 addr_expr = data->Iex.Load.addr;
638 size_expr = mkIRExpr_HWord(sizeofIRType(data->Iex.Load.ty));
639 argv = mkIRExprVec_2(addr_expr, size_expr);
640 di = unsafeIRDirty_0_N(/*regparms*/2,
641 "drd_trace_load",
642 VG_(fnptr_to_fnentry)(drd_trace_load),
643 argv);
644 addStmtToIRSB(bb, IRStmt_Dirty(di));
645 }
646 }
647 addStmtToIRSB(bb, st);
648 break;
649
650 case Ist_Dirty:
651 if (instrument)
652 {
653 IRDirty* d = st->Ist.Dirty.details;
654 IREffect const mFx = d->mFx;
655 switch (mFx) {
656 case Ifx_None:
657 break;
658 case Ifx_Read:
659 case Ifx_Write:
660 case Ifx_Modify:
661 tl_assert(d->mAddr);
662 tl_assert(d->mSize > 0);
663 argv = mkIRExprVec_2(d->mAddr, mkIRExpr_HWord(d->mSize));
664 if (mFx == Ifx_Read || mFx == Ifx_Modify) {
665 di = unsafeIRDirty_0_N(
666 /*regparms*/2,
667 "drd_trace_load",
668 VG_(fnptr_to_fnentry)(drd_trace_load),
669 argv);
670 addStmtToIRSB(bb, IRStmt_Dirty(di));
671 }
672 if (mFx == Ifx_Write || mFx == Ifx_Modify) {
673 di = unsafeIRDirty_0_N(
674 /*regparms*/2,
675 "drd_trace_store",
676 VG_(fnptr_to_fnentry)(drd_trace_store),
677 argv);
678 addStmtToIRSB(bb, IRStmt_Dirty(di));
679 }
680 break;
681 default:
682 tl_assert(0);
683 }
684 }
685 addStmtToIRSB(bb, st);
686 break;
687
688 default:
689 addStmtToIRSB(bb, st);
690 break;
691 }
692 }
693
694 return bb;
695}
696
697static void drd_set_running_tid(const ThreadId tid)
698{
699 static ThreadId s_last_tid = VG_INVALID_THREADID;
700 if (tid != s_last_tid)
701 {
702 const DrdThreadId drd_tid = VgThreadIdToDrdThreadId(tid);
703 tl_assert(drd_tid != DRD_INVALID_THREADID);
704 s_last_tid = tid;
705 if (drd_trace_fork_join)
706 {
707 VG_(message)(Vg_DebugMsg,
708 "drd_track_thread_run tid = %d / drd tid %d",
709 tid, drd_tid);
710 }
711 thread_set_running_tid(drd_tid);
712 }
713}
714
715static void drd_start_client_code(const ThreadId tid, const ULong bbs_done)
716{
717 drd_set_running_tid(tid);
718}
719
720static
721void drd_fini(Int exitcode)
722{
723 // thread_print_all();
724#ifdef OLD_RACE_DETECTION_ALGORITHM
725 thread_report_all_races();
726#endif
727 if (VG_(clo_verbosity) > 1 || drd_print_stats)
728 {
729 VG_(message)(Vg_DebugMsg,
730 " thread: %lld context switches"
731 " / %lld updates of the danger set",
732 thread_get_context_switch_count(),
733 thread_get_update_danger_set_count());
734#ifdef OLD_RACE_DETECTION_ALGORITHM
735 VG_(message)(Vg_DebugMsg,
736 " analysis: %lld data race analysis points",
737 thread_get_report_races_count());
738#endif
739 VG_(message)(Vg_DebugMsg,
740 " segments: %lld total, %lld max, %lld discard points",
741 sg_get_segments_created_count(),
742 sg_get_max_segments_alive_count(),
743 thread_get_discard_ordered_segments_count());
744 VG_(message)(Vg_DebugMsg,
745 " bitmaps: %lld / %lld bitmaps were allocated"
746 " and %lld / %lld for danger set updates",
747 bm_get_bitmap_creation_count(),
748 bm_get_bitmap2_creation_count(),
749 thread_get_danger_set_bitmap_creation_count(),
750 thread_get_danger_set_bitmap2_creation_count());
751 VG_(message)(Vg_DebugMsg,
752 " mutex: %lld non-recursive lock/unlock events",
753 get_mutex_lock_count());
754 drd_print_malloc_stats();
755 }
756}
757
758static void drd_load_suppression_file(void)
759{
760 tl_assert(VG_(clo_n_suppressions) < VG_CLO_MAX_SFILES - 1);
761 {
762 /* If we haven't reached the max number of suppression files, load
763 the drd suppression patterns file. */
764 static const Char drd_supp[] = "glibc-2.X-drd.supp";
765 const Int len = VG_(strlen)(VG_(libdir)) + 1 + sizeof(drd_supp);
766 Char* const buf = VG_(arena_malloc)(VG_AR_CORE, len);
767 VG_(sprintf)(buf, "%s/%s", VG_(libdir), drd_supp);
768 VG_(clo_suppressions)[VG_(clo_n_suppressions)] = buf;
769 VG_(clo_n_suppressions)++;
770 }
771}
772
773static
774void drd_pre_clo_init(void)
775{
776 // Basic tool stuff.
777
778 VG_(details_name) ("exp-drd");
779 VG_(details_version) (NULL);
780 VG_(details_description) ("a data race detector");
781 VG_(details_copyright_author)("Copyright (C) 2006-2007, and GNU GPL'd,"
782 " by Bart Van Assche.");
783 VG_(details_bug_reports_to) (VG_BUGS_TO);
784
785 VG_(basic_tool_funcs) (drd_post_clo_init,
786 drd_instrument,
787 drd_fini);
788
789 // Command line stuff.
790 VG_(needs_command_line_options)(drd_process_cmd_line_option,
791 drd_print_usage,
792 drd_print_debug_usage);
793
794 drd_register_error_handlers();
795
796 // Core event tracking.
797 VG_(track_pre_mem_read) (drd_pre_mem_read);
798 VG_(track_post_mem_write) (drd_post_mem_write);
799 VG_(track_new_mem_stack) (drd_start_using_mem_stack);
800 VG_(track_die_mem_stack) (drd_stop_using_mem_stack);
801 VG_(track_new_mem_mmap) (drd_start_using_mem_mmap);
802 VG_(track_die_mem_munmap) (drd_stop_using_mem_munmap);
803 VG_(track_start_client_code) (drd_start_client_code);
804 VG_(track_pre_thread_ll_create) (drd_pre_thread_create);
805 VG_(track_pre_thread_first_insn)(drd_post_thread_create);
806 VG_(track_pre_thread_ll_exit) (drd_thread_finished);
807
808 // Other stuff.
809 VG_(needs_data_syms)();
810
811 drd_register_malloc_wrappers(drd_start_using_mem, drd_stop_using_mem);
812
813 drd_clientreq_init();
814
815 drd_suppression_init();
816
817 drd_load_suppression_file();
818}
819
820
821VG_DETERMINE_INTERFACE_VERSION(drd_pre_clo_init)
822
823
824/*
825 * Local variables:
826 * c-basic-offset: 3
827 * End:
828 */