blob: 07a9d5f88364e26cb701d555a9423934bd45e4a9 [file] [log] [blame]
sewardjaf44c822007-11-25 14:01:38 +00001/*
2 This file is part of drd, a data race detector.
3
sewardj85642922008-01-14 11:54:56 +00004 Copyright (C) 2006-2008 Bart Van Assche
sewardjaf44c822007-11-25 14:01:38 +00005 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
sewardj85642922008-01-14 11:54:56 +000026#include "drd_barrier.h"
sewardjaf44c822007-11-25 14:01:38 +000027#include "drd_clientreq.h"
bart4bb53d82008-02-28 19:06:34 +000028#include "drd_clientobj.h"
sewardjaf44c822007-11-25 14:01:38 +000029#include "drd_cond.h"
30#include "drd_error.h"
31#include "drd_malloc_wrappers.h"
32#include "drd_mutex.h"
33#include "drd_segment.h"
sewardj85642922008-01-14 11:54:56 +000034#include "drd_semaphore.h"
sewardjaf44c822007-11-25 14:01:38 +000035#include "drd_suppression.h"
36#include "drd_thread.h"
37#include "drd_track.h"
38#include "drd_vc.h"
sewardj721ad7b2007-11-30 08:30:29 +000039#include "priv_drd_clientreq.h"
sewardj85642922008-01-14 11:54:56 +000040#include "pub_drd_bitmap.h"
sewardjaf44c822007-11-25 14:01:38 +000041#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)
sewardj85642922008-01-14 11:54:56 +000046#include "pub_tool_vki.h" // Must be included before pub_tool_libcproc
sewardjaf44c822007-11-25 14:01:38 +000047#include "pub_tool_libcproc.h"
48#include "pub_tool_machine.h"
49#include "pub_tool_options.h" // command line options
50#include "pub_tool_threadstate.h" // VG_(get_running_tid)
51#include "pub_tool_tooliface.h"
52
53
sewardjaf44c822007-11-25 14:01:38 +000054// Function declarations.
55
barteb8b8c82008-02-26 19:11:20 +000056static void instrument_memory_bus_event(IRSB* const bb,
57 const IRMBusEvent event);
sewardjaf44c822007-11-25 14:01:38 +000058static void drd_start_client_code(const ThreadId tid, const ULong bbs_done);
59static void drd_set_running_tid(const ThreadId tid);
barteb8b8c82008-02-26 19:11:20 +000060static void evh__bus_lock(void);
61static void evh__bus_unlock(void);
sewardjaf44c822007-11-25 14:01:38 +000062
63
64
65// Local variables.
66
67static Bool drd_print_stats = False;
sewardjaf44c822007-11-25 14:01:38 +000068static Bool drd_trace_fork_join = False;
sewardj85642922008-01-14 11:54:56 +000069static Bool drd_trace_mem = False;
sewardjaf44c822007-11-25 14:01:38 +000070static Addr drd_trace_address = 0;
sewardjaf44c822007-11-25 14:01:38 +000071
72
73//
74// Implement the needs_command_line_options for drd.
75//
76
77static Bool drd_process_cmd_line_option(Char* arg)
78{
sewardj85642922008-01-14 11:54:56 +000079 Bool trace_barrier = False;
sewardjaf44c822007-11-25 14:01:38 +000080 Bool trace_cond = False;
bartecbf1662008-02-24 18:46:05 +000081 Bool trace_csw = False;
82 Bool trace_danger_set = False;
sewardjaf44c822007-11-25 14:01:38 +000083 Bool trace_mutex = False;
84 Bool trace_segment = False;
85 Bool trace_suppression = False;
86 Char* trace_address = 0;
87
88 VG_BOOL_CLO (arg, "--drd-stats", drd_print_stats)
sewardj85642922008-01-14 11:54:56 +000089 else VG_BOOL_CLO(arg, "--trace-barrier", trace_barrier)
sewardjaf44c822007-11-25 14:01:38 +000090 else VG_BOOL_CLO(arg, "--trace-cond", trace_cond)
bartecbf1662008-02-24 18:46:05 +000091 else VG_BOOL_CLO(arg, "--trace-csw", trace_csw)
92 else VG_BOOL_CLO(arg, "--trace-danger-set", trace_danger_set)
sewardjaf44c822007-11-25 14:01:38 +000093 else VG_BOOL_CLO(arg, "--trace-fork-join", drd_trace_fork_join)
94 else VG_BOOL_CLO(arg, "--trace-mem", drd_trace_mem)
95 else VG_BOOL_CLO(arg, "--trace-mutex", trace_mutex)
96 else VG_BOOL_CLO(arg, "--trace-segment", trace_segment)
97 else VG_BOOL_CLO(arg, "--trace-suppression", trace_suppression)
98 else VG_STR_CLO (arg, "--trace-address", trace_address)
99 else
100 return False;
101
102 if (trace_address)
sewardjc0be9252008-02-11 11:00:51 +0000103 {
sewardjaf44c822007-11-25 14:01:38 +0000104 drd_trace_address = VG_(strtoll16)(trace_address, 0);
sewardjc0be9252008-02-11 11:00:51 +0000105 }
sewardj85642922008-01-14 11:54:56 +0000106 if (trace_barrier)
107 barrier_set_trace(trace_barrier);
sewardjaf44c822007-11-25 14:01:38 +0000108 if (trace_cond)
109 cond_set_trace(trace_cond);
bartecbf1662008-02-24 18:46:05 +0000110 if (trace_csw)
111 thread_trace_context_switches(trace_csw);
112 if (trace_danger_set)
113 thread_trace_danger_set(trace_danger_set);
sewardjaf44c822007-11-25 14:01:38 +0000114 if (trace_mutex)
115 mutex_set_trace(trace_mutex);
116 if (trace_segment)
117 sg_set_trace(trace_segment);
118 if (trace_suppression)
119 suppression_set_trace(trace_suppression);
120
121 return True;
122}
123
124static void drd_print_usage(void)
125{
126 VG_(printf)(" --trace-mem=no|yes Trace all memory accesses to stdout[no]"
127 "\n"
128 " --trace-fork-join=no|yes Trace all thread creation and join"
129 " activity\n"
130 " --trace-mutex=no|yes Trace all mutex activity\n"
131 " --trace-segment=no|yes Trace segment actions\n"
132 );
133}
134
135static void drd_print_debug_usage(void)
136{
137}
138
139
140//
141// Implements the thread-related core callbacks.
142//
143
144static
145VG_REGPARM(2) void drd_trace_load(Addr addr, SizeT size)
146{
147 Segment* sg;
148
sewardj8b09d4f2007-12-04 21:27:18 +0000149 thread_set_vg_running_tid(VG_(get_running_tid)());
150
sewardjaf44c822007-11-25 14:01:38 +0000151 if (! thread_is_recording(thread_get_running_tid()))
152 return;
153
154#if 1
155 if (drd_trace_mem || (addr == drd_trace_address))
156 {
157 VG_(message)(Vg_UserMsg, "load 0x%lx size %ld %s (vg %d / drd %d)",
158 addr,
159 size,
160 thread_get_name(thread_get_running_tid()),
161 VG_(get_running_tid)(),
162 thread_get_running_tid());
sewardj85642922008-01-14 11:54:56 +0000163 VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(),
164 VG_(clo_backtrace_size));
sewardjaf44c822007-11-25 14:01:38 +0000165 tl_assert(DrdThreadIdToVgThreadId(thread_get_running_tid())
166 == VG_(get_running_tid)());
167 }
168#endif
169 sg = thread_get_segment(thread_get_running_tid());
170 bm_access_range(sg->bm, addr, size, eLoad);
171 if (thread_conflicting_access(addr, size, eLoad))
172 {
173 DataRaceErrInfo drei;
174 drei.tid = VG_(get_running_tid)();
175 drei.addr = addr;
176 drei.size = size;
177 drei.access_type = eLoad;
178 VG_(maybe_record_error)(VG_(get_running_tid)(),
179 DataRaceErr,
180 VG_(get_IP)(VG_(get_running_tid)()),
181 "Conflicting accesses",
182 &drei);
183 }
184}
185
186static
187VG_REGPARM(2) void drd_trace_store(Addr addr, SizeT size)
188{
189 Segment* sg;
190
sewardj8b09d4f2007-12-04 21:27:18 +0000191 thread_set_vg_running_tid(VG_(get_running_tid)());
192
sewardjaf44c822007-11-25 14:01:38 +0000193 if (! thread_is_recording(thread_get_running_tid()))
194 return;
195
196#if 1
197 if (drd_trace_mem || (addr == drd_trace_address))
198 {
199 VG_(message)(Vg_UserMsg, "store 0x%lx size %ld %s (vg %d / drd %d / off %d)",
200 addr,
201 size,
202 thread_get_name(thread_get_running_tid()),
203 VG_(get_running_tid)(),
204 thread_get_running_tid(),
205 addr - thread_get_stack_min(thread_get_running_tid()));
sewardj85642922008-01-14 11:54:56 +0000206 VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(),
207 VG_(clo_backtrace_size));
sewardjaf44c822007-11-25 14:01:38 +0000208 tl_assert(DrdThreadIdToVgThreadId(thread_get_running_tid())
209 == VG_(get_running_tid)());
210 }
211#endif
212 sg = thread_get_segment(thread_get_running_tid());
213 bm_access_range(sg->bm, addr, size, eStore);
214 if (thread_conflicting_access(addr, size, eStore))
215 {
216 DataRaceErrInfo drei;
217 drei.tid = VG_(get_running_tid)();
218 drei.addr = addr;
219 drei.size = size;
220 drei.access_type = eStore;
221 VG_(maybe_record_error)(VG_(get_running_tid)(),
222 DataRaceErr,
223 VG_(get_IP)(VG_(get_running_tid)()),
224 "Conflicting accesses",
225 &drei);
226 }
227}
228
229static void drd_pre_mem_read(const CorePart part,
230 const ThreadId tid,
231 Char* const s,
232 const Addr a,
233 const SizeT size)
234{
sewardj8b09d4f2007-12-04 21:27:18 +0000235 if (size > 0)
sewardjaf44c822007-11-25 14:01:38 +0000236 {
237 drd_trace_load(a, size);
238 }
239}
240
241static void drd_post_mem_write(const CorePart part,
242 const ThreadId tid,
243 const Addr a,
244 const SizeT size)
245{
sewardj8b09d4f2007-12-04 21:27:18 +0000246 if (size > 0)
sewardjaf44c822007-11-25 14:01:38 +0000247 {
248 drd_trace_store(a, size);
249 }
250}
251
252static void drd_start_using_mem(const Addr a1, const Addr a2)
253{
sewardj8b09d4f2007-12-04 21:27:18 +0000254 thread_set_vg_running_tid(VG_(get_running_tid)());
255
sewardjaf44c822007-11-25 14:01:38 +0000256 if (a1 <= drd_trace_address && drd_trace_address < a2
257 && thread_is_recording(thread_get_running_tid()))
258 {
259 VG_(message)(Vg_UserMsg, "start 0x%lx size %ld %s (tracing 0x%lx)",
260 a1, a2 - a1, thread_get_name(thread_get_running_tid()),
261 drd_trace_address);
sewardj85642922008-01-14 11:54:56 +0000262 VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(),
263 VG_(clo_backtrace_size));
sewardjaf44c822007-11-25 14:01:38 +0000264 }
265}
266
267static void drd_stop_using_mem(const Addr a1, const Addr a2)
268{
269 if (a1 <= drd_trace_address && drd_trace_address < a2
270 && thread_is_recording(thread_get_running_tid()))
271 {
272 VG_(message)(Vg_UserMsg, "end 0x%lx size %ld %s (tracing 0x%lx)",
273 a1, a2 - a1, thread_get_name(thread_get_running_tid()),
274 drd_trace_address);
sewardj85642922008-01-14 11:54:56 +0000275 VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(),
276 VG_(clo_backtrace_size));
sewardjaf44c822007-11-25 14:01:38 +0000277 }
278 thread_stop_using_mem(a1, a2);
bart4bb53d82008-02-28 19:06:34 +0000279 drd_clientobj_stop_using_mem(a1, a2);
sewardjaf44c822007-11-25 14:01:38 +0000280 cond_stop_using_mem(a1, a2);
sewardj85642922008-01-14 11:54:56 +0000281 semaphore_stop_using_mem(a1, a2);
282 barrier_stop_using_mem(a1, a2);
sewardjaf44c822007-11-25 14:01:38 +0000283 drd_suppression_stop_using_mem(a1, a2);
284}
285
286static VG_REGPARM(2)
287 void drd_make_stack_uninit(const Addr base, const UWord len)
288{
289#if 0
290 VG_(message)(Vg_DebugMsg, "make_stack_uninit(0x%lx, %ld)", base, len);
291#endif
292 drd_stop_using_mem(base, base + len);
293}
294
295/* Called by the core when the stack of a thread grows, to indicate that */
296/* the addresses in range [ a, a + len [ may now be used by the client. */
297/* Assumption: stacks grow downward. */
298static void drd_start_using_mem_stack(const Addr a, const SizeT len)
299{
300 thread_set_stack_min(thread_get_running_tid(), a - VG_STACK_REDZONE_SZB);
301 drd_start_using_mem(a - VG_STACK_REDZONE_SZB,
302 a - VG_STACK_REDZONE_SZB + len);
303}
304
305/* Called by the core when the stack of a thread shrinks, to indicate that */
306/* the addresses [ a, a + len [ are no longer accessible for the client. */
307/* Assumption: stacks grow downward. */
308static void drd_stop_using_mem_stack(const Addr a, const SizeT len)
309{
sewardj8b09d4f2007-12-04 21:27:18 +0000310 thread_set_vg_running_tid(VG_(get_running_tid)());
sewardjaf44c822007-11-25 14:01:38 +0000311 thread_set_stack_min(thread_get_running_tid(),
312 a + len - VG_STACK_REDZONE_SZB);
313 drd_stop_using_mem(a - VG_STACK_REDZONE_SZB,
314 a + len - VG_STACK_REDZONE_SZB);
315}
316
317static void drd_start_using_mem_mmap(Addr a, SizeT len,
318 Bool rr, Bool ww, Bool xx)
319{
320 drd_start_using_mem(a, a + len);
321}
322
323static void drd_stop_using_mem_munmap(Addr a, SizeT len)
324{
325 drd_stop_using_mem(a, a + len);
326}
327
328static
329void drd_pre_thread_create(const ThreadId creator, const ThreadId created)
330{
331 const DrdThreadId drd_creator = VgThreadIdToDrdThreadId(creator);
332 tl_assert(created != VG_INVALID_THREADID);
333 thread_pre_create(drd_creator, created);
sewardjaf44c822007-11-25 14:01:38 +0000334 if (IsValidDrdThreadId(drd_creator))
335 {
336 thread_new_segment(drd_creator);
337 }
338 if (drd_trace_fork_join)
339 {
340 VG_(message)(Vg_DebugMsg,
341 "drd_pre_thread_create creator = %d/%d, created = %d",
342 creator, drd_creator, created);
343 }
344}
345
346/* Called by Valgrind's core before any loads or stores are performed on */
347/* the context of thread "created". At startup, this function is called */
348/* with arguments (0,1). */
349static
350void drd_post_thread_create(const ThreadId created)
351{
352 const DrdThreadId drd_created = thread_post_create(created);
353 tl_assert(created != VG_INVALID_THREADID);
354 if (drd_trace_fork_join)
355 {
356 VG_(message)(Vg_DebugMsg,
357 "drd_post_thread_create created = %d/%d",
358 created, drd_created);
359 }
360}
361
362/* Process VG_USERREQ__POST_THREAD_JOIN. This client request is invoked just */
363/* after thread drd_joiner joined thread drd_joinee. */
364void drd_post_thread_join(DrdThreadId drd_joiner, DrdThreadId drd_joinee)
365{
366 tl_assert(IsValidDrdThreadId(drd_joiner));
367 tl_assert(IsValidDrdThreadId(drd_joinee));
368 thread_new_segment(drd_joinee);
369 thread_combine_vc(drd_joiner, drd_joinee);
370 thread_new_segment(drd_joiner);
371
372 if (drd_trace_fork_join)
373 {
374 char msg[256];
375 const ThreadId joiner = DrdThreadIdToVgThreadId(drd_joiner);
376 const ThreadId joinee = DrdThreadIdToVgThreadId(drd_joinee);
377 VG_(snprintf)(msg, sizeof(msg),
378 "drd_post_thread_join joiner = %d/%d, joinee = %d/%d",
379 joiner, drd_joiner, joinee, drd_joinee);
380 if (joiner)
381 {
382 VG_(snprintf)(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
383 ", new vc: ");
384 vc_snprint(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
385 thread_get_vc(drd_joiner));
386 }
387 VG_(message)(Vg_DebugMsg, msg);
388 }
389
390 thread_delete(drd_joinee);
391 mutex_thread_delete(drd_joinee);
sewardj85642922008-01-14 11:54:56 +0000392 cond_thread_delete(drd_joinee);
393 semaphore_thread_delete(drd_joinee);
394 barrier_thread_delete(drd_joinee);
sewardjaf44c822007-11-25 14:01:38 +0000395}
396
397/* Called after a thread has performed its last memory access. */
398static void drd_thread_finished(ThreadId tid)
399{
sewardj85642922008-01-14 11:54:56 +0000400 DrdThreadId drd_tid;
401
402 drd_set_running_tid(tid);
403
404 drd_tid = VgThreadIdToDrdThreadId(tid);
sewardjaf44c822007-11-25 14:01:38 +0000405 if (drd_trace_fork_join)
406 {
407 VG_(message)(Vg_DebugMsg,
408 "drd_thread_finished tid = %d/%d%s",
409 tid,
410 drd_tid,
411 thread_get_joinable(drd_tid)
412 ? ""
413 : " (which is a detached thread)");
414
415 }
416 thread_finished(drd_tid);
417}
418
sewardj347eeba2008-01-21 14:19:07 +0000419void drd_pre_mutex_init(const Addr mutex, const SizeT size,
420 const MutexT mutex_type)
sewardjaf44c822007-11-25 14:01:38 +0000421{
sewardj721ad7b2007-11-30 08:30:29 +0000422 mutex_init(mutex, size, mutex_type);
sewardjaf44c822007-11-25 14:01:38 +0000423}
424
sewardj347eeba2008-01-21 14:19:07 +0000425void drd_post_mutex_destroy(const Addr mutex, const MutexT mutex_type)
sewardjaf44c822007-11-25 14:01:38 +0000426{
sewardj347eeba2008-01-21 14:19:07 +0000427 mutex_post_destroy(mutex);
sewardjaf44c822007-11-25 14:01:38 +0000428}
429
430void drd_pre_mutex_lock(const DrdThreadId drd_tid,
431 const Addr mutex,
sewardj721ad7b2007-11-30 08:30:29 +0000432 const SizeT size,
433 const MutexT mutex_type)
sewardjaf44c822007-11-25 14:01:38 +0000434{
bart8bba1f72008-02-27 16:13:05 +0000435 mutex_pre_lock(mutex, size, mutex_type);
sewardjaf44c822007-11-25 14:01:38 +0000436}
437
438void drd_post_mutex_lock(const DrdThreadId drd_tid,
439 const Addr mutex,
sewardj721ad7b2007-11-30 08:30:29 +0000440 const SizeT size,
441 const MutexT mutex_type)
sewardjaf44c822007-11-25 14:01:38 +0000442{
bart8bba1f72008-02-27 16:13:05 +0000443 mutex_post_lock(mutex, size, mutex_type);
sewardjaf44c822007-11-25 14:01:38 +0000444}
445
sewardj721ad7b2007-11-30 08:30:29 +0000446void drd_pre_mutex_unlock(const DrdThreadId drd_tid,
447 const Addr mutex,
448 const MutexT mutex_type)
sewardjaf44c822007-11-25 14:01:38 +0000449{
sewardj721ad7b2007-11-30 08:30:29 +0000450 mutex_unlock(mutex, mutex_type);
sewardjaf44c822007-11-25 14:01:38 +0000451}
452
453void drd_post_cond_init(Addr cond, SizeT s)
454{
sewardjaf44c822007-11-25 14:01:38 +0000455 if (cond_get(cond))
456 {
457 CondErrInfo cei = { .cond = cond };
458 VG_(maybe_record_error)(VG_(get_running_tid)(),
459 CondErr,
460 VG_(get_IP)(VG_(get_running_tid)()),
461 "initialized twice",
462 &cei);
463 }
sewardj721ad7b2007-11-30 08:30:29 +0000464 cond_init(cond, s);
sewardjaf44c822007-11-25 14:01:38 +0000465}
466
sewardj721ad7b2007-11-30 08:30:29 +0000467void drd_pre_cond_destroy(Addr cond)
sewardjaf44c822007-11-25 14:01:38 +0000468{
469 struct cond_info* cond_p;
470
sewardjaf44c822007-11-25 14:01:38 +0000471 cond_p = cond_get(cond);
472 if (cond_p)
473 {
474 cond_destroy(cond_p);
475 }
476 else
477 {
478 CondErrInfo cei = { .cond = cond };
479 VG_(maybe_record_error)(VG_(get_running_tid)(),
480 CondErr,
481 VG_(get_IP)(VG_(get_running_tid)()),
482 "destroy requested but not initialized",
483 &cei);
484 }
485}
486
sewardj85642922008-01-14 11:54:56 +0000487void drd_semaphore_init(const Addr semaphore, const SizeT size,
488 const Word pshared, const Word value)
489{
490 semaphore_init(semaphore, size, pshared, value);
491}
492
493void drd_semaphore_destroy(const Addr semaphore)
494{
495 struct semaphore_info* p;
496
497 p = semaphore_get(semaphore);
498 tl_assert(p);
499 if (p)
500 {
501 semaphore_destroy(p);
502 }
503}
504
505void drd_semaphore_post_wait(const DrdThreadId tid, const Addr semaphore,
506 const SizeT size)
507{
508 semaphore_post_wait(tid, semaphore, size);
509}
510
511void drd_semaphore_pre_post(const DrdThreadId tid, const Addr semaphore,
512 const SizeT size)
513{
514 semaphore_pre_post(tid, semaphore, size);
515}
516
517void drd_semaphore_post_post(const DrdThreadId tid, const Addr semaphore,
sewardje3b57aa2008-01-18 07:42:01 +0000518 const SizeT size, const Bool waited)
sewardj85642922008-01-14 11:54:56 +0000519{
sewardje3b57aa2008-01-18 07:42:01 +0000520 semaphore_post_post(tid, semaphore, size, waited);
sewardj85642922008-01-14 11:54:56 +0000521}
522
523
524void drd_barrier_init(const Addr barrier, const SizeT size, const Word count)
525{
526 barrier_init(barrier, size, count);
527}
528
529void drd_barrier_destroy(const Addr barrier)
530{
531 struct barrier_info* p;
532
533 p = barrier_get(barrier);
534 if (p)
535 {
536 barrier_destroy(p);
537 }
538}
539
540void drd_barrier_pre_wait(const DrdThreadId tid, const Addr barrier)
541{
542 barrier_pre_wait(tid, barrier);
543}
544
545void drd_barrier_post_wait(const DrdThreadId tid, const Addr barrier,
546 const Bool waited)
547{
548 barrier_post_wait(tid, barrier, waited);
549}
550
sewardjaf44c822007-11-25 14:01:38 +0000551
552//
553// Implementation of the tool interface.
554//
555
556static
557void drd_post_clo_init(void)
sewardjdcbb8d32007-11-26 21:34:30 +0000558{
559# if defined(VGP_x86_linux) || defined(VGP_amd64_linux)
560 /* fine */
561# else
sewardj8b09d4f2007-12-04 21:27:18 +0000562 VG_(printf)("\nWARNING: DRD has only been tested on x86-linux and amd64-linux.\n\n");
sewardjdcbb8d32007-11-26 21:34:30 +0000563# endif
564}
sewardjaf44c822007-11-25 14:01:38 +0000565
566static
567IRSB* drd_instrument(VgCallbackClosure* const closure,
sewardj347eeba2008-01-21 14:19:07 +0000568 IRSB* const bb_in,
569 VexGuestLayout* const layout,
570 VexGuestExtents* const vge,
571 IRType const gWordTy,
572 IRType const hWordTy)
sewardjaf44c822007-11-25 14:01:38 +0000573{
574 IRDirty* di;
575 Int i;
576 IRSB* bb;
577 IRExpr** argv;
578 IRExpr* addr_expr;
579 IRExpr* size_expr;
580 Bool instrument = True;
581
582 /* Set up BB */
583 bb = emptyIRSB();
584 bb->tyenv = deepCopyIRTypeEnv(bb_in->tyenv);
585 bb->next = deepCopyIRExpr(bb_in->next);
586 bb->jumpkind = bb_in->jumpkind;
587
588 for (i = 0; i < bb_in->stmts_used; i++)
589 {
590 IRStmt* const st = bb_in->stmts[i];
barteb8b8c82008-02-26 19:11:20 +0000591 tl_assert(st);
592 if (st->tag == Ist_NoOp)
sewardjaf44c822007-11-25 14:01:38 +0000593 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
barteb8b8c82008-02-26 19:11:20 +0000615 case Ist_MBE:
616 instrument_memory_bus_event(bb, st->Ist.MBE.event);
617 addStmtToIRSB(bb, st);
618 break;
619
sewardjaf44c822007-11-25 14:01:38 +0000620 case Ist_Store:
621 if (instrument)
622 {
623 addr_expr = st->Ist.Store.addr;
624 size_expr = mkIRExpr_HWord(
625 sizeofIRType(typeOfIRExpr(bb->tyenv, st->Ist.Store.data)));
626 argv = mkIRExprVec_2(addr_expr, size_expr);
627 di = unsafeIRDirty_0_N(/*regparms*/2,
628 "drd_trace_store",
629 VG_(fnptr_to_fnentry)(drd_trace_store),
630 argv);
631 addStmtToIRSB(bb, IRStmt_Dirty(di));
632 }
633 addStmtToIRSB(bb, st);
634 break;
635
636 case Ist_WrTmp:
637 if (instrument)
638 {
639 const IRExpr* const data = st->Ist.WrTmp.data;
640 if (data->tag == Iex_Load)
641 {
642 addr_expr = data->Iex.Load.addr;
643 size_expr = mkIRExpr_HWord(sizeofIRType(data->Iex.Load.ty));
644 argv = mkIRExprVec_2(addr_expr, size_expr);
645 di = unsafeIRDirty_0_N(/*regparms*/2,
646 "drd_trace_load",
647 VG_(fnptr_to_fnentry)(drd_trace_load),
648 argv);
649 addStmtToIRSB(bb, IRStmt_Dirty(di));
650 }
651 }
652 addStmtToIRSB(bb, st);
653 break;
654
655 case Ist_Dirty:
656 if (instrument)
657 {
658 IRDirty* d = st->Ist.Dirty.details;
659 IREffect const mFx = d->mFx;
660 switch (mFx) {
661 case Ifx_None:
662 break;
663 case Ifx_Read:
664 case Ifx_Write:
665 case Ifx_Modify:
666 tl_assert(d->mAddr);
667 tl_assert(d->mSize > 0);
668 argv = mkIRExprVec_2(d->mAddr, mkIRExpr_HWord(d->mSize));
669 if (mFx == Ifx_Read || mFx == Ifx_Modify) {
670 di = unsafeIRDirty_0_N(
671 /*regparms*/2,
672 "drd_trace_load",
673 VG_(fnptr_to_fnentry)(drd_trace_load),
674 argv);
675 addStmtToIRSB(bb, IRStmt_Dirty(di));
676 }
677 if (mFx == Ifx_Write || mFx == Ifx_Modify) {
678 di = unsafeIRDirty_0_N(
679 /*regparms*/2,
680 "drd_trace_store",
681 VG_(fnptr_to_fnentry)(drd_trace_store),
682 argv);
683 addStmtToIRSB(bb, IRStmt_Dirty(di));
684 }
685 break;
686 default:
687 tl_assert(0);
688 }
689 }
690 addStmtToIRSB(bb, st);
691 break;
692
693 default:
694 addStmtToIRSB(bb, st);
695 break;
696 }
697 }
698
699 return bb;
700}
701
barteb8b8c82008-02-26 19:11:20 +0000702/* Based on the function with the same name in Helgrind's hg_main.c */
703static void instrument_memory_bus_event(IRSB* const bb,
704 const IRMBusEvent const event)
705{
706 switch (event)
707 {
708 case Imbe_Fence:
709 break; /* not interesting */
710 case Imbe_BusLock:
711 addStmtToIRSB(bb,
712 IRStmt_Dirty(unsafeIRDirty_0_N(0/*regparms*/, "evh__bus_lock",
713 VG_(fnptr_to_fnentry)(&evh__bus_lock), mkIRExprVec_0())
714 ));
715 break;
716 case Imbe_BusUnlock:
717 addStmtToIRSB(bb,
718 IRStmt_Dirty(unsafeIRDirty_0_N(0/*regparms*/, "evh__bus_unlock",
719 VG_(fnptr_to_fnentry)(&evh__bus_unlock), mkIRExprVec_0())
720 ));
721 break;
722 default:
723 tl_assert(0);
724 }
725}
726
727/** Locking the memory bus is a way to serialize store operations.
728 * What the lwarx / stwcx instructions do on PowerPC is to detect whether
729 * any other CPU has invalidated the cache line in which the location
730 * specified by lwarx resides has been invalidated at the time the stwcx
731 * instruction is executed.
732 */
733static void evh__bus_lock(void)
734{
735 /* To do: implement this function. */
736}
737
738static void evh__bus_unlock(void)
739{
740 /* To do: implement this function. */
741}
742
sewardj8b09d4f2007-12-04 21:27:18 +0000743static void drd_set_running_tid(const ThreadId vg_tid)
sewardjaf44c822007-11-25 14:01:38 +0000744{
sewardj8b09d4f2007-12-04 21:27:18 +0000745 static ThreadId s_last_vg_tid = VG_INVALID_THREADID;
746 if (vg_tid != s_last_vg_tid)
sewardjaf44c822007-11-25 14:01:38 +0000747 {
sewardj8b09d4f2007-12-04 21:27:18 +0000748 const DrdThreadId drd_tid = VgThreadIdToDrdThreadId(vg_tid);
sewardjaf44c822007-11-25 14:01:38 +0000749 tl_assert(drd_tid != DRD_INVALID_THREADID);
sewardj8b09d4f2007-12-04 21:27:18 +0000750 s_last_vg_tid = vg_tid;
sewardjaf44c822007-11-25 14:01:38 +0000751 if (drd_trace_fork_join)
752 {
753 VG_(message)(Vg_DebugMsg,
754 "drd_track_thread_run tid = %d / drd tid %d",
sewardj8b09d4f2007-12-04 21:27:18 +0000755 vg_tid, drd_tid);
sewardjaf44c822007-11-25 14:01:38 +0000756 }
sewardj8b09d4f2007-12-04 21:27:18 +0000757 thread_set_running_tid(vg_tid, drd_tid);
sewardjaf44c822007-11-25 14:01:38 +0000758 }
759}
760
761static void drd_start_client_code(const ThreadId tid, const ULong bbs_done)
762{
763 drd_set_running_tid(tid);
764}
765
766static
767void drd_fini(Int exitcode)
768{
769 // thread_print_all();
sewardjaf44c822007-11-25 14:01:38 +0000770 if (VG_(clo_verbosity) > 1 || drd_print_stats)
771 {
772 VG_(message)(Vg_DebugMsg,
773 " thread: %lld context switches"
774 " / %lld updates of the danger set",
775 thread_get_context_switch_count(),
776 thread_get_update_danger_set_count());
sewardjaf44c822007-11-25 14:01:38 +0000777 VG_(message)(Vg_DebugMsg,
778 " segments: %lld total, %lld max, %lld discard points",
779 sg_get_segments_created_count(),
780 sg_get_max_segments_alive_count(),
781 thread_get_discard_ordered_segments_count());
782 VG_(message)(Vg_DebugMsg,
783 " bitmaps: %lld / %lld bitmaps were allocated"
784 " and %lld / %lld for danger set updates",
785 bm_get_bitmap_creation_count(),
786 bm_get_bitmap2_creation_count(),
787 thread_get_danger_set_bitmap_creation_count(),
788 thread_get_danger_set_bitmap2_creation_count());
789 VG_(message)(Vg_DebugMsg,
790 " mutex: %lld non-recursive lock/unlock events",
791 get_mutex_lock_count());
792 drd_print_malloc_stats();
793 }
794}
795
sewardjaf44c822007-11-25 14:01:38 +0000796static
797void drd_pre_clo_init(void)
798{
799 // Basic tool stuff.
800
801 VG_(details_name) ("exp-drd");
802 VG_(details_version) (NULL);
803 VG_(details_description) ("a data race detector");
sewardj85642922008-01-14 11:54:56 +0000804 VG_(details_copyright_author)("Copyright (C) 2006-2008, and GNU GPL'd,"
sewardjaf44c822007-11-25 14:01:38 +0000805 " by Bart Van Assche.");
806 VG_(details_bug_reports_to) (VG_BUGS_TO);
807
808 VG_(basic_tool_funcs) (drd_post_clo_init,
809 drd_instrument,
810 drd_fini);
811
812 // Command line stuff.
813 VG_(needs_command_line_options)(drd_process_cmd_line_option,
814 drd_print_usage,
815 drd_print_debug_usage);
816
817 drd_register_error_handlers();
818
819 // Core event tracking.
820 VG_(track_pre_mem_read) (drd_pre_mem_read);
821 VG_(track_post_mem_write) (drd_post_mem_write);
822 VG_(track_new_mem_stack) (drd_start_using_mem_stack);
823 VG_(track_die_mem_stack) (drd_stop_using_mem_stack);
824 VG_(track_new_mem_mmap) (drd_start_using_mem_mmap);
825 VG_(track_die_mem_munmap) (drd_stop_using_mem_munmap);
826 VG_(track_start_client_code) (drd_start_client_code);
827 VG_(track_pre_thread_ll_create) (drd_pre_thread_create);
828 VG_(track_pre_thread_first_insn)(drd_post_thread_create);
829 VG_(track_pre_thread_ll_exit) (drd_thread_finished);
830
831 // Other stuff.
832 VG_(needs_data_syms)();
833
834 drd_register_malloc_wrappers(drd_start_using_mem, drd_stop_using_mem);
835
836 drd_clientreq_init();
837
838 drd_suppression_init();
bart4bb53d82008-02-28 19:06:34 +0000839
840 drd_clientobj_init();
sewardjaf44c822007-11-25 14:01:38 +0000841}
842
843
844VG_DETERMINE_INTERFACE_VERSION(drd_pre_clo_init)
845
846
847/*
848 * Local variables:
849 * c-basic-offset: 3
850 * End:
851 */