All Downloads are FREE. Search and download functionalities are using the official Maven repository.

soot.coffi.ClassFile Maven / Gradle / Ivy

package soot.coffi;

/*-
 * #%L
 * Soot - a J*va Optimization Framework
 * %%
 * Copyright (C) 1997 Clark Verbrugge
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 2.1 of the
 * License, or (at your option) any later version.
 * 
 * This program 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 Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import soot.Timers;
import soot.options.Options;

/**
 * A ClassFile object represents the contents of a .class file.
 * 

* A ClassFile contains code for manipulation of its constituents. * * @author Clark Verbrugge */ public class ClassFile { private static final Logger logger = LoggerFactory.getLogger(ClassFile.class); /** Magic number. */ static final long MAGIC = 0xCAFEBABEL; /** Access bit flag. */ static final short ACC_PUBLIC = 0x0001; /** Access bit flag. */ static final short ACC_PRIVATE = 0x0002; /** Access bit flag. */ static final short ACC_PROTECTED = 0x0004; /** Access bit flag. */ static final short ACC_STATIC = 0x0008; /** Access bit flag. */ static final short ACC_FINAL = 0x0010; /** Access bit flag. */ static final short ACC_SUPER = 0x0020; /** Access bit flag. */ static final short ACC_VOLATILE = 0x0040; /** Access bit flag. */ static final short ACC_TRANSIENT = 0x0080; /** Access bit flag. */ static final short ACC_INTERFACE = 0x0200; /** Access bit flag. */ static final short ACC_ABSTRACT = 0x0400; /** Access bit flag. */ static final short ACC_STRICT = 0x0800; /** Access bit flag. */ static final short ACC_ANNOTATION = 0x2000; /** Access bit flag. */ static final short ACC_ENUM = 0x4000; /** Remaining bits in the access bit flag. */ static final short ACC_UNKNOWN = 0x7000; /** Descriptor code string. */ static final String DESC_BYTE = "B"; /** Descriptor code string. */ static final String DESC_CHAR = "C"; /** Descriptor code string. */ static final String DESC_DOUBLE = "D"; /** Descriptor code string. */ static final String DESC_FLOAT = "F"; /** Descriptor code string. */ static final String DESC_INT = "I"; /** Descriptor code string. */ static final String DESC_LONG = "J"; /** Descriptor code string. */ static final String DESC_OBJECT = "L"; /** Descriptor code string. */ static final String DESC_SHORT = "S"; /** Descriptor code string. */ static final String DESC_BOOLEAN = "Z"; /** Descriptor code string. */ static final String DESC_VOID = "V"; /** Descriptor code string. */ static final String DESC_ARRAY = "["; /** Debugging flag. */ boolean debug; /** File name of the .class this represents. */ String fn; /* * For chaining ClassFiles into a list. ClassFile next; */ /** * Magic number read in. * * @see ClassFile#MAGIC */ long magic; /** Minor version. */ int minor_version; /** Major version. */ int major_version; /** Number of items in the constant pool. */ public int constant_pool_count; /** * Array of constant pool items. * * @see cp_info */ public cp_info constant_pool[]; /** * Access flags for this Class. */ public int access_flags; /** * Constant pool index of the Class constant describing this. * * @see CONSTANT_Class_info */ public int this_class; /** * Constant pool index of the Class constant describing super. * * @see CONSTANT_Class_info */ public int super_class; /** Count of interfaces implemented. */ public int interfaces_count; /** * Array of constant pool indices of Class constants describing each interace implemented by this class, as given in the * source for this class. * * @see CONSTANT_Class_info */ public int interfaces[]; /** Count of fields this Class contains. */ public int fields_count; /** * Array of field_info objects describing each field. * * @see field_info */ public field_info fields[]; /** Count of methods this Class contains. */ public int methods_count; /** * Array of method_info objects describing each field. * * @see method_info */ public method_info methods[]; /** Count of attributes this class contains. */ public int attributes_count; /** * Array of attribute_info objects for this class. * * @see attribute_info */ public attribute_info attributes[]; /** bootstrap-methods attribute (if any) */ public BootstrapMethods_attribute bootstrap_methods_attribute; /** * Creates a new ClassFile object given the name of the file. * * @param nfn * file name which this ClassFile will represent. */ public ClassFile(String nfn) { fn = nfn; } /** Returns the name of this Class. */ public String toString() { return (constant_pool[this_class].toString(constant_pool)); } public boolean loadClassFile(InputStream is) { InputStream f = null; InputStream classFileStream; DataInputStream d; boolean b; classFileStream = is; byte[] data; if (Options.v().time()) { Timers.v().readTimer.start(); } try { DataInputStream classDataStream = new DataInputStream(classFileStream); data = new byte[classDataStream.available()]; classDataStream.readFully(data); f = new ByteArrayInputStream(data); } catch (IOException e) { logger.debug(e.getMessage(), e); } if (Options.v().time()) { Timers.v().readTimer.end(); } d = new DataInputStream(f); b = readClass(d); try { classFileStream.close(); d.close(); if (f != null) { f.close(); } } catch (IOException e) { logger.debug("IOException with " + fn + ": " + e.getMessage()); return false; } if (!b) { return false; } // parse(); // parse all methods & builds CFGs // logger.debug("-- Read " + cf + " --"); return true; } /** * Main entry point for writing a class file. The file name is given in the constructor; this opens the file and writes the * internal representation. * * @return true on success. */ boolean saveClassFile() { FileOutputStream f; DataOutputStream d; boolean b; try { f = new FileOutputStream(fn); } catch (FileNotFoundException e) { if (fn.indexOf(".class") >= 0) { logger.debug("Can't find " + fn); return false; } fn = fn + ".class"; try { f = new FileOutputStream(fn); } catch (FileNotFoundException ee) { logger.debug("Can't find " + fn); return false; } } d = new DataOutputStream(f); b = writeClass(d); try { d.close(); f.close(); } catch (IOException e) { logger.debug("IOException with " + fn + ": " + e.getMessage()); return false; } return b; } /** * Returns a String constructed by parsing the bits in the given access code (as defined by the ACC_* constants). * * @param af * access code. * @param separator * String used to separate words used for access bits. * @see ClassFile#access_flags * @see method_info#access_flags * @see field_info#access_flags */ static String access_string(int af, String separator) { boolean hasone = false; String s = ""; if ((af & ACC_PUBLIC) != 0) { s = "public"; hasone = true; } if ((af & ACC_PRIVATE) != 0) { if (hasone) { s = s + separator; } else { hasone = true; } s = s + "private"; } if ((af & ACC_PROTECTED) != 0) { if (hasone) { s = s + separator; } else { hasone = true; } s = s + "protected"; } if ((af & ACC_STATIC) != 0) { if (hasone) { s = s + separator; } else { hasone = true; } s = s + "static"; } if ((af & ACC_FINAL) != 0) { if (hasone) { s = s + separator; } else { hasone = true; } s = s + "final"; } if ((af & ACC_SUPER) != 0) { if (hasone) { s = s + separator; } else { hasone = true; } s = s + "super"; } if ((af & ACC_VOLATILE) != 0) { if (hasone) { s = s + separator; } else { hasone = true; } s = s + "volatile"; } if ((af & ACC_TRANSIENT) != 0) { if (hasone) { s = s + separator; } else { hasone = true; } s = s + "transient"; } if ((af & ACC_INTERFACE) != 0) { if (hasone) { s = s + separator; } else { hasone = true; } s = s + "interface"; } if ((af & ACC_ABSTRACT) != 0) { if (hasone) { s = s + separator; } else { hasone = true; } s = s + "abstract"; } if ((af & ACC_STRICT) != 0) { if (hasone) { s = s + separator; } else { hasone = true; } s = s + "strict"; } if ((af & ACC_ANNOTATION) != 0) { if (hasone) { s = s + separator; } else { hasone = true; } s = s + "annotation"; } if ((af & ACC_ENUM) != 0) { if (hasone) { s = s + separator; } else { hasone = true; } s = s + "enum"; } if ((af & ACC_UNKNOWN) != 0) { if (hasone) { s = s + separator; } else { hasone = true; } s = s + "unknown"; } return s; } /** * Builds the internal representation of this Class by reading in the given class file. * * @param d * Stream forming the .class file. * @return true if read was successful, false on some error. */ public boolean readClass(DataInputStream d) { try { // first read in magic number magic = d.readInt() & 0xFFFFFFFFL; if (magic != MAGIC) { logger.debug("Wrong magic number in " + fn + ": " + magic); return false; } minor_version = d.readUnsignedShort(); major_version = d.readUnsignedShort(); constant_pool_count = d.readUnsignedShort(); if (!readConstantPool(d)) { return false; } access_flags = d.readUnsignedShort(); this_class = d.readUnsignedShort(); super_class = d.readUnsignedShort(); interfaces_count = d.readUnsignedShort(); if (interfaces_count > 0) { interfaces = new int[interfaces_count]; int j; for (j = 0; j < interfaces_count; j++) { interfaces[j] = d.readUnsignedShort(); } } if (Options.v().time()) { Timers.v().fieldTimer.start(); } fields_count = d.readUnsignedShort(); readFields(d); if (Options.v().time()) { Timers.v().fieldTimer.end(); } if (Options.v().time()) { Timers.v().methodTimer.start(); } methods_count = d.readUnsignedShort(); readMethods(d); if (Options.v().time()) { Timers.v().methodTimer.end(); } if (Options.v().time()) { Timers.v().attributeTimer.start(); } attributes_count = d.readUnsignedShort(); if (attributes_count > 0) { attributes = new attribute_info[attributes_count]; readAttributes(d, attributes_count, attributes); } if (Options.v().time()) { Timers.v().attributeTimer.end(); } } catch (IOException e) { throw new RuntimeException("IOException with " + fn + ": " + e.getMessage(), e); } return true; } /** * Reads in the constant pool from the given stream. * * @param d * Stream forming the .class file. * @return true if read was successful, false on some error. * @exception java.io.IOException * on error. */ protected boolean readConstantPool(DataInputStream d) throws IOException { byte tag; cp_info cp; int i; boolean skipone; // set if next cp entry is to be skipped constant_pool = new cp_info[constant_pool_count]; // Instruction.constant_pool = constant_pool; skipone = false; for (i = 1; i < constant_pool_count; i++) { if (skipone) { skipone = false; continue; } tag = (byte) d.readUnsignedByte(); switch (tag) { case cp_info.CONSTANT_Class: cp = new CONSTANT_Class_info(); ((CONSTANT_Class_info) cp).name_index = d.readUnsignedShort(); if (debug) { logger.debug("Constant pool[" + i + "]: Class"); } break; case cp_info.CONSTANT_Fieldref: cp = new CONSTANT_Fieldref_info(); ((CONSTANT_Fieldref_info) cp).class_index = d.readUnsignedShort(); ((CONSTANT_Fieldref_info) cp).name_and_type_index = d.readUnsignedShort(); if (debug) { logger.debug("Constant pool[" + i + "]: Fieldref"); } break; case cp_info.CONSTANT_Methodref: cp = new CONSTANT_Methodref_info(); ((CONSTANT_Methodref_info) cp).class_index = d.readUnsignedShort(); ((CONSTANT_Methodref_info) cp).name_and_type_index = d.readUnsignedShort(); if (debug) { logger.debug("Constant pool[" + i + "]: Methodref"); } break; case cp_info.CONSTANT_InterfaceMethodref: cp = new CONSTANT_InterfaceMethodref_info(); ((CONSTANT_InterfaceMethodref_info) cp).class_index = d.readUnsignedShort(); ((CONSTANT_InterfaceMethodref_info) cp).name_and_type_index = d.readUnsignedShort(); if (debug) { logger.debug("Constant pool[" + i + "]: MethodHandle"); } break; case cp_info.CONSTANT_String: cp = new CONSTANT_String_info(); ((CONSTANT_String_info) cp).string_index = d.readUnsignedShort(); if (debug) { logger.debug("Constant pool[" + i + "]: String"); } break; case cp_info.CONSTANT_Integer: cp = new CONSTANT_Integer_info(); ((CONSTANT_Integer_info) cp).bytes = d.readInt(); if (debug) { logger.debug("Constant pool[" + i + "]: Integer = " + ((CONSTANT_Integer_info) cp).bytes); } break; case cp_info.CONSTANT_Float: cp = new CONSTANT_Float_info(); ((CONSTANT_Float_info) cp).bytes = d.readInt(); if (debug) { logger.debug("Constant pool[" + i + "]: Float = " + ((CONSTANT_Float_info) cp).convert()); } break; case cp_info.CONSTANT_Long: cp = new CONSTANT_Long_info(); ((CONSTANT_Long_info) cp).high = d.readInt() & 0xFFFFFFFFL; ((CONSTANT_Long_info) cp).low = d.readInt() & 0xFFFFFFFFL; if (debug) { String temp = cp.toString(constant_pool); logger.debug("Constant pool[" + i + "]: Long = " + temp); /* * logger.debug("Constant pool[" + i + "]: that's " + cp.printBits(((CONSTANT_Long_info)cp).high) + " <<32 + " + * cp.printBits(((CONSTANT_Long_info)cp).low) + " = " + cp.printBits(((CONSTANT_Long_info)cp).convert())); */ } skipone = true; // next entry needs to be skipped break; case cp_info.CONSTANT_Double: cp = new CONSTANT_Double_info(); ((CONSTANT_Double_info) cp).high = d.readInt() & 0xFFFFFFFFL; ((CONSTANT_Double_info) cp).low = d.readInt() & 0xFFFFFFFFL; if (debug) { logger.debug("Constant pool[" + i + "]: Double = " + ((CONSTANT_Double_info) cp).convert()); } skipone = true; // next entry needs to be skipped break; case cp_info.CONSTANT_NameAndType: cp = new CONSTANT_NameAndType_info(); ((CONSTANT_NameAndType_info) cp).name_index = d.readUnsignedShort(); ((CONSTANT_NameAndType_info) cp).descriptor_index = d.readUnsignedShort(); if (debug) { logger.debug("Constant pool[" + i + "]: Name and Type"); } break; case cp_info.CONSTANT_Utf8: CONSTANT_Utf8_info cputf8 = new CONSTANT_Utf8_info(d); // If an equivalent CONSTANT_Utf8 already exists, we return // the pre-existing one and allow cputf8 to be GC'd. cp = (cp_info) CONSTANT_Utf8_collector.v().add(cputf8); if (debug) { logger.debug("Constant pool[" + i + "]: Utf8 = \"" + cputf8.convert() + "\""); } break; case cp_info.CONSTANT_MethodHandle: cp = new CONSTANT_MethodHandle_info(); ((CONSTANT_MethodHandle_info) cp).kind = d.readByte(); ((CONSTANT_MethodHandle_info) cp).target_index = d.readUnsignedShort(); break; case cp_info.CONSTANT_InvokeDynamic: cp = new CONSTANT_InvokeDynamic_info(); ((CONSTANT_InvokeDynamic_info) cp).bootstrap_method_index = d.readUnsignedShort(); ((CONSTANT_InvokeDynamic_info) cp).name_and_type_index = d.readUnsignedShort(); break; default: logger.debug("Unknown tag in constant pool: " + tag + " at entry " + i); return false; } cp.tag = tag; constant_pool[i] = cp; } return true; } private void readAllBytes(byte[] dest, DataInputStream d) throws IOException { int total_len = dest.length; int read_len = 0; while (read_len < total_len) { int to_read = total_len - read_len; int curr_read = d.read(dest, read_len, to_read); read_len += curr_read; } } /** * Reads in the given number of attributes from the given stream. * * @param d * Stream forming the .class file. * @param attributes_count * number of attributes to read in. * @param ai * pre-allocated array of attributes to be filled in. * @return true if read was successful, false on some error. * @exception java.io.IOException * on error. */ protected boolean readAttributes(DataInputStream d, int attributes_count, attribute_info[] ai) throws IOException { attribute_info a = null; int i; int j; long len; String s; for (i = 0; i < attributes_count; i++) { j = d.readUnsignedShort(); // read attribute name before allocating len = d.readInt() & 0xFFFFFFFFL; s = ((CONSTANT_Utf8_info) (constant_pool[j])).convert(); if (s.compareTo(attribute_info.SourceFile) == 0) { SourceFile_attribute sa = new SourceFile_attribute(); sa.sourcefile_index = d.readUnsignedShort(); a = (attribute_info) sa; } else if (s.compareTo(attribute_info.ConstantValue) == 0) { ConstantValue_attribute ca = new ConstantValue_attribute(); ca.constantvalue_index = d.readUnsignedShort(); a = (attribute_info) ca; } else if (s.compareTo(attribute_info.Code) == 0) { Code_attribute ca = new Code_attribute(); ca.max_stack = d.readUnsignedShort(); ca.max_locals = d.readUnsignedShort(); ca.code_length = d.readInt() & 0xFFFFFFFFL; ca.code = new byte[(int) ca.code_length]; readAllBytes(ca.code, d); ca.exception_table_length = d.readUnsignedShort(); ca.exception_table = new exception_table_entry[ca.exception_table_length]; int k; exception_table_entry e; for (k = 0; k < ca.exception_table_length; k++) { e = new exception_table_entry(); e.start_pc = d.readUnsignedShort(); e.end_pc = d.readUnsignedShort(); e.handler_pc = d.readUnsignedShort(); e.catch_type = d.readUnsignedShort(); ca.exception_table[k] = e; } ca.attributes_count = d.readUnsignedShort(); ca.attributes = new attribute_info[ca.attributes_count]; readAttributes(d, ca.attributes_count, ca.attributes); a = (attribute_info) ca; } else if (s.compareTo(attribute_info.Exceptions) == 0) { Exception_attribute ea = new Exception_attribute(); ea.number_of_exceptions = d.readUnsignedShort(); if (ea.number_of_exceptions > 0) { int k; ea.exception_index_table = new int[ea.number_of_exceptions]; for (k = 0; k < ea.number_of_exceptions; k++) { ea.exception_index_table[k] = d.readUnsignedShort(); } } a = (attribute_info) ea; } else if (s.compareTo(attribute_info.LineNumberTable) == 0) { LineNumberTable_attribute la = new LineNumberTable_attribute(); la.line_number_table_length = d.readUnsignedShort(); int k; line_number_table_entry e; la.line_number_table = new line_number_table_entry[la.line_number_table_length]; for (k = 0; k < la.line_number_table_length; k++) { e = new line_number_table_entry(); e.start_pc = d.readUnsignedShort(); e.line_number = d.readUnsignedShort(); la.line_number_table[k] = e; } a = (attribute_info) la; } else if (s.compareTo(attribute_info.LocalVariableTable) == 0) { LocalVariableTable_attribute la = new LocalVariableTable_attribute(); la.local_variable_table_length = d.readUnsignedShort(); int k; local_variable_table_entry e; la.local_variable_table = new local_variable_table_entry[la.local_variable_table_length]; for (k = 0; k < la.local_variable_table_length; k++) { e = new local_variable_table_entry(); e.start_pc = d.readUnsignedShort(); e.length = d.readUnsignedShort(); e.name_index = d.readUnsignedShort(); e.descriptor_index = d.readUnsignedShort(); e.index = d.readUnsignedShort(); la.local_variable_table[k] = e; } a = (attribute_info) la; } else if (s.compareTo(attribute_info.LocalVariableTypeTable) == 0) { LocalVariableTypeTable_attribute la = new LocalVariableTypeTable_attribute(); la.local_variable_type_table_length = d.readUnsignedShort(); int k; local_variable_type_table_entry e; la.local_variable_type_table = new local_variable_type_table_entry[la.local_variable_type_table_length]; for (k = 0; k < la.local_variable_type_table_length; k++) { e = new local_variable_type_table_entry(); e.start_pc = d.readUnsignedShort(); e.length = d.readUnsignedShort(); e.name_index = d.readUnsignedShort(); e.signature_index = d.readUnsignedShort(); e.index = d.readUnsignedShort(); la.local_variable_type_table[k] = e; } a = (attribute_info) la; } else if (s.compareTo(attribute_info.Synthetic) == 0) { Synthetic_attribute ia = new Synthetic_attribute(); a = (attribute_info) ia; } else if (s.compareTo(attribute_info.Signature) == 0) { Signature_attribute ia = new Signature_attribute(); ia.signature_index = d.readUnsignedShort(); a = (attribute_info) ia; } else if (s.compareTo(attribute_info.Deprecated) == 0) { Deprecated_attribute da = new Deprecated_attribute(); a = (attribute_info) da; } else if (s.compareTo(attribute_info.EnclosingMethod) == 0) { EnclosingMethod_attribute ea = new EnclosingMethod_attribute(); ea.class_index = d.readUnsignedShort(); ea.method_index = d.readUnsignedShort(); a = (attribute_info) ea; } else if (s.compareTo(attribute_info.InnerClasses) == 0) { InnerClasses_attribute ia = new InnerClasses_attribute(); ia.inner_classes_length = d.readUnsignedShort(); ia.inner_classes = new inner_class_entry[ia.inner_classes_length]; for (int k = 0; k < ia.inner_classes_length; k++) { inner_class_entry e = new inner_class_entry(); e.inner_class_index = d.readUnsignedShort(); e.outer_class_index = d.readUnsignedShort(); e.name_index = d.readUnsignedShort(); e.access_flags = d.readUnsignedShort(); ia.inner_classes[k] = e; } a = (attribute_info) ia; } else if (s.compareTo(attribute_info.RuntimeVisibleAnnotations) == 0) { RuntimeVisibleAnnotations_attribute ra = new RuntimeVisibleAnnotations_attribute(); ra.number_of_annotations = d.readUnsignedShort(); ra.annotations = new annotation[ra.number_of_annotations]; for (int k = 0; k < ra.number_of_annotations; k++) { annotation annot = new annotation(); annot.type_index = d.readUnsignedShort(); annot.num_element_value_pairs = d.readUnsignedShort(); annot.element_value_pairs = readElementValues(annot.num_element_value_pairs, d, true, 0); ra.annotations[k] = annot; } a = (attribute_info) ra; } else if (s.compareTo(attribute_info.RuntimeInvisibleAnnotations) == 0) { RuntimeInvisibleAnnotations_attribute ra = new RuntimeInvisibleAnnotations_attribute(); ra.number_of_annotations = d.readUnsignedShort(); ra.annotations = new annotation[ra.number_of_annotations]; for (int k = 0; k < ra.number_of_annotations; k++) { annotation annot = new annotation(); annot.type_index = d.readUnsignedShort(); annot.num_element_value_pairs = d.readUnsignedShort(); annot.element_value_pairs = readElementValues(annot.num_element_value_pairs, d, true, 0); ra.annotations[k] = annot; } a = (attribute_info) ra; } else if (s.compareTo(attribute_info.RuntimeVisibleParameterAnnotations) == 0) { RuntimeVisibleParameterAnnotations_attribute ra = new RuntimeVisibleParameterAnnotations_attribute(); ra.num_parameters = d.readUnsignedByte(); ra.parameter_annotations = new parameter_annotation[ra.num_parameters]; for (int x = 0; x < ra.num_parameters; x++) { parameter_annotation pAnnot = new parameter_annotation(); pAnnot.num_annotations = d.readUnsignedShort(); pAnnot.annotations = new annotation[pAnnot.num_annotations]; for (int k = 0; k < pAnnot.num_annotations; k++) { annotation annot = new annotation(); annot.type_index = d.readUnsignedShort(); annot.num_element_value_pairs = d.readUnsignedShort(); annot.element_value_pairs = readElementValues(annot.num_element_value_pairs, d, true, 0); pAnnot.annotations[k] = annot; } ra.parameter_annotations[x] = pAnnot; } a = (attribute_info) ra; } else if (s.compareTo(attribute_info.RuntimeInvisibleParameterAnnotations) == 0) { RuntimeInvisibleParameterAnnotations_attribute ra = new RuntimeInvisibleParameterAnnotations_attribute(); ra.num_parameters = d.readUnsignedByte(); ra.parameter_annotations = new parameter_annotation[ra.num_parameters]; for (int x = 0; x < ra.num_parameters; x++) { parameter_annotation pAnnot = new parameter_annotation(); pAnnot.num_annotations = d.readUnsignedShort(); pAnnot.annotations = new annotation[pAnnot.num_annotations]; for (int k = 0; k < pAnnot.num_annotations; k++) { annotation annot = new annotation(); annot.type_index = d.readUnsignedShort(); annot.num_element_value_pairs = d.readUnsignedShort(); annot.element_value_pairs = readElementValues(annot.num_element_value_pairs, d, true, 0); pAnnot.annotations[k] = annot; } ra.parameter_annotations[x] = pAnnot; } a = (attribute_info) ra; } else if (s.compareTo(attribute_info.AnnotationDefault) == 0) { AnnotationDefault_attribute da = new AnnotationDefault_attribute(); element_value[] result = readElementValues(1, d, false, 0); da.default_value = result[0]; a = (attribute_info) da; } else if (s.equals(attribute_info.BootstrapMethods)) { BootstrapMethods_attribute bsma = new BootstrapMethods_attribute(); int count = d.readUnsignedShort(); bsma.method_handles = new short[count]; bsma.arg_indices = new short[count][]; for (int num = 0; num < count; num++) { short index = (short) d.readUnsignedShort(); bsma.method_handles[num] = index; int argCount = d.readUnsignedShort(); bsma.arg_indices[num] = new short[argCount]; for (int numArg = 0; numArg < argCount; numArg++) { short indexArg = (short) d.readUnsignedShort(); bsma.arg_indices[num][numArg] = indexArg; } } assert bootstrap_methods_attribute == null : "More than one bootstrap methods attribute!"; a = bootstrap_methods_attribute = bsma; } else { // unknown attribute // logger.debug("Generic/Unknown Attribute: " + s); Generic_attribute ga = new Generic_attribute(); if (len > 0) { ga.info = new byte[(int) len]; readAllBytes(ga.info, d); } a = (attribute_info) ga; } a.attribute_name = j; a.attribute_length = len; ai[i] = a; } return true; } private element_value[] readElementValues(int count, DataInputStream d, boolean needName, int name_index) throws IOException { element_value[] list = new element_value[count]; for (int x = 0; x < count; x++) { if (needName) { name_index = d.readUnsignedShort(); } int tag = d.readUnsignedByte(); char kind = (char) tag; if (kind == 'B' || kind == 'C' || kind == 'D' || kind == 'F' || kind == 'I' || kind == 'J' || kind == 'S' || kind == 'Z' || kind == 's') { constant_element_value elem = new constant_element_value(); elem.name_index = name_index; elem.tag = kind; elem.constant_value_index = d.readUnsignedShort(); list[x] = elem; } else if (kind == 'e') { enum_constant_element_value elem = new enum_constant_element_value(); elem.name_index = name_index; elem.tag = kind; elem.type_name_index = d.readUnsignedShort(); elem.constant_name_index = d.readUnsignedShort(); list[x] = elem; } else if (kind == 'c') { class_element_value elem = new class_element_value(); elem.name_index = name_index; elem.tag = kind; elem.class_info_index = d.readUnsignedShort(); list[x] = elem; } else if (kind == '[') { array_element_value elem = new array_element_value(); elem.name_index = name_index; elem.tag = kind; elem.num_values = d.readUnsignedShort(); elem.values = readElementValues(elem.num_values, d, false, name_index); list[x] = elem; } else if (kind == '@') { annotation_element_value elem = new annotation_element_value(); elem.name_index = name_index; elem.tag = kind; annotation annot = new annotation(); annot.type_index = d.readUnsignedShort(); annot.num_element_value_pairs = d.readUnsignedShort(); annot.element_value_pairs = readElementValues(annot.num_element_value_pairs, d, true, 0); elem.annotation_value = annot; list[x] = elem; } else { throw new RuntimeException("Unknown element value pair kind: " + kind); } } return list; } /** * Reads in the fields from the given stream. * * @param d * Stream forming the .class file. * @return true if read was successful, false on some error. * @exception java.io.IOException * on error. */ protected boolean readFields(DataInputStream d) throws IOException { field_info fi; int i; fields = new field_info[fields_count]; for (i = 0; i < fields_count; i++) { fi = new field_info(); fi.access_flags = d.readUnsignedShort(); fi.name_index = d.readUnsignedShort(); fi.descriptor_index = d.readUnsignedShort(); fi.attributes_count = d.readUnsignedShort(); if (fi.attributes_count > 0) { fi.attributes = new attribute_info[fi.attributes_count]; readAttributes(d, fi.attributes_count, fi.attributes); } /* * CONSTANT_Utf8_info ci; ci = (CONSTANT_Utf8_info)(constant_pool[fi.name_index]); logger.debug("Field: " + * ci.convert()); */ fields[i] = fi; } return true; } /** * Reads in the methods from the given stream. * * @param d * Stream forming the .class file. * @return true if read was successful, false on some error. * @exception java.io.IOException * on error. */ protected boolean readMethods(DataInputStream d) throws IOException { method_info mi; int i; methods = new method_info[methods_count]; for (i = 0; i < methods_count; i++) { mi = new method_info(); mi.access_flags = d.readUnsignedShort(); mi.name_index = d.readUnsignedShort(); mi.descriptor_index = d.readUnsignedShort(); mi.attributes_count = d.readUnsignedShort(); // logger.debug("Has " + mi.attributes_count + " attribute(s)"); if (mi.attributes_count > 0) { mi.attributes = new attribute_info[mi.attributes_count]; readAttributes(d, mi.attributes_count, mi.attributes); for (int j = 0; j < mi.attributes_count; j++) { if (mi.attributes[j] instanceof Code_attribute) { mi.code_attr = (Code_attribute) mi.attributes[j]; break; } } } /* * if ("main".compareTo(ci.convert())==0) { decompile(mi); } */ methods[i] = mi; } return true; } /* * DEPRECATED public void showByteCode(Code_attribute ca) { int i=0,j; * * logger.debug("Code bytes follow..."); while(itrue if write was successful, false on some error. * @exception java.io.IOException * on error. */ protected boolean writeConstantPool(DataOutputStream dd) throws IOException { cp_info cp; int i; boolean skipone = false; for (i = 1; i < constant_pool_count; i++) { if (skipone) { skipone = false; continue; } cp = constant_pool[i]; dd.writeByte(cp.tag); switch (cp.tag) { case cp_info.CONSTANT_Class: dd.writeShort(((CONSTANT_Class_info) cp).name_index); break; case cp_info.CONSTANT_Fieldref: dd.writeShort(((CONSTANT_Fieldref_info) cp).class_index); dd.writeShort(((CONSTANT_Fieldref_info) cp).name_and_type_index); break; case cp_info.CONSTANT_Methodref: dd.writeShort(((CONSTANT_Methodref_info) cp).class_index); dd.writeShort(((CONSTANT_Methodref_info) cp).name_and_type_index); break; case cp_info.CONSTANT_InterfaceMethodref: dd.writeShort(((CONSTANT_InterfaceMethodref_info) cp).class_index); dd.writeShort(((CONSTANT_InterfaceMethodref_info) cp).name_and_type_index); break; case cp_info.CONSTANT_String: dd.writeShort(((CONSTANT_String_info) cp).string_index); break; case cp_info.CONSTANT_Integer: dd.writeInt((int) ((CONSTANT_Integer_info) cp).bytes); break; case cp_info.CONSTANT_Float: dd.writeInt((int) ((CONSTANT_Float_info) cp).bytes); break; case cp_info.CONSTANT_Long: dd.writeInt((int) ((CONSTANT_Long_info) cp).high); dd.writeInt((int) ((CONSTANT_Long_info) cp).low); skipone = true; break; case cp_info.CONSTANT_Double: dd.writeInt((int) ((CONSTANT_Double_info) cp).high); dd.writeInt((int) ((CONSTANT_Double_info) cp).low); skipone = true; break; case cp_info.CONSTANT_NameAndType: dd.writeShort(((CONSTANT_NameAndType_info) cp).name_index); dd.writeShort(((CONSTANT_NameAndType_info) cp).descriptor_index); break; case cp_info.CONSTANT_Utf8: ((CONSTANT_Utf8_info) cp).writeBytes(dd); break; default: logger.debug("Unknown tag in constant pool: " + cp.tag); return false; } } return true; } /** * Writes the given array of attributes to the given stream. * * @param dd * output stream. * @param attributes_count * number of attributes to write. * @param ai * array of attributes to write. * @return true if write was successful, false on some error. * @exception java.io.IOException * on error. */ protected boolean writeAttributes(DataOutputStream dd, int attributes_count, attribute_info[] ai) throws IOException { attribute_info a = null; int i; for (i = 0; i < attributes_count; i++) { a = ai[i]; dd.writeShort(a.attribute_name); dd.writeInt((int) a.attribute_length); if (a instanceof SourceFile_attribute) { SourceFile_attribute sa = (SourceFile_attribute) a; dd.writeShort(sa.sourcefile_index); } else if (a instanceof ConstantValue_attribute) { ConstantValue_attribute ca = (ConstantValue_attribute) a; dd.writeShort(ca.constantvalue_index); } else if (a instanceof Code_attribute) { Code_attribute ca = (Code_attribute) a; dd.writeShort(ca.max_stack); dd.writeShort(ca.max_locals); dd.writeInt((int) ca.code_length); dd.write(ca.code, 0, (int) ca.code_length); dd.writeShort(ca.exception_table_length); int k; exception_table_entry e; for (k = 0; k < ca.exception_table_length; k++) { e = ca.exception_table[k]; dd.writeShort(e.start_pc); dd.writeShort(e.end_pc); dd.writeShort(e.handler_pc); dd.writeShort(e.catch_type); } dd.writeShort(ca.attributes_count); if (ca.attributes_count > 0) { writeAttributes(dd, ca.attributes_count, ca.attributes); } } else if (a instanceof Exception_attribute) { Exception_attribute ea = (Exception_attribute) a; dd.writeShort(ea.number_of_exceptions); if (ea.number_of_exceptions > 0) { int k; for (k = 0; k < ea.number_of_exceptions; k++) { dd.writeShort(ea.exception_index_table[k]); } } } else if (a instanceof LineNumberTable_attribute) { LineNumberTable_attribute la = (LineNumberTable_attribute) a; dd.writeShort(la.line_number_table_length); int k; line_number_table_entry e; for (k = 0; k < la.line_number_table_length; k++) { e = la.line_number_table[k]; dd.writeShort(e.start_pc); dd.writeShort(e.line_number); } } else if (a instanceof LocalVariableTable_attribute) { LocalVariableTable_attribute la = (LocalVariableTable_attribute) a; dd.writeShort(la.local_variable_table_length); int k; local_variable_table_entry e; for (k = 0; k < la.local_variable_table_length; k++) { e = la.local_variable_table[k]; dd.writeShort(e.start_pc); dd.writeShort(e.length); dd.writeShort(e.name_index); dd.writeShort(e.descriptor_index); dd.writeShort(e.index); } } else { // unknown attribute logger.debug("Generic/Unknown Attribute in output"); Generic_attribute ga = (Generic_attribute) a; if (ga.attribute_length > 0) { dd.write(ga.info, 0, (int) ga.attribute_length); } } } return true; } /** * Writes the fields to the given stream. * * @param dd * output stream. * @return true if write was successful, false on some error. * @exception java.io.IOException * on error. */ protected boolean writeFields(DataOutputStream dd) throws IOException { field_info fi; int i; for (i = 0; i < fields_count; i++) { fi = fields[i]; dd.writeShort(fi.access_flags); dd.writeShort(fi.name_index); dd.writeShort(fi.descriptor_index); dd.writeShort(fi.attributes_count); if (fi.attributes_count > 0) { writeAttributes(dd, fi.attributes_count, fi.attributes); } } return true; } /** * Writes the methods to the given stream. * * @param dd * output stream. * @return true if write was successful, false on some error. * @exception java.io.IOException * on error. */ protected boolean writeMethods(DataOutputStream dd) throws IOException { method_info mi; int i; for (i = 0; i < methods_count; i++) { mi = methods[i]; dd.writeShort(mi.access_flags); dd.writeShort(mi.name_index); dd.writeShort(mi.descriptor_index); dd.writeShort(mi.attributes_count); if (mi.attributes_count > 0) { writeAttributes(dd, mi.attributes_count, mi.attributes); } } return true; } /** * Writes this entire ClassFile object to the given stream. * * @param dd * output stream. * @return true if write was successful, false on some error. */ boolean writeClass(DataOutputStream dd) { // outputs the .class file from the loaded one try { // first write magic number dd.writeInt((int) magic); dd.writeShort(minor_version); dd.writeShort(major_version); dd.writeShort(constant_pool_count); if (!writeConstantPool(dd)) { return false; } dd.writeShort(access_flags); dd.writeShort(this_class); dd.writeShort(super_class); dd.writeShort(interfaces_count); if (interfaces_count > 0) { int j; for (j = 0; j < interfaces_count; j++) { dd.writeShort(interfaces[j]); } } dd.writeShort(fields_count); writeFields(dd); dd.writeShort(methods_count); writeMethods(dd); dd.writeShort(attributes_count); if (attributes_count > 0) { writeAttributes(dd, attributes_count, attributes); } } catch (IOException e) { logger.debug("IOException with " + fn + ": " + e.getMessage()); return false; } return true; } /** * Parses the given method, converting its bytecode array into a list of Instruction objects. * * @param m * method to parse. * @return head of a list of Instructions. * @see Instruction * @see ByteCode * @see ByteCode#disassemble_bytecode */ public Instruction parseMethod(method_info m) { // first task, look through attributes for a code attribute int j; Code_attribute ca; ByteCode bc; Instruction inst, head, tail; exception_table_entry e; head = null; tail = null; bc = new ByteCode(); ca = m.locate_code_attribute(); if (ca == null) { return null; } j = 0; while (j < ca.code_length) { inst = bc.disassemble_bytecode(ca.code, j); inst.originalIndex = j; // logger.debug(""+inst + ": " + (((int)(inst.code))&0xff)); // logger.debug(""+j + " : " + inst); if (inst instanceof Instruction_Unknown) { logger.debug("Unknown instruction in \"" + m.toName(constant_pool) + "\" at offset " + j); logger.debug(" bytecode = " + (((int) (inst.code)) & 0xff)); } // logger.debug("before: " + j); j = inst.nextOffset(j); // logger.debug("after: " + j); if (head == null) { head = inst; } else { tail.next = inst; inst.prev = tail; } tail = inst; } // bytecode converted into instructions, now build pointers bc.build(head); // also change exception table to use pointers instead of absolute addresses for (j = 0; j < ca.exception_table_length; j++) { e = ca.exception_table[j]; e.start_inst = bc.locateInst(e.start_pc); if (e.end_pc == ca.code_length) { e.end_inst = null; } else { e.end_inst = bc.locateInst(e.end_pc); } e.handler_inst = bc.locateInst(e.handler_pc); if (e.handler_inst != null) { e.handler_inst.labelled = true; } } m.instructions = head; for (attribute_info element : ca.attributes) { if (element instanceof LineNumberTable_attribute) { LineNumberTable_attribute lntattr = (LineNumberTable_attribute) element; for (line_number_table_entry element0 : lntattr.line_number_table) { element0.start_inst = bc.locateInst(element0.start_pc); } } } return head; } /** * For every method, this calls parseMethod, storing the list of Instructions in the method_info object, and also * constructs the corresponding CFG. * * @see ClassFile#parseMethod * @see CFG */ public void parse() { method_info mi; int i; for (i = 0; i < methods_count; i++) { mi = methods[i]; mi.instructions = parseMethod(mi); // new CFG(mi); // don't build it right away for now } } /** * Recomputes the offset of each Instruction starting from 0; used when converting references back to offsets. * * @param i * list of Instructions to process. * @return length of corresponding bytecode. * @see Instruction#nextOffset */ int relabel(Instruction i) { int index = 0; while (i != null) { i.label = index; index = i.nextOffset(index); i = i.next; } return index; } /** * Inversive to parseMethod, this converts the list of Instructions stored in a method_info object back to an array of * bytecode. * * @param m * method to unparse. * @return array of bytecode, or null on error. * @see CFG#reconstructInstructions * @see ClassFile#parseMethod * @see ClassFile#relabel * @see Instruction#compile */ byte[] unparseMethod(method_info m) { int codesize; byte bc[]; Instruction i; // Rebuild instruction sequence m.cfg.reconstructInstructions(); // relabel instructions and get size of code array codesize = relabel(m.instructions); // construct a new array for the byte-code bc = new byte[codesize]; // then recompile the instructions into byte-code i = m.instructions; codesize = 0; while (i != null) { codesize = i.compile(bc, codesize); i = i.next; } if (codesize != bc.length) { logger.warn("code size doesn't match array length!"); } return bc; } /** * Inversive to parse, this method calls unparseMethod for each method, storing the resulting bytecode in the method's code * attribute, and recomputing offsets for exception handlers. * * @see ClassFile#unparseMethod */ void unparse() { int i, j; Code_attribute ca; byte bc[]; method_info mi; exception_table_entry e; for (i = 0; i < methods_count; i++) { mi = methods[i]; // locate code attribute ca = mi.locate_code_attribute(); if (ca == null) { continue; } bc = unparseMethod(mi); if (bc == null) { logger.debug("Recompile of " + mi.toName(constant_pool) + " failed!"); } else { ca.code_length = bc.length; ca.code = bc; // also recompile exception table for (j = 0; j < ca.exception_table_length; j++) { e = ca.exception_table[j]; e.start_pc = (e.start_inst.label); if (e.end_inst != null) { e.end_pc = (e.end_inst.label); } else { e.end_pc = (int) (ca.code_length); } e.handler_pc = (e.handler_inst.label); } } } } /** * Static utility method to parse the given method descriptor string. * * @param s * descriptor string. * @return return type of method. * @see ClassFile#parseDesc * @see ClassFile#parseMethodDesc_params */ static String parseMethodDesc_return(String s) { int j; j = s.lastIndexOf(')'); if (j >= 0) { return parseDesc(s.substring(j + 1), ","); } return parseDesc(s, ","); } /** * Static utility method to parse the given method descriptor string. * * @param s * descriptor string. * @return comma-separated ordered list of parameter types * @see ClassFile#parseDesc * @see ClassFile#parseMethodDesc_return */ static String parseMethodDesc_params(String s) { int i, j; i = s.indexOf('('); if (i >= 0) { j = s.indexOf(')', i + 1); if (j >= 0) { return parseDesc(s.substring(i + 1, j), ","); } } return ""; } /** * Static utility method to parse the given method descriptor string. * * @param desc * descriptor string. * @param sep * String to use as a separator between types. * @return String of types parsed. * @see ClassFile#parseDesc * @see ClassFile#parseMethodDesc_return */ static String parseDesc(String desc, String sep) { String params = "", param; char c; int i, len, arraylevel = 0; boolean didone = false; len = desc.length(); for (i = 0; i < len; i++) { c = desc.charAt(i); if (c == DESC_BYTE.charAt(0)) { param = "byte"; } else if (c == DESC_CHAR.charAt(0)) { param = "char"; } else if (c == DESC_DOUBLE.charAt(0)) { param = "double"; } else if (c == DESC_FLOAT.charAt(0)) { param = "float"; } else if (c == DESC_INT.charAt(0)) { param = "int"; } else if (c == DESC_LONG.charAt(0)) { param = "long"; } else if (c == DESC_SHORT.charAt(0)) { param = "short"; } else if (c == DESC_BOOLEAN.charAt(0)) { param = "boolean"; } else if (c == DESC_VOID.charAt(0)) { param = "void"; } else if (c == DESC_ARRAY.charAt(0)) { arraylevel++; continue; } else if (c == DESC_OBJECT.charAt(0)) { int j; j = desc.indexOf(';', i + 1); if (j < 0) { logger.warn("Parse error -- can't find a ; in " + desc.substring(i + 1)); param = ""; } else { if (j - i > 10 && desc.substring(i + 1, i + 11).compareTo("java/lang/") == 0) { i = i + 10; } param = desc.substring(i + 1, j); // replace '/'s with '.'s param = param.replace('/', '.'); i = j; } } else { param = "???"; } if (didone) { params = params + sep; } params = params + param; while (arraylevel > 0) { params = params + "[]"; arraylevel--; } didone = true; } return params; } /** * Locates a method by name. * * @param s * name of method. * @return method_info object representing method, or null if not found. * @see method_info#toName */ method_info findMethod(String s) { method_info m; int i; for (i = 0; i < methods_count; i++) { m = methods[i]; if (s.equals(m.toName(constant_pool))) { return m; } } return null; } /** * Displays a the prototypes for all the methods defined in this ClassFile. * * @see ClassFile#methods * @see ClassFile#methods_count * @see method_info#prototype */ void listMethods() { int i; for (i = 0; i < methods_count; i++) { logger.debug("" + methods[i].prototype(constant_pool)); } } /** * Displays the entire constant pool. * * @see ClassFile#constant_pool * @see ClassFile#constant_pool_count * @see cp_info#toString */ void listConstantPool() { cp_info c; int i; // note that we start at 1 in the constant pool for (i = 1; i < constant_pool_count; i++) { c = constant_pool[i]; logger.debug("[" + i + "] " + c.typeName() + "=" + c.toString(constant_pool)); if ((constant_pool[i]).tag == cp_info.CONSTANT_Long || (constant_pool[i]).tag == cp_info.CONSTANT_Double) { // must skip an entry after a long or double constant i++; } } } /** * Displays the list of fields defined in this ClassFile, including any static initializers (constants). * * @see ClassFile#fields * @see ClassFile#fields_count * @see field_info#prototype * @see ConstantValue_attribute */ void listFields() { field_info fi; ConstantValue_attribute cva; CONSTANT_Utf8_info cm; int i, j; for (i = 0; i < fields_count; i++) { fi = fields[i]; logger.debug("" + fi.prototype(constant_pool)); // see if has a constant value attribute for (j = 0; j < fi.attributes_count; j++) { cm = (CONSTANT_Utf8_info) (constant_pool[fi.attributes[j].attribute_name]); if (cm.convert().compareTo(attribute_info.ConstantValue) == 0) { cva = (ConstantValue_attribute) (fi.attributes[j]); // dm = (CONSTANT_Utf8_info)(constant_pool[cva.constantvalue_index]); logger.debug(" = " + constant_pool[cva.constantvalue_index].toString(constant_pool)); break; } } logger.debug(";"); } } /** * Moves a method to a different index in the methods array. * * @param m * name of method to move. * @param pos * desired index. * @see ClassFile#methods */ void moveMethod(String m, int pos) { int i, j; method_info mthd; logger.debug("Moving " + m + " to position " + pos + " of " + methods_count); for (i = 0; i < methods_count; i++) { if (m.compareTo(methods[i].toName(constant_pool)) == 0) { mthd = methods[i]; if (i > pos) { for (j = i; j > pos && j > 0; j--) { methods[j] = methods[j - 1]; } methods[pos] = mthd; } else if (i < pos) { for (j = i; j < pos && j < methods_count - 1; j++) { methods[j] = methods[j + 1]; } methods[pos] = mthd; } return; } } } /** * Answers whether this class is an immediate descendant (as subclass or as an implementation of an interface) of the given * class. * * @param cf * ClassFile of supposed parent. * @return true if it is a parent, false otherwise. * @see ClassFile#descendsFrom(String) */ boolean descendsFrom(ClassFile cf) { return descendsFrom(cf.toString()); } /** * Answers whether this class is an immediate descendant (as subclass or as an implementation of an interface) of the given * class. * * @param cname * name of supposed parent. * @return true if it is a parent, false otherwise. * @see ClassFile#descendsFrom(ClassFile) */ boolean descendsFrom(String cname) { cp_info cf; int i; cf = constant_pool[super_class]; if (cf.toString(constant_pool).compareTo(cname) == 0) { return true; } for (i = 0; i < interfaces_count; i++) { cf = constant_pool[interfaces[i]]; if (cf.toString(constant_pool).compareTo(cname) == 0) { return true; } } return false; } /** * Answers whether this class can have subclasses outside its package. * * @return true if it cannot, false if it might. */ boolean isSterile() { if ((access_flags & ACC_PUBLIC) != 0 && (access_flags & ACC_FINAL) == 0) { return false; } return true; } /** * Given the name of a class --- possibly with .class after it, this answers whether the class might refer to this * ClassFile object. * * @return true if it does, false if it doesn't. */ boolean sameClass(String cfn) { String s = cfn; int i = s.lastIndexOf(".class"); if (i > 0) { // has .class after it s = s.substring(0, i); // cut off the .class } if (s.compareTo(toString()) == 0) { return true; } return false; } /** * Returns the name of a specific field in the field array. * * @param i * index of field in field array. * @return name of field. */ String fieldName(int i) { return fields[i].toName(constant_pool); } /* * DEPRECATED // Locates the given classfile, and extracts it from the list. // It cannot be the first one in the list, and * this returns null // or the classfile. static ClassFile removeClassFile(ClassFile cfhead,String cfn) { ClassFile * cf,cfprev; cf = cfhead; cfprev = null; while (cf!=null) { if (cf.sameClass(cfn)) { if (cfprev==null) return null; // * this shouldn't happen cfprev.next = cf.next; cf.next = null; return cf; } cfprev = cf; cf = cf.next; } return null; } * * // returns true if this class contains any references to the given // cuClass.cuName, which is of type cuDesc. Searches * for methods if // ismethod is true, fields otherwise. boolean refersTo(boolean ismethod,CONSTANT_Utf8_info cuClass, * CONSTANT_Utf8_info cuName,CONSTANT_Utf8_info cuDesc) { int i; CONSTANT_Utf8_info cu; // note that we start at 1 in the * constant pool if (ismethod) { for (i=1;i=1;largest--) { for (i=0;ia[largest]) { s = a[i]; a[i] = a[largest]; a[largest] = s; } } } return a; } * * // Given a new constant pool, and a list of redirections // (new index = redirect[old index]), this changes all constant * // pool entries, and installs the new constant pool of size size void changeConstantPool(short redirect[],cp_info * newCP[],short size) { Debig d = new Debig(this); d.redirectCPRefs(redirect); constant_pool = newCP; constant_pool_count * = size; } * * // the constant pool is typically a few hundred entries in size, and so // is just a bit too big to make use of * insertion/selection sort. // However, the variable size of the entries makes using a heapsort // or quicksort rather * cumbersome, so since it is quite close to the // limits of efficient insertion/selection sort, we'll use that anyway. * void sortConstantPool() { cp_info newcp[] = new cp_info[constant_pool_count]; short redirect[] = new * short[constant_pool_count]; newcp[0] = constant_pool[0]; // the 0-entry stays put redirect[0] = (short)0; int * smallest,j; for (int i=1;i " + i); * * if (constant_pool[smallest].tag==cp_info.CONSTANT_Double || constant_pool[smallest].tag==cp_info.CONSTANT_Long) { * redirect[++smallest] = (short)(++i); newcp[i] = constant_pool[smallest]; } } // constant pool is now sorted into newcp * changeConstantPool(redirect,newcp,constant_pool_count); logger.debug("Finished sorting constant pool"); } * * // just a wrapper for the debigulation, so we can elegantly allocate // a new debigulator, debigualte and then produce * some output void debigulate(boolean attribs,boolean privates) { Debig debigulator = new Debig(this); * debigulator.debigulate(attribs,privates); debigulator.setCF(null); * * inf.verboseReport(G.v().out); } */ }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy