blob: 6da3b1f26a8d3e47b1676880fbba8a907110f1f7 [file] [log] [blame]
/*
* 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"
/* comment everything, of course! */
#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 the header, static fields references, and interface
* pointers of a class object.
*/
static void verifyClassObject(const ClassObject *obj)
{
int i;
char ch;
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) {
ch = obj->sfields[i].field.signature[0];
if (ch == '[' || ch == 'L') {
VERIFY_REFERENCE(obj->sfields[i].value.l);
}
}
/* 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)
{
ClassObject *clazz;
Object **contents;
size_t i;
LOGV("Entering verifyArrayObject(obj=%p)", obj);
/* 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. */
contents = (Object **) array->contents;
for (i = 0; i < array->length; ++i) {
VERIFY_REFERENCE(contents[i]);
}
}
LOGV("Exiting verifyArrayObject(obj=%p)", obj);
}
/*
* Verifies the header and field references of a data object.
*/
static void verifyDataObject(const DataObject *obj)
{
ClassObject *clazz;
InstField *field;
void *addr;
size_t offset;
int i, count;
LOGV("Entering verifyDataObject(obj=%p)", obj);
/* Verify the class object. */
assert(obj->obj.clazz != NULL);
VERIFY_REFERENCE(obj->obj.clazz);
/* Verify the instance fields. */
for (clazz = obj->obj.clazz; clazz != NULL; clazz = clazz->super) {
field = clazz->ifields;
count = clazz->ifieldRefCount;
for (i = 0; i < count; ++i, ++field) {
addr = BYTE_OFFSET((Object *)obj, field->byteOffset);
VERIFY_REFERENCE(((JValue *)addr)->l);
}
}
if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISREFERENCE)) {
/*
* Reference.referent is not included in the above loop. See
* precacheReferenceOffsets in Class.c for details.
*/
addr = BYTE_OFFSET((Object *)obj,
gDvm.offJavaLangRefReference_referent);
VERIFY_REFERENCE(((JValue *)addr)->l);
}
LOGV("Exiting verifyDataObject(obj=%p) %zx", obj, length);
}
/*
* 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);
clazz = obj->clazz;
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 heap
* is locked.
*/
void dvmVerifyBitmapUnlocked(const HeapBitmap *bitmap)
{
/* TODO: check that locks are held and the VM is suspended. */
dvmHeapBitmapWalk(bitmap, verifyBitmapCallback, NULL);
}
/*
* Verifies the object references in a heap bitmap. Suspends the VM
* for the duration of verification.
*/
void dvmVerifyBitmap(const HeapBitmap *bitmap)
{
/* Suspend the VM. */
dvmSuspendAllThreads(SUSPEND_FOR_VERIFY);
dvmLockMutex(&gDvm.heapWorkerLock);
dvmAssertHeapWorkerThreadRunning();
dvmLockMutex(&gDvm.heapWorkerListLock);
dvmVerifyBitmapUnlocked(bitmap);
/* Resume the VM. */
dvmUnlockMutex(&gDvm.heapWorkerListLock);
dvmUnlockMutex(&gDvm.heapWorkerLock);
dvmResumeAllThreads(SUSPEND_FOR_VERIFY);
}