/* * Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved. * * Licensed 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. See accompanying * LICENSE file. */ package com.gemstone.gemfire.codeAnalysis.decode; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.lang.reflect.Field; import com.gemstone.gemfire.DataSerializable; import com.gemstone.gemfire.codeAnalysis.decode.cp.Cp; import com.gemstone.gemfire.codeAnalysis.decode.cp.CpClass; import com.gemstone.gemfire.codeAnalysis.decode.cp.CpDouble; import com.gemstone.gemfire.codeAnalysis.decode.cp.CpLong; /** * 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[]; 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() { if (superClassName().equals("java/lang/Object") || fullyQualifiedName().equals("com.gemstone.gemfire.internal.HostStatHelper")) { // throws RuntimeException return false; } String name = fullyQualifiedName().replace('/', '.'); try { Class realClass = Class.forName(name); return Serializable.class.isAssignableFrom(realClass) && !DataSerializable.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); } }