blob: 00b9cb6a1dc9fcf9a64f2d39926076272f0e646f [file] [log] [blame]
/*
* 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.
*/
package org.apache.geode.codeAnalysis.decode;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.io.Serializable;
import org.apache.geode.DataSerializable;
import org.apache.geode.LogWriter;
import org.apache.geode.codeAnalysis.decode.cp.Cp;
import org.apache.geode.codeAnalysis.decode.cp.CpClass;
import org.apache.geode.codeAnalysis.decode.cp.CpDouble;
import org.apache.geode.codeAnalysis.decode.cp.CpLong;
import org.apache.geode.internal.DataSerializableFixedID;
import org.apache.geode.internal.ExitCode;
import org.apache.geode.internal.logging.PureLogWriter;
/**
* Decoder represents a jdk ClassFile header
*/
public class CompiledClass implements Comparable {
public long magic;
public int minor_version;
public int major_version;
public int constant_pool_count;
public Cp constant_pool[];
public int access_flags;
public int this_class; // ptr into constant_pool
public int super_class; // ptr into constant_pool
public int interfaces_count;
public int interfaces[];
public int fields_count;
public CompiledField fields[];
public int methods_count;
public CompiledMethod methods[];
public int attributes_count;
public CompiledAttribute attributes[];
static LogWriter debugLog;
static PrintStream debugStream;
static {
try {
debugStream = new PrintStream("loadedClasses.log");
debugLog = new PureLogWriter(PureLogWriter.ALL_LEVEL, debugStream);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public static CompiledClass getInstance(File classFile) throws IOException {
FileInputStream fstream = new FileInputStream(classFile);
DataInputStream source = new DataInputStream(fstream);
CompiledClass instance = new CompiledClass(source);
fstream.close();
return instance;
}
public static CompiledClass getInstance(InputStream classStream) throws IOException {
DataInputStream source = new DataInputStream(classStream);
CompiledClass instance = new CompiledClass(source);
classStream.close();
return instance;
}
/**
* read a ClassFile structure from the given input source (usually a file)
*/
public CompiledClass(DataInputStream source) throws IOException {
int idx;
magic = (long) source.readInt();
minor_version = source.readUnsignedShort();
major_version = source.readUnsignedShort();
// the first constant-pool slot is reserved by Java and is not in the classes file
constant_pool_count = source.readUnsignedShort();
// read the constant pool list
constant_pool = new Cp[constant_pool_count];
constant_pool[0] = null;
for (idx = 1; idx < constant_pool_count; idx++) {
constant_pool[idx] = Cp.readCp(source);
// from Venkatesh: workaround for Javasoft hack
// From the Java Virtual Machine Specification,
// all eight-byte constants take up two spots in the constant pool.
// If this is the nth item in the constant pool, then the next
// item will be numbered n+2.
if ((constant_pool[idx] instanceof CpLong) || (constant_pool[idx] instanceof CpDouble))
idx++;
}
access_flags = source.readUnsignedShort();
this_class = source.readUnsignedShort();
super_class = source.readUnsignedShort();
interfaces_count = source.readUnsignedShort();
// read the interfaces list (ptrs into constant_pool)
interfaces = new int[interfaces_count];
for (idx = 0; idx < interfaces_count; idx++) {
interfaces[idx] = source.readUnsignedShort();
}
fields_count = source.readUnsignedShort();
// read the fields list (only includes this class, not inherited variables)
fields = new CompiledField[fields_count];
for (idx = 0; idx < fields_count; idx++) {
fields[idx] = new CompiledField(source, this);
}
methods_count = source.readUnsignedShort();
// read the methods list
methods = new CompiledMethod[methods_count];
for (idx = 0; idx < methods_count; idx++) {
methods[idx] = new CompiledMethod(source, this);
}
attributes_count = source.readUnsignedShort();
// read the attributes
attributes = new CompiledAttribute[attributes_count];
for (idx = 0; idx < attributes_count; idx++) {
attributes[idx] = new CompiledAttribute(source);
}
}
String accessString() {
StringBuffer result;
result = new StringBuffer();
if ((access_flags & 0x0001) != 0)
result.append("public ");
if ((access_flags & 0x0002) != 0)
result.append("(private?) ");
if ((access_flags & 0x0004) != 0)
result.append("(protected?) ");
if ((access_flags & 0x0008) != 0)
result.append("(static?) ");
if ((access_flags & 0x0010) != 0)
result.append("final ");
if ((access_flags & 0x0020) != 0)
result.append("(??0x20??) ");
if ((access_flags & 0x0040) != 0)
result.append("(volatile?) ");
if ((access_flags & 0x0080) != 0)
result.append("(transient?) ");
if ((access_flags & 0x0100) != 0)
result = result.append("(??0x100??) ");
if ((access_flags & 0x0200) != 0)
result = result.append("interface ");
if ((access_flags & 0x0400) != 0)
result = result.append("abstract ");
if ((access_flags & 0x0800) != 0)
result = result.append("(??0x800??) ");
return result.toString();
}
public boolean isInterface() {
return (access_flags & 0x0200) != 0;
}
public boolean isSerializableAndNotDataSerializable() {
// these classes throw exceptions or log ugly messages when you try to load them
// in junit
String name = fullyQualifiedName().replace('/', '.');
if (name.startsWith("org.apache.geode.internal.shared.NativeCallsJNAImpl")
|| name.startsWith("org.apache.geode.internal.statistics.HostStatHelper")) {
return false;
}
try {
debugLog.info("isSerializableAndNotDataSerializable loading class " + name);
debugStream.flush();
Class realClass = Class.forName(name);
return Serializable.class.isAssignableFrom(realClass)
&& !DataSerializable.class.isAssignableFrom(realClass)
&& !DataSerializableFixedID.class.isAssignableFrom(realClass);
} catch (UnsatisfiedLinkError e) {
System.out.println("Unable to load actual class " + name + " external JNI dependencies");
} catch (NoClassDefFoundError e) {
System.out.println("Unable to load actual class " + name + " not in JUnit classpath");
} catch (Throwable e) {
System.out.println("Unable to load actual class " + name + ": " + e);
}
return false;
}
public String fullyQualifiedName() {
return ((CpClass) constant_pool[this_class]).className(this);
}
public String superClassName() {
return ((CpClass) constant_pool[super_class]).className(this);
}
@Override
public int compareTo(Object other) {
if (!(other instanceof CompiledClass)) {
return -1;
}
String otherName = ((CompiledClass) other).fullyQualifiedName();
return this.fullyQualifiedName().compareTo(otherName);
}
public static void main(String argv[]) {
File classFile;
CompiledClass instance;
int idx;
classFile = null;
try {
classFile = new File(argv[0]);
} catch (NullPointerException e) {
System.err.println("You must give the name of a class file on the command line");
System.exit(3);
}
if (!classFile.canRead()) {
System.err.println("Unable to read " + argv[0]);
System.exit(3);
}
try {
instance = getInstance(classFile);
System.out.println("Class name is " + instance.fullyQualifiedName());
System.out.println("Class access is " + instance.accessString());
System.out.println("Superclass name is " + instance.superClassName());
System.out.println("Fields:");
for (idx = 0; idx < instance.fields_count; idx++) {
System.out.println(" " + instance.fields[idx].signature());
}
System.out.println("Methods:");
for (idx = 0; idx < instance.methods_count; idx++) {
System.out.println(" " + instance.methods[idx].signature());
// if (idx == 0) {
System.out.println("..method attributes");
for (int i = 0; i < instance.methods[idx].attributes_count; i++) {
System.out.println(".." + instance.methods[idx].attributes[i].name(instance));
}
// }
}
} catch (Throwable e) {
System.err.println("Error reading file: " + e.getMessage());
System.exit(3);
}
ExitCode.NORMAL.doSystemExit();
}
}