/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2011 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 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 Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package proguard.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.annotation.visitor.*; import proguard.classfile.attribute.preverification.*; import proguard.classfile.attribute.preverification.visitor.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.*; /** * This ClassVisitor remaps all possible references to constant pool entries * of the classes that it visits, based on a given index map. It is assumed that * the constant pool entries themselves have already been remapped. * * @author Eric Lafortune */ public class ConstantPoolRemapper extends SimplifiedVisitor implements ClassVisitor, ConstantVisitor, MemberVisitor, AttributeVisitor, BootstrapMethodInfoVisitor, InnerClassesInfoVisitor, ExceptionInfoVisitor, InstructionVisitor, StackMapFrameVisitor, VerificationTypeVisitor, LocalVariableInfoVisitor, LocalVariableTypeInfoVisitor, AnnotationVisitor, ElementValueVisitor { private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(false); private int[] constantIndexMap; /** * Sets the given mapping of old constant pool entry indexes to their new * indexes. */ public void setConstantIndexMap(int[] constantIndexMap) { this.constantIndexMap = constantIndexMap; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Remap the local constant pool references. programClass.u2thisClass = remapConstantIndex(programClass.u2thisClass); programClass.u2superClass = remapConstantIndex(programClass.u2superClass); remapConstantIndexArray(programClass.u2interfaces, programClass.u2interfacesCount); // Remap the references of the contant pool entries themselves. programClass.constantPoolEntriesAccept(this); // Remap the references in all fields, methods, and attributes. programClass.fieldsAccept(this); programClass.methodsAccept(this); programClass.attributesAccept(this); } public void visitLibraryClass(LibraryClass libraryClass) { } // Implementations for ConstantVisitor. public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) { // Nothing to do. } public void visitLongConstant(Clazz clazz, LongConstant longConstant) { // Nothing to do. } public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) { // Nothing to do. } public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) { // Nothing to do. } public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { stringConstant.u2stringIndex = remapConstantIndex(stringConstant.u2stringIndex); } public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) { // Nothing to do. } public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) { invokeDynamicConstant.u2nameAndTypeIndex = remapConstantIndex(invokeDynamicConstant.u2nameAndTypeIndex); } public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) { methodHandleConstant.u2referenceIndex = remapConstantIndex(methodHandleConstant.u2referenceIndex); } public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant) { fieldrefConstant.u2classIndex = remapConstantIndex(fieldrefConstant.u2classIndex); fieldrefConstant.u2nameAndTypeIndex = remapConstantIndex(fieldrefConstant.u2nameAndTypeIndex); } public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant) { interfaceMethodrefConstant.u2classIndex = remapConstantIndex(interfaceMethodrefConstant.u2classIndex); interfaceMethodrefConstant.u2nameAndTypeIndex = remapConstantIndex(interfaceMethodrefConstant.u2nameAndTypeIndex); } public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant) { methodrefConstant.u2classIndex = remapConstantIndex(methodrefConstant.u2classIndex); methodrefConstant.u2nameAndTypeIndex = remapConstantIndex(methodrefConstant.u2nameAndTypeIndex); } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { classConstant.u2nameIndex = remapConstantIndex(classConstant.u2nameIndex); } public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) { methodTypeConstant.u2descriptorIndex = remapConstantIndex(methodTypeConstant.u2descriptorIndex); } public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) { nameAndTypeConstant.u2nameIndex = remapConstantIndex(nameAndTypeConstant.u2nameIndex); nameAndTypeConstant.u2descriptorIndex = remapConstantIndex(nameAndTypeConstant.u2descriptorIndex); } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { visitMember(programClass, programField); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { visitMember(programClass, programMethod); } private void visitMember(ProgramClass programClass, ProgramMember programMember) { // Remap the local constant pool references. programMember.u2nameIndex = remapConstantIndex(programMember.u2nameIndex); programMember.u2descriptorIndex = remapConstantIndex(programMember.u2descriptorIndex); // Remap the constant pool references of the remaining attributes. programMember.attributesAccept(programClass, this); } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { // Library classes are left unchanged. } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { // Library classes are left unchanged. } // Implementations for AttributeVisitor. public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute) { unknownAttribute.u2attributeNameIndex = remapConstantIndex(unknownAttribute.u2attributeNameIndex); // There's not much else we can do with unknown attributes. } public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) { bootstrapMethodsAttribute.u2attributeNameIndex = remapConstantIndex(bootstrapMethodsAttribute.u2attributeNameIndex); // Remap the constant pool references of the bootstrap method entries. bootstrapMethodsAttribute.bootstrapMethodEntriesAccept(clazz, this); } public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) { sourceFileAttribute.u2attributeNameIndex = remapConstantIndex(sourceFileAttribute.u2attributeNameIndex); sourceFileAttribute.u2sourceFileIndex = remapConstantIndex(sourceFileAttribute.u2sourceFileIndex); } public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute) { sourceDirAttribute.u2attributeNameIndex = remapConstantIndex(sourceDirAttribute.u2attributeNameIndex); sourceDirAttribute.u2sourceDirIndex = remapConstantIndex(sourceDirAttribute.u2sourceDirIndex); } public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { innerClassesAttribute.u2attributeNameIndex = remapConstantIndex(innerClassesAttribute.u2attributeNameIndex); // Remap the constant pool references of the inner classes. innerClassesAttribute.innerClassEntriesAccept(clazz, this); } public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) { enclosingMethodAttribute.u2attributeNameIndex = remapConstantIndex(enclosingMethodAttribute.u2attributeNameIndex); enclosingMethodAttribute.u2classIndex = remapConstantIndex(enclosingMethodAttribute.u2classIndex); enclosingMethodAttribute.u2nameAndTypeIndex = remapConstantIndex(enclosingMethodAttribute.u2nameAndTypeIndex); } public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute) { deprecatedAttribute.u2attributeNameIndex = remapConstantIndex(deprecatedAttribute.u2attributeNameIndex); } public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute) { syntheticAttribute.u2attributeNameIndex = remapConstantIndex(syntheticAttribute.u2attributeNameIndex); } public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) { signatureAttribute.u2attributeNameIndex = remapConstantIndex(signatureAttribute.u2attributeNameIndex); signatureAttribute.u2signatureIndex = remapConstantIndex(signatureAttribute.u2signatureIndex); } public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) { constantValueAttribute.u2attributeNameIndex = remapConstantIndex(constantValueAttribute.u2attributeNameIndex); constantValueAttribute.u2constantValueIndex = remapConstantIndex(constantValueAttribute.u2constantValueIndex); } public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute) { exceptionsAttribute.u2attributeNameIndex = remapConstantIndex(exceptionsAttribute.u2attributeNameIndex); // Remap the constant pool references of the exceptions. remapConstantIndexArray(exceptionsAttribute.u2exceptionIndexTable, exceptionsAttribute.u2exceptionIndexTableLength); } public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { codeAttribute.u2attributeNameIndex = remapConstantIndex(codeAttribute.u2attributeNameIndex); // Initially, the code attribute editor doesn't contain any changes. codeAttributeEditor.reset(codeAttribute.u4codeLength); // Remap the constant pool references of the instructions. codeAttribute.instructionsAccept(clazz, method, this); // Apply the code atribute editor. It will only contain any changes if // the code length is changing at any point. codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute); // Remap the constant pool references of the exceptions and attributes. codeAttribute.exceptionsAccept(clazz, method, this); codeAttribute.attributesAccept(clazz, method, this); } public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) { stackMapAttribute.u2attributeNameIndex = remapConstantIndex(stackMapAttribute.u2attributeNameIndex); // Remap the constant pool references of the stack map frames. stackMapAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); } public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) { stackMapTableAttribute.u2attributeNameIndex = remapConstantIndex(stackMapTableAttribute.u2attributeNameIndex); // Remap the constant pool references of the stack map frames. stackMapTableAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); } public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) { lineNumberTableAttribute.u2attributeNameIndex = remapConstantIndex(lineNumberTableAttribute.u2attributeNameIndex); } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { localVariableTableAttribute.u2attributeNameIndex = remapConstantIndex(localVariableTableAttribute.u2attributeNameIndex); // Remap the constant pool references of the local variables. localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { localVariableTypeTableAttribute.u2attributeNameIndex = remapConstantIndex(localVariableTypeTableAttribute.u2attributeNameIndex); // Remap the constant pool references of the local variables. localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) { annotationsAttribute.u2attributeNameIndex = remapConstantIndex(annotationsAttribute.u2attributeNameIndex); // Remap the constant pool references of the annotations. annotationsAttribute.annotationsAccept(clazz, this); } public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) { parameterAnnotationsAttribute.u2attributeNameIndex = remapConstantIndex(parameterAnnotationsAttribute.u2attributeNameIndex); // Remap the constant pool references of the annotations. parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); } public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) { annotationDefaultAttribute.u2attributeNameIndex = remapConstantIndex(annotationDefaultAttribute.u2attributeNameIndex); // Remap the constant pool references of the annotations. annotationDefaultAttribute.defaultValueAccept(clazz, this); } // Implementations for BootstrapMethodInfoVisitor. public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo) { bootstrapMethodInfo.u2methodHandleIndex = remapConstantIndex(bootstrapMethodInfo.u2methodHandleIndex); // Remap the constant pool references of the bootstrap methods.. remapConstantIndexArray(bootstrapMethodInfo.u2methodArguments, bootstrapMethodInfo.u2methodArgumentCount); } // Implementations for InnerClassesInfoVisitor. public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) { if (innerClassesInfo.u2innerClassIndex != 0) { innerClassesInfo.u2innerClassIndex = remapConstantIndex(innerClassesInfo.u2innerClassIndex); } if (innerClassesInfo.u2outerClassIndex != 0) { innerClassesInfo.u2outerClassIndex = remapConstantIndex(innerClassesInfo.u2outerClassIndex); } if (innerClassesInfo.u2innerNameIndex != 0) { innerClassesInfo.u2innerNameIndex = remapConstantIndex(innerClassesInfo.u2innerNameIndex); } } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { if (exceptionInfo.u2catchType != 0) { exceptionInfo.u2catchType = remapConstantIndex(exceptionInfo.u2catchType); } } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { // Is the new constant pool index different from the original one? int newConstantIndex = remapConstantIndex(constantInstruction.constantIndex); if (newConstantIndex != constantInstruction.constantIndex) { // Replace the instruction. Instruction replacementInstruction = new ConstantInstruction(constantInstruction.opcode, newConstantIndex, constantInstruction.constant).shrink(); codeAttributeEditor.replaceInstruction(offset, replacementInstruction); } } // Implementations for StackMapFrameVisitor. public void visitAnyStackMapFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrame stackMapFrame) {} public void visitSameOneFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame) { // Remap the constant pool references of the verification types. sameOneFrame.stackItemAccept(clazz, method, codeAttribute, offset, this); } public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame) { // Remap the constant pool references of the verification types. moreZeroFrame.additionalVariablesAccept(clazz, method, codeAttribute, offset, this); } public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame) { // Remap the constant pool references of the verification types. fullFrame.variablesAccept(clazz, method, codeAttribute, offset, this); fullFrame.stackAccept(clazz, method, codeAttribute, offset, this); } // Implementations for VerificationTypeVisitor. public void visitAnyVerificationType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationType verificationType) {} public void visitObjectType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ObjectType objectType) { objectType.u2classIndex = remapConstantIndex(objectType.u2classIndex); } // Implementations for LocalVariableInfoVisitor. public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) { localVariableInfo.u2nameIndex = remapConstantIndex(localVariableInfo.u2nameIndex); localVariableInfo.u2descriptorIndex = remapConstantIndex(localVariableInfo.u2descriptorIndex); } // Implementations for LocalVariableTypeInfoVisitor. public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) { localVariableTypeInfo.u2nameIndex = remapConstantIndex(localVariableTypeInfo.u2nameIndex); localVariableTypeInfo.u2signatureIndex = remapConstantIndex(localVariableTypeInfo.u2signatureIndex); } // Implementations for AnnotationVisitor. public void visitAnnotation(Clazz clazz, Annotation annotation) { annotation.u2typeIndex = remapConstantIndex(annotation.u2typeIndex); // Remap the constant pool references of the element values. annotation.elementValuesAccept(clazz, this); } // Implementations for ElementValueVisitor. public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue) { constantElementValue.u2elementNameIndex = remapConstantIndex(constantElementValue.u2elementNameIndex); constantElementValue.u2constantValueIndex = remapConstantIndex(constantElementValue.u2constantValueIndex); } public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) { enumConstantElementValue.u2elementNameIndex = remapConstantIndex(enumConstantElementValue.u2elementNameIndex); enumConstantElementValue.u2typeNameIndex = remapConstantIndex(enumConstantElementValue.u2typeNameIndex); enumConstantElementValue.u2constantNameIndex = remapConstantIndex(enumConstantElementValue.u2constantNameIndex); } public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue) { classElementValue.u2elementNameIndex = remapConstantIndex(classElementValue.u2elementNameIndex); classElementValue.u2classInfoIndex = remapConstantIndex(classElementValue.u2classInfoIndex); } public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) { annotationElementValue.u2elementNameIndex = remapConstantIndex(annotationElementValue.u2elementNameIndex); // Remap the constant pool references of the annotation. annotationElementValue.annotationAccept(clazz, this); } public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) { arrayElementValue.u2elementNameIndex = remapConstantIndex(arrayElementValue.u2elementNameIndex); // Remap the constant pool references of the element values. arrayElementValue.elementValuesAccept(clazz, annotation, this); } // Small utility methods. /** * Remaps all constant pool indices in the given array. */ private void remapConstantIndexArray(int[] array, int length) { for (int index = 0; index < length; index++) { array[index] = remapConstantIndex(array[index]); } } /** * Returns the new constant pool index of the entry at the * given index. */ private int remapConstantIndex(int constantIndex) { return constantIndexMap[constantIndex]; } }