/*
* 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);
}
}
}