Improve the error report generated by the card table verifier.

With this change, when a gray object has been found on an unmarked
card all references are sent to the log stream.  This will usually
provide enough context to diagnose issues with the write barrier.

Change-Id: Ib6b7d98160e18393f54fc6ebc38c9ca9ca7dad2e
diff --git a/vm/alloc/CardTable.c b/vm/alloc/CardTable.c
index 9e3677b..240e657 100644
--- a/vm/alloc/CardTable.c
+++ b/vm/alloc/CardTable.c
@@ -179,6 +179,76 @@
 }
 
 /*
+ * Visitor that logs white references.
+ */
+static void dumpWhiteReferenceVisitor(void *addr, void *arg)
+{
+    WhiteReferenceCounter *ctx;
+    Object *obj;
+
+    assert(addr != NULL);
+    assert(arg != NULL);
+    obj = *(Object **)addr;
+    if (obj == NULL) {
+        return;
+    }
+    assert(dvmIsValidObject(obj));
+    ctx = arg;
+    if (dvmHeapBitmapIsObjectBitSet(ctx->markBits, obj)) {
+        return;
+    }
+    LOGE("object %p is white", obj);
+}
+
+/*
+ * Visitor that signals the caller when a matching reference is found.
+ */
+static void dumpReferencesVisitor(void *pObj, void *arg)
+{
+    Object *obj = *(Object **)pObj;
+    Object *lookingFor = *(Object **)arg;
+    if (lookingFor != NULL && lookingFor == obj) {
+        *(Object **)arg = NULL;
+    }
+}
+
+static void dumpReferencesCallback(void *ptr, void *arg)
+{
+    Object *obj = arg;
+    if (ptr == obj) {
+        return;
+    }
+    dvmVisitObject(dumpReferencesVisitor, ptr, &obj);
+    if (obj == NULL) {
+        LOGD("Found %p in the heap @ %p", arg, ptr);
+        dvmDumpObject(ptr);
+    }
+}
+
+/*
+ * Root visitor that looks for matching references.
+ */
+static void dumpReferencesRootVisitor(void *ptr, void *arg)
+{
+    Object *obj = *(Object **)ptr;
+    Object *lookingFor = *(Object **)arg;
+    if (obj == lookingFor) {
+        LOGD("Found %p in a root @ %p", arg, ptr);
+    }
+}
+
+/*
+ * Invokes visitors to search for references to an object.
+ */
+static void dumpReferences(const Object *obj)
+{
+    HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
+    void *arg = (void *)obj;
+    dvmVisitRoots(dumpReferencesRootVisitor, arg);
+    dvmHeapBitmapWalk(bitmap, dumpReferencesCallback, arg);
+}
+
+/*
  * Returns true if the given object is a reference object and the
  * just the referent is unmarked.
  */
@@ -257,6 +327,8 @@
     } else {
         LOGE("Verify failed, object %p is gray and on an unmarked card", obj);
         dvmDumpObject(obj);
+        dvmVisitObject(dumpWhiteReferenceVisitor, obj, &ctx);
+        dumpReferences(obj);
         dvmAbort();
     }
 }