You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by se...@apache.org on 2015/08/24 21:47:29 UTC
svn commit: r1697494 -
/commons/proper/bcel/trunk/src/examples/ClassDumper.java
Author: sebb
Date: Mon Aug 24 19:47:28 2015
New Revision: 1697494
URL: http://svn.apache.org/r1697494
Log:
BCEL-254 Two more methods that would be nice to be public.
Sample class using BCEL to produce output like javap
Added:
commons/proper/bcel/trunk/src/examples/ClassDumper.java (with props)
Added: commons/proper/bcel/trunk/src/examples/ClassDumper.java
URL: http://svn.apache.org/viewvc/commons/proper/bcel/trunk/src/examples/ClassDumper.java?rev=1697494&view=auto
==============================================================================
--- commons/proper/bcel/trunk/src/examples/ClassDumper.java (added)
+++ commons/proper/bcel/trunk/src/examples/ClassDumper.java Mon Aug 24 19:47:28 2015
@@ -0,0 +1,367 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ *
+ */
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.imageio.stream.FileImageInputStream;
+
+import org.apache.commons.bcel6.Constants;
+import org.apache.commons.bcel6.classfile.Attribute;
+import org.apache.commons.bcel6.classfile.ClassFormatException;
+import org.apache.commons.bcel6.classfile.Constant;
+import org.apache.commons.bcel6.classfile.ConstantPool;
+import org.apache.commons.bcel6.classfile.Field;
+import org.apache.commons.bcel6.classfile.Method;
+import org.apache.commons.bcel6.util.BCELifier;
+
+/**
+ * Display Java .class file data.
+ * Output is based on javap tool.
+ * Built using the BCEL libary.
+ *
+ */
+
+
+class ClassDumper {
+
+ private FileImageInputStream file;
+ private String file_name;
+ private int class_name_index;
+ private int superclass_name_index;
+ private int major;
+ private int minor; // Compiler version
+ private int access_flags; // Access rights of parsed class
+ private int[] interfaces; // Names of implemented interfaces
+ private ConstantPool constant_pool; // collection of constants
+ private Constant[] constant_items; // collection of constants
+ private Field[] fields; // class fields, i.e., its variables
+ private Method[] methods; // methods defined in the class
+ private Attribute[] attributes; // attributes defined in the class
+
+ /**
+ * Parse class from the given stream.
+ *
+ * @param file Input stream
+ * @param file_name File name
+ */
+ public ClassDumper (FileImageInputStream file, String file_name) {
+ this.file_name = file_name;
+ this.file = file;
+ }
+
+ /**
+ * Parse the given Java class file and return an object that represents
+ * the contained data, i.e., constants, methods, fields and commands.
+ * A <em>ClassFormatException</em> is raised, if the file is not a valid
+ * .class file. (This does not include verification of the byte code as it
+ * is performed by the java interpreter).
+ *
+ * @throws IOException
+ * @throws ClassFormatException
+ */
+ public void dump () throws IOException, ClassFormatException {
+ try {
+ // Check magic tag of class file
+ processID();
+ // Get compiler version
+ processVersion();
+ // process constant pool entries
+ processConstantPool();
+ // Get class information
+ processClassInfo();
+ // Get interface information, i.e., implemented interfaces
+ processInterfaces();
+ // process class fields, i.e., the variables of the class
+ processFields();
+ // process class methods, i.e., the functions in the class
+ processMethods();
+ // process class attributes
+ processAttributes();
+ } finally {
+ // Processed everything of interest, so close the file
+ try {
+ if (file != null) {
+ file.close();
+ }
+ } catch (IOException ioe) {
+ //ignore close exceptions
+ }
+ }
+ }
+
+ /**
+ * Check whether the header of the file is ok.
+ * Of course, this has to be the first action on successive file reads.
+ * @throws IOException
+ * @throws ClassFormatException
+ */
+ private final void processID () throws IOException, ClassFormatException {
+ final int magic = file.readInt();
+ if (magic != Constants.JVM_CLASSFILE_MAGIC) {
+ throw new ClassFormatException(file_name + " is not a Java .class file");
+ }
+ System.out.println("Java Class Dump");
+ System.out.println(" file: " + file_name);
+ System.out.printf("%nClass header:%n");
+ System.out.printf(" magic: %X%n", magic);
+ }
+
+ /**
+ * Process major and minor version of compiler which created the file.
+ * @throws IOException
+ * @throws ClassFormatException
+ */
+ private final void processVersion () throws IOException, ClassFormatException {
+ minor = file.readUnsignedShort();
+ System.out.printf(" minor version: %s%n", minor);
+
+ major = file.readUnsignedShort();
+ System.out.printf(" major version: %s%n", major);
+ }
+
+ /**
+ * Process constant pool entries.
+ * @throws IOException
+ * @throws ClassFormatException
+ */
+ private final void processConstantPool () throws IOException, ClassFormatException {
+ byte tag;
+ int constant_pool_count = file.readUnsignedShort();
+ constant_items = new Constant[constant_pool_count];
+ constant_pool = new ConstantPool(constant_items);
+
+ // constant_pool[0] is unused by the compiler
+ System.out.printf("%nConstant pool(%d):%n", constant_pool_count - 1);
+
+ for (int i = 1; i < constant_pool_count; i++) {
+ constant_items[i] = Constant.readConstant(file);
+ // i'm sure there is a better way to do this
+ if (i < 10) {
+ System.out.printf(" #%1d = ", i);
+ } else if (i <100) {
+ System.out.printf(" #%2d = ", i);
+ } else {
+ System.out.printf(" #%d = ", i);
+ }
+ System.out.println(constant_items[i]);
+
+ // All eight byte constants take up two spots in the constant pool
+ tag = constant_items[i].getTag();
+ if ((tag == Constants.CONSTANT_Double) ||
+ (tag == Constants.CONSTANT_Long)) {
+ i++;
+ }
+ }
+ }
+
+ /**
+ * Process information about the class and its super class.
+ * @throws IOException
+ * @throws ClassFormatException
+ */
+ private final void processClassInfo () throws IOException, ClassFormatException {
+ access_flags = file.readUnsignedShort();
+ /* Interfaces are implicitely abstract, the flag should be set
+ * according to the JVM specification.
+ */
+ if ((access_flags & Constants.ACC_INTERFACE) != 0) {
+ access_flags |= Constants.ACC_ABSTRACT;
+ }
+ if (((access_flags & Constants.ACC_ABSTRACT) != 0)
+ && ((access_flags & Constants.ACC_FINAL) != 0)) {
+ throw new ClassFormatException("Class " + file_name +
+ " can't be both final and abstract");
+ }
+
+ System.out.printf("%nClass info:%n");
+ System.out.println(" flags: " + BCELifier.printFlags(access_flags,
+ BCELifier.FLAGS.CLASS));
+ class_name_index = file.readUnsignedShort();
+ System.out.printf(" this_class: %d (", class_name_index);
+ System.out.println(constantToString(class_name_index) + ")");
+
+ superclass_name_index = file.readUnsignedShort();
+ System.out.printf(" super_class: %d (", superclass_name_index);
+ System.out.println(constantToString(superclass_name_index) + ")");
+ }
+
+ /**
+ * Process information about the interfaces implemented by this class.
+ * @throws IOException
+ * @throws ClassFormatException
+ */
+ private final void processInterfaces () throws IOException, ClassFormatException {
+ int interfaces_count;
+ interfaces_count = file.readUnsignedShort();
+ interfaces = new int[interfaces_count];
+
+ System.out.printf("%nInterfaces(%d):%n", interfaces_count);
+
+ for (int i = 0; i < interfaces_count; i++) {
+ interfaces[i] = file.readUnsignedShort();
+ // i'm sure there is a better way to do this
+ if (i < 10) {
+ System.out.printf(" #%1d = ", i);
+ } else if (i <100) {
+ System.out.printf(" #%2d = ", i);
+ } else {
+ System.out.printf(" #%d = ", i);
+ }
+ System.out.println(interfaces[i] + " (" +
+ constant_pool.getConstantString(interfaces[i],
+ Constants.CONSTANT_Class) + ")");
+ }
+ }
+
+ /**
+ * Process information about the fields of the class, i.e., its variables.
+ * @throws IOException
+ * @throws ClassFormatException
+ */
+ private final void processFields () throws IOException, ClassFormatException {
+ int fields_count;
+ fields_count = file.readUnsignedShort();
+ fields = new Field[fields_count];
+
+ // sometimes fields[0] is magic used for serialization
+ System.out.printf("%nFields(%d):%n", fields_count);
+
+ for (int i = 0; i < fields_count; i++) {
+ processFieldOrMethod(true);
+ if (i < fields_count - 1) {
+ System.out.println();
+ }
+ }
+ }
+
+ /**
+ * Process information about the methods of the class.
+ * @throws IOException
+ * @throws ClassFormatException
+ */
+ private final void processMethods () throws IOException, ClassFormatException {
+ int methods_count;
+ methods_count = file.readUnsignedShort();
+ methods = new Method[methods_count];
+
+ System.out.printf("%nMethods(%d):%n", methods_count);
+
+ for (int i = 0; i < methods_count; i++) {
+ processFieldOrMethod(false);
+ if (i < methods_count - 1) {
+ System.out.println();
+ }
+ }
+ }
+
+ /**
+ * Process information about the attributes of the class.
+ * @throws IOException
+ * @throws ClassFormatException
+ */
+ private final void processAttributes () throws IOException, ClassFormatException {
+ int attributes_count;
+ attributes_count = file.readUnsignedShort();
+ attributes = new Attribute[attributes_count];
+
+ System.out.printf("%nAttributes(%d):%n", attributes_count);
+
+ for (int i = 0; i < attributes_count; i++) {
+ attributes[i] = Attribute.readAttribute(file, constant_pool);
+ System.out.printf(" %s%n", attributes[i]);
+ }
+ }
+
+ /**
+ * Construct object from file stream.
+ * @param file Input stream
+ * @throws IOException
+ * @throws ClassFormatException
+ */
+ private final void processFieldOrMethod (boolean isField) throws IOException, ClassFormatException {
+ int access_flags = file.readUnsignedShort();
+ int name_index = file.readUnsignedShort();
+ System.out.printf(" name_index: %d (", name_index);
+ System.out.println(constantToString(name_index) + ")");
+ System.out.println(" access_flags: " + BCELifier.printFlags(access_flags,
+ BCELifier.FLAGS.METHOD));
+ int descriptor_index = file.readUnsignedShort();
+ System.out.printf(" descriptor_index: %d (", descriptor_index);
+ System.out.println(constantToString(descriptor_index) + ")");
+
+ int attributes_count = file.readUnsignedShort();
+ Attribute[] attributes = new Attribute[attributes_count];
+ System.out.println(" attribute count: " + attributes_count);
+
+ for (int i = 0; i < attributes_count; i++) {
+ // going to peek ahead a bit
+ file.mark();
+ int attribute_name_index = file.readUnsignedShort();
+ int attribute_length = file.readInt();
+ // restore file location
+ file.reset();
+ // Usefull for debugging
+ // System.out.printf(" attribute_name_index: %d (", attribute_name_index);
+ // System.out.println(constantToString(attribute_name_index) + ")");
+ // System.out.printf(" atribute offset in file: %x%n", + file.getStreamPosition());
+ // System.out.println(" atribute_length: " + attribute_length);
+
+ // A stronger verification test would be to read attribute_length bytes
+ // into a buffer. Then pass that buffer to readAttribute and also
+ // verify we're at EOF of the buffer on return.
+
+ long pos1 = file.getStreamPosition();
+ attributes[i] = Attribute.readAttribute(file, constant_pool);
+ long pos2 = file.getStreamPosition();
+ if ((pos2 - pos1) != (attribute_length + 6)) {
+ System.out.printf("%nWHOOPS attribute_length: %d pos2-pos1-6: %d pos1: %x(%d) pos2: %x(%d)%n",
+ attribute_length, pos2-pos1-6, pos1, pos1, pos2, pos2);
+ }
+ System.out.printf(" ");
+ if (isField) {
+ System.out.printf("%s: ", attributes[i].getName());
+ }
+ System.out.println(attributes[i]);
+ }
+ }
+
+ private final String constantToString (int index) {
+ Constant c = constant_items[index];
+ return constant_pool.constantToString(c);
+ }
+
+}
+
+class DumpClass {
+
+ public static void main (String[] args) throws IOException {
+
+ if (args.length != 1) {
+ throw new RuntimeException("Require filename as only argument");
+ }
+
+ FileImageInputStream file = new FileImageInputStream(new File(args[0]));
+
+ ClassDumper cd = new ClassDumper(file, args[0]);
+ cd.dump();
+
+ System.out.printf("End of Class Dump%n");
+
+ }
+}
Propchange: commons/proper/bcel/trunk/src/examples/ClassDumper.java
------------------------------------------------------------------------------
svn:eol-style = native