/* * 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.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); } 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"); exit(3); } if (classFile == null) { System.err.println("Unable to access " + argv[0]); exit(3); } if (!classFile.canRead()) { System.err.println("Unable to read " + argv[0]); 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()); exit(3); } exit(0); } private static void exit(int exitCode) { int b; // if (false) { // if (exitCode == 0) // System.out.println("Done - press Enter to exit: "); // else // System.out.println("Press Enter to exit:"); // try { // b = System.in.read(); // } catch (java.io.IOException e) {}; // } System.exit(exitCode); } }