diff options
Diffstat (limited to 'tools/external/asm/org/objectweb/asm/util/TraceClassVisitor.java')
-rw-r--r-- | tools/external/asm/org/objectweb/asm/util/TraceClassVisitor.java | 534 |
1 files changed, 534 insertions, 0 deletions
diff --git a/tools/external/asm/org/objectweb/asm/util/TraceClassVisitor.java b/tools/external/asm/org/objectweb/asm/util/TraceClassVisitor.java new file mode 100644 index 000000000..9a727e50f --- /dev/null +++ b/tools/external/asm/org/objectweb/asm/util/TraceClassVisitor.java @@ -0,0 +1,534 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.util; + +import java.io.FileInputStream; +import java.io.PrintWriter; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Attribute; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.signature.SignatureReader; + +/** + * A {@link ClassVisitor} that prints a disassembled view of the classes it + * visits. This class visitor can be used alone (see the {@link #main main} + * method) to disassemble a class. It can also be used in the middle of class + * visitor chain to trace the class that is visited at a given point in this + * chain. This may be uselful for debugging purposes. <p> The trace printed when + * visiting the <tt>Hello</tt> class is the following: <p> <blockquote> + * + * <pre> + * // class version 49.0 (49) + * // access flags 33 + * public class Hello { + * + * // compiled from: Hello.java + * + * // access flags 1 + * public <init> ()V + * ALOAD 0 + * INVOKESPECIAL java/lang/Object <init> ()V + * RETURN + * MAXSTACK = 1 + * MAXLOCALS = 1 + * + * // access flags 9 + * public static main ([Ljava/lang/String;)V + * GETSTATIC java/lang/System out Ljava/io/PrintStream; + * LDC "hello" + * INVOKEVIRTUAL java/io/PrintStream println (Ljava/lang/String;)V + * RETURN + * MAXSTACK = 2 + * MAXLOCALS = 1 + * } + * </pre> + * + * </blockquote> where <tt>Hello</tt> is defined by: <p> <blockquote> + * + * <pre> + * public class Hello { + * + * public static void main(String[] args) { + * System.out.println("hello"); + * } + * } + * </pre> + * + * </blockquote> + * + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +public class TraceClassVisitor extends TraceAbstractVisitor implements + ClassVisitor +{ + + /** + * The {@link ClassVisitor} to which this visitor delegates calls. May be + * <tt>null</tt>. + */ + protected final ClassVisitor cv; + + /** + * The print writer to be used to print the class. + */ + protected final PrintWriter pw; + + /** + * Prints a disassembled view of the given class to the standard output. <p> + * Usage: TraceClassVisitor [-debug] <fully qualified class name or class + * file name > + * + * @param args the command line arguments. + * + * @throws Exception if the class cannot be found, or if an IO exception + * occurs. + */ + public static void main(final String[] args) throws Exception { + int i = 0; + boolean skipDebug = true; + + boolean ok = true; + if (args.length < 1 || args.length > 2) { + ok = false; + } + if (ok && args[0].equals("-debug")) { + i = 1; + skipDebug = false; + if (args.length != 2) { + ok = false; + } + } + if (!ok) { + System.err.println("Prints a disassembled view of the given class."); + System.err.println("Usage: TraceClassVisitor [-debug] " + + "<fully qualified class name or class file name>"); + return; + } + ClassReader cr; + if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1 + || args[i].indexOf('/') > -1) + { + cr = new ClassReader(new FileInputStream(args[i])); + } else { + cr = new ClassReader(args[i]); + } + cr.accept(new TraceClassVisitor(new PrintWriter(System.out)), + getDefaultAttributes(), + skipDebug); + } + + /** + * Constructs a new {@link TraceClassVisitor}. + * + * @param pw the print writer to be used to print the class. + */ + public TraceClassVisitor(final PrintWriter pw) { + this(null, pw); + } + + /** + * Constructs a new {@link TraceClassVisitor}. + * + * @param cv the {@link ClassVisitor} to which this visitor delegates calls. + * May be <tt>null</tt>. + * @param pw the print writer to be used to print the class. + */ + public TraceClassVisitor(final ClassVisitor cv, final PrintWriter pw) { + this.cv = cv; + this.pw = pw; + } + + // ------------------------------------------------------------------------ + // Implementation of the ClassVisitor interface + // ------------------------------------------------------------------------ + + public void visit( + final int version, + final int access, + final String name, + final String signature, + final String superName, + final String[] interfaces) + { + int major = version & 0xFFFF; + int minor = version >>> 16; + buf.setLength(0); + buf.append("// class version ") + .append(major) + .append('.') + .append(minor) + .append(" (") + .append(version) + .append(")\n"); + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + buf.append("// DEPRECATED\n"); + } + buf.append("// access flags ").append(access).append('\n'); + + appendDescriptor(CLASS_SIGNATURE, signature); + if (signature != null) { + TraceSignatureVisitor sv = new TraceSignatureVisitor(access); + SignatureReader r = new SignatureReader(signature); + r.accept(sv); + buf.append("// declaration: ") + .append(name) + .append(sv.getDeclaration()) + .append('\n'); + } + + appendAccess(access & ~Opcodes.ACC_SUPER); + if ((access & Opcodes.ACC_ANNOTATION) != 0) { + buf.append("@interface "); + } else if ((access & Opcodes.ACC_INTERFACE) != 0) { + buf.append("interface "); + } else if ((access & Opcodes.ACC_ENUM) != 0) { + buf.append("enum "); + } else { + buf.append("class "); + } + appendDescriptor(INTERNAL_NAME, name); + + if (superName != null && !superName.equals("java/lang/Object")) { + buf.append(" extends "); + appendDescriptor(INTERNAL_NAME, superName); + buf.append(' '); + } + if (interfaces != null && interfaces.length > 0) { + buf.append(" implements "); + for (int i = 0; i < interfaces.length; ++i) { + appendDescriptor(INTERNAL_NAME, interfaces[i]); + buf.append(' '); + } + } + buf.append(" {\n\n"); + + text.add(buf.toString()); + + if (cv != null) { + cv.visit(version, access, name, signature, superName, interfaces); + } + } + + public void visitSource(final String file, final String debug) { + buf.setLength(0); + if (file != null) { + buf.append(tab) + .append("// compiled from: ") + .append(file) + .append('\n'); + } + if (debug != null) { + buf.append(tab) + .append("// debug info: ") + .append(debug) + .append('\n'); + } + if (buf.length() > 0) { + text.add(buf.toString()); + } + + if (cv != null) { + cv.visitSource(file, debug); + } + } + + public void visitOuterClass( + final String owner, + final String name, + final String desc) + { + buf.setLength(0); + buf.append(tab).append("OUTERCLASS "); + appendDescriptor(INTERNAL_NAME, owner); + // if enclosing name is null, so why should we show this info? + if (name != null) { + buf.append(' ').append(name).append(' '); + } else { + buf.append(' '); + } + appendDescriptor(METHOD_DESCRIPTOR, desc); + buf.append('\n'); + text.add(buf.toString()); + + if (cv != null) { + cv.visitOuterClass(owner, name, desc); + } + } + + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + text.add("\n"); + AnnotationVisitor tav = super.visitAnnotation(desc, visible); + if (cv != null) { + ((TraceAnnotationVisitor) tav).av = cv.visitAnnotation(desc, + visible); + } + return tav; + } + + public void visitAttribute(final Attribute attr) { + text.add("\n"); + super.visitAttribute(attr); + + if (cv != null) { + cv.visitAttribute(attr); + } + } + + public void visitInnerClass( + final String name, + final String outerName, + final String innerName, + final int access) + { + buf.setLength(0); + buf.append(tab).append("// access flags ").append(access + & ~Opcodes.ACC_SUPER).append('\n'); + buf.append(tab); + appendAccess(access); + buf.append("INNERCLASS "); + if ((access & Opcodes.ACC_ENUM) != 0) { + buf.append("enum "); + } + appendDescriptor(INTERNAL_NAME, name); + buf.append(' '); + appendDescriptor(INTERNAL_NAME, outerName); + buf.append(' '); + appendDescriptor(INTERNAL_NAME, innerName); + buf.append('\n'); + text.add(buf.toString()); + + if (cv != null) { + cv.visitInnerClass(name, outerName, innerName, access); + } + } + + public FieldVisitor visitField( + final int access, + final String name, + final String desc, + final String signature, + final Object value) + { + buf.setLength(0); + buf.append('\n'); + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + buf.append(tab).append("// DEPRECATED\n"); + } + buf.append(tab).append("// access flags ").append(access).append('\n'); + if (signature != null) { + buf.append(tab); + appendDescriptor(FIELD_SIGNATURE, signature); + + TraceSignatureVisitor sv = new TraceSignatureVisitor(0); + SignatureReader r = new SignatureReader(signature); + r.acceptType(sv); + buf.append(tab) + .append("// declaration: ") + .append(sv.getDeclaration()) + .append('\n'); + } + + buf.append(tab); + appendAccess(access); + if ((access & Opcodes.ACC_ENUM) != 0) { + buf.append("enum "); + } + + appendDescriptor(FIELD_DESCRIPTOR, desc); + buf.append(' ').append(name); + if (value != null) { + buf.append(" = "); + if (value instanceof String) { + buf.append("\"").append(value).append("\""); + } else { + buf.append(value); + } + } + + buf.append('\n'); + text.add(buf.toString()); + + TraceFieldVisitor tav = createTraceFieldVisitor(); + text.add(tav.getText()); + + if (cv != null) { + tav.fv = cv.visitField(access, name, desc, signature, value); + } + + return tav; + } + + public MethodVisitor visitMethod( + final int access, + final String name, + final String desc, + final String signature, + final String[] exceptions) + { + buf.setLength(0); + buf.append('\n'); + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + buf.append(tab).append("// DEPRECATED\n"); + } + buf.append(tab).append("// access flags ").append(access).append('\n'); + buf.append(tab); + appendDescriptor(METHOD_SIGNATURE, signature); + + if (signature != null) { + TraceSignatureVisitor v = new TraceSignatureVisitor(0); + SignatureReader r = new SignatureReader(signature); + r.accept(v); + String genericDecl = v.getDeclaration(); + String genericReturn = v.getReturnType(); + String genericExceptions = v.getExceptions(); + + buf.append(tab) + .append("// declaration: ") + .append(genericReturn) + .append(' ') + .append(name) + .append(genericDecl); + if (genericExceptions != null) { + buf.append(" throws ").append(genericExceptions); + } + buf.append('\n'); + } + + appendAccess(access); + if ((access & Opcodes.ACC_NATIVE) != 0) { + buf.append("native "); + } + if ((access & Opcodes.ACC_VARARGS) != 0) { + buf.append("varargs "); + } + if ((access & Opcodes.ACC_BRIDGE) != 0) { + buf.append("bridge "); + } + + buf.append(name); + appendDescriptor(METHOD_DESCRIPTOR, desc); + if (exceptions != null && exceptions.length > 0) { + buf.append(" throws "); + for (int i = 0; i < exceptions.length; ++i) { + appendDescriptor(INTERNAL_NAME, exceptions[i]); + buf.append(' '); + } + } + + buf.append('\n'); + text.add(buf.toString()); + + TraceMethodVisitor tcv = createTraceMethodVisitor(); + text.add(tcv.getText()); + + if (cv != null) { + tcv.mv = cv.visitMethod(access, name, desc, signature, exceptions); + } + + return tcv; + } + + public void visitEnd() { + text.add("}\n"); + + printList(pw, text); + pw.flush(); + + if (cv != null) { + cv.visitEnd(); + } + } + + // ------------------------------------------------------------------------ + // Utility methods + // ------------------------------------------------------------------------ + + protected TraceFieldVisitor createTraceFieldVisitor() { + return new TraceFieldVisitor(); + } + + protected TraceMethodVisitor createTraceMethodVisitor() { + return new TraceMethodVisitor(); + } + + /** + * Appends a string representation of the given access modifiers to {@link + * #buf buf}. + * + * @param access some access modifiers. + */ + private void appendAccess(final int access) { + if ((access & Opcodes.ACC_PUBLIC) != 0) { + buf.append("public "); + } + if ((access & Opcodes.ACC_PRIVATE) != 0) { + buf.append("private "); + } + if ((access & Opcodes.ACC_PROTECTED) != 0) { + buf.append("protected "); + } + if ((access & Opcodes.ACC_FINAL) != 0) { + buf.append("final "); + } + if ((access & Opcodes.ACC_STATIC) != 0) { + buf.append("static "); + } + if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) { + buf.append("synchronized "); + } + if ((access & Opcodes.ACC_VOLATILE) != 0) { + buf.append("volatile "); + } + if ((access & Opcodes.ACC_TRANSIENT) != 0) { + buf.append("transient "); + } + // if ((access & Constants.ACC_NATIVE) != 0) { + // buf.append("native "); + // } + if ((access & Opcodes.ACC_ABSTRACT) != 0) { + buf.append("abstract "); + } + if ((access & Opcodes.ACC_STRICT) != 0) { + buf.append("strictfp "); + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + buf.append("synthetic "); + } + } +} |