| /* |
| * Copyright (c) 2005, 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 ilib; |
| |
| import java.io.IOException; |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.DataOutputStream; |
| import java.io.PrintStream; |
| import java.io.PrintWriter; |
| import java.io.CharArrayWriter; |
| import java.util.List; |
| import java.util.Iterator; |
| import java.util.ArrayList; |
| |
| public class ClassDump implements RuntimeConstants { |
| |
| public static void dump(Options opt, |
| ClassLoader loader, |
| String className, |
| byte[] classfileBuffer) { |
| ClassReaderWriter c = new ClassReaderWriter(classfileBuffer); |
| (new ClassDump(className, c)).doit(); |
| } |
| |
| static boolean verbose = true; |
| |
| final String className; |
| final ClassReaderWriter c; |
| private final PrintStream output; |
| |
| int constantPoolCount; |
| int methodsCount; |
| |
| ClassDump(String className, ClassReaderWriter c) { |
| this.className = className; |
| this.c = c; |
| this.output = System.err; |
| } |
| |
| void doit() { |
| int i; |
| c.copy(4 + 2 + 2); // magic min/maj version |
| constantPoolCount = c.copyU2(); |
| // copy old constant pool |
| c.copyConstantPool(constantPoolCount); |
| |
| traceln("ConstantPool size: " + constantPoolCount); |
| |
| c.copy(2 + 2 + 2); // access, this, super |
| int interfaceCount = c.copyU2(); |
| traceln("interfaceCount: " + interfaceCount); |
| c.copy(interfaceCount * 2); |
| copyFields(); // fields |
| copyMethods(); // methods |
| int attrCount = c.copyU2(); |
| traceln("class attrCount: " + attrCount); |
| // copy the class attributes |
| copyAttrs(attrCount); |
| } |
| |
| |
| void copyFields() { |
| int count = c.copyU2(); |
| if (verbose) { |
| System.out.println("fields count: " + count); |
| } |
| for (int i = 0; i < count; ++i) { |
| c.copy(6); // access, name, descriptor |
| int attrCount = c.copyU2(); |
| if (verbose) { |
| System.out.println("field attr count: " + attrCount); |
| } |
| copyAttrs(attrCount); |
| } |
| } |
| |
| void copyMethods() { |
| methodsCount = c.copyU2(); |
| if (verbose) { |
| System.out.println("methods count: " + methodsCount); |
| } |
| for (int i = 0; i < methodsCount; ++i) { |
| copyMethod(); |
| } |
| } |
| |
| void copyMethod() { |
| int accessFlags = c.copyU2();// access flags |
| int nameIndex = c.copyU2(); // name |
| checkIndex(nameIndex, "Method name"); |
| String methodName = c.constantPoolString(nameIndex); |
| traceln("method: " + methodName); |
| int descriptorIndex = c.copyU2(); // descriptor |
| checkIndex(descriptorIndex, "Method descriptor"); |
| int attrCount = c.copyU2(); // attribute count |
| if (verbose) { |
| System.out.println("method attr count: " + attrCount); |
| } |
| for (int i = 0; i < attrCount; ++i) { |
| copyAttrForMethod(methodName, accessFlags); |
| } |
| } |
| |
| void copyAttrs(int attrCount) { |
| for (int i = 0; i < attrCount; ++i) { |
| copyAttr(); |
| } |
| } |
| |
| void copyAttr() { |
| c.copy(2); // name |
| int len = c.copyU4(); // attr len |
| if (verbose) { |
| System.out.println("attr len: " + len); |
| } |
| c.copy(len); // attribute info |
| } |
| |
| void copyAttrForMethod(String methodName, int accessFlags) { |
| int nameIndex = c.copyU2(); // name |
| // check for Code attr |
| checkIndex(nameIndex, "Method attr name"); |
| if (nameIndex == c.codeAttributeIndex) { |
| try { |
| copyCodeAttr(methodName); |
| } catch (IOException exc) { |
| System.err.println("Code Exception - " + exc); |
| System.exit(1); |
| } |
| } else { |
| int len = c.copyU4(); // attr len |
| traceln("method attr len: " + len); |
| c.copy(len); // attribute info |
| } |
| } |
| |
| void copyAttrForCode() throws IOException { |
| int nameIndex = c.copyU2(); // name |
| |
| checkIndex(nameIndex, "Code attr name"); |
| int len = c.copyU4(); // attr len |
| traceln("code attr len: " + len); |
| c.copy(len); // attribute info |
| } |
| |
| void copyCodeAttr(String methodName) throws IOException { |
| traceln("Code attr found"); |
| int attrLength = c.copyU4(); // attr len |
| checkLength(attrLength, "Code attr length"); |
| int maxStack = c.readU2(); // max stack |
| c.copyU2(); // max locals |
| int codeLength = c.copyU4(); // code length |
| checkLength(codeLength, "Code length"); |
| |
| copyExceptionTable(); |
| |
| int attrCount = c.copyU2(); |
| checkLength(attrCount, "Code attr count"); |
| for (int i = 0; i < attrCount; ++i) { |
| copyAttrForCode(); |
| } |
| } |
| |
| /** |
| * Copy the exception table for this method code |
| */ |
| void copyExceptionTable() throws IOException { |
| int tableLength = c.copyU2(); // exception table len |
| checkLength(tableLength, "Exception Table length"); |
| if (tableLength > 0) { |
| traceln(); |
| traceln("Exception table:"); |
| traceln(" from:old/new to:old/new target:old/new type"); |
| for (int tcnt = tableLength; tcnt > 0; --tcnt) { |
| int startPC = c.readU2(); |
| int endPC = c.readU2(); |
| int handlerPC = c.readU2(); |
| int catchType = c.copyU2(); |
| if (verbose) { |
| traceFixedWidthInt(startPC, 6); |
| traceFixedWidthInt(endPC, 6); |
| traceFixedWidthInt(handlerPC, 6); |
| trace(" "); |
| if (catchType == 0) |
| traceln("any"); |
| else { |
| traceln("" + catchType); |
| } |
| } |
| } |
| } |
| } |
| |
| private void checkIndex(int index, String comment) { |
| if (index > constantPoolCount) { |
| output.println("ERROR BAD INDEX " + comment + " : " + index); |
| } else { |
| traceln(comment + " : " + index); |
| } |
| } |
| |
| private void checkLength(int length, String comment) { |
| if (length > c.inputBytes().length) { |
| output.println("ERROR BAD LENGTH " + comment + " : " + length); |
| } else { |
| traceln(comment + " : " + length); |
| } |
| } |
| |
| private void trace(String str) { |
| if (verbose) { |
| output.print(str); |
| } |
| } |
| |
| private void traceln(String str) { |
| if (verbose) { |
| output.println(str); |
| } |
| } |
| |
| private void traceln() { |
| if (verbose) { |
| output.println(); |
| } |
| } |
| |
| private void trace(int i) { |
| if (verbose) { |
| output.print(i); |
| } |
| } |
| |
| /** |
| * Print an integer so that it takes 'length' characters in |
| * the output. Temporary until formatting code is stable. |
| */ |
| private void traceFixedWidthInt(int x, int length) { |
| if (verbose) { |
| CharArrayWriter baStream = new CharArrayWriter(); |
| PrintWriter pStream = new PrintWriter(baStream); |
| pStream.print(x); |
| String str = baStream.toString(); |
| for (int cnt = length - str.length(); cnt > 0; --cnt) |
| trace(" "); |
| trace(str); |
| } |
| } |
| |
| |
| } |