diff options
Diffstat (limited to 'src/main/java/cuchaz/enigma/bytecode/LocalVariableRenamer.java')
| -rw-r--r-- | src/main/java/cuchaz/enigma/bytecode/LocalVariableRenamer.java | 249 |
1 files changed, 124 insertions, 125 deletions
diff --git a/src/main/java/cuchaz/enigma/bytecode/LocalVariableRenamer.java b/src/main/java/cuchaz/enigma/bytecode/LocalVariableRenamer.java index 24b5f36..8909d81 100644 --- a/src/main/java/cuchaz/enigma/bytecode/LocalVariableRenamer.java +++ b/src/main/java/cuchaz/enigma/bytecode/LocalVariableRenamer.java | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | |||
| 11 | package cuchaz.enigma.bytecode; | 12 | package cuchaz.enigma.bytecode; |
| 12 | 13 | ||
| 13 | import cuchaz.enigma.mapping.*; | 14 | import cuchaz.enigma.mapping.*; |
| @@ -15,131 +16,129 @@ import javassist.CtBehavior; | |||
| 15 | import javassist.CtClass; | 16 | import javassist.CtClass; |
| 16 | import javassist.bytecode.*; | 17 | import javassist.bytecode.*; |
| 17 | 18 | ||
| 18 | |||
| 19 | public class LocalVariableRenamer { | 19 | public class LocalVariableRenamer { |
| 20 | 20 | ||
| 21 | private Translator translator; | 21 | private Translator translator; |
| 22 | 22 | ||
| 23 | public LocalVariableRenamer(Translator translator) { | 23 | public LocalVariableRenamer(Translator translator) { |
| 24 | this.translator = translator; | 24 | this.translator = translator; |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | public void rename(CtClass c) { | 27 | public void rename(CtClass c) { |
| 28 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { | 28 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { |
| 29 | 29 | ||
| 30 | // if there's a local variable table, just rename everything to v1, v2, v3, ... for now | 30 | // if there's a local variable table, just rename everything to v1, v2, v3, ... for now |
| 31 | CodeAttribute codeAttribute = behavior.getMethodInfo().getCodeAttribute(); | 31 | CodeAttribute codeAttribute = behavior.getMethodInfo().getCodeAttribute(); |
| 32 | if (codeAttribute == null) { | 32 | if (codeAttribute == null) { |
| 33 | continue; | 33 | continue; |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); | 36 | BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); |
| 37 | ConstPool constants = c.getClassFile().getConstPool(); | 37 | ConstPool constants = c.getClassFile().getConstPool(); |
| 38 | 38 | ||
| 39 | LocalVariableAttribute table = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag); | 39 | LocalVariableAttribute table = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag); |
| 40 | if (table != null) { | 40 | if (table != null) { |
| 41 | renameLVT(behaviorEntry, constants, table); | 41 | renameLVT(behaviorEntry, constants, table); |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | LocalVariableTypeAttribute typeTable = (LocalVariableTypeAttribute) codeAttribute.getAttribute(LocalVariableAttribute.typeTag); | 44 | LocalVariableTypeAttribute typeTable = (LocalVariableTypeAttribute) codeAttribute.getAttribute(LocalVariableAttribute.typeTag); |
| 45 | if (typeTable != null) { | 45 | if (typeTable != null) { |
| 46 | renameLVTT(typeTable, table); | 46 | renameLVTT(typeTable, table); |
| 47 | } | 47 | } |
| 48 | } | 48 | } |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | // DEBUG | 51 | // DEBUG |
| 52 | @SuppressWarnings("unused") | 52 | @SuppressWarnings("unused") |
| 53 | private void dumpTable(LocalVariableAttribute table) { | 53 | private void dumpTable(LocalVariableAttribute table) { |
| 54 | for (int i = 0; i < table.tableLength(); i++) { | 54 | for (int i = 0; i < table.tableLength(); i++) { |
| 55 | System.out.println(String.format("\t%d (%d): %s %s", | 55 | System.out.println(String.format("\t%d (%d): %s %s", |
| 56 | i, table.index(i), table.variableName(i), table.descriptor(i) | 56 | i, table.index(i), table.variableName(i), table.descriptor(i) |
| 57 | )); | 57 | )); |
| 58 | } | 58 | } |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | private void renameLVT(BehaviorEntry behaviorEntry, ConstPool constants, LocalVariableAttribute table) { | 61 | private void renameLVT(BehaviorEntry behaviorEntry, ConstPool constants, LocalVariableAttribute table) { |
| 62 | 62 | ||
| 63 | // skip empty tables | 63 | // skip empty tables |
| 64 | if (table.tableLength() <= 0) { | 64 | if (table.tableLength() <= 0) { |
| 65 | return; | 65 | return; |
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | // where do we start counting variables? | 68 | // where do we start counting variables? |
| 69 | int starti = 0; | 69 | int starti = 0; |
| 70 | if (table.variableName(0).equals("this")) { | 70 | if (table.variableName(0).equals("this")) { |
| 71 | // skip the "this" variable | 71 | // skip the "this" variable |
| 72 | starti = 1; | 72 | starti = 1; |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | // rename method arguments first | 75 | // rename method arguments first |
| 76 | int numArgs = 0; | 76 | int numArgs = 0; |
| 77 | if (behaviorEntry.getSignature() != null) { | 77 | if (behaviorEntry.getSignature() != null) { |
| 78 | numArgs = behaviorEntry.getSignature().getArgumentTypes().size(); | 78 | numArgs = behaviorEntry.getSignature().getArgumentTypes().size(); |
| 79 | 79 | ||
| 80 | boolean isNestedClassConstructor = false; | 80 | boolean isNestedClassConstructor = false; |
| 81 | 81 | ||
| 82 | // If the behavior is a constructor and if it have more than one arg, it's probably from a nested! | 82 | // If the behavior is a constructor and if it have more than one arg, it's probably from a nested! |
| 83 | if (behaviorEntry instanceof ConstructorEntry && behaviorEntry.getClassEntry() != null && behaviorEntry.getClassEntry().isInnerClass() && numArgs >= 1) | 83 | if (behaviorEntry instanceof ConstructorEntry && behaviorEntry.getClassEntry() != null && behaviorEntry.getClassEntry().isInnerClass() && numArgs >= 1) { |
| 84 | { | 84 | // Get the first arg type |
| 85 | // Get the first arg type | 85 | Type firstArg = behaviorEntry.getSignature().getArgumentTypes().get(0); |
| 86 | Type firstArg = behaviorEntry.getSignature().getArgumentTypes().get(0); | 86 | |
| 87 | 87 | // If the arg is a class and if the class name match the outer class name of the constructor, it's definitely a constructor of a nested class | |
| 88 | // If the arg is a class and if the class name match the outer class name of the constructor, it's definitely a constructor of a nested class | 88 | if (firstArg.isClass() && firstArg.getClassEntry().equals(behaviorEntry.getClassEntry().getOuterClassEntry())) { |
| 89 | if (firstArg.isClass() && firstArg.getClassEntry().equals(behaviorEntry.getClassEntry().getOuterClassEntry())) { | 89 | isNestedClassConstructor = true; |
| 90 | isNestedClassConstructor = true; | 90 | numArgs--; |
| 91 | numArgs--; | 91 | } |
| 92 | } | 92 | } |
| 93 | } | 93 | |
| 94 | 94 | for (int i = starti; i < starti + numArgs && i < table.tableLength(); i++) { | |
| 95 | for (int i = starti; i < starti + numArgs && i < table.tableLength(); i++) { | 95 | int argi = i - starti; |
| 96 | int argi = i - starti; | 96 | String argName = this.translator.translate(new ArgumentEntry(behaviorEntry, argi, "")); |
| 97 | String argName = this.translator.translate(new ArgumentEntry(behaviorEntry, argi, "")); | 97 | if (argName == null) { |
| 98 | if (argName == null) { | 98 | Type argType = behaviorEntry.getSignature().getArgumentTypes().get(isNestedClassConstructor ? argi + 1 : argi); |
| 99 | Type argType = behaviorEntry.getSignature().getArgumentTypes().get(isNestedClassConstructor ? argi + 1 : argi); | 99 | // Unfortunately each of these have different name getters, so they have different code paths |
| 100 | // Unfortunately each of these have different name getters, so they have different code paths | 100 | if (argType.isPrimitive()) { |
| 101 | if (argType.isPrimitive()) { | 101 | Type.Primitive argCls = argType.getPrimitive(); |
| 102 | Type.Primitive argCls = argType.getPrimitive(); | 102 | argName = "a" + argCls.name() + (argi + 1); |
| 103 | argName = "a" + argCls.name() + (argi + 1); | 103 | } else if (argType.isArray()) { |
| 104 | } else if (argType.isArray()) { | 104 | // List types would require this whole block again, so just go with aListx |
| 105 | // List types would require this whole block again, so just go with aListx | 105 | argName = "aList" + (argi + 1); |
| 106 | argName = "aList" + (argi + 1); | 106 | } else if (argType.isClass()) { |
| 107 | } else if (argType.isClass()) { | 107 | ClassEntry argClsTrans = this.translator.translateEntry(argType.getClassEntry()); |
| 108 | ClassEntry argClsTrans = this.translator.translateEntry(argType.getClassEntry()); | 108 | argName = "a" + argClsTrans.getSimpleName().replace("$", "") + (argi + 1); |
| 109 | argName = "a" + argClsTrans.getSimpleName().replace("$", "") + (argi + 1); | 109 | } else { |
| 110 | } else { | 110 | argName = "a" + (argi + 1); |
| 111 | argName = "a" + (argi + 1); | 111 | } |
| 112 | } | 112 | } |
| 113 | } | 113 | renameVariable(table, i, constants.addUtf8Info(argName)); |
| 114 | renameVariable(table, i, constants.addUtf8Info(argName)); | 114 | } |
| 115 | } | 115 | } |
| 116 | } | 116 | |
| 117 | 117 | // then rename the rest of the args, if any | |
| 118 | // then rename the rest of the args, if any | 118 | for (int i = starti + numArgs; i < table.tableLength(); i++) { |
| 119 | for (int i = starti + numArgs; i < table.tableLength(); i++) { | 119 | int firstIndex = table.index(starti + numArgs); |
| 120 | int firstIndex = table.index(starti + numArgs); | 120 | renameVariable(table, i, constants.addUtf8Info("v" + (table.index(i) - firstIndex + 1))); |
| 121 | renameVariable(table, i, constants.addUtf8Info("v" + (table.index(i) - firstIndex + 1))); | 121 | } |
| 122 | } | 122 | } |
| 123 | } | 123 | |
| 124 | 124 | private void renameLVTT(LocalVariableTypeAttribute typeTable, LocalVariableAttribute table) { | |
| 125 | private void renameLVTT(LocalVariableTypeAttribute typeTable, LocalVariableAttribute table) { | 125 | // rename args to the same names as in the LVT |
| 126 | // rename args to the same names as in the LVT | 126 | for (int i = 0; i < typeTable.tableLength(); i++) { |
| 127 | for (int i = 0; i < typeTable.tableLength(); i++) { | 127 | renameVariable(typeTable, i, getNameIndex(table, typeTable.index(i))); |
| 128 | renameVariable(typeTable, i, getNameIndex(table, typeTable.index(i))); | 128 | } |
| 129 | } | 129 | } |
| 130 | } | 130 | |
| 131 | 131 | private void renameVariable(LocalVariableAttribute table, int i, int stringId) { | |
| 132 | private void renameVariable(LocalVariableAttribute table, int i, int stringId) { | 132 | // based off of LocalVariableAttribute.nameIndex() |
| 133 | // based off of LocalVariableAttribute.nameIndex() | 133 | ByteArray.write16bit(stringId, table.get(), i * 10 + 6); |
| 134 | ByteArray.write16bit(stringId, table.get(), i * 10 + 6); | 134 | } |
| 135 | } | 135 | |
| 136 | 136 | private int getNameIndex(LocalVariableAttribute table, int index) { | |
| 137 | private int getNameIndex(LocalVariableAttribute table, int index) { | 137 | for (int i = 0; i < table.tableLength(); i++) { |
| 138 | for (int i = 0; i < table.tableLength(); i++) { | 138 | if (table.index(i) == index) { |
| 139 | if (table.index(i) == index) { | 139 | return table.nameIndex(i); |
| 140 | return table.nameIndex(i); | 140 | } |
| 141 | } | 141 | } |
| 142 | } | 142 | return 0; |
| 143 | return 0; | 143 | } |
| 144 | } | ||
| 145 | } | 144 | } |