blob: b8ac19f0a9c3dbe0ad6dba33a1a624437a196ef7 [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"
#include "alloc/HeapBitmap.h"
/*
* Helper routine for verifyRefernce that masks low-tag bits before
* applying verification checks. TODO: eliminate the use of low-tag
* bits and move this code into verfiyReference.
*/
static void verifyReferenceUnmask(const void *addr, uintptr_t mask)
{
const Object *obj;
uintptr_t tmp;
bool isValid;
tmp = (uintptr_t)*(const Object **)addr;
obj = (const Object *)(tmp & ~mask);
if (obj == NULL) {
isValid = true;
} else {
isValid = dvmIsValidObject(obj);
}
if (!isValid) {
LOGE("Verify of object %p @ %p failed", obj, addr);
dvmAbort();
}
}
/*
* Assertion that the given reference points to a valid object.
*/
static void verifyReference(const void *addr)
{
verifyReferenceUnmask(addr, 0);
}
/*
* 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);
verifyReference(&((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)
{
int i;
LOGV("Entering verifyClassObject(obj=%p)", obj);
if (obj == gDvm.unlinkedJavaLangClass) {
assert(obj->obj.clazz == NULL);
goto exit;
}
verifyReference(&obj->obj.clazz);
assert(!strcmp(obj->obj.clazz->descriptor, "Ljava/lang/Class;"));
if (IS_CLASS_FLAG_SET(obj, CLASS_ISARRAY)) {
verifyReference(&obj->elementClass);
}
verifyReference(&obj->super);
verifyReference(&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') {
verifyReference(&obj->sfields[i].value.l);
}
}
/* Verify the instance fields. */
verifyInstanceFields((const Object *)obj);
/* Verify interface references. */
for (i = 0; i < obj->interfaceCount; ++i) {
verifyReference(&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);
verifyReference(&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) {
verifyReference(&contents[i]);
}
}
LOGV("Exiting verifyArrayObject(array=%p)", array);
}
/*
* Verifies the header and field references of a data object.
*/
static void verifyDataObject(const DataObject *obj)
{
LOGV("Entering verifyDataObject(obj=%p)", obj);
/* Verify the class object. */
assert(obj->obj.clazz != NULL);
verifyReference(&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);
verifyReference(&((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);
}
/*
* Applies a verification function to all present values in the hash table.
*/
static void verifyHashTable(HashTable *table,
void (*callback)(const void *arg))
{
int i;
assert(table != NULL);
assert(callback != NULL);
dvmHashTableLock(table);
for (i = 0; i < table->tableSize; ++i) {
const HashEntry *entry = &table->pEntries[i];
if (entry->data != NULL && entry->data != HASH_TOMBSTONE) {
(*callback)(&entry->data);
}
}
dvmHashTableUnlock(table);
}
/*
* Applies the verify routine to the given object.
*/
static void verifyStringReference(const void *arg)
{
assert(arg != NULL);
verifyReferenceUnmask(arg, 0x1);
}
/*
* Verifies all entries in the reference table.
*/
static void verifyReferenceTable(const ReferenceTable *table)
{
Object **entry;
assert(table != NULL);
for (entry = table->table; entry < table->nextEntry; ++entry) {
assert(entry != NULL);
verifyReference(entry);
}
}
/*
* Verifies roots. TODO: verify all roots.
*/
void dvmVerifyRoots(void)
{
verifyHashTable(gDvm.loadedClasses, verifyReference);
verifyHashTable(gDvm.dbgRegistry, verifyReference);
verifyHashTable(gDvm.internedStrings, verifyStringReference);
verifyReferenceTable(&gDvm.jniGlobalRefTable);
verifyReferenceTable(&gDvm.jniPinRefTable);
verifyReferenceTable(&gDvm.gcHeap->nonCollectableRefs);
/* TODO: verify cached global references. */
/* TODO: verify threads and stacks. */
/* TODO: verify finalizer and reference operation queues. */
}