/** * Auxiliary method to extract the signature associated with the resource. This is fetched from * the 'Signature_attribute' structure, which has the following format: * * <p>[java 8] Signature_attribute { u2 attribute_name_index; u4 attribute_length; u2 * signature_index; } * * <p>- signature_index: The value of the 'signature_index' must be a valid index in the * 'constant_pool' table. The 'constant_pool' entry at that index must be a 'CONSTANT_Utf8_info' * structure representing a class signature if this 'Signature' is an attribute of a 'ClassFile' * structure. It is a method signature of this 'Signature' is an attribute of a 'method_info' * structure. It is a field signature otherwise. * * @param dataInputStream The byte stream associated with the resource (aka .class file). * @param resource The resource associated with the attribute. * @throws IOException When reading bytes from the stream fails. */ public static void extractSignature( DataInputStream dataInputStream, String location, Resource resource) throws IOException { int signatureIndex = dataInputStream.readUnsignedShort(); String signature = ConstantPoolAnalyser.extractStringValueByConstantPoolIndex( resource.getConstantPool(), signatureIndex); LOGGER.debug("Class signature: " + signature + " (location: " + location + ")"); // Add signature (when applicable) to the referenced classes SignatureAnalyser.referencedClasses(resource.getReferencedClasses(), signature); }
/** * The structure has the following (general) format: * * <p>[java 8] annotation { u2 type_index; u2 num_element_value_pairs; element_value_pairs * element_value_pair[num_element_value_pairs] } * * <p>- type_index: The value of the 'type_index' item must be a valid index in the * 'constant_pool' table. The 'constant_pool' table entry at that index must be a * 'CONSTANT_Utf8_info' structure representing a field descriptor. The field descriptor denotes * the type of the annotation represented by this 'annotation' structure. - * num_element_value_pairs: The value of 'num_element_value_pairs' item gives the number of * element-value pairs of the annotation represented by this 'annotation' structure. * * @param dataInputStream The byte stream associated with the resource (aka .class file). * @param index The annotation index, used for precise data logging. * @param resource The resource associated with the attribute. * @throws IOException When reading bytes from the stream fails. */ protected static void extractAnnotation( DataInputStream dataInputStream, int index, Resource resource) throws IOException { StringBuilder buffer = new StringBuilder(); buffer.append("Annotation (index: ").append(index).append(")"); // Read the type index int typeIndex = dataInputStream.readUnsignedShort(); String descriptor = ConstantPoolAnalyser.extractStringValueByConstantPoolIndex( resource.getConstantPool(), typeIndex); buffer.append(", of type (index: ").append(typeIndex).append("): ").append(descriptor); LOGGER.debug(buffer.toString()); // Add signature (when applicable) to the referenced classes SignatureAnalyser.referencedClasses(resource.getReferencedClasses(), descriptor); // Read the element value pairs int numberOfElementValuePairs = dataInputStream.readUnsignedShort(); extractElementValuePairs(dataInputStream, numberOfElementValuePairs, resource); }
/** * Auxiliary method to extract an 'element_value' from the data input stream. Note that this * method can be called recursively (in case the value of the element_value is an array with more * element_value's). * * @param dataInputStream The byte stream associated with the resource (aka .class file). * @param buffer The buffer with relevant text to support (deep and semantic) logging. * @param resource The resource associated with the attribute. * @throws IOException When reading bytes from the stream fails. */ public static void extractElementValue( DataInputStream dataInputStream, StringBuilder buffer, Resource resource) throws IOException { // Read the tag int tag = dataInputStream.readUnsignedByte(); // Read the element value switch ((char) tag) { case 'B': int constantByteValueIndex = dataInputStream.readUnsignedShort(); ConstantInfo byteValue = findConstantByIndex(constantByteValueIndex, resource.getConstantPool()); buffer .append(", with value (index: ") .append(constantByteValueIndex) .append(", type: byte): ") .append(byteValue.getIntValue()); LOGGER.debug(buffer.toString()); break; case 'C': int constantCharValueIndex = dataInputStream.readUnsignedShort(); ConstantInfo charValue = findConstantByIndex(constantCharValueIndex, resource.getConstantPool()); buffer .append(", with value (index: ") .append(constantCharValueIndex) .append(", type: char): ") .append((char) charValue.getIntValue()); LOGGER.debug(buffer.toString()); break; case 'D': int constantDoubleValueIndex = dataInputStream.readUnsignedShort(); ConstantInfo doubleValue = findConstantByIndex(constantDoubleValueIndex, resource.getConstantPool()); buffer .append(", with value (index: ") .append(constantDoubleValueIndex) .append(", type: double): ") .append(doubleValue.getIntValue()); LOGGER.debug(buffer.toString()); break; case 'F': int constantFloatValueIndex = dataInputStream.readUnsignedShort(); ConstantInfo floatValue = findConstantByIndex(constantFloatValueIndex, resource.getConstantPool()); buffer .append(", with value (index: ") .append(constantFloatValueIndex) .append(", type: float): ") .append(floatValue.getIntValue()); LOGGER.debug(buffer.toString()); break; case 'I': // Read the value index int constantIntegerValueIndex = dataInputStream.readUnsignedShort(); ConstantInfo integerValue = findConstantByIndex(constantIntegerValueIndex, resource.getConstantPool()); buffer .append(", with value (index: ") .append(constantIntegerValueIndex) .append(", type: integer): ") .append(integerValue.getIntValue()); LOGGER.debug(buffer.toString()); break; case 'J': // Read the value index int constantLongValueIndex = dataInputStream.readUnsignedShort(); ConstantInfo longValue = findConstantByIndex(constantLongValueIndex, resource.getConstantPool()); buffer .append(", with value (index: ") .append(constantLongValueIndex) .append(", type: long): ") .append(longValue.getIntValue()); LOGGER.debug(buffer.toString()); break; case 'S': // Read the value index int constantShortValueIndex = dataInputStream.readUnsignedShort(); ConstantInfo shortValue = findConstantByIndex(constantShortValueIndex, resource.getConstantPool()); buffer .append(", with value (index: ") .append(constantShortValueIndex) .append(", type: short): ") .append(shortValue.getIntValue()); LOGGER.debug(buffer.toString()); break; case 'Z': // Read the value index int constantBooleanValueIndex = dataInputStream.readUnsignedShort(); ConstantInfo booleanValue = findConstantByIndex(constantBooleanValueIndex, resource.getConstantPool()); buffer .append(", with value (index: ") .append(constantBooleanValueIndex) .append(", type: boolean): ") .append(booleanValue.getIntValue()); LOGGER.debug(buffer.toString()); break; case 's': // Read the value index int constantStringValueIndex = dataInputStream.readUnsignedShort(); ConstantInfo stringValue = findConstantByIndex(constantStringValueIndex, resource.getConstantPool()); buffer .append(", with value (index: ") .append(constantStringValueIndex) .append(", type: String): ") .append(stringValue.getStringValue()); LOGGER.debug(buffer.toString()); break; case 'e': // Read the enum type index int typeNameIndex = dataInputStream.readUnsignedShort(); // The value of the type_name_index item must be a valid index in the 'constant_pool' table. // The 'constant_pool' // entry at that index must be a 'CONSTANT_Utf8_info' structure representing a field // descriptor. String typeNameDescriptor = ConstantPoolAnalyser.extractStringValueByConstantPoolIndex( resource.getConstantPool(), typeNameIndex); // Read the constant name index int constantNameIndex = dataInputStream.readUnsignedShort(); // The value of constant_name_index item must be a valid index in the 'constant_pool' table. // The 'constant_pool' // entry at that index must be a 'CONSTANT_Utf8_info' structure. String enumValue = ConstantPoolAnalyser.extractStringValueByConstantPoolIndex( resource.getConstantPool(), constantNameIndex); buffer .append(", with type name (index: ") .append(typeNameIndex) .append(", type: enum): ") .append(typeNameDescriptor); buffer .append(" and value (index: ") .append(constantNameIndex) .append("): ") .append(enumValue); LOGGER.debug(buffer.toString()); // Add signature (when applicable) to the referenced classes SignatureAnalyser.referencedClasses(resource.getReferencedClasses(), typeNameDescriptor); break; case 'c': // Read the class index int classInfoIndex = dataInputStream.readUnsignedShort(); // The class_info_index denotes a class literal as the value of this element-value pair. The // class_info_index // must be a valid index into the 'constant_pool' table. The 'constant_pool' entry at that // index must be a // 'CONSTANT_Utf8_info' structure representing a return descriptor. The return descriptor // give the type // corresponding to the class literal represented by this 'element_value' structure. Types // correspond to class // literals as follows: // // - For a class literal C.class, where C is the name of the class, interface, or array // type, the corresponding // type is C. The return descriptor in the 'constant_pool' will be an ObjectType or an // ArrayType. // Example: the class literal Object.class corresponds to Object, so the 'constant_pool' // entry is Ljava/lang/Object; // - For a class literal p.class, where p is the name of a primitive type, the corresponding // type is p. The // return descriptor in the 'constant_pool' will be a BaseType character. // Example: the literal int.class corresponds to the type int, so the 'constant_pool' // entry is I. // - For a class literal void.class, the corresponding type is void. The return descriptor // in the 'constant_pool' // will be V. // Example: the literal void.class corresponds to void, so the 'constant_pool' entry is V, // whereas // the class literal Void.class corresponds to the type Void, so the 'constant_pool' entry // is Ljava/lang/Void; String descriptor = ConstantPoolAnalyser.extractStringValueByConstantPoolIndex( resource.getConstantPool(), classInfoIndex); buffer .append(", with value (index: ") .append(classInfoIndex) .append(", type: Class) with descriptor: ") .append(descriptor); LOGGER.debug(buffer.toString()); // Add signature (when applicable) to the referenced classes SignatureAnalyser.referencedClasses(resource.getReferencedClasses(), descriptor); break; case '@': buffer.append( ", with type annotation -> delegating to extract annotation (with index: -1)..."); LOGGER.debug(buffer.toString()); // Read annotation extractAnnotation(dataInputStream, -1, resource); break; case '[': int numberOfValues = dataInputStream.readUnsignedShort(); buffer .append(", with type array (size: ") .append(numberOfValues) .append(") entering recursion..."); LOGGER.debug(buffer.toString()); // Read array members, delegate by recursion LOGGER.debug("Number of nested element-value pairs: " + numberOfValues); for (int index = 0; index < numberOfValues; index++) { StringBuilder nestedBuffer = new StringBuilder(); nestedBuffer.append("Nested element-value pair (index: ").append(index).append(")"); extractElementValue(dataInputStream, nestedBuffer, resource); } break; default: buffer.append(", but tag is unsupported: ").append(tag); LOGGER.warn(buffer.toString()); } }