1 /* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu) 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the Free 9 * Software Foundation; either version 2 of the License, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, write to the Free Software Foundation, Inc., 19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 package proguard.classfile.editor; 22 23 import proguard.classfile.*; 24 import proguard.classfile.attribute.*; 25 import proguard.classfile.attribute.annotation.*; 26 import proguard.classfile.attribute.annotation.target.*; 27 import proguard.classfile.attribute.annotation.target.visitor.*; 28 import proguard.classfile.attribute.annotation.visitor.TypeAnnotationVisitor; 29 import proguard.classfile.attribute.visitor.*; 30 import proguard.classfile.instruction.*; 31 import proguard.classfile.instruction.visitor.InstructionVisitor; 32 import proguard.classfile.util.SimplifiedVisitor; 33 34 /** 35 * This AttributeVisitor remaps variable indexes in all attributes that it 36 * visits, based on a given index map. 37 * 38 * @author Eric Lafortune 39 */ 40 public class VariableRemapper 41 extends SimplifiedVisitor 42 implements AttributeVisitor, 43 InstructionVisitor, 44 LocalVariableInfoVisitor, 45 LocalVariableTypeInfoVisitor, 46 TypeAnnotationVisitor, 47 TargetInfoVisitor, 48 LocalVariableTargetElementVisitor 49 { 50 private static final boolean DEBUG = false; 51 52 53 private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(); 54 55 private int[] variableMap; 56 57 58 /** 59 * Sets the given mapping of old variable indexes to their new indexes. 60 * Variables that should disappear can be mapped to -1. 61 */ setVariableMap(int[] variableMap)62 public void setVariableMap(int[] variableMap) 63 { 64 this.variableMap = variableMap; 65 } 66 67 68 // Implementations for AttributeVisitor. 69 visitAnyAttribute(Clazz clazz, Attribute attribute)70 public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 71 72 visitMethodParametersAttribute(Clazz clazz, Method method, MethodParametersAttribute methodParametersAttribute)73 public void visitMethodParametersAttribute(Clazz clazz, Method method, MethodParametersAttribute methodParametersAttribute) 74 { 75 // Reorder the array with parameter information. 76 ParameterInfo[] oldParameters = methodParametersAttribute.parameters; 77 ParameterInfo[] newParameters = 78 new ParameterInfo[methodParametersAttribute.u1parametersCount]; 79 80 for (int index = 0; index < methodParametersAttribute.u1parametersCount; index++) 81 { 82 newParameters[remapVariable(index)] = oldParameters[index]; 83 } 84 85 methodParametersAttribute.parameters = newParameters; 86 } 87 88 visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)89 public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) 90 { 91 if (DEBUG) 92 { 93 System.out.println("VariableRemapper: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)); 94 for (int index= 0; index < codeAttribute.u2maxLocals; index++) 95 { 96 System.out.println(" v"+index+" -> "+variableMap[index]); 97 } 98 } 99 100 // Remap the variables of the attributes, before editing the code and 101 // cleaning up its local variable frame. 102 codeAttribute.attributesAccept(clazz, method, this); 103 104 // Initially, the code attribute editor doesn't contain any changes. 105 codeAttributeEditor.reset(codeAttribute.u4codeLength); 106 107 // Remap the variables of the instructions. 108 codeAttribute.instructionsAccept(clazz, method, this); 109 110 // Apply the code atribute editor. 111 codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute); 112 } 113 114 visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute)115 public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) 116 { 117 // Remap the variable references of the local variables. 118 localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); 119 } 120 121 visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute)122 public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) 123 { 124 // Remap the variable references of the local variables. 125 localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); 126 } 127 128 visitAnyTypeAnnotationsAttribute(Clazz clazz, TypeAnnotationsAttribute typeAnnotationsAttribute)129 public void visitAnyTypeAnnotationsAttribute(Clazz clazz, TypeAnnotationsAttribute typeAnnotationsAttribute) 130 { 131 // Remap the variable references of local variable type annotations. 132 typeAnnotationsAttribute.typeAnnotationsAccept(clazz, this); 133 } 134 135 136 // Implementations for LocalVariableInfoVisitor. 137 visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo)138 public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) 139 { 140 localVariableInfo.u2index = 141 remapVariable(localVariableInfo.u2index); 142 } 143 144 145 // Implementations for LocalVariableTypeInfoVisitor. 146 visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo)147 public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) 148 { 149 localVariableTypeInfo.u2index = 150 remapVariable(localVariableTypeInfo.u2index); 151 } 152 153 154 // Implementations for TypeAnnotationVisitor. 155 visitTypeAnnotation(Clazz clazz, TypeAnnotation typeAnnotation)156 public void visitTypeAnnotation(Clazz clazz, TypeAnnotation typeAnnotation) 157 { 158 typeAnnotation.targetInfoAccept(clazz, this); 159 } 160 161 162 // Implementations for TargetInfoVisitor. 163 visitAnyTargetInfo(Clazz clazz, TypeAnnotation typeAnnotation, TargetInfo targetInfo)164 public void visitAnyTargetInfo(Clazz clazz, TypeAnnotation typeAnnotation, TargetInfo targetInfo) {} 165 166 visitLocalVariableTargetInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, TypeAnnotation typeAnnotation, LocalVariableTargetInfo localVariableTargetInfo)167 public void visitLocalVariableTargetInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, TypeAnnotation typeAnnotation, LocalVariableTargetInfo localVariableTargetInfo) 168 { 169 localVariableTargetInfo.targetElementsAccept(clazz, method, codeAttribute, typeAnnotation, this); 170 } 171 172 173 // Implementations for LocalVariableTargetElementVisitor. 174 visitLocalVariableTargetElement(Clazz clazz, Method method, CodeAttribute codeAttribute, TypeAnnotation typeAnnotation, LocalVariableTargetInfo localVariableTargetInfo, LocalVariableTargetElement localVariableTargetElement)175 public void visitLocalVariableTargetElement(Clazz clazz, Method method, CodeAttribute codeAttribute, TypeAnnotation typeAnnotation, LocalVariableTargetInfo localVariableTargetInfo, LocalVariableTargetElement localVariableTargetElement) 176 { 177 localVariableTargetElement.u2index = 178 remapVariable(localVariableTargetElement.u2index); 179 } 180 181 182 // Implementations for InstructionVisitor. 183 visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)184 public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} 185 186 visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)187 public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) 188 { 189 // Is the new variable index different from the original one? 190 int oldVariableIndex = variableInstruction.variableIndex; 191 int newVariableIndex = remapVariable(oldVariableIndex); 192 if (newVariableIndex != oldVariableIndex) 193 { 194 // Replace the instruction. 195 Instruction replacementInstruction = 196 new VariableInstruction(variableInstruction.opcode, 197 newVariableIndex, 198 variableInstruction.constant); 199 200 codeAttributeEditor.replaceInstruction(offset, replacementInstruction); 201 } 202 } 203 204 205 // Small utility methods. 206 207 /** 208 * Returns the new variable index of the given variable. 209 */ remapVariable(int variableIndex)210 private int remapVariable(int variableIndex) 211 { 212 return variableMap[variableIndex]; 213 } 214 } 215