• 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_bitmap.h"
26 #include "drd_thread_bitmap.h"
27 #include "drd_vc.h"            /* DRD_(vc_snprint)() */
28 
29 /* Include several source files here in order to allow the compiler to */
30 /* do more inlining.                                                   */
31 #include "drd_bitmap.c"
32 #include "drd_load_store.h"
33 #include "drd_segment.c"
34 #include "drd_thread.c"
35 #include "drd_vc.c"
36 #include "libvex_guest_offsets.h"
37 
38 
39 /* STACK_POINTER_OFFSET: VEX register offset for the stack pointer register. */
40 #if defined(VGA_x86)
41 #define STACK_POINTER_OFFSET OFFSET_x86_ESP
42 #elif defined(VGA_amd64)
43 #define STACK_POINTER_OFFSET OFFSET_amd64_RSP
44 #elif defined(VGA_ppc32)
45 #define STACK_POINTER_OFFSET OFFSET_ppc32_GPR1
46 #elif defined(VGA_ppc64)
47 #define STACK_POINTER_OFFSET OFFSET_ppc64_GPR1
48 #elif defined(VGA_arm)
49 #define STACK_POINTER_OFFSET OFFSET_arm_R13
50 #elif defined(VGA_s390x)
51 #define STACK_POINTER_OFFSET OFFSET_s390x_r15
52 #elif defined(VGA_mips32)
53 #define STACK_POINTER_OFFSET OFFSET_mips32_r29
54 #else
55 #error Unknown architecture.
56 #endif
57 
58 
59 /* Local variables. */
60 
61 static Bool s_check_stack_accesses = False;
62 static Bool s_first_race_only      = False;
63 
64 
65 /* Function definitions. */
66 
DRD_(get_check_stack_accesses)67 Bool DRD_(get_check_stack_accesses)()
68 {
69    return s_check_stack_accesses;
70 }
71 
DRD_(set_check_stack_accesses)72 void DRD_(set_check_stack_accesses)(const Bool c)
73 {
74    tl_assert(c == False || c == True);
75    s_check_stack_accesses = c;
76 }
77 
DRD_(get_first_race_only)78 Bool DRD_(get_first_race_only)()
79 {
80    return s_first_race_only;
81 }
82 
DRD_(set_first_race_only)83 void DRD_(set_first_race_only)(const Bool fro)
84 {
85    tl_assert(fro == False || fro == True);
86    s_first_race_only = fro;
87 }
88 
DRD_(trace_mem_access)89 void DRD_(trace_mem_access)(const Addr addr, const SizeT size,
90                             const BmAccessTypeT access_type,
91                             const HWord stored_value_hi,
92                             const HWord stored_value_lo)
93 {
94    if (DRD_(is_any_traced)(addr, addr + size))
95    {
96       char* vc;
97 
98       vc = DRD_(vc_aprint)(DRD_(thread_get_vc)(DRD_(thread_get_running_tid)()));
99       if (access_type == eStore && size <= sizeof(HWord)) {
100          DRD_(trace_msg_w_bt)("store 0x%lx size %ld val %ld/0x%lx (thread %d /"
101                               " vc %s)", addr, size, stored_value_lo,
102                               stored_value_lo, DRD_(thread_get_running_tid)(),
103                               vc);
104       } else if (access_type == eStore && size > sizeof(HWord)) {
105          ULong sv;
106 
107          tl_assert(sizeof(HWord) == 4);
108          sv = ((ULong)stored_value_hi << 32) | stored_value_lo;
109          DRD_(trace_msg_w_bt)("store 0x%lx size %ld val %lld/0x%llx (thread %d"
110                               " / vc %s)", addr, size, sv, sv,
111                               DRD_(thread_get_running_tid)(), vc);
112       } else {
113          DRD_(trace_msg_w_bt)("%s 0x%lx size %ld (thread %d / vc %s)",
114                               access_type == eLoad ? "load "
115                               : access_type == eStore ? "store"
116                               : access_type == eStart ? "start"
117                               : access_type == eEnd ? "end  " : "????",
118                               addr, size, DRD_(thread_get_running_tid)(), vc);
119       }
120       VG_(free)(vc);
121       tl_assert(DRD_(DrdThreadIdToVgThreadId)(DRD_(thread_get_running_tid)())
122                 == VG_(get_running_tid)());
123    }
124 }
125 
drd_trace_mem_load(const Addr addr,const SizeT size)126 static VG_REGPARM(2) void drd_trace_mem_load(const Addr addr, const SizeT size)
127 {
128    return DRD_(trace_mem_access)(addr, size, eLoad, 0, 0);
129 }
130 
drd_trace_mem_store(const Addr addr,const SizeT size,const HWord stored_value_hi,const HWord stored_value_lo)131 static VG_REGPARM(3) void drd_trace_mem_store(const Addr addr,const SizeT size,
132                                               const HWord stored_value_hi,
133                                               const HWord stored_value_lo)
134 {
135    return DRD_(trace_mem_access)(addr, size, eStore, stored_value_hi,
136                                  stored_value_lo);
137 }
138 
drd_report_race(const Addr addr,const SizeT size,const BmAccessTypeT access_type)139 static void drd_report_race(const Addr addr, const SizeT size,
140                             const BmAccessTypeT access_type)
141 {
142    ThreadId vg_tid;
143 
144    vg_tid = VG_(get_running_tid)();
145    if (!DRD_(get_check_stack_accesses)()
146        && DRD_(thread_address_on_any_stack)(addr)) {
147 #if 0
148       GenericErrInfo GEI = {
149          .tid = DRD_(thread_get_running_tid)(),
150          .addr = addr,
151       };
152       VG_(maybe_record_error)(vg_tid, GenericErr, VG_(get_IP)(vg_tid),
153                               "--check-stack-var=no skips checking stack"
154                               " variables shared over threads",
155                               &GEI);
156 #endif
157   } else {
158       DataRaceErrInfo drei = {
159          .tid  = DRD_(thread_get_running_tid)(),
160          .addr = addr,
161          .size = size,
162          .access_type = access_type,
163       };
164       VG_(maybe_record_error)(vg_tid, DataRaceErr, VG_(get_IP)(vg_tid),
165                               "Conflicting access", &drei);
166 
167       if (s_first_race_only)
168          DRD_(start_suppression)(addr, addr + size, "first race only");
169    }
170 }
171 
DRD_(trace_load)172 VG_REGPARM(2) void DRD_(trace_load)(Addr addr, SizeT size)
173 {
174 #ifdef ENABLE_DRD_CONSISTENCY_CHECKS
175    /* The assert below has been commented out because of performance reasons.*/
176    tl_assert(DRD_(thread_get_running_tid)()
177              == DRD_(VgThreadIdToDrdThreadId)(VG_(get_running_tid())));
178 #endif
179 
180    if (DRD_(running_thread_is_recording_loads)()
181        && (s_check_stack_accesses
182            || ! DRD_(thread_address_on_stack)(addr))
183        && bm_access_load_triggers_conflict(addr, addr + size)
184        && ! DRD_(is_suppressed)(addr, addr + size))
185    {
186       drd_report_race(addr, size, eLoad);
187    }
188 }
189 
drd_trace_load_1(Addr addr)190 static VG_REGPARM(1) void drd_trace_load_1(Addr addr)
191 {
192    if (DRD_(running_thread_is_recording_loads)()
193        && (s_check_stack_accesses
194            || ! DRD_(thread_address_on_stack)(addr))
195        && bm_access_load_1_triggers_conflict(addr)
196        && ! DRD_(is_suppressed)(addr, addr + 1))
197    {
198       drd_report_race(addr, 1, eLoad);
199    }
200 }
201 
drd_trace_load_2(Addr addr)202 static VG_REGPARM(1) void drd_trace_load_2(Addr addr)
203 {
204    if (DRD_(running_thread_is_recording_loads)()
205        && (s_check_stack_accesses
206            || ! DRD_(thread_address_on_stack)(addr))
207        && bm_access_load_2_triggers_conflict(addr)
208        && ! DRD_(is_suppressed)(addr, addr + 2))
209    {
210       drd_report_race(addr, 2, eLoad);
211    }
212 }
213 
drd_trace_load_4(Addr addr)214 static VG_REGPARM(1) void drd_trace_load_4(Addr addr)
215 {
216    if (DRD_(running_thread_is_recording_loads)()
217        && (s_check_stack_accesses
218            || ! DRD_(thread_address_on_stack)(addr))
219        && bm_access_load_4_triggers_conflict(addr)
220        && ! DRD_(is_suppressed)(addr, addr + 4))
221    {
222       drd_report_race(addr, 4, eLoad);
223    }
224 }
225 
drd_trace_load_8(Addr addr)226 static VG_REGPARM(1) void drd_trace_load_8(Addr addr)
227 {
228    if (DRD_(running_thread_is_recording_loads)()
229        && (s_check_stack_accesses
230            || ! DRD_(thread_address_on_stack)(addr))
231        && bm_access_load_8_triggers_conflict(addr)
232        && ! DRD_(is_suppressed)(addr, addr + 8))
233    {
234       drd_report_race(addr, 8, eLoad);
235    }
236 }
237 
DRD_(trace_store)238 VG_REGPARM(2) void DRD_(trace_store)(Addr addr, SizeT size)
239 {
240 #ifdef ENABLE_DRD_CONSISTENCY_CHECKS
241    /* The assert below has been commented out because of performance reasons.*/
242    tl_assert(DRD_(thread_get_running_tid)()
243              == DRD_(VgThreadIdToDrdThreadId)(VG_(get_running_tid())));
244 #endif
245 
246    if (DRD_(running_thread_is_recording_stores)()
247        && (s_check_stack_accesses
248            || ! DRD_(thread_address_on_stack)(addr))
249        && bm_access_store_triggers_conflict(addr, addr + size)
250        && ! DRD_(is_suppressed)(addr, addr + size))
251    {
252       drd_report_race(addr, size, eStore);
253    }
254 }
255 
drd_trace_store_1(Addr addr)256 static VG_REGPARM(1) void drd_trace_store_1(Addr addr)
257 {
258    if (DRD_(running_thread_is_recording_stores)()
259        && (s_check_stack_accesses
260            || ! DRD_(thread_address_on_stack)(addr))
261        && bm_access_store_1_triggers_conflict(addr)
262        && ! DRD_(is_suppressed)(addr, addr + 1))
263    {
264       drd_report_race(addr, 1, eStore);
265    }
266 }
267 
drd_trace_store_2(Addr addr)268 static VG_REGPARM(1) void drd_trace_store_2(Addr addr)
269 {
270    if (DRD_(running_thread_is_recording_stores)()
271        && (s_check_stack_accesses
272            || ! DRD_(thread_address_on_stack)(addr))
273        && bm_access_store_2_triggers_conflict(addr)
274        && ! DRD_(is_suppressed)(addr, addr + 2))
275    {
276       drd_report_race(addr, 2, eStore);
277    }
278 }
279 
drd_trace_store_4(Addr addr)280 static VG_REGPARM(1) void drd_trace_store_4(Addr addr)
281 {
282    if (DRD_(running_thread_is_recording_stores)()
283        && (s_check_stack_accesses
284            || !DRD_(thread_address_on_stack)(addr))
285        && bm_access_store_4_triggers_conflict(addr)
286        && !DRD_(is_suppressed)(addr, addr + 4))
287    {
288       drd_report_race(addr, 4, eStore);
289    }
290 }
291 
drd_trace_store_8(Addr addr)292 static VG_REGPARM(1) void drd_trace_store_8(Addr addr)
293 {
294    if (DRD_(running_thread_is_recording_stores)()
295        && (s_check_stack_accesses
296            || ! DRD_(thread_address_on_stack)(addr))
297        && bm_access_store_8_triggers_conflict(addr)
298        && ! DRD_(is_suppressed)(addr, addr + 8))
299    {
300       drd_report_race(addr, 8, eStore);
301    }
302 }
303 
304 /**
305  * Return true if and only if addr_expr matches the pattern (SP) or
306  * <offset>(SP).
307  */
is_stack_access(IRSB * const bb,IRExpr * const addr_expr)308 static Bool is_stack_access(IRSB* const bb, IRExpr* const addr_expr)
309 {
310    Bool result = False;
311 
312    if (addr_expr->tag == Iex_RdTmp)
313    {
314       int i;
315       for (i = 0; i < bb->stmts_size; i++)
316       {
317          if (bb->stmts[i]
318              && bb->stmts[i]->tag == Ist_WrTmp
319              && bb->stmts[i]->Ist.WrTmp.tmp == addr_expr->Iex.RdTmp.tmp)
320          {
321             IRExpr* e = bb->stmts[i]->Ist.WrTmp.data;
322             if (e->tag == Iex_Get && e->Iex.Get.offset == STACK_POINTER_OFFSET)
323             {
324                result = True;
325             }
326 
327             //ppIRExpr(e);
328             //VG_(printf)(" (%s)\n", result ? "True" : "False");
329             break;
330          }
331       }
332    }
333    return result;
334 }
335 
336 static const IROp u_widen_irop[5][9] = {
337    [Ity_I1  - Ity_I1] = { [4] = Iop_1Uto32,  [8] = Iop_1Uto64 },
338    [Ity_I8  - Ity_I1] = { [4] = Iop_8Uto32,  [8] = Iop_8Uto64 },
339    [Ity_I16 - Ity_I1] = { [4] = Iop_16Uto32, [8] = Iop_16Uto64 },
340    [Ity_I32 - Ity_I1] = {                    [8] = Iop_32Uto64 },
341 };
342 
343 /**
344  * Instrument the client code to trace a memory load (--trace-addr).
345  */
instr_trace_mem_load(IRSB * const bb,IRExpr * addr_expr,const HWord size)346 static IRExpr* instr_trace_mem_load(IRSB* const bb, IRExpr* addr_expr,
347                                     const HWord size)
348 {
349    IRTemp tmp;
350 
351    tmp = newIRTemp(bb->tyenv, typeOfIRExpr(bb->tyenv, addr_expr));
352    addStmtToIRSB(bb, IRStmt_WrTmp(tmp, addr_expr));
353    addr_expr = IRExpr_RdTmp(tmp);
354 
355    addStmtToIRSB(bb,
356       IRStmt_Dirty(
357          unsafeIRDirty_0_N(/*regparms*/2,
358                            "drd_trace_mem_load",
359                            VG_(fnptr_to_fnentry)
360                            (drd_trace_mem_load),
361                            mkIRExprVec_2(addr_expr, mkIRExpr_HWord(size)))));
362 
363    return addr_expr;
364 }
365 
366 /**
367  * Instrument the client code to trace a memory store (--trace-addr).
368  */
instr_trace_mem_store(IRSB * const bb,IRExpr * const addr_expr,IRExpr * data_expr_hi,IRExpr * data_expr_lo)369 static void instr_trace_mem_store(IRSB* const bb, IRExpr* const addr_expr,
370                                   IRExpr* data_expr_hi, IRExpr* data_expr_lo)
371 {
372    IRType ty_data_expr;
373    HWord size;
374 
375    tl_assert(sizeof(HWord) == 4 || sizeof(HWord) == 8);
376    tl_assert(!data_expr_hi || typeOfIRExpr(bb->tyenv, data_expr_hi) == Ity_I32);
377 
378    ty_data_expr = typeOfIRExpr(bb->tyenv, data_expr_lo);
379    size = sizeofIRType(ty_data_expr);
380 
381 #if 0
382    // Test code
383    if (ty_data_expr == Ity_I32) {
384       IRTemp tmp = newIRTemp(bb->tyenv, Ity_F32);
385       data_expr_lo = IRExpr_Unop(Iop_ReinterpI32asF32, data_expr_lo);
386       addStmtToIRSB(bb, IRStmt_WrTmp(tmp, data_expr_lo));
387       data_expr_lo = IRExpr_RdTmp(tmp);
388       ty_data_expr = Ity_F32;
389    } else if (ty_data_expr == Ity_I64) {
390       IRTemp tmp = newIRTemp(bb->tyenv, Ity_F64);
391       data_expr_lo = IRExpr_Unop(Iop_ReinterpI64asF64, data_expr_lo);
392       addStmtToIRSB(bb, IRStmt_WrTmp(tmp, data_expr_lo));
393       data_expr_lo = IRExpr_RdTmp(tmp);
394       ty_data_expr = Ity_F64;
395    }
396 #endif
397 
398    if (ty_data_expr == Ity_F32) {
399       IRTemp tmp = newIRTemp(bb->tyenv, Ity_I32);
400       addStmtToIRSB(bb, IRStmt_WrTmp(tmp, IRExpr_Unop(Iop_ReinterpF32asI32,
401                                                       data_expr_lo)));
402       data_expr_lo = IRExpr_RdTmp(tmp);
403       ty_data_expr = Ity_I32;
404    } else if (ty_data_expr == Ity_F64) {
405       IRTemp tmp = newIRTemp(bb->tyenv, Ity_I64);
406       addStmtToIRSB(bb, IRStmt_WrTmp(tmp, IRExpr_Unop(Iop_ReinterpF64asI64,
407                                                       data_expr_lo)));
408       data_expr_lo = IRExpr_RdTmp(tmp);
409       ty_data_expr = Ity_I64;
410    }
411 
412    if (size == sizeof(HWord)
413        && (ty_data_expr == Ity_I32 || ty_data_expr == Ity_I64))
414    {
415       /* No conversion necessary */
416    } else {
417       IROp widen_op;
418 
419       if (Ity_I1 <= ty_data_expr
420           && ty_data_expr
421              < Ity_I1 + sizeof(u_widen_irop)/sizeof(u_widen_irop[0]))
422       {
423          widen_op = u_widen_irop[ty_data_expr - Ity_I1][sizeof(HWord)];
424          if (!widen_op)
425             widen_op = Iop_INVALID;
426       } else {
427          widen_op = Iop_INVALID;
428       }
429       if (widen_op != Iop_INVALID) {
430          IRTemp tmp;
431 
432          /* Widen the integer expression to a HWord */
433          tmp = newIRTemp(bb->tyenv, sizeof(HWord) == 4 ? Ity_I32 : Ity_I64);
434          addStmtToIRSB(bb,
435                        IRStmt_WrTmp(tmp, IRExpr_Unop(widen_op, data_expr_lo)));
436          data_expr_lo = IRExpr_RdTmp(tmp);
437       } else if (size > sizeof(HWord) && !data_expr_hi
438                  && ty_data_expr == Ity_I64) {
439          IRTemp tmp;
440 
441          tl_assert(sizeof(HWord) == 4);
442          tl_assert(size == 8);
443          tmp = newIRTemp(bb->tyenv, Ity_I32);
444          addStmtToIRSB(bb,
445                        IRStmt_WrTmp(tmp,
446                                     IRExpr_Unop(Iop_64HIto32, data_expr_lo)));
447          data_expr_hi = IRExpr_RdTmp(tmp);
448          tmp = newIRTemp(bb->tyenv, Ity_I32);
449          addStmtToIRSB(bb, IRStmt_WrTmp(tmp,
450                                         IRExpr_Unop(Iop_64to32, data_expr_lo)));
451          data_expr_lo = IRExpr_RdTmp(tmp);
452       } else {
453          data_expr_lo = mkIRExpr_HWord(0);
454       }
455    }
456    addStmtToIRSB(bb,
457       IRStmt_Dirty(
458          unsafeIRDirty_0_N(/*regparms*/3,
459                            "drd_trace_mem_store",
460                            VG_(fnptr_to_fnentry)(drd_trace_mem_store),
461                            mkIRExprVec_4(addr_expr, mkIRExpr_HWord(size),
462                                          data_expr_hi ? data_expr_hi
463                                          : mkIRExpr_HWord(0), data_expr_lo))));
464 }
465 
instrument_load(IRSB * const bb,IRExpr * const addr_expr,const HWord size)466 static void instrument_load(IRSB* const bb, IRExpr* const addr_expr,
467                             const HWord size)
468 {
469    IRExpr* size_expr;
470    IRExpr** argv;
471    IRDirty* di;
472 
473    if (!s_check_stack_accesses && is_stack_access(bb, addr_expr))
474       return;
475 
476    switch (size)
477    {
478    case 1:
479       argv = mkIRExprVec_1(addr_expr);
480       di = unsafeIRDirty_0_N(/*regparms*/1,
481                              "drd_trace_load_1",
482                              VG_(fnptr_to_fnentry)(drd_trace_load_1),
483                              argv);
484       break;
485    case 2:
486       argv = mkIRExprVec_1(addr_expr);
487       di = unsafeIRDirty_0_N(/*regparms*/1,
488                              "drd_trace_load_2",
489                              VG_(fnptr_to_fnentry)(drd_trace_load_2),
490                              argv);
491       break;
492    case 4:
493       argv = mkIRExprVec_1(addr_expr);
494       di = unsafeIRDirty_0_N(/*regparms*/1,
495                              "drd_trace_load_4",
496                              VG_(fnptr_to_fnentry)(drd_trace_load_4),
497                              argv);
498       break;
499    case 8:
500       argv = mkIRExprVec_1(addr_expr);
501       di = unsafeIRDirty_0_N(/*regparms*/1,
502                              "drd_trace_load_8",
503                              VG_(fnptr_to_fnentry)(drd_trace_load_8),
504                              argv);
505       break;
506    default:
507       size_expr = mkIRExpr_HWord(size);
508       argv = mkIRExprVec_2(addr_expr, size_expr);
509       di = unsafeIRDirty_0_N(/*regparms*/2,
510                              "drd_trace_load",
511                              VG_(fnptr_to_fnentry)(DRD_(trace_load)),
512                              argv);
513       break;
514    }
515    addStmtToIRSB(bb, IRStmt_Dirty(di));
516 }
517 
instrument_store(IRSB * const bb,IRExpr * addr_expr,IRExpr * const data_expr)518 static void instrument_store(IRSB* const bb, IRExpr* addr_expr,
519                              IRExpr* const data_expr)
520 {
521    IRExpr* size_expr;
522    IRExpr** argv;
523    IRDirty* di;
524    HWord size;
525 
526    size = sizeofIRType(typeOfIRExpr(bb->tyenv, data_expr));
527 
528    if (UNLIKELY(DRD_(any_address_is_traced)())) {
529       IRTemp tmp = newIRTemp(bb->tyenv, typeOfIRExpr(bb->tyenv, addr_expr));
530       addStmtToIRSB(bb, IRStmt_WrTmp(tmp, addr_expr));
531       addr_expr = IRExpr_RdTmp(tmp);
532       instr_trace_mem_store(bb, addr_expr, NULL, data_expr);
533    }
534 
535    if (!s_check_stack_accesses && is_stack_access(bb, addr_expr))
536       return;
537 
538    switch (size)
539    {
540    case 1:
541       argv = mkIRExprVec_1(addr_expr);
542       di = unsafeIRDirty_0_N(/*regparms*/1,
543                              "drd_trace_store_1",
544                              VG_(fnptr_to_fnentry)(drd_trace_store_1),
545                              argv);
546       break;
547    case 2:
548       argv = mkIRExprVec_1(addr_expr);
549       di = unsafeIRDirty_0_N(/*regparms*/1,
550                              "drd_trace_store_2",
551                              VG_(fnptr_to_fnentry)(drd_trace_store_2),
552                              argv);
553       break;
554    case 4:
555       argv = mkIRExprVec_1(addr_expr);
556       di = unsafeIRDirty_0_N(/*regparms*/1,
557                              "drd_trace_store_4",
558                              VG_(fnptr_to_fnentry)(drd_trace_store_4),
559                              argv);
560       break;
561    case 8:
562       argv = mkIRExprVec_1(addr_expr);
563       di = unsafeIRDirty_0_N(/*regparms*/1,
564                              "drd_trace_store_8",
565                              VG_(fnptr_to_fnentry)(drd_trace_store_8),
566                              argv);
567       break;
568    default:
569       size_expr = mkIRExpr_HWord(size);
570       argv = mkIRExprVec_2(addr_expr, size_expr);
571       di = unsafeIRDirty_0_N(/*regparms*/2,
572                              "drd_trace_store",
573                              VG_(fnptr_to_fnentry)(DRD_(trace_store)),
574                              argv);
575       break;
576    }
577    addStmtToIRSB(bb, IRStmt_Dirty(di));
578 }
579 
DRD_(instrument)580 IRSB* DRD_(instrument)(VgCallbackClosure* const closure,
581                        IRSB* const bb_in,
582                        VexGuestLayout* const layout,
583                        VexGuestExtents* const vge,
584                        IRType const gWordTy,
585                        IRType const hWordTy)
586 {
587    IRDirty* di;
588    Int      i;
589    IRSB*    bb;
590    IRExpr** argv;
591    Bool     instrument = True;
592 
593    /* Set up BB */
594    bb           = emptyIRSB();
595    bb->tyenv    = deepCopyIRTypeEnv(bb_in->tyenv);
596    bb->next     = deepCopyIRExpr(bb_in->next);
597    bb->jumpkind = bb_in->jumpkind;
598    bb->offsIP   = bb_in->offsIP;
599 
600    for (i = 0; i < bb_in->stmts_used; i++)
601    {
602       IRStmt* const st = bb_in->stmts[i];
603       tl_assert(st);
604       tl_assert(isFlatIRStmt(st));
605 
606       switch (st->tag)
607       {
608          /* Note: the code for not instrumenting the code in .plt          */
609          /* sections is only necessary on CentOS 3.0 x86 (kernel 2.4.21    */
610          /* + glibc 2.3.2 + NPTL 0.60 + binutils 2.14.90.0.4).             */
611          /* This is because on this platform dynamic library symbols are   */
612          /* relocated in another way than by later binutils versions. The  */
613          /* linker e.g. does not generate .got.plt sections on CentOS 3.0. */
614       case Ist_IMark:
615          instrument = VG_(DebugInfo_sect_kind)(NULL, 0, st->Ist.IMark.addr)
616             != Vg_SectPLT;
617          addStmtToIRSB(bb, st);
618          break;
619 
620       case Ist_MBE:
621          switch (st->Ist.MBE.event)
622          {
623          case Imbe_Fence:
624             break; /* not interesting */
625          default:
626             tl_assert(0);
627          }
628          addStmtToIRSB(bb, st);
629          break;
630 
631       case Ist_Store:
632          if (instrument)
633             instrument_store(bb, st->Ist.Store.addr, st->Ist.Store.data);
634          addStmtToIRSB(bb, st);
635          break;
636 
637       case Ist_WrTmp:
638          if (instrument) {
639             const IRExpr* const data = st->Ist.WrTmp.data;
640             IRExpr* addr_expr = data->Iex.Load.addr;
641             if (data->tag == Iex_Load) {
642                if (UNLIKELY(DRD_(any_address_is_traced)())) {
643                   addr_expr = instr_trace_mem_load(bb, addr_expr,
644                                        sizeofIRType(data->Iex.Load.ty));
645                }
646                instrument_load(bb, data->Iex.Load.addr,
647                                sizeofIRType(data->Iex.Load.ty));
648             }
649          }
650          addStmtToIRSB(bb, st);
651          break;
652 
653       case Ist_Dirty:
654          if (instrument) {
655             IRDirty* d = st->Ist.Dirty.details;
656             IREffect const mFx = d->mFx;
657             switch (mFx) {
658             case Ifx_None:
659                break;
660             case Ifx_Read:
661             case Ifx_Write:
662             case Ifx_Modify:
663                tl_assert(d->mAddr);
664                tl_assert(d->mSize > 0);
665                argv = mkIRExprVec_2(d->mAddr, mkIRExpr_HWord(d->mSize));
666                if (mFx == Ifx_Read || mFx == Ifx_Modify) {
667                   di = unsafeIRDirty_0_N(
668                           /*regparms*/2,
669                           "drd_trace_load",
670                           VG_(fnptr_to_fnentry)(DRD_(trace_load)),
671                           argv);
672                   addStmtToIRSB(bb, IRStmt_Dirty(di));
673                }
674                if (mFx == Ifx_Write || mFx == Ifx_Modify)
675                {
676                   di = unsafeIRDirty_0_N(
677                           /*regparms*/2,
678                           "drd_trace_store",
679                           VG_(fnptr_to_fnentry)(DRD_(trace_store)),
680                           argv);
681                   addStmtToIRSB(bb, IRStmt_Dirty(di));
682                }
683                break;
684             default:
685                tl_assert(0);
686             }
687          }
688          addStmtToIRSB(bb, st);
689          break;
690 
691       case Ist_CAS:
692          if (instrument) {
693             /*
694              * Treat compare-and-swap as a read. By handling atomic
695              * instructions as read instructions no data races are reported
696              * between conflicting atomic operations nor between atomic
697              * operations and non-atomic reads. Conflicts between atomic
698              * operations and non-atomic write operations are still reported
699              * however.
700              */
701             Int    dataSize;
702             IRCAS* cas = st->Ist.CAS.details;
703 
704             tl_assert(cas->addr != NULL);
705             tl_assert(cas->dataLo != NULL);
706             dataSize = sizeofIRType(typeOfIRExpr(bb->tyenv, cas->dataLo));
707             if (cas->dataHi != NULL)
708                dataSize *= 2; /* since it's a doubleword-CAS */
709 
710             if (UNLIKELY(DRD_(any_address_is_traced)()))
711                instr_trace_mem_store(bb, cas->addr, cas->dataHi, cas->dataLo);
712 
713             instrument_load(bb, cas->addr, dataSize);
714          }
715          addStmtToIRSB(bb, st);
716          break;
717 
718       case Ist_LLSC: {
719          /*
720           * Ignore store-conditionals (except for tracing), and handle
721           * load-linked's exactly like normal loads.
722           */
723          IRType dataTy;
724 
725          if (st->Ist.LLSC.storedata == NULL) {
726             /* LL */
727             dataTy = typeOfIRTemp(bb_in->tyenv, st->Ist.LLSC.result);
728             if (instrument) {
729                IRExpr* addr_expr = st->Ist.LLSC.addr;
730                if (UNLIKELY(DRD_(any_address_is_traced)()))
731                   addr_expr = instr_trace_mem_load(bb, addr_expr,
732                                                    sizeofIRType(dataTy));
733 
734                instrument_load(bb, addr_expr, sizeofIRType(dataTy));
735             }
736          } else {
737             /* SC */
738             instr_trace_mem_store(bb, st->Ist.LLSC.addr, NULL,
739                                   st->Ist.LLSC.storedata);
740          }
741          addStmtToIRSB(bb, st);
742          break;
743       }
744 
745       case Ist_NoOp:
746       case Ist_AbiHint:
747       case Ist_Put:
748       case Ist_PutI:
749       case Ist_Exit:
750          /* None of these can contain any memory references. */
751          addStmtToIRSB(bb, st);
752          break;
753 
754       default:
755          ppIRStmt(st);
756          tl_assert(0);
757       }
758    }
759 
760    return bb;
761 }
762 
763