fe008ae27a
Reviewed-by: darcy, weijun
274 lines
8.4 KiB
Java
274 lines
8.4 KiB
Java
/*
|
|
* 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);
|
|
}
|
|
}
|
|
|
|
|
|
}
|