![JAR search and dependency download from the Maven repository](/logo.png)
com.sun.btrace.runtime.Verifier Maven / Gradle / Ivy
/*
* Copyright 2008-2010 Sun Microsystems, Inc. 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.btrace.runtime;
import java.io.File;
import java.io.FileInputStream;
import java.io.BufferedInputStream;
import java.util.ArrayList;
import java.util.List;
import com.sun.btrace.VerifierException;
import com.sun.btrace.annotations.TargetInstance;
import com.sun.btrace.annotations.TargetMethodOrField;
import com.sun.btrace.annotations.Duration;
import static com.sun.btrace.org.objectweb.asm.Opcodes.*;
import static com.sun.btrace.runtime.Constants.*;
import com.sun.btrace.annotations.Kind;
import com.sun.btrace.annotations.ProbeClassName;
import com.sun.btrace.annotations.ProbeMethodName;
import com.sun.btrace.annotations.Return;
import com.sun.btrace.annotations.Self;
import com.sun.btrace.annotations.Where;
import com.sun.btrace.util.Messages;
import com.sun.btrace.org.objectweb.asm.AnnotationVisitor;
import com.sun.btrace.org.objectweb.asm.ClassReader;
import com.sun.btrace.org.objectweb.asm.ClassVisitor;
import com.sun.btrace.org.objectweb.asm.FieldVisitor;
import com.sun.btrace.org.objectweb.asm.MethodVisitor;
import com.sun.btrace.org.objectweb.asm.Opcodes;
import com.sun.btrace.org.objectweb.asm.Type;
/**
* This class verifies that a BTrace program is safe
* and well-formed.
* Also it fills the onMethods and onProbes structures with the data taken from
* the annotations
*
* @author A. Sundararajan
* @autohr J. Bachorik
*/
public class Verifier extends ClassVisitor {
public static final String BTRACE_SELF_DESC = Type.getDescriptor(Self.class);
public static final String BTRACE_RETURN_DESC = Type.getDescriptor(Return.class);
public static final String BTRACE_TARGETMETHOD_DESC = Type.getDescriptor(TargetMethodOrField.class);
public static final String BTRACE_TARGETINSTANCE_DESC = Type.getDescriptor(TargetInstance.class);
public static final String BTRACE_DURATION_DESC = Type.getDescriptor(Duration.class);
public static final String BTRACE_PROBECLASSNAME_DESC = Type.getDescriptor(ProbeClassName.class);
public static final String BTRACE_PROBEMETHODNAME_DESC = Type.getDescriptor(ProbeMethodName.class);
private boolean seenBTrace;
private String className;
private List onMethods;
private List onProbes;
private boolean unsafe;
private CycleDetector cycleDetector;
public Verifier(ClassVisitor cv, boolean unsafe) {
super(Opcodes.ASM4, cv);
this.unsafe = unsafe;
onMethods = new ArrayList();
onProbes = new ArrayList();
cycleDetector = new CycleDetector();
}
public Verifier(ClassVisitor cv) {
this(cv, false);
}
public String getClassName() {
return className;
}
public List getOnMethods() {
return onMethods;
}
public List getOnProbes() {
return onProbes;
}
@Override
public void visitEnd() {
if (cycleDetector.hasCycle()) {
reportError("execution.loop.danger");
}
super.visitEnd();
}
public void visit(int version, int access, String name,
String signature, String superName, String[] interfaces) {
if ((access & ACC_INTERFACE) != 0 ||
(access & ACC_ENUM) != 0 ) {
reportError("btrace.program.should.be.class");
}
if ((access & ACC_PUBLIC) == 0) {
reportError("class.should.be.public", name);
}
if (! superName.equals(JAVA_LANG_OBJECT)) {
reportError("object.superclass.required", superName);
}
if (interfaces != null && interfaces.length > 0) {
reportError("no.interface.implementation");
}
className = name;
super.visit(version, access, name, signature,
superName, interfaces);
}
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
if (desc.equals(BTRACE_DESC)) {
seenBTrace = true;
}
return super.visitAnnotation(desc, visible);
}
public FieldVisitor visitField(int access, String name,
String desc, String signature, Object value) {
if (! seenBTrace) {
reportError("not.a.btrace.program");
}
if ((access & ACC_STATIC) == 0) {
reportError("agent.no.instance.variables", name);
}
return super.visitField(access, name, desc, signature, value);
}
public void visitInnerClass(String name, String outerName,
String innerName, int access) {
if (className.equals(outerName)) {
reportError("no.nested.class");
}
}
public MethodVisitor visitMethod(final int access, final String methodName,
final String methodDesc, String signature, String[] exceptions) {
if (! seenBTrace) {
reportError("not.a.btrace.program");
}
if ((access & ACC_SYNCHRONIZED) != 0) {
reportError("no.synchronized.methods", methodName + methodDesc);
}
if (! methodName.equals(CONSTRUCTOR)) {
if ((access & ACC_STATIC) == 0) {
reportError("no.instance.method", methodName + methodDesc);
}
}
MethodVisitor mv = super.visitMethod(access, methodName,
methodDesc, signature, exceptions);
return new MethodVerifier(this, mv, className, cycleDetector, methodName + methodDesc) {
private OnMethod om = null;
private boolean asBTrace = false;
@Override
public void visitEnd() {
if ((access & ACC_PUBLIC) == 0 && !methodName.equals(CLASS_INITIALIZER)) {
if (asBTrace) { // only btrace handlers are enforced to be public
reportError("method.should.be.public", methodName + methodDesc);
}
}
if (Type.getReturnType(methodDesc) != Type.VOID_TYPE) {
if (asBTrace) {
reportError("return.type.should.be.void", methodName + methodDesc);
}
}
super.visitEnd();
}
@Override
public AnnotationVisitor visitParameterAnnotation(int parameter, final String desc, boolean visible) {
if (desc.equals(BTRACE_SELF_DESC)) {
// all allowed
if (om != null) {
om.setSelfParameter(parameter);
}
}
if (desc.equals(BTRACE_RETURN_DESC)) {
if (om != null) {
if (om.getLocation().getValue() == Kind.RETURN ||
(om.getLocation().getValue() == Kind.CALL && om.getLocation().getWhere() == Where.AFTER) ||
(om.getLocation().getValue() == Kind.ARRAY_GET && om.getLocation().getWhere() == Where.AFTER) ||
(om.getLocation().getValue() == Kind.FIELD_GET && om.getLocation().getWhere() == Where.AFTER) ||
(om.getLocation().getValue() == Kind.NEW && om.getLocation().getWhere() == Where.AFTER) ||
(om.getLocation().getValue() == Kind.NEWARRAY && om.getLocation().getWhere() == Where.AFTER)) {
om.setReturnParameter(parameter);
} else {
reportError("return.desc.invalid", methodName + methodDesc + "(" + parameter + ")");
}
}
}
if (desc.equals(BTRACE_TARGETMETHOD_DESC)) {
if (om != null) {
if (om.getLocation().getValue() == Kind.CALL ||
om.getLocation().getValue() == Kind.FIELD_GET ||
om.getLocation().getValue() == Kind.FIELD_SET) {
om.setTargetMethodOrFieldParameter(parameter);
} else {
reportError("called-method.desc.invalid", methodName + methodDesc + "(" + parameter + ")");
}
}
}
if (desc.equals(BTRACE_TARGETINSTANCE_DESC)) {
if (om != null) {
if (om.getLocation().getValue() == Kind.CALL ||
om.getLocation().getValue() == Kind.FIELD_GET ||
om.getLocation().getValue() == Kind.FIELD_SET) {
om.setTargetInstanceParameter(parameter);
} else {
reportError("called-instance.desc.invalid", methodName + methodDesc + "(" + parameter + ")");
}
}
}
if (desc.equals(BTRACE_DURATION_DESC)) {
if (om != null) {
if (om.getLocation().getValue() == Kind.RETURN || om.getLocation().getValue() == Kind.ERROR) {
om.setDurationParameter(parameter);
} else {
reportError("duration.desc.invalid", methodName + methodDesc + "(" + parameter + ")");
}
}
}
if (desc.equals(BTRACE_PROBECLASSNAME_DESC)) {
// allowed for all
if (om != null) {
om.setClassNameParameter(parameter);
}
}
if (desc.equals(BTRACE_PROBEMETHODNAME_DESC)) {
// allowed for all
if (om != null) {
om.setMethodParameter(parameter);
}
}
return new AnnotationVisitor(Opcodes.ASM4, super.visitParameterAnnotation(parameter, desc, visible)) {
public void visit(String string, Object o) {
if (om != null && string.equals("fqn")) { // NOI18N
if (desc.equals(BTRACE_TARGETMETHOD_DESC)) {
om.setTargetMethodOrFieldFqn((Boolean)o);
} else if (desc.equals(BTRACE_PROBEMETHODNAME_DESC)) {
om.setMethodFqn((Boolean)o);
}
}
super.visit(string, o);
}
};
}
public AnnotationVisitor visitAnnotation(String desc,
boolean visible) {
if (desc.startsWith("Lcom/sun/btrace/annotations/")) {
asBTrace = true;
cycleDetector.addStarting(new CycleDetector.Node(methodName + methodDesc));
}
if (desc.equals(ONMETHOD_DESC)) {
om = new OnMethod();
onMethods.add(om);
om.setTargetName(methodName);
om.setTargetDescriptor(methodDesc);
return new AnnotationVisitor(Opcodes.ASM4) {
public void visit(String name, Object value) {
if (name.equals("clazz")) {
om.setClazz((String)value);
} else if (name.equals("method")) {
om.setMethod((String)value);
} else if (name.equals("type")) {
om.setType((String)value);
}
}
public AnnotationVisitor visitAnnotation(String name,
String desc) {
if (desc.equals(LOCATION_DESC)) {
final Location loc = new Location();
return new AnnotationVisitor(Opcodes.ASM4) {
public void visitEnum(String name, String desc, String value) {
if (desc.equals(WHERE_DESC)) {
loc.setWhere(Enum.valueOf(Where.class, value));
} else if (desc.equals(KIND_DESC)) {
loc.setValue(Enum.valueOf(Kind.class, value));
}
}
public void visit(String name, Object value) {
if (name.equals("clazz")) {
loc.setClazz((String)value);
} else if (name.equals("method")) {
loc.setMethod((String)value);
} else if (name.equals("type")) {
loc.setType((String)value);
} else if (name.equals("field")) {
loc.setField((String)value);
} else if (name.equals("line")) {
loc.setLine(((Number)value).intValue());
}
}
public void visitEnd() {
om.setLocation(loc);
}
};
}
return super.visitAnnotation(name, desc);
}
};
} else if (desc.equals(ONPROBE_DESC)) {
final OnProbe op = new OnProbe();
onProbes.add(op);
op.setTargetName(methodName);
op.setTargetDescriptor(methodDesc);
return new AnnotationVisitor(Opcodes.ASM4) {
public void visit(String name, Object value) {
if (name.equals("namespace")) {
op.setNamespace((String)value);
} else if (name.equals("name")) {
op.setName((String)value);
}
}
};
} else {
return new AnnotationVisitor(Opcodes.ASM4) {};
}
}
};
}
public void visitOuterClass(String owner, String name,
String desc) {
reportError("no.outer.class");
}
void reportError(String err) {
reportError(err, null);
}
void reportError(String err, String msg) {
if (unsafe) return;
String str = Messages.get(err);
if (msg != null) {
str += ": " + msg;
}
throw new VerifierException(str);
}
private static void usage(String msg) {
System.err.println(msg);
System.exit(1);
}
// simple test main
public static void main(String[] args) throws Exception {
if (args.length == 0) {
usage("java com.sun.btrace.runtime.Verifier <.class file>");
}
args[0] = args[0].replace('.', '/');
File file = new File(args[0] + ".class");
if (! file.exists()) {
usage("file '" + args[0] + ".class' does not exist");
}
FileInputStream fis = new FileInputStream(file);
ClassReader reader = new ClassReader(new BufferedInputStream(fis));
Verifier verifier = new Verifier(new ClassVisitor(Opcodes.ASM4) {});
reader.accept(verifier, 0);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy