Add DRD as an experimental tool.  Bart Van Assche is the maintainer.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@7211 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/exp-drd/drd_bitmap.c b/exp-drd/drd_bitmap.c
new file mode 100644
index 0000000..21d9bb3
--- /dev/null
+++ b/exp-drd/drd_bitmap.c
@@ -0,0 +1,776 @@
+/*
+  This file is part of drd, a data race detector.
+
+  Copyright (C) 2006-2007 Bart Van Assche
+  bart.vanassche@gmail.com
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of the
+  License, or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+  02111-1307, USA.
+
+  The GNU General Public License is contained in the file COPYING.
+*/
+
+
+#include "pub_tool_basics.h"      // Addr, SizeT
+#include "pub_tool_debuginfo.h"   // VG_(get_objname)()
+#include "pub_tool_libcassert.h"  // tl_assert()
+#include "pub_tool_libcbase.h"    // VG_(memset)
+#include "pub_tool_libcprint.h"   // VG_(printf)
+#include "pub_tool_machine.h"     // VG_(get_IP)()
+#include "pub_tool_mallocfree.h"  // VG_(malloc), VG_(free)
+#include "pub_drd_bitmap.h"
+#include "drd_bitmap.h"
+#include "drd_error.h"
+#include "drd_suppression.h"
+
+
+// Local constants.
+
+static ULong s_bitmap_creation_count;
+
+
+// Local function declarations.
+
+static void bm2_merge(struct bitmap2* const bm2l,
+                      const struct bitmap2* const bm2r);
+
+
+// Function definitions.
+
+struct bitmap* bm_new()
+{
+   struct bitmap* bm;
+
+   // If this assert fails, fix the definition of BITS_PER_BITS_PER_UWORD
+   // in drd_bitmap.h.
+   tl_assert((1 << BITS_PER_BITS_PER_UWORD) == BITS_PER_UWORD);
+
+   bm = VG_(malloc)(sizeof(*bm));
+   tl_assert(bm);
+   bm->oset = VG_(OSetGen_Create)(0, 0, VG_(malloc), VG_(free));
+
+   s_bitmap_creation_count++;
+
+   return bm;
+}
+
+void bm_delete(struct bitmap* const bm)
+{
+   tl_assert(bm);
+   VG_(OSetGen_Destroy)(bm->oset);
+   VG_(free)(bm);
+}
+
+/**
+ * Record an access of type access_type at addresses a in bitmap bm.
+ */
+static
+__inline__
+void bm_access_1(struct bitmap* const bm,
+                 const Addr a,
+                 const BmAccessTypeT access_type)
+{
+   struct bitmap2* p2;
+   struct bitmap1* p1;
+   UWord* p0;
+   SPLIT_ADDRESS(a);
+
+   tl_assert(bm);
+
+   p2 = bm2_lookup_or_insert(bm, a1);
+   p1 = &p2->bm1;
+   p0 = (access_type == eLoad) ? p1->bm0_r : p1->bm0_w;
+   bm0_set(p0, a0);
+}
+
+static
+void bm_access_4_nonaligned(struct bitmap* const bm,
+                            const Addr a,
+                            const BmAccessTypeT access_type)
+{
+   bm_access_1(bm, a + 0, access_type);
+   bm_access_1(bm, a + 1, access_type);
+   bm_access_1(bm, a + 2, access_type);
+   bm_access_1(bm, a + 3, access_type);
+}
+
+static
+__inline__
+void bm_access_4_aligned(struct bitmap* const bm,
+                         const Addr a,
+                         const BmAccessTypeT access_type)
+{
+   struct bitmap2* p2;
+   struct bitmap1* p1;
+   UWord* p0;
+   SPLIT_ADDRESS(a);
+
+   tl_assert(bm);
+
+   p2 = bm2_lookup_or_insert(bm, a1);
+   p1 = &p2->bm1;
+   p0 = (access_type == eLoad) ? p1->bm0_r : p1->bm0_w;
+   bm0_set(p0, a0+0);
+   bm0_set(p0, a0+1);
+   bm0_set(p0, a0+2);
+   bm0_set(p0, a0+3);
+}
+
+/**
+ * Record an access of type access_type at addresses a .. a + 3 in bitmap bm.
+ */
+void bm_access_4(struct bitmap* const bm,
+                 const Addr a,
+                 const BmAccessTypeT access_type)
+{
+   tl_assert(bm);
+   if ((a & 3) != 0)
+   {
+      bm_access_4_nonaligned(bm, a, access_type);
+   }
+   else
+   {
+      bm_access_4_aligned(bm, a, access_type);
+   }
+}
+
+/**
+ * Record an access of type access_type at addresses a .. a + size - 1 in
+ * bitmap bm.
+ */
+void bm_access_range(struct bitmap* const bm,
+		     const Addr a,
+		     const SizeT size,
+		     const BmAccessTypeT access_type)
+{
+   tl_assert(bm);
+   tl_assert(size > 0);
+
+   if (size == 4)
+      bm_access_4(bm, a, access_type);
+   else if (size == 1)
+      bm_access_1(bm, a, access_type);
+   else
+   {
+      Addr b;
+      for (b = a; b != a + size; b++)
+      {
+         bm_access_1(bm, b, access_type);
+      }
+   }
+}
+
+Bool bm_has(const struct bitmap* const bm,
+            const Addr a1,
+            const Addr a2,
+            const BmAccessTypeT access_type)
+{
+   Addr b;
+   for (b = a1; b < a2; b++)
+   {
+      if (! bm_has_1(bm, b, access_type))
+      {
+         return False;
+      }
+   }
+   return True;
+}
+
+Bool bm_has_any(const struct bitmap* const bm,
+                const Addr a1,
+                const Addr a2,
+                const BmAccessTypeT access_type)
+{
+   Addr b;
+
+   tl_assert(bm);
+
+   for (b = a1; b < a2; b++)
+   {
+      if (bm_has_1(bm, b, access_type))
+      {
+         return True;
+      }
+   }
+   return False;
+}
+
+/* Return a non-zero value if there is a read access, write access or both */
+/* to any of the addresses in the range [ a1, a2 [ in bitmap bm.           */
+UWord bm_has_any_access(const struct bitmap* const bm,
+                        const Addr a1,
+                        const Addr a2)
+{
+   Addr b, b_next;
+
+   tl_assert(bm);
+
+   for (b = a1; b < a2; b = b_next)
+   {
+      struct bitmap2* bm2 = bm_lookup(bm, b);
+
+      b_next = (b & ~ADDR0_MASK) + ADDR0_COUNT;
+      if (b_next > a2)
+      {
+         b_next = a2;
+      }
+
+      if (bm2)
+      {
+         Addr b_start;
+         Addr b_end;
+         UWord b0;
+
+         if ((bm2->addr << ADDR0_BITS) < a1)
+            b_start = a1;
+         else
+            if ((bm2->addr << ADDR0_BITS) < a2)
+               b_start = (bm2->addr << ADDR0_BITS);
+            else
+               break;
+         tl_assert(a1 <= b_start && b_start <= a2);
+
+         if ((bm2->addr << ADDR0_BITS) + ADDR0_COUNT < a2)
+            b_end = (bm2->addr << ADDR0_BITS) + ADDR0_COUNT;
+         else
+            b_end = a2;
+#if 0
+         VG_(message)(Vg_DebugMsg,
+                      "in 0x%lx 0x%lx / cur 0x%lx 0x%lx / out 0x%lx 0x%lx",
+                      a1, a2,
+                      (bm2->addr << ADDR0_BITS),
+                      (bm2->addr << ADDR0_BITS) + ADDR0_COUNT,
+                      b_start, b_end);
+#endif
+         tl_assert(a1 <= b_end && b_end <= a2);
+         tl_assert(b_start < b_end);
+         tl_assert((b_start & ADDR0_MASK) <= ((b_end - 1) & ADDR0_MASK));
+      
+         for (b0 = b_start & ADDR0_MASK; b0 <= ((b_end - 1) & ADDR0_MASK); b0++)
+         {
+            const struct bitmap1* const p1 = &bm2->bm1;
+            const UWord mask
+               = bm0_is_set(p1->bm0_r, b0) | bm0_is_set(p1->bm0_w, b0);
+            if (mask)
+            {
+               return mask;
+            }
+         }
+      }
+   }
+   return 0;
+}
+
+/**
+ * Report whether an access of type access_type at address a is recorded in
+ * bitmap bm.
+ * @return != 0 means true, and == 0 means false
+ */
+UWord bm_has_1(const struct bitmap* const bm,
+               const Addr a,
+               const BmAccessTypeT access_type)
+{
+   struct bitmap2* p2;
+   struct bitmap1* p1;
+   UWord* p0;
+   const UWord a0 = a & ADDR0_MASK;
+
+   tl_assert(bm);
+
+   p2 = bm_lookup(bm, a);
+   if (p2)
+   {
+      p1 = &p2->bm1;
+      p0 = (access_type == eLoad) ? p1->bm0_r : p1->bm0_w;
+      return bm0_is_set(p0, a0);
+   }
+   return 0;
+}
+
+static __inline__
+void bm1_clear(struct bitmap1* const bm1, const Addr a1, const Addr a2)
+{
+   UWord idx;
+   UWord mask;
+
+#if 0
+   // Commented out the assert statements below because of performance reasons.
+   tl_assert(a1);
+   tl_assert(a1 <= a2);
+   tl_assert(UWORD_MSB(a1) == UWORD_MSB(a2)
+             || UWORD_MSB(a1) == UWORD_MSB(a2 - 1));
+#endif
+
+   idx = (a1 & ADDR0_MASK) >> BITS_PER_BITS_PER_UWORD;
+   /* mask: a contiguous series of one bits. The first bit set is bit */
+   /* UWORD_LSB(a2-1), and the last bit set is UWORD_LSB(a1).         */
+   mask = UWORD_LSB(a2) ? bm0_mask(a2) - bm0_mask(a1) : - bm0_mask(a1);
+   bm1->bm0_r[idx] &= ~mask;
+   bm1->bm0_w[idx] &= ~mask;
+}
+
+void bm_clear_all(const struct bitmap* const bm)
+{
+   struct bitmap2* bm2;
+
+   VG_(OSetGen_ResetIter)(bm->oset);
+
+   for ( ; (bm2 = VG_(OSetGen_Next)(bm->oset)) != 0; )
+   {
+      struct bitmap1* const bm1 = &bm2->bm1;
+      tl_assert(bm1);
+      VG_(memset)(&bm1->bm0_r[0], 0, sizeof(bm1->bm0_r));
+      VG_(memset)(&bm1->bm0_w[0], 0, sizeof(bm1->bm0_w));
+   }
+}
+
+#if 1
+// New and fast implementation.
+void bm_clear(const struct bitmap* const bm,
+              const Addr a1,
+              const Addr a2)
+{
+   Addr b, b_next;
+
+   tl_assert(bm);
+   tl_assert(a1);
+   tl_assert(a1 <= a2);
+
+   for (b = a1; b < a2; b = b_next)
+   {
+      struct bitmap2* const p2 = bm_lookup(bm, b);
+
+      b_next = (b & ~ADDR0_MASK) + ADDR0_COUNT;
+      if (b_next > a2)
+      {
+         b_next = a2;
+      }
+
+      if (p2)
+      {
+         Addr c = b;
+         if (UWORD_LSB(c))
+         {
+            Addr c_next = UWORD_MSB(c) + BITS_PER_UWORD;
+            if (c_next > b_next)
+               c_next = b_next;
+            bm1_clear(&p2->bm1, c, c_next);
+            c = c_next;
+         }
+         if (UWORD_LSB(c) == 0)
+         {
+            const Addr c_next = UWORD_MSB(b_next);
+            tl_assert(UWORD_LSB(c) == 0);
+            tl_assert(UWORD_LSB(c_next) == 0);
+            tl_assert(c_next <= b_next);
+            tl_assert(c <= c_next);
+            if (c_next > c)
+            {
+               UWord idx = (c & ADDR0_MASK) >> BITS_PER_BITS_PER_UWORD;
+               VG_(memset)(&p2->bm1.bm0_r[idx], 0, (c_next - c) / 8);
+               VG_(memset)(&p2->bm1.bm0_w[idx], 0, (c_next - c) / 8);
+               c = c_next;
+            }
+         }
+         if (c != b_next)
+         {
+            bm1_clear(&p2->bm1, c, b_next);
+         }
+      }
+   }
+}
+#else
+// Old and slow implementation
+void bm_clear(const struct bitmap* const bm,
+              const Addr a1,
+              const Addr a2)
+{
+   Addr b, b_next, c;
+
+   tl_assert(bm);
+   tl_assert(a1);
+   tl_assert(a1 <= a2);
+
+   for (b = a1; b < a2; b = b_next)
+   {
+      struct bitmap2* const p2 = bm_lookup(bm, b);
+
+      b_next = (b & ~ADDR0_MASK) + ADDR0_COUNT;
+      if (b_next > a2)
+      {
+         b_next = a2;
+      }
+
+      if (p2)
+      {
+         for (c = b; c < b_next; c++)
+         {
+            const UWord c0 = c & ADDR0_MASK;
+
+            p2->bm1.bm0_r[c0 / (8*sizeof(UWord))]
+               &= ~(1UL << (c0 % (8*sizeof(UWord))));
+            p2->bm1.bm0_w[c0 / (8*sizeof(UWord))]
+               &= ~(1UL << (c0 % (8*sizeof(UWord))));
+         }
+      }
+   }
+}
+#endif
+
+static
+__inline__
+UWord bm_has_conflict_with_1(const struct bitmap* const bm,
+                             const Addr a,
+                             const BmAccessTypeT access_type)
+{
+   struct bitmap2* p2;
+   const UWord a0 = a & ADDR0_MASK;
+
+   tl_assert(bm);
+
+   p2 = bm_lookup(bm, a);
+   if (p2)
+   {
+      if (access_type == eLoad)
+      {
+         return bm0_is_set(p2->bm1.bm0_w, a0);
+      }
+      else
+      {
+         tl_assert(access_type == eStore);
+         return (bm0_is_set(p2->bm1.bm0_r, a0)
+                 | bm0_is_set(p2->bm1.bm0_w, a0));
+      }
+   }
+   return False;
+}
+
+/**
+ * Return true if the access to [a,a+size[ of type access_type conflicts with
+ * any access stored in bitmap bm.
+ */
+Bool bm_has_conflict_with(const struct bitmap* const bm,
+                          const Addr a1,
+                          const Addr a2,
+                          const BmAccessTypeT access_type)
+{
+   Addr b;
+   for (b = a1; b != a2; b++)
+   {
+      if (bm_has_conflict_with_1(bm, b, access_type))
+      {
+         return True;
+      }
+   }
+   return False;
+}
+
+void bm_swap(struct bitmap* const bm1, struct bitmap* const bm2)
+{
+   OSet* const tmp = bm1->oset;
+   bm1->oset = bm2->oset;
+   bm2->oset = tmp;
+}
+
+void bm_merge2(struct bitmap* const lhs,
+               const struct bitmap* const rhs)
+{
+   struct bitmap2* bm2l;
+   const struct bitmap2* bm2r;
+
+   // First step: allocate any missing bitmaps in *lhs.
+   VG_(OSetGen_ResetIter)(rhs->oset);
+   for ( ; (bm2r = VG_(OSetGen_Next)(rhs->oset)) != 0; )
+   {
+      bm2_lookup_or_insert(lhs, bm2r->addr);
+   }
+
+   VG_(OSetGen_ResetIter)(lhs->oset);
+   VG_(OSetGen_ResetIter)(rhs->oset);
+
+   for ( ; (bm2r = VG_(OSetGen_Next)(rhs->oset)) != 0; )
+   {
+      do
+      {
+         bm2l = VG_(OSetGen_Next)(lhs->oset);
+         //VG_(message)(Vg_DebugMsg, "0x%x 0x%x", bm2l->addr, bm2r->addr);
+      } while (bm2l->addr < bm2r->addr);
+
+      tl_assert(bm2l->addr == bm2r->addr);
+
+      bm2_merge(bm2l, bm2r);
+   }
+}
+
+/**
+ * Report whether there are any RW / WR / WW patterns in lhs and rhs.
+ * @param lhs First bitmap.
+ * @param rhs Bitmap to be compared with lhs.
+ * @return !=0 if there are data races, == 0 if there are none.
+ */
+int bm_has_races(const struct bitmap* const lhs,
+                 const struct bitmap* const rhs)
+{
+   VG_(OSetGen_ResetIter)(lhs->oset);
+   VG_(OSetGen_ResetIter)(rhs->oset);
+
+   for (;;)
+   {
+      const struct bitmap2* bm2l = VG_(OSetGen_Next)(lhs->oset);
+      const struct bitmap2* bm2r = VG_(OSetGen_Next)(rhs->oset);
+      const struct bitmap1* bm1l;
+      const struct bitmap1* bm1r;
+      unsigned k;
+
+      while (bm2l && bm2r && bm2l->addr != bm2r->addr)
+      {
+         if (bm2l->addr < bm2r->addr)
+            bm2l = VG_(OSetGen_Next)(lhs->oset);
+         else
+            bm2r = VG_(OSetGen_Next)(rhs->oset);
+      }
+      if (bm2l == 0 || bm2r == 0)
+         break;
+
+      bm1l = &bm2l->bm1;
+      bm1r = &bm2r->bm1;
+
+      for (k = 0; k < BITMAP1_UWORD_COUNT; k++)
+      {
+         unsigned b;
+         for (b = 0; b < BITS_PER_UWORD; b++)
+         {
+            UWord const access
+               = ((bm1l->bm0_r[k] & bm0_mask(b)) ? LHS_R : 0)
+               | ((bm1l->bm0_w[k] & bm0_mask(b)) ? LHS_W : 0)
+               | ((bm1r->bm0_r[k] & bm0_mask(b)) ? RHS_R : 0)
+               | ((bm1r->bm0_w[k] & bm0_mask(b)) ? RHS_W : 0);
+            Addr const a = MAKE_ADDRESS(bm2l->addr, k * BITS_PER_UWORD | b);
+            if (HAS_RACE(access) && ! drd_is_suppressed(a, a + 1))
+            {
+               return 1;
+            }
+         }
+      }
+   }
+   return 0;
+}
+
+#ifdef OLD_RACE_DETECTION_ALGORITHM
+/**
+ * Report RW / WR / WW patterns between lhs and rhs.
+ * @param tid1 Thread ID of lhs.
+ * @param tid2 Thread ID of rhs.
+ * @param lhs First bitmap.
+ * @param rhs Bitmap to be compared with lhs.
+ * @return Number of reported ranges with data races.
+ */
+void bm_report_races(const ThreadId tid1,
+                     const ThreadId tid2,
+                     const struct bitmap* const lhs,
+                     const struct bitmap* const rhs)
+{
+   Addr     range_begin  = 0;
+   Addr     range_end    = 0;
+   UWord range_access = 0;
+
+   VG_(message)(Vg_UserMsg, "Data addresses accessed by both segments:");
+
+   VG_(OSetGen_ResetIter)(lhs->oset);
+   VG_(OSetGen_ResetIter)(rhs->oset);
+
+   for (;;)
+   {
+      const struct bitmap2* bm2l = VG_(OSetGen_Next)(lhs->oset);
+      const struct bitmap2* bm2r = VG_(OSetGen_Next)(rhs->oset);
+      const struct bitmap1* bm1l;
+      const struct bitmap1* bm1r;
+      unsigned k;
+
+      while (bm2l && bm2r && bm2l->addr != bm2r->addr)
+      {
+         if (bm2l->addr < bm2r->addr)
+            bm2l = VG_(OSetGen_Next)(lhs->oset);
+         else
+            bm2r = VG_(OSetGen_Next)(rhs->oset);
+      }
+      if (bm2l == 0 || bm2r == 0)
+         break;
+
+      bm1l = &bm2l->bm1;
+      bm1r = &bm2r->bm1;
+
+      for (k = 0; k < BITMAP1_UWORD_COUNT; k++)
+      {
+         unsigned b;
+         for (b = 0; b < BITS_PER_UWORD; b++)
+         {
+            UWord const access
+               = ((bm1l->bm0_r[k] & bm0_mask(b)) ? LHS_R : 0)
+               | ((bm1l->bm0_w[k] & bm0_mask(b)) ? LHS_W : 0)
+               | ((bm1r->bm0_r[k] & bm0_mask(b)) ? RHS_R : 0)
+               | ((bm1r->bm0_w[k] & bm0_mask(b)) ? RHS_W : 0);
+            Addr const a = MAKE_ADDRESS(bm2l->addr, k * BITS_PER_UWORD | b);
+            if (access == range_access)
+               range_end = a + 1;
+            else
+            {
+               tl_assert(range_begin < range_end);
+               if (HAS_RACE(range_access)
+                   && ! drd_is_suppressed(range_begin, range_end))
+               {
+                  DataRaceInfo dri;
+                  dri.tid1         = tid1;
+                  dri.tid2         = tid2;
+                  dri.range_begin  = range_begin;
+                  dri.range_end    = range_end;
+                  dri.range_access = range_access;
+                  tl_assert(dri.range_begin < dri.range_end);
+#if 0
+                  VG_(maybe_record_error)(tid1,
+                                          DataRaceErr,
+                                          VG_(get_IP)(tid1), // where
+                                          "data race",
+                                          &dri);
+#else
+                  drd_report_data_race(&dri);
+#endif
+               }
+               range_access = access;
+               range_begin  = a;
+               range_end    = a + 1;
+            }
+         }
+      }
+   }
+}
+#endif
+
+void bm_print(const struct bitmap* const bm)
+{
+   struct bitmap2* bm2;
+
+   VG_(OSetGen_ResetIter)(bm->oset);
+
+   for ( ; (bm2 = VG_(OSetGen_Next)(bm->oset)) != 0; )
+   {
+      const struct bitmap1* const bm1 = &bm2->bm1;
+      unsigned k;
+      for (k = 0; k < BITMAP1_UWORD_COUNT; k++)
+      {
+         unsigned b;
+         for (b = 0; b < BITS_PER_UWORD; b++)
+         {
+            int const r = bm1->bm0_r[k] & bm0_mask(b);
+            int const w = bm1->bm0_w[k] & bm0_mask(b);
+            Addr const a = MAKE_ADDRESS(bm2->addr, k * BITS_PER_UWORD | b);
+            if (r || w)
+            {
+               VG_(printf)("0x%08lx %c %c\n",
+                           (Addr)(a), 
+                           w ? 'W' : ' ', r ? 'R' : ' ');
+            }
+         }
+      }
+   }
+}
+
+ULong bm_get_bitmap_creation_count(void)
+{
+   return s_bitmap_creation_count;
+}
+
+ULong bm_get_bitmap2_creation_count(void)
+{
+   return s_bitmap2_creation_count;
+}
+
+static void bm2_merge(struct bitmap2* const bm2l,
+                      const struct bitmap2* const bm2r)
+{
+   unsigned k;
+
+   tl_assert(bm2l->addr == bm2r->addr);
+
+   for (k = 0; k < BITMAP1_UWORD_COUNT; k++)
+   {
+      bm2l->bm1.bm0_r[k] |= bm2r->bm1.bm0_r[k];
+   }
+   for (k = 0; k < BITMAP1_UWORD_COUNT; k++)
+   {
+      bm2l->bm1.bm0_w[k] |= bm2r->bm1.bm0_w[k];
+   }
+}
+
+#if 0
+
+/* Unit test */
+static
+struct { Addr address; SizeT size; BmAccessTypeT access_type; }
+   s_args[] = {
+      {          0, 1, eLoad  },
+      {        666, 4, eLoad  },
+      {        667, 2, eStore },
+      {       1024, 1, eStore },
+      { 0x0000ffff, 1, eLoad  },
+      { 0x0001ffff, 1, eLoad  },
+      { 0x00ffffff, 1, eLoad  },
+      { 0xffffffff, 1, eStore },
+   };
+
+void bm_test(void)
+{
+   struct bitmap* bm;
+   struct bitmap* bm2;
+   int i, j;
+
+   VG_(printf)("Start of DRD BM unit test.\n");
+
+   bm = bm_new();
+
+   for (i = 0; i < sizeof(s_args)/sizeof(s_args[0]); i++)
+   {
+      bm_access_range(bm, s_args[i].address,
+                      s_args[i].size, s_args[i].access_type);
+   }
+
+   VG_(printf)("Map contents -- should contain 10 addresses:\n");
+   bm_print(bm);
+
+   for (i = 0; i < sizeof(s_args)/sizeof(s_args[0]); i++)
+   {
+      for (j = 0; j < s_args[i].size; j++)
+      {
+         tl_assert(bm_has_1(bm, s_args[i].address + j, s_args[i].access_type));
+      }
+   }
+
+   VG_(printf)("Merge result:\n");
+   bm2 = bm_merge(bm, bm);
+   bm_print(bm);
+
+   bm_delete(bm);
+   bm_delete(bm2);
+
+   VG_(printf)("End of DRD BM unit test.\n");
+}
+#endif
+
+
+/*
+ * Local variables:
+ * c-basic-offset: 3
+ * End:
+ */