| /* |
| * Copyright (C) 2010 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "Dalvik.h" |
| #include "alloc/HeapSource.h" |
| #include "alloc/Verify.h" |
| #include "alloc/HeapBitmap.h" |
| |
| /* |
| * Assertion that the given reference points to a valid object. |
| */ |
| #define VERIFY_REFERENCE(x) do { \ |
| if (!verifyReference((x), &(x))) { \ |
| LOGE("Verify of %p at %p failed", (x), &(x)); \ |
| dvmAbort(); \ |
| } \ |
| } while (0) |
| |
| /* |
| * Verifies that a reference points to an object header. |
| */ |
| static bool verifyReference(const void *obj, const void *addr) |
| { |
| if (obj == NULL) { |
| return true; |
| } |
| return dvmIsValidObject(obj); |
| } |
| |
| /* |
| * Verifies instance fields. |
| */ |
| static void verifyInstanceFields(const Object *obj) |
| { |
| ClassObject *clazz; |
| int i; |
| |
| assert(obj != NULL); |
| assert(obj->clazz != NULL); |
| LOGV("Entering verifyInstanceFields(obj=%p)", obj); |
| /* TODO(cshapiro): check reference offsets bitmap for agreement. */ |
| for (clazz = obj->clazz; clazz != NULL; clazz = clazz->super) { |
| InstField *field = clazz->ifields; |
| for (i = 0; i < clazz->ifieldRefCount; ++i, ++field) { |
| void *addr = BYTE_OFFSET((Object *)obj, field->byteOffset); |
| VERIFY_REFERENCE(((JValue *)addr)->l); |
| } |
| } |
| LOGV("Exiting verifyInstanceFields(obj=%p)", obj); |
| } |
| |
| /* |
| * Verifies the header, static field references, and interface |
| * pointers of a class object. |
| */ |
| static void verifyClassObject(const ClassObject *obj) |
| { |
| ClassObject *clazz; |
| int i; |
| |
| LOGV("Entering verifyClassObject(obj=%p)", obj); |
| if (obj == gDvm.unlinkedJavaLangClass) { |
| assert(obj->obj.clazz == NULL); |
| goto exit; |
| } |
| VERIFY_REFERENCE(obj->obj.clazz); |
| assert(!strcmp(obj->obj.clazz->descriptor, "Ljava/lang/Class;")); |
| if (IS_CLASS_FLAG_SET(obj, CLASS_ISARRAY)) { |
| VERIFY_REFERENCE(obj->elementClass); |
| } |
| VERIFY_REFERENCE(obj->super); |
| VERIFY_REFERENCE(obj->classLoader); |
| /* Verify static field references. */ |
| for (i = 0; i < obj->sfieldCount; ++i) { |
| char ch = obj->sfields[i].field.signature[0]; |
| if (ch == '[' || ch == 'L') { |
| VERIFY_REFERENCE(obj->sfields[i].value.l); |
| } |
| } |
| /* Verify the instance fields. */ |
| verifyInstanceFields((const Object *)obj); |
| /* Verify interface references. */ |
| for (i = 0; i < obj->interfaceCount; ++i) { |
| VERIFY_REFERENCE(obj->interfaces[i]); |
| } |
| exit: |
| LOGV("Exiting verifyClassObject(obj=%p)", obj); |
| } |
| |
| /* |
| * Verifies the header of all array objects. If the array object is |
| * specialized to a reference type, verifies the array data as well. |
| */ |
| static void verifyArrayObject(const ArrayObject *array) |
| { |
| size_t i; |
| |
| LOGV("Entering verifyArrayObject(array=%p)", array); |
| /* Verify the class object reference. */ |
| assert(array->obj.clazz != NULL); |
| VERIFY_REFERENCE(array->obj.clazz); |
| if (IS_CLASS_FLAG_SET(array->obj.clazz, CLASS_ISOBJECTARRAY)) { |
| /* Verify the array contents. */ |
| Object **contents = (Object **)array->contents; |
| for (i = 0; i < array->length; ++i) { |
| VERIFY_REFERENCE(contents[i]); |
| } |
| } |
| LOGV("Exiting verifyArrayObject(array=%p)", array); |
| } |
| |
| /* |
| * Verifies the header and field references of a data object. |
| */ |
| static void verifyDataObject(const DataObject *obj) |
| { |
| ClassObject *clazz; |
| int i; |
| |
| LOGV("Entering verifyDataObject(obj=%p)", obj); |
| /* Verify the class object. */ |
| assert(obj->obj.clazz != NULL); |
| VERIFY_REFERENCE(obj->obj.clazz); |
| /* Verify the instance fields. */ |
| verifyInstanceFields((const Object *)obj); |
| if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISREFERENCE)) { |
| /* Verify the hidden Reference.referent field. */ |
| size_t offset = gDvm.offJavaLangRefReference_referent; |
| void *addr = BYTE_OFFSET((Object *)obj, offset); |
| VERIFY_REFERENCE(((JValue *)addr)->l); |
| } |
| LOGV("Exiting verifyDataObject(obj=%p)", obj); |
| } |
| |
| /* |
| * Verifies an object reference. Determines the type of the reference |
| * and dispatches to a specialized verification routine. |
| */ |
| void dvmVerifyObject(const Object *obj) |
| { |
| ClassObject *clazz; |
| |
| LOGV("Entering dvmVerifyObject(obj=%p)", obj); |
| assert(obj != NULL); |
| /* Check that the object is aligned. */ |
| assert(((uintptr_t)obj & 7) == 0); |
| clazz = obj->clazz; |
| /* Check that the class object is aligned. */ |
| assert(((uintptr_t)clazz & 7) == 0); |
| /* Dispatch a type-specific verification routine. */ |
| if (clazz == gDvm.classJavaLangClass || |
| obj == (Object *)gDvm.unlinkedJavaLangClass) { |
| verifyClassObject((ClassObject *)obj); |
| } else { |
| assert(clazz != NULL); |
| if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) { |
| verifyArrayObject((ArrayObject *)obj); |
| } else { |
| verifyDataObject((DataObject *)obj); |
| } |
| } |
| LOGV("Exiting dvmVerifyObject(obj=%p)", obj); |
| } |
| |
| /* |
| * Helper function to call dvmVerifyObject from a bitmap walker. |
| */ |
| static bool verifyBitmapCallback(size_t numPtrs, void **ptrs, |
| const void *finger, void *arg) |
| { |
| size_t i; |
| |
| for (i = 0; i < numPtrs; i++) { |
| dvmVerifyObject(*ptrs++); |
| } |
| return true; |
| } |
| |
| /* |
| * Verifies the object references in a heap bitmap. Assumes the VM is |
| * suspended. |
| */ |
| void dvmVerifyBitmap(const HeapBitmap *bitmap) |
| { |
| /* TODO: check that locks are held and the VM is suspended. */ |
| dvmHeapBitmapWalk(bitmap, verifyBitmapCallback, NULL); |
| } |