diff options
| author | 2019-01-30 21:05:32 +0200 | |
|---|---|---|
| committer | 2019-01-30 21:05:32 +0200 | |
| commit | ba7a354efae7d49833c887cf147ac940c975a1fa (patch) | |
| tree | 02e14fda81dd5984e24f2df392c57c6e829fc875 /src/main/java/cuchaz/enigma/bytecode | |
| parent | Rewrite the Jenkinsfile to use the new declarative pipeline syntax, lets hope... (diff) | |
| download | enigma-fork-ba7a354efae7d49833c887cf147ac940c975a1fa.tar.gz enigma-fork-ba7a354efae7d49833c887cf147ac940c975a1fa.tar.xz enigma-fork-ba7a354efae7d49833c887cf147ac940c975a1fa.zip | |
Remap sources (#106)
* Source remapping beginnings
* Fix navigation to remapped classes
* Translate identifier info reference
* Remap local variables with default names in source
* Caching translator
* Fix lack of highlighting for first opened class
* Fix unicode variable names
* Unicode checker shouldn't be checking just alphanumeric
* Fix package tree being built from obf names
* Don't index `this` as method call for method::reference
* Apply proposed names
* Fix source export issues
* Replace unicode var names at bytecode level uniquely
* Drop imports from editor source
* Class selector fixes
* Delta keep track of base mappings to enable lookup of old names
* Optimize source remapping by remapping source with a StringBuffer instead of copying
* Bump version
Diffstat (limited to 'src/main/java/cuchaz/enigma/bytecode')
3 files changed, 119 insertions, 79 deletions
diff --git a/src/main/java/cuchaz/enigma/bytecode/translators/LocalVariableFixVisitor.java b/src/main/java/cuchaz/enigma/bytecode/translators/LocalVariableFixVisitor.java new file mode 100644 index 0000000..16dbba1 --- /dev/null +++ b/src/main/java/cuchaz/enigma/bytecode/translators/LocalVariableFixVisitor.java | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | package cuchaz.enigma.bytecode.translators; | ||
| 2 | |||
| 3 | import com.google.common.base.CharMatcher; | ||
| 4 | import cuchaz.enigma.translation.representation.TypeDescriptor; | ||
| 5 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; | ||
| 6 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | ||
| 7 | import org.objectweb.asm.ClassVisitor; | ||
| 8 | import org.objectweb.asm.Label; | ||
| 9 | import org.objectweb.asm.MethodVisitor; | ||
| 10 | |||
| 11 | import java.util.List; | ||
| 12 | |||
| 13 | public class LocalVariableFixVisitor extends ClassVisitor { | ||
| 14 | private ClassDefEntry ownerEntry; | ||
| 15 | |||
| 16 | public LocalVariableFixVisitor(int api, ClassVisitor visitor) { | ||
| 17 | super(api, visitor); | ||
| 18 | } | ||
| 19 | |||
| 20 | @Override | ||
| 21 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { | ||
| 22 | ownerEntry = ClassDefEntry.parse(access, name, signature, superName, interfaces); | ||
| 23 | super.visit(version, access, name, signature, superName, interfaces); | ||
| 24 | } | ||
| 25 | |||
| 26 | @Override | ||
| 27 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { | ||
| 28 | MethodDefEntry methodEntry = MethodDefEntry.parse(ownerEntry, access, name, descriptor, signature); | ||
| 29 | return new Method(api, methodEntry, super.visitMethod(access, name, descriptor, signature, exceptions)); | ||
| 30 | } | ||
| 31 | |||
| 32 | private class Method extends MethodVisitor { | ||
| 33 | private final MethodDefEntry methodEntry; | ||
| 34 | private boolean hasLvt; | ||
| 35 | |||
| 36 | Method(int api, MethodDefEntry methodEntry, MethodVisitor visitor) { | ||
| 37 | super(api, visitor); | ||
| 38 | this.methodEntry = methodEntry; | ||
| 39 | } | ||
| 40 | |||
| 41 | @Override | ||
| 42 | public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) { | ||
| 43 | hasLvt = true; | ||
| 44 | |||
| 45 | String translatedName = name; | ||
| 46 | |||
| 47 | if (isInvalidName(name)) { | ||
| 48 | int argumentIndex = methodEntry.getArgumentIndex(ownerEntry, index); | ||
| 49 | |||
| 50 | if (argumentIndex >= 0) { | ||
| 51 | List<TypeDescriptor> arguments = methodEntry.getDesc().getArgumentDescs(); | ||
| 52 | boolean argument = argumentIndex < arguments.size(); | ||
| 53 | if (argument) { | ||
| 54 | translatedName = "arg" + (argumentIndex + 1); | ||
| 55 | } else { | ||
| 56 | translatedName = "var" + (argumentIndex + 1); | ||
| 57 | } | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | super.visitLocalVariable(translatedName, desc, signature, start, end, index); | ||
| 62 | } | ||
| 63 | |||
| 64 | private boolean isInvalidName(String name) { | ||
| 65 | return !CharMatcher.ascii().matchesAllOf(name); | ||
| 66 | } | ||
| 67 | |||
| 68 | @Override | ||
| 69 | public void visitEnd() { | ||
| 70 | if (!hasLvt) { | ||
| 71 | List<TypeDescriptor> arguments = methodEntry.getDesc().getArgumentDescs(); | ||
| 72 | for (int argumentIndex = 0; argumentIndex < arguments.size(); argumentIndex++) { | ||
| 73 | super.visitParameter("arg" + (argumentIndex + 1), 0); | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | super.visitEnd(); | ||
| 78 | } | ||
| 79 | } | ||
| 80 | } | ||
diff --git a/src/main/java/cuchaz/enigma/bytecode/translators/TranslationClassVisitor.java b/src/main/java/cuchaz/enigma/bytecode/translators/TranslationClassVisitor.java index 53d09bb..e4c41d3 100644 --- a/src/main/java/cuchaz/enigma/bytecode/translators/TranslationClassVisitor.java +++ b/src/main/java/cuchaz/enigma/bytecode/translators/TranslationClassVisitor.java | |||
| @@ -13,7 +13,6 @@ package cuchaz.enigma.bytecode.translators; | |||
| 13 | 13 | ||
| 14 | import cuchaz.enigma.translation.Translator; | 14 | import cuchaz.enigma.translation.Translator; |
| 15 | import cuchaz.enigma.translation.representation.MethodDescriptor; | 15 | import cuchaz.enigma.translation.representation.MethodDescriptor; |
| 16 | import cuchaz.enigma.translation.representation.ReferencedEntryPool; | ||
| 17 | import cuchaz.enigma.translation.representation.TypeDescriptor; | 16 | import cuchaz.enigma.translation.representation.TypeDescriptor; |
| 18 | import cuchaz.enigma.translation.representation.entry.*; | 17 | import cuchaz.enigma.translation.representation.entry.*; |
| 19 | import org.objectweb.asm.*; | 18 | import org.objectweb.asm.*; |
| @@ -22,14 +21,12 @@ import java.util.Arrays; | |||
| 22 | 21 | ||
| 23 | public class TranslationClassVisitor extends ClassVisitor { | 22 | public class TranslationClassVisitor extends ClassVisitor { |
| 24 | private final Translator translator; | 23 | private final Translator translator; |
| 25 | private final ReferencedEntryPool entryPool; | ||
| 26 | 24 | ||
| 27 | private ClassDefEntry obfClassEntry; | 25 | private ClassDefEntry obfClassEntry; |
| 28 | 26 | ||
| 29 | public TranslationClassVisitor(Translator translator, ReferencedEntryPool entryPool, int api, ClassVisitor cv) { | 27 | public TranslationClassVisitor(Translator translator, int api, ClassVisitor cv) { |
| 30 | super(api, cv); | 28 | super(api, cv); |
| 31 | this.translator = translator; | 29 | this.translator = translator; |
| 32 | this.entryPool = entryPool; | ||
| 33 | } | 30 | } |
| 34 | 31 | ||
| 35 | @Override | 32 | @Override |
| @@ -57,7 +54,7 @@ public class TranslationClassVisitor extends ClassVisitor { | |||
| 57 | MethodDefEntry translatedEntry = translator.translate(entry); | 54 | MethodDefEntry translatedEntry = translator.translate(entry); |
| 58 | String[] translatedExceptions = new String[exceptions.length]; | 55 | String[] translatedExceptions = new String[exceptions.length]; |
| 59 | for (int i = 0; i < exceptions.length; i++) { | 56 | for (int i = 0; i < exceptions.length; i++) { |
| 60 | translatedExceptions[i] = translator.translate(entryPool.getClass(exceptions[i])).getFullName(); | 57 | translatedExceptions[i] = translator.translate(new ClassEntry(exceptions[i])).getFullName(); |
| 61 | } | 58 | } |
| 62 | MethodVisitor mv = super.visitMethod(translatedEntry.getAccess().getFlags(), translatedEntry.getName(), translatedEntry.getDesc().toString(), translatedEntry.getSignature().toString(), translatedExceptions); | 59 | MethodVisitor mv = super.visitMethod(translatedEntry.getAccess().getFlags(), translatedEntry.getName(), translatedEntry.getDesc().toString(), translatedEntry.getSignature().toString(), translatedExceptions); |
| 63 | return new TranslationMethodVisitor(translator, obfClassEntry, entry, api, mv); | 60 | return new TranslationMethodVisitor(translator, obfClassEntry, entry, api, mv); |
diff --git a/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java b/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java index a5a33e6..c824265 100644 --- a/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java +++ b/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java | |||
| @@ -1,16 +1,14 @@ | |||
| 1 | package cuchaz.enigma.bytecode.translators; | 1 | package cuchaz.enigma.bytecode.translators; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.translation.LocalNameGenerator; | ||
| 3 | import cuchaz.enigma.translation.Translator; | 4 | import cuchaz.enigma.translation.Translator; |
| 4 | import cuchaz.enigma.translation.mapping.NameValidator; | ||
| 5 | import cuchaz.enigma.translation.representation.MethodDescriptor; | 5 | import cuchaz.enigma.translation.representation.MethodDescriptor; |
| 6 | import cuchaz.enigma.translation.representation.Signature; | 6 | import cuchaz.enigma.translation.representation.Signature; |
| 7 | import cuchaz.enigma.translation.representation.TypeDescriptor; | 7 | import cuchaz.enigma.translation.representation.TypeDescriptor; |
| 8 | import cuchaz.enigma.translation.representation.entry.*; | 8 | import cuchaz.enigma.translation.representation.entry.*; |
| 9 | import org.objectweb.asm.*; | 9 | import org.objectweb.asm.*; |
| 10 | 10 | ||
| 11 | import java.util.Collection; | ||
| 12 | import java.util.List; | 11 | import java.util.List; |
| 13 | import java.util.Locale; | ||
| 14 | import java.util.stream.Collectors; | 12 | import java.util.stream.Collectors; |
| 15 | 13 | ||
| 16 | public class TranslationMethodVisitor extends MethodVisitor { | 14 | public class TranslationMethodVisitor extends MethodVisitor { |
| @@ -84,40 +82,6 @@ public class TranslationMethodVisitor extends MethodVisitor { | |||
| 84 | } | 82 | } |
| 85 | 83 | ||
| 86 | @Override | 84 | @Override |
| 87 | public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) { | ||
| 88 | hasParameterMeta = true; | ||
| 89 | |||
| 90 | String translatedSignature = translator.translate(Signature.createTypedSignature(signature)).toString(); | ||
| 91 | int argumentIndex = methodEntry.getArgumentIndex(ownerEntry, index); | ||
| 92 | |||
| 93 | if (argumentIndex >= 0) { | ||
| 94 | LocalVariableDefEntry entry = new LocalVariableDefEntry(methodEntry, index, name, true, new TypeDescriptor(desc)); | ||
| 95 | LocalVariableDefEntry translatedEntry = translator.translate(entry); | ||
| 96 | String translatedName = translatedEntry.getName(); | ||
| 97 | |||
| 98 | if (translatedName.equals(entry.getName())) { | ||
| 99 | List<TypeDescriptor> arguments = methodEntry.getDesc().getArgumentDescs(); | ||
| 100 | List<TypeDescriptor> translatedArguments = arguments.stream() | ||
| 101 | .map(translator::translate) | ||
| 102 | .collect(Collectors.toList()); | ||
| 103 | |||
| 104 | boolean argument = argumentIndex < arguments.size(); | ||
| 105 | if (argument) { | ||
| 106 | translatedName = inferArgumentName(argumentIndex, translatedEntry.getDesc(), translatedArguments); | ||
| 107 | } else { | ||
| 108 | translatedName = inferLocalVariableName(argumentIndex, translatedEntry.getDesc()); | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | super.visitLocalVariable(translatedName, translatedEntry.getDesc().toString(), translatedSignature, start, end, index); | ||
| 113 | } else { | ||
| 114 | // Handle "this" variable | ||
| 115 | TypeDescriptor translatedDesc = translator.translate(new TypeDescriptor(desc)); | ||
| 116 | super.visitLocalVariable(name, translatedDesc.toString(), translatedSignature, start, end, index); | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | @Override | ||
| 121 | public void visitTypeInsn(int opcode, String type) { | 85 | public void visitTypeInsn(int opcode, String type) { |
| 122 | ClassEntry translatedEntry = translator.translate(new ClassEntry(type)); | 86 | ClassEntry translatedEntry = translator.translate(new ClassEntry(type)); |
| 123 | super.visitTypeInsn(opcode, translatedEntry.getFullName()); | 87 | super.visitTypeInsn(opcode, translatedEntry.getFullName()); |
| @@ -154,10 +118,44 @@ public class TranslationMethodVisitor extends MethodVisitor { | |||
| 154 | } | 118 | } |
| 155 | 119 | ||
| 156 | @Override | 120 | @Override |
| 121 | public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) { | ||
| 122 | hasParameterMeta = true; | ||
| 123 | |||
| 124 | String translatedSignature = translator.translate(Signature.createTypedSignature(signature)).toString(); | ||
| 125 | int argumentIndex = methodEntry.getArgumentIndex(ownerEntry, index); | ||
| 126 | |||
| 127 | if (argumentIndex >= 0) { | ||
| 128 | LocalVariableDefEntry entry = new LocalVariableDefEntry(methodEntry, index, name, true, new TypeDescriptor(desc)); | ||
| 129 | LocalVariableDefEntry translatedEntry = translator.translate(entry); | ||
| 130 | String translatedName = translatedEntry.getName(); | ||
| 131 | |||
| 132 | if (translatedName.equals(entry.getName())) { | ||
| 133 | List<TypeDescriptor> arguments = methodEntry.getDesc().getArgumentDescs(); | ||
| 134 | List<TypeDescriptor> translatedArguments = arguments.stream() | ||
| 135 | .map(translator::translate) | ||
| 136 | .collect(Collectors.toList()); | ||
| 137 | |||
| 138 | boolean argument = argumentIndex < arguments.size(); | ||
| 139 | if (argument) { | ||
| 140 | translatedName = LocalNameGenerator.generateArgumentName(argumentIndex, translatedEntry.getDesc(), translatedArguments); | ||
| 141 | } else { | ||
| 142 | translatedName = LocalNameGenerator.generateLocalVariableName(argumentIndex, translatedEntry.getDesc()); | ||
| 143 | } | ||
| 144 | } | ||
| 145 | |||
| 146 | super.visitLocalVariable(translatedName, translatedEntry.getDesc().toString(), translatedSignature, start, end, index); | ||
| 147 | } else { | ||
| 148 | // Handle "this" variable | ||
| 149 | TypeDescriptor translatedDesc = translator.translate(new TypeDescriptor(desc)); | ||
| 150 | super.visitLocalVariable(name, translatedDesc.toString(), translatedSignature, start, end, index); | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | @Override | ||
| 157 | public void visitEnd() { | 155 | public void visitEnd() { |
| 158 | // If we didn't receive any parameter metadata, generate it | 156 | // If we didn't receive any parameter metadata, generate it |
| 159 | if (!hasParameterMeta) { | 157 | if (!hasParameterMeta) { |
| 160 | List<TypeDescriptor> arguments = methodEntry.getDesc().getArgumentDescs(); | 158 | List<TypeDescriptor> arguments = translator.translate(methodEntry.getDesc()).getArgumentDescs(); |
| 161 | int offset = ((methodEntry.getAccess().getFlags() & Opcodes.ACC_ABSTRACT) != 0) ? 1 : 0; | 159 | int offset = ((methodEntry.getAccess().getFlags() & Opcodes.ACC_ABSTRACT) != 0) ? 1 : 0; |
| 162 | 160 | ||
| 163 | for (int argumentIndex = 0; argumentIndex < arguments.size(); argumentIndex++) { | 161 | for (int argumentIndex = 0; argumentIndex < arguments.size(); argumentIndex++) { |
| @@ -165,7 +163,7 @@ public class TranslationMethodVisitor extends MethodVisitor { | |||
| 165 | LocalVariableEntry translatedEntry = translator.translate(entry); | 163 | LocalVariableEntry translatedEntry = translator.translate(entry); |
| 166 | String translatedName = translatedEntry.getName(); | 164 | String translatedName = translatedEntry.getName(); |
| 167 | if (translatedName.equals(entry.getName())) { | 165 | if (translatedName.equals(entry.getName())) { |
| 168 | super.visitParameter(inferArgumentName(argumentIndex, arguments.get(argumentIndex), arguments), 0); | 166 | super.visitParameter(LocalNameGenerator.generateArgumentName(argumentIndex, arguments.get(argumentIndex), arguments), 0); |
| 169 | } else { | 167 | } else { |
| 170 | super.visitParameter(translatedName, 0); | 168 | super.visitParameter(translatedName, 0); |
| 171 | } | 169 | } |
| @@ -175,39 +173,4 @@ public class TranslationMethodVisitor extends MethodVisitor { | |||
| 175 | } | 173 | } |
| 176 | super.visitEnd(); | 174 | super.visitEnd(); |
| 177 | } | 175 | } |
| 178 | |||
| 179 | private String inferArgumentName(int index, TypeDescriptor desc, Collection<TypeDescriptor> arguments) { | ||
| 180 | boolean uniqueType = arguments.stream().filter(desc::equals).count() <= 1; | ||
| 181 | String translatedName; | ||
| 182 | int nameIndex = index + 1; | ||
| 183 | StringBuilder nameBuilder = new StringBuilder(getTypeName(desc)); | ||
| 184 | if (!uniqueType || NameValidator.isReserved(nameBuilder.toString())) { | ||
| 185 | nameBuilder.append(nameIndex); | ||
| 186 | } | ||
| 187 | translatedName = nameBuilder.toString(); | ||
| 188 | return translatedName; | ||
| 189 | } | ||
| 190 | |||
| 191 | private String inferLocalVariableName(int index, TypeDescriptor desc) { | ||
| 192 | int nameIndex = index + 1; | ||
| 193 | return getTypeName(desc) + nameIndex; | ||
| 194 | } | ||
| 195 | |||
| 196 | private String getTypeName(TypeDescriptor desc) { | ||
| 197 | // Unfortunately each of these have different name getters, so they have different code paths | ||
| 198 | if (desc.isPrimitive()) { | ||
| 199 | TypeDescriptor.Primitive argCls = desc.getPrimitive(); | ||
| 200 | return argCls.name().toLowerCase(Locale.ROOT); | ||
| 201 | } else if (desc.isArray()) { | ||
| 202 | // List types would require this whole block again, so just go with aListx | ||
| 203 | return "arr"; | ||
| 204 | } else if (desc.isType()) { | ||
| 205 | String typeName = desc.getTypeEntry().getSimpleName().replace("$", ""); | ||
| 206 | typeName = typeName.substring(0, 1).toLowerCase(Locale.ROOT) + typeName.substring(1); | ||
| 207 | return typeName; | ||
| 208 | } else { | ||
| 209 | System.err.println("Encountered invalid argument type descriptor " + desc.toString()); | ||
| 210 | return "var"; | ||
| 211 | } | ||
| 212 | } | ||
| 213 | } | 176 | } |