/* * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code 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 * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.max.vm.verifier; import static com.sun.max.vm.verifier.types.VerificationType.*; import java.util.*; import com.sun.max.annotate.*; import com.sun.max.collect.*; import com.sun.max.unsafe.*; import com.sun.max.vm.*; import com.sun.max.vm.actor.holder.*; import com.sun.max.vm.classfile.constant.*; import com.sun.max.vm.type.*; import com.sun.max.vm.verifier.types.*; /** * Encapsulates the contexts an options for bytecode verification. */ public class Verifier implements VerificationRegistry { static final int TRACE_NONE = 0; static final int TRACE_CLASS = 1; static final int TRACE_METHOD = 2; /** * The level of bytecode verification tracing. */ public static int TraceVerifierLevel; static { VMOptions.addFieldOption("-XX:", "TraceVerifierLevel", "Trace bytecode verification level: 0 = none, 1 = class, 2 = methods."); } /** * If non-null, then the verification of any methods whose fully qualified name contains this field value as * a substring is traced in detail. */ public static String TraceVerification; static { VMOptions.addFieldOption("-XX:", "TraceVerification", "Trace bytecode verification in detail of method(s) whose qualified name contains <value>."); } /** * Determines if verification is performed for classes loaded locally. */ @RESET private static boolean BytecodeVerificationLocal; static { VMOptions.addFieldOption("-XX:", "BytecodeVerificationLocal", "Enable verification of local classes."); } /** * Determines if verification is performed for classes loaded over network. */ private static boolean BytecodeVerificationRemote = true; static { VMOptions.addFieldOption("-XX:", "BytecodeVerificationRemote", "Enable verification of remote classes."); } static { // -Xverify option VMOptions.register(new VMOption("-Xverify", "Enable verification process on classes loaded over network (default), all classes, or no classes respectively.") { @Override public boolean parseValue(Pointer optionValue) { if (CString.equals(optionValue, ":all") || CString.length(optionValue).isZero()) { BytecodeVerificationLocal = true; BytecodeVerificationRemote = true; } else if (CString.equals(optionValue, ":none")) { BytecodeVerificationLocal = false; BytecodeVerificationRemote = false; } else if (CString.equals(optionValue, ":remote")) { BytecodeVerificationLocal = false; BytecodeVerificationRemote = true; } else { return false; } return true; } @Override public void printHelp() { VMOptions.printHelpForOption(category(), "-Xverify[:remote|all|none]", "", help); } }, MaxineVM.Phase.STARTING); } /** * Hotspot supports this undocumented option. Maxine must do some verification because it must process class files * whose version is older than 50.0 to remove jsr/ret constriucts, which it does by using the verifier. So this * option simply turns of the error reporting and lets the verifier continue. */ static VMOption noVerify = new VMOption("-noverify ", "suppress all verification"); static { VMOptions.register(noVerify, MaxineVM.Phase.PRISTINE); } /** * Determines if a class loaded by a given class loader needs bytecode verification. * The answer depends upon {@code classLoader} <i>and</i> the values of * {@link #BytecodeVerificationLocal} and {@link #BytecodeVerificationRemote}. * * @param classLoader the class loader to test * @param isRemote specifies if the stream is from a remote/untrusted (e.g. network) source. This is mainly used to * determine the default bytecode verification policy for the class. * @return {@code true} if a class loaded by {@code classLoader} need bytecode verification */ public static boolean shouldBeVerified(ClassLoader classLoader, boolean isRemote) { if (classLoader == BootClassLoader.BOOT_CLASS_LOADER || classLoader == null || !isRemote) { return BytecodeVerificationLocal; } return BytecodeVerificationRemote; } public static boolean relaxVerificationFor(ClassLoader classLoader) { boolean trusted = isTrustedLoader(classLoader); boolean needVerify = // -Xverify:all (BytecodeVerificationLocal && BytecodeVerificationRemote) || // -Xverify:remote (!BytecodeVerificationLocal && BytecodeVerificationRemote && !trusted); return !needVerify; } private static boolean isTrustedLoader(ClassLoader classLoader) { ClassLoader cl = ClassLoader.getSystemClassLoader(); while (cl != null) { if (cl == classLoader) { return true; } cl = cl.getParent(); } return false; } private final ConstantPool constantPool; private final Map<TypeDescriptor, ObjectType> objectTypes; private final IntHashMap<UninitializedNewType> uninitializedNewTypes; private IntHashMap<Subroutine> subroutines; public boolean verbose; public Verifier(ConstantPool constantPool) { this.constantPool = constantPool; this.objectTypes = new HashMap<TypeDescriptor, ObjectType>(); this.uninitializedNewTypes = new IntHashMap<UninitializedNewType>(); for (ObjectType objectType : PREDEFINED_OBJECT_TYPES) { objectTypes.put(objectType.typeDescriptor(), objectType); } } public VerificationType getObjectType(TypeDescriptor typeDescriptor) { if (JavaTypeDescriptor.isPrimitive(typeDescriptor)) { return null; } if (typeDescriptor.toKind().isWord) { return VerificationType.WORD; } ObjectType objectType = objectTypes.get(typeDescriptor); if (objectType == null) { // throws LinkageError if type can't be resolved resolve(typeDescriptor); objectType = JavaTypeDescriptor.isArray(typeDescriptor) ? new ArrayType(typeDescriptor, this) : new ObjectType(typeDescriptor, this); objectTypes.put(typeDescriptor, objectType); } return objectType; } public UninitializedNewType getUninitializedNewType(int bci) { UninitializedNewType uninitializedNewType = uninitializedNewTypes.get(bci); if (uninitializedNewType == null) { uninitializedNewType = new UninitializedNewType(bci); uninitializedNewTypes.put(bci, uninitializedNewType); } return uninitializedNewType; } public int clearSubroutines() { if (subroutines != null) { final int count = subroutines.count(); subroutines = null; return count; } return 0; } public Subroutine getSubroutine(int entryBCI, int maxLocals) { if (subroutines == null) { subroutines = new IntHashMap<Subroutine>(); } Subroutine subroutine = subroutines.get(entryBCI); if (subroutine == null) { subroutine = new Subroutine(entryBCI, maxLocals); subroutines.put(entryBCI, subroutine); } return subroutine; } public VerificationType getVerificationType(TypeDescriptor typeDescriptor) { return VerificationType.getVerificationType(typeDescriptor, this); } public ConstantPool constantPool() { return constantPool; } public static ClassVerifier verifierFor(ClassActor classActor) { final int majorVersion = classActor.majorVersion; if (majorVersion >= 50) { return new TypeCheckingVerifier(classActor); } return new TypeInferencingVerifier(classActor); } /** * Resolves a given TypeDescriptor to a class actor. */ public ClassActor resolve(TypeDescriptor type) { return ClassActor.fromJava(type.resolveType(constantPool().classLoader())); } }