From 96d9c3b8bcc2e1c4f835a23994ea75df907fa50a Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 24 Sep 2013 11:09:27 -0400 Subject: [PATCH] Add debugging for deobfuscation Add negative caching for field and method maps. Should shortcut some work Fix handling the case where a class doesn't exist, but still needs deobf Ask the patch manager for the bytes for the class, not the classLoader Fix up some more places where we should look for a patched class Fix problem with empty source classes and runtime deobfuscation --- .../mods/fml/common/asm/FMLSanityChecker.java | 2 +- .../deobf/FMLDeobfuscatingRemapper.java | 53 +++++++++++++------ .../fml/common/patcher/ClassPatchManager.java | 19 ++++++- .../patcher/ClassPatchingTransformer.java | 5 -- 4 files changed, 57 insertions(+), 22 deletions(-) delete mode 100644 fml/common/cpw/mods/fml/common/patcher/ClassPatchingTransformer.java diff --git a/fml/common/cpw/mods/fml/common/asm/FMLSanityChecker.java b/fml/common/cpw/mods/fml/common/asm/FMLSanityChecker.java index c77aeb6bf..c08c43ad7 100644 --- a/fml/common/cpw/mods/fml/common/asm/FMLSanityChecker.java +++ b/fml/common/cpw/mods/fml/common/asm/FMLSanityChecker.java @@ -241,8 +241,8 @@ public class FMLSanityChecker implements IFMLCallHook cl = (LaunchClassLoader) data.get("classLoader"); File mcDir = (File)data.get("mcLocation"); fmlLocation = (File)data.get("coremodLocation"); - FMLDeobfuscatingRemapper.INSTANCE.setup(mcDir, cl, (String) data.get("deobfuscationFileName")); ClassPatchManager.INSTANCE.setup(FMLLaunchHandler.side()); + FMLDeobfuscatingRemapper.INSTANCE.setup(mcDir, cl, (String) data.get("deobfuscationFileName")); } } diff --git a/fml/common/cpw/mods/fml/common/asm/transformers/deobf/FMLDeobfuscatingRemapper.java b/fml/common/cpw/mods/fml/common/asm/transformers/deobf/FMLDeobfuscatingRemapper.java index d1088743c..06513d0af 100644 --- a/fml/common/cpw/mods/fml/common/asm/transformers/deobf/FMLDeobfuscatingRemapper.java +++ b/fml/common/cpw/mods/fml/common/asm/transformers/deobf/FMLDeobfuscatingRemapper.java @@ -53,6 +53,7 @@ import com.google.common.io.CharStreams; import com.google.common.io.InputSupplier; import cpw.mods.fml.common.FMLLog; +import cpw.mods.fml.common.patcher.ClassPatchManager; import cpw.mods.fml.relauncher.FMLRelaunchLog; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; @@ -71,6 +72,11 @@ public class FMLDeobfuscatingRemapper extends Remapper { private LaunchClassLoader classLoader; + + private static final boolean DEBUG_REMAPPING = Boolean.parseBoolean(System.getProperty("fml.remappingDebug", "false")); + private static final boolean DUMP_FIELD_MAPS = Boolean.parseBoolean(System.getProperty("fml.remappingDebug.dumpFieldMaps", "false")) && DEBUG_REMAPPING; + private static final boolean DUMP_METHOD_MAPS = Boolean.parseBoolean(System.getProperty("fml.remappingDebug.dumpMethodMaps", "false")) && DEBUG_REMAPPING; + private FMLDeobfuscatingRemapper() { classNameBiMap=ImmutableBiMap.of(); @@ -202,6 +208,10 @@ public class FMLDeobfuscatingRemapper extends Remapper { */ private Map> fieldDescriptions = Maps.newHashMap(); + // Cache null values so we don't waste time trying to recompute classes with no field or method maps + private Set negativeCacheMethods = Sets.newHashSet(); + private Set negativeCacheFields = Sets.newHashSet(); + private String getFieldType(String owner, String name) { if (fieldDescriptions.containsKey(owner)) @@ -212,7 +222,7 @@ public class FMLDeobfuscatingRemapper extends Remapper { { try { - byte[] classBytes = classLoader.getClassBytes(owner); + byte[] classBytes = ClassPatchManager.INSTANCE.getPatchedResource(owner, map(owner).replace('/', '.'), classLoader); if (classBytes == null) { return null; @@ -288,7 +298,6 @@ public class FMLDeobfuscatingRemapper extends Remapper { String result = classNameBiMap.containsKey(realType) ? classNameBiMap.get(realType) : mcpNameBiMap.containsKey(realType) ? mcpNameBiMap.get(realType) : realType; result = dollarIdx > -1 ? result+"$"+subType : result; -// System.out.printf("Mapping %s=>%s\n",typeName,result); return result; } @@ -305,7 +314,6 @@ public class FMLDeobfuscatingRemapper extends Remapper { String result = classNameBiMap.containsValue(realType) ? classNameBiMap.inverse().get(realType) : mcpNameBiMap.containsValue(realType) ? mcpNameBiMap.inverse().get(realType) : realType; result = dollarIdx > -1 ? result+"$"+subType : result; -// System.out.printf("Unmapping %s=>%s\n",typeName,result); return result; } @@ -324,18 +332,36 @@ public class FMLDeobfuscatingRemapper extends Remapper { private Map getFieldMap(String className) { - if (!fieldNameMaps.containsKey(className)) + if (!fieldNameMaps.containsKey(className) && !negativeCacheFields.contains(className)) { findAndMergeSuperMaps(className); + if (!fieldNameMaps.containsKey(className)) + { + negativeCacheFields.add(className); + } + + if (DUMP_FIELD_MAPS) + { + FMLRelaunchLog.finest("Field map for %s : %s", className, fieldNameMaps.get(className)); + } } return fieldNameMaps.get(className); } private Map getMethodMap(String className) { - if (!methodNameMaps.containsKey(className)) + if (!methodNameMaps.containsKey(className) && !negativeCacheMethods.contains(className)) { findAndMergeSuperMaps(className); + if (!methodNameMaps.containsKey(className)) + { + negativeCacheMethods.add(className); + } + if (DUMP_METHOD_MAPS) + { + FMLRelaunchLog.finest("Method map for %s : %s", className, methodNameMaps.get(className)); + } + } return methodNameMaps.get(className); } @@ -344,17 +370,14 @@ public class FMLDeobfuscatingRemapper extends Remapper { { try { - byte[] classBytes = classLoader.getClassBytes(name); - if (classBytes == null) + String superName = null; + String[] interfaces = new String[0]; + byte[] classBytes = ClassPatchManager.INSTANCE.getPatchedResource(name, map(name), classLoader); + if (classBytes != null) { - return; - } - ClassReader cr = new ClassReader(classBytes); - String superName = cr.getSuperName(); - String[] interfaces = cr.getInterfaces(); - if (interfaces == null) - { - interfaces = new String[0]; + ClassReader cr = new ClassReader(classBytes); + superName = cr.getSuperName(); + interfaces = cr.getInterfaces(); } mergeSuperMaps(name, superName, interfaces); } diff --git a/fml/common/cpw/mods/fml/common/patcher/ClassPatchManager.java b/fml/common/cpw/mods/fml/common/patcher/ClassPatchManager.java index 4d031bb12..98627afc6 100644 --- a/fml/common/cpw/mods/fml/common/patcher/ClassPatchManager.java +++ b/fml/common/cpw/mods/fml/common/patcher/ClassPatchManager.java @@ -11,6 +11,7 @@ import java.security.CodeSource; import java.util.Collections; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.JarInputStream; @@ -19,6 +20,8 @@ import java.util.jar.Pack200; import java.util.logging.Level; import java.util.regex.Pattern; +import net.minecraft.launchwrapper.LaunchClassLoader; + import LZMA.LzmaInputStream; import com.google.common.base.Joiner; @@ -26,6 +29,7 @@ import com.google.common.base.Strings; import com.google.common.base.Throwables; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; +import com.google.common.collect.Maps; import com.google.common.hash.Hashing; import com.google.common.io.ByteArrayDataInput; import com.google.common.io.ByteStreams; @@ -44,6 +48,7 @@ public class ClassPatchManager { private GDiffPatcher patcher = new GDiffPatcher(); private ListMultimap patches; + private Map patchedClasses = Maps.newHashMap(); private File tempDir; private ClassPatchManager() { @@ -54,12 +59,22 @@ public class ClassPatchManager { } } + + public byte[] getPatchedResource(String name, String mappedName, LaunchClassLoader loader) throws IOException + { + byte[] rawClassBytes = loader.getClassBytes(name); + return applyPatch(name, mappedName, rawClassBytes); + } public byte[] applyPatch(String name, String mappedName, byte[] inputData) { if (patches == null) { return inputData; } + if (patchedClasses.containsKey(name)) + { + return patchedClasses.get(name); + } List list = patches.get(name); if (list.isEmpty()) { @@ -69,7 +84,7 @@ public class ClassPatchManager { FMLRelaunchLog.fine("Runtime patching class %s (input size %d), found %d patch%s", mappedName, (inputData == null ? 0 : inputData.length), list.size(), list.size()!=1 ? "es" : ""); for (ClassPatch patch: list) { - if (!patch.targetClassName.equals(mappedName)) + if (!patch.targetClassName.equals(mappedName) && !patch.sourceClassName.equals(name)) { FMLRelaunchLog.warning("Binary patch found %s for wrong class %s", patch.targetClassName, mappedName); } @@ -128,6 +143,7 @@ public class ClassPatchManager { FMLRelaunchLog.log(Level.SEVERE, e, "Failed to write %s to %s", mappedName, tempDir.getAbsolutePath()); } } + patchedClasses.put(name,inputData); return inputData; } @@ -185,6 +201,7 @@ public class ClassPatchManager { } while (true); FMLRelaunchLog.fine("Read %d binary patches", patches.size()); FMLRelaunchLog.fine("Patch list :\n\t%s", Joiner.on("\t\n").join(patches.asMap().entrySet())); + patchedClasses.clear(); } private ClassPatch readPatch(JarEntry patchEntry, JarInputStream jis) diff --git a/fml/common/cpw/mods/fml/common/patcher/ClassPatchingTransformer.java b/fml/common/cpw/mods/fml/common/patcher/ClassPatchingTransformer.java deleted file mode 100644 index 40c8e5728..000000000 --- a/fml/common/cpw/mods/fml/common/patcher/ClassPatchingTransformer.java +++ /dev/null @@ -1,5 +0,0 @@ -package cpw.mods.fml.common.patcher; - -public class ClassPatchingTransformer { - -}