diff options
| author | 2019-11-22 15:40:50 -0500 | |
|---|---|---|
| committer | 2019-11-22 20:40:50 +0000 | |
| commit | 37cafdb5a837cbe29e4cc9a34737e24f496bc94f (patch) | |
| tree | 413ec17d5593984465ffc6005f3fa3c096d7225f /src/main | |
| parent | Tweak runemoro's stats generator to be compatible with multiple services (#178) (diff) | |
| download | enigma-37cafdb5a837cbe29e4cc9a34737e24f496bc94f.tar.gz enigma-37cafdb5a837cbe29e4cc9a34737e24f496bc94f.tar.xz enigma-37cafdb5a837cbe29e4cc9a34737e24f496bc94f.zip | |
Correctly decompile bridges, and add command to add bridges to mappings (#180)
Diffstat (limited to 'src/main')
5 files changed, 85 insertions, 7 deletions
diff --git a/src/main/java/cuchaz/enigma/CommandMain.java b/src/main/java/cuchaz/enigma/CommandMain.java index 5e7a1af6..93b013d5 100644 --- a/src/main/java/cuchaz/enigma/CommandMain.java +++ b/src/main/java/cuchaz/enigma/CommandMain.java | |||
| @@ -86,6 +86,7 @@ public class CommandMain { | |||
| 86 | register(new ComposeMappingsCommand()); | 86 | register(new ComposeMappingsCommand()); |
| 87 | register(new InvertMappingsCommand()); | 87 | register(new InvertMappingsCommand()); |
| 88 | register(new CheckMappingsCommand()); | 88 | register(new CheckMappingsCommand()); |
| 89 | register(new MapSpecializedMethodsCommand()); | ||
| 89 | } | 90 | } |
| 90 | 91 | ||
| 91 | private static final class CommandHelpException extends IllegalArgumentException { | 92 | private static final class CommandHelpException extends IllegalArgumentException { |
diff --git a/src/main/java/cuchaz/enigma/EnigmaProject.java b/src/main/java/cuchaz/enigma/EnigmaProject.java index 47a37907..2a7ca988 100644 --- a/src/main/java/cuchaz/enigma/EnigmaProject.java +++ b/src/main/java/cuchaz/enigma/EnigmaProject.java | |||
| @@ -158,7 +158,7 @@ public class EnigmaProject { | |||
| 158 | ClassNode node = classCache.getClassNode(entry.getFullName()); | 158 | ClassNode node = classCache.getClassNode(entry.getFullName()); |
| 159 | if (node != null) { | 159 | if (node != null) { |
| 160 | ClassNode translatedNode = new ClassNode(); | 160 | ClassNode translatedNode = new ClassNode(); |
| 161 | node.accept(new TranslationClassVisitor(deobfuscator, Opcodes.ASM5, translatedNode)); | 161 | node.accept(new TranslationClassVisitor(deobfuscator, Opcodes.ASM5, new SourceFixVisitor(Opcodes.ASM5, translatedNode, jarIndex))); |
| 162 | return translatedNode; | 162 | return translatedNode; |
| 163 | } | 163 | } |
| 164 | 164 | ||
| @@ -209,7 +209,6 @@ public class EnigmaProject { | |||
| 209 | 209 | ||
| 210 | //create a common instance outside the loop as mappings shouldn't be changing while this is happening | 210 | //create a common instance outside the loop as mappings shouldn't be changing while this is happening |
| 211 | CompiledSourceTypeLoader typeLoader = new CompiledSourceTypeLoader(this.compiled::get); | 211 | CompiledSourceTypeLoader typeLoader = new CompiledSourceTypeLoader(this.compiled::get); |
| 212 | typeLoader.addVisitor(visitor -> new SourceFixVisitor(Opcodes.ASM5, visitor, jarIndex)); | ||
| 213 | 212 | ||
| 214 | //synchronized to make sure the parallelStream doesn't CME with the cache | 213 | //synchronized to make sure the parallelStream doesn't CME with the cache |
| 215 | ITypeLoader synchronizedTypeLoader = new SynchronizedTypeLoader(typeLoader); | 214 | ITypeLoader synchronizedTypeLoader = new SynchronizedTypeLoader(typeLoader); |
diff --git a/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java b/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java index 8a9b4593..a4b1aac9 100644 --- a/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java +++ b/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | package cuchaz.enigma.analysis.index; | 1 | package cuchaz.enigma.analysis.index; |
| 2 | 2 | ||
| 3 | import com.google.common.collect.Maps; | 3 | import com.google.common.collect.Maps; |
| 4 | import com.google.common.collect.Sets; | ||
| 5 | import cuchaz.enigma.translation.representation.AccessFlags; | 4 | import cuchaz.enigma.translation.representation.AccessFlags; |
| 6 | import cuchaz.enigma.translation.representation.MethodDescriptor; | 5 | import cuchaz.enigma.translation.representation.MethodDescriptor; |
| 7 | import cuchaz.enigma.translation.representation.TypeDescriptor; | 6 | import cuchaz.enigma.translation.representation.TypeDescriptor; |
| @@ -17,7 +16,7 @@ public class BridgeMethodIndex implements JarIndexer { | |||
| 17 | private final InheritanceIndex inheritanceIndex; | 16 | private final InheritanceIndex inheritanceIndex; |
| 18 | private final ReferenceIndex referenceIndex; | 17 | private final ReferenceIndex referenceIndex; |
| 19 | 18 | ||
| 20 | private final Set<MethodEntry> bridgeToSpecialized = Sets.newHashSet(); | 19 | private final Map<MethodEntry, MethodEntry> bridgeToSpecialized = Maps.newHashMap(); |
| 21 | private final Map<MethodEntry, MethodEntry> specializedToBridge = Maps.newHashMap(); | 20 | private final Map<MethodEntry, MethodEntry> specializedToBridge = Maps.newHashMap(); |
| 22 | 21 | ||
| 23 | public BridgeMethodIndex(EntryIndex entryIndex, InheritanceIndex inheritanceIndex, ReferenceIndex referenceIndex) { | 22 | public BridgeMethodIndex(EntryIndex entryIndex, InheritanceIndex inheritanceIndex, ReferenceIndex referenceIndex) { |
| @@ -52,7 +51,6 @@ public class BridgeMethodIndex implements JarIndexer { | |||
| 52 | } | 51 | } |
| 53 | 52 | ||
| 54 | MethodEntry renamedSpecializedEntry = specializedEntry.withName(bridgeEntry.getName()); | 53 | MethodEntry renamedSpecializedEntry = specializedEntry.withName(bridgeEntry.getName()); |
| 55 | bridgeToSpecialized.add(renamedSpecializedEntry); | ||
| 56 | specializedToBridge.put(renamedSpecializedEntry, specializedToBridge.get(specializedEntry)); | 54 | specializedToBridge.put(renamedSpecializedEntry, specializedToBridge.get(specializedEntry)); |
| 57 | } | 55 | } |
| 58 | } | 56 | } |
| @@ -64,7 +62,7 @@ public class BridgeMethodIndex implements JarIndexer { | |||
| 64 | } | 62 | } |
| 65 | 63 | ||
| 66 | if (access.isBridge() || isPotentialBridge(syntheticMethod, specializedMethod)) { | 64 | if (access.isBridge() || isPotentialBridge(syntheticMethod, specializedMethod)) { |
| 67 | bridgeToSpecialized.add(syntheticMethod); | 65 | bridgeToSpecialized.put(syntheticMethod, specializedMethod); |
| 68 | specializedToBridge.put(specializedMethod, syntheticMethod); | 66 | specializedToBridge.put(specializedMethod, syntheticMethod); |
| 69 | } | 67 | } |
| 70 | } | 68 | } |
| @@ -130,7 +128,7 @@ public class BridgeMethodIndex implements JarIndexer { | |||
| 130 | } | 128 | } |
| 131 | 129 | ||
| 132 | public boolean isBridgeMethod(MethodEntry entry) { | 130 | public boolean isBridgeMethod(MethodEntry entry) { |
| 133 | return bridgeToSpecialized.contains(entry); | 131 | return bridgeToSpecialized.containsKey(entry); |
| 134 | } | 132 | } |
| 135 | 133 | ||
| 136 | public boolean isSpecializedMethod(MethodEntry entry) { | 134 | public boolean isSpecializedMethod(MethodEntry entry) { |
| @@ -142,7 +140,17 @@ public class BridgeMethodIndex implements JarIndexer { | |||
| 142 | return specializedToBridge.get(specialized); | 140 | return specializedToBridge.get(specialized); |
| 143 | } | 141 | } |
| 144 | 142 | ||
| 143 | public MethodEntry getSpecializedFromBridge(MethodEntry bridge) { | ||
| 144 | return bridgeToSpecialized.get(bridge); | ||
| 145 | } | ||
| 146 | |||
| 147 | /** Includes "renamed specialized -> bridge" entries. */ | ||
| 145 | public Map<MethodEntry, MethodEntry> getSpecializedToBridge() { | 148 | public Map<MethodEntry, MethodEntry> getSpecializedToBridge() { |
| 146 | return Collections.unmodifiableMap(specializedToBridge); | 149 | return Collections.unmodifiableMap(specializedToBridge); |
| 147 | } | 150 | } |
| 151 | |||
| 152 | /** Only "bridge -> original name" entries. **/ | ||
| 153 | public Map<MethodEntry, MethodEntry> getBridgeToSpecialized() { | ||
| 154 | return Collections.unmodifiableMap(bridgeToSpecialized); | ||
| 155 | } | ||
| 148 | } | 156 | } |
diff --git a/src/main/java/cuchaz/enigma/bytecode/translators/SourceFixVisitor.java b/src/main/java/cuchaz/enigma/bytecode/translators/SourceFixVisitor.java index 735a65f2..d672622c 100644 --- a/src/main/java/cuchaz/enigma/bytecode/translators/SourceFixVisitor.java +++ b/src/main/java/cuchaz/enigma/bytecode/translators/SourceFixVisitor.java | |||
| @@ -4,6 +4,7 @@ import cuchaz.enigma.analysis.index.BridgeMethodIndex; | |||
| 4 | import cuchaz.enigma.analysis.index.JarIndex; | 4 | import cuchaz.enigma.analysis.index.JarIndex; |
| 5 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; | 5 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; |
| 6 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | 6 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; |
| 7 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 7 | import org.objectweb.asm.ClassVisitor; | 8 | import org.objectweb.asm.ClassVisitor; |
| 8 | import org.objectweb.asm.MethodVisitor; | 9 | import org.objectweb.asm.MethodVisitor; |
| 9 | import org.objectweb.asm.Opcodes; | 10 | import org.objectweb.asm.Opcodes; |
| @@ -30,6 +31,8 @@ public class SourceFixVisitor extends ClassVisitor { | |||
| 30 | BridgeMethodIndex bridgeIndex = index.getBridgeMethodIndex(); | 31 | BridgeMethodIndex bridgeIndex = index.getBridgeMethodIndex(); |
| 31 | if (bridgeIndex.isBridgeMethod(methodEntry)) { | 32 | if (bridgeIndex.isBridgeMethod(methodEntry)) { |
| 32 | access |= Opcodes.ACC_BRIDGE; | 33 | access |= Opcodes.ACC_BRIDGE; |
| 34 | } else if (bridgeIndex.isSpecializedMethod(methodEntry)) { | ||
| 35 | name = bridgeIndex.getBridgeFromSpecialized(methodEntry).getName(); | ||
| 33 | } | 36 | } |
| 34 | 37 | ||
| 35 | return super.visitMethod(access, name, descriptor, signature, exceptions); | 38 | return super.visitMethod(access, name, descriptor, signature, exceptions); |
diff --git a/src/main/java/cuchaz/enigma/command/MapSpecializedMethodsCommand.java b/src/main/java/cuchaz/enigma/command/MapSpecializedMethodsCommand.java new file mode 100644 index 00000000..7696f0f1 --- /dev/null +++ b/src/main/java/cuchaz/enigma/command/MapSpecializedMethodsCommand.java | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | package cuchaz.enigma.command; | ||
| 2 | |||
| 3 | import cuchaz.enigma.ProgressListener; | ||
| 4 | import cuchaz.enigma.analysis.ClassCache; | ||
| 5 | import cuchaz.enigma.analysis.index.BridgeMethodIndex; | ||
| 6 | import cuchaz.enigma.analysis.index.JarIndex; | ||
| 7 | import cuchaz.enigma.throwables.MappingParseException; | ||
| 8 | import cuchaz.enigma.translation.MappingTranslator; | ||
| 9 | import cuchaz.enigma.translation.Translator; | ||
| 10 | import cuchaz.enigma.translation.mapping.*; | ||
| 11 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | ||
| 12 | import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; | ||
| 13 | import cuchaz.enigma.translation.mapping.tree.HashEntryTree; | ||
| 14 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 15 | import cuchaz.enigma.utils.Utils; | ||
| 16 | |||
| 17 | import java.io.IOException; | ||
| 18 | import java.nio.file.Path; | ||
| 19 | import java.nio.file.Paths; | ||
| 20 | import java.util.Map; | ||
| 21 | |||
| 22 | public class MapSpecializedMethodsCommand extends Command { | ||
| 23 | public MapSpecializedMethodsCommand() { | ||
| 24 | super("map-specialized-methods"); | ||
| 25 | } | ||
| 26 | |||
| 27 | @Override | ||
| 28 | public String getUsage() { | ||
| 29 | return "<jar> <source-format> <source> <result-format> <result>"; | ||
| 30 | } | ||
| 31 | |||
| 32 | @Override | ||
| 33 | public boolean isValidArgument(int length) { | ||
| 34 | return length == 5; | ||
| 35 | } | ||
| 36 | |||
| 37 | @Override | ||
| 38 | public void run(String... args) throws IOException, MappingParseException { | ||
| 39 | MappingSaveParameters saveParameters = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF); | ||
| 40 | EntryTree<EntryMapping> source = MappingCommandsUtil.read(args[1], Paths.get(args[2]), saveParameters); | ||
| 41 | EntryTree<EntryMapping> result = new HashEntryTree<>(); | ||
| 42 | Path jar = Paths.get(args[0]); | ||
| 43 | ClassCache classCache = ClassCache.of(jar); | ||
| 44 | JarIndex jarIndex = classCache.index(ProgressListener.none()); | ||
| 45 | BridgeMethodIndex bridgeMethodIndex = jarIndex.getBridgeMethodIndex(); | ||
| 46 | Translator translator = new MappingTranslator(source, jarIndex.getEntryResolver()); | ||
| 47 | |||
| 48 | // Copy all non-specialized methods | ||
| 49 | for (EntryTreeNode<EntryMapping> node : source) { | ||
| 50 | if (!(node.getEntry() instanceof MethodEntry) || !bridgeMethodIndex.isSpecializedMethod((MethodEntry) node.getEntry())) { | ||
| 51 | result.insert(node.getEntry(), node.getValue()); | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | // Add correct mappings for specialized methods | ||
| 56 | for (Map.Entry<MethodEntry, MethodEntry> entry : bridgeMethodIndex.getBridgeToSpecialized().entrySet()) { | ||
| 57 | MethodEntry bridge = entry.getKey(); | ||
| 58 | MethodEntry specialized = entry.getValue(); | ||
| 59 | String name = translator.translate(bridge).getName(); | ||
| 60 | result.insert(specialized, new EntryMapping(name)); | ||
| 61 | } | ||
| 62 | |||
| 63 | Path output = Paths.get(args[4]); | ||
| 64 | Utils.delete(output); | ||
| 65 | MappingCommandsUtil.write(result, args[3], output, saveParameters); | ||
| 66 | } | ||
| 67 | } | ||