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
This commit is contained in:
Christian 2013-09-24 11:09:27 -04:00
parent c1623cb8e3
commit 96d9c3b8bc
4 changed files with 57 additions and 22 deletions

View File

@ -241,8 +241,8 @@ public class FMLSanityChecker implements IFMLCallHook
cl = (LaunchClassLoader) data.get("classLoader"); cl = (LaunchClassLoader) data.get("classLoader");
File mcDir = (File)data.get("mcLocation"); File mcDir = (File)data.get("mcLocation");
fmlLocation = (File)data.get("coremodLocation"); fmlLocation = (File)data.get("coremodLocation");
FMLDeobfuscatingRemapper.INSTANCE.setup(mcDir, cl, (String) data.get("deobfuscationFileName"));
ClassPatchManager.INSTANCE.setup(FMLLaunchHandler.side()); ClassPatchManager.INSTANCE.setup(FMLLaunchHandler.side());
FMLDeobfuscatingRemapper.INSTANCE.setup(mcDir, cl, (String) data.get("deobfuscationFileName"));
} }
} }

View File

@ -53,6 +53,7 @@ import com.google.common.io.CharStreams;
import com.google.common.io.InputSupplier; import com.google.common.io.InputSupplier;
import cpw.mods.fml.common.FMLLog; import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.patcher.ClassPatchManager;
import cpw.mods.fml.relauncher.FMLRelaunchLog; import cpw.mods.fml.relauncher.FMLRelaunchLog;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.FieldNode;
@ -71,6 +72,11 @@ public class FMLDeobfuscatingRemapper extends Remapper {
private LaunchClassLoader classLoader; 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() private FMLDeobfuscatingRemapper()
{ {
classNameBiMap=ImmutableBiMap.of(); classNameBiMap=ImmutableBiMap.of();
@ -202,6 +208,10 @@ public class FMLDeobfuscatingRemapper extends Remapper {
*/ */
private Map<String,Map<String,String>> fieldDescriptions = Maps.newHashMap(); private Map<String,Map<String,String>> fieldDescriptions = Maps.newHashMap();
// Cache null values so we don't waste time trying to recompute classes with no field or method maps
private Set<String> negativeCacheMethods = Sets.newHashSet();
private Set<String> negativeCacheFields = Sets.newHashSet();
private String getFieldType(String owner, String name) private String getFieldType(String owner, String name)
{ {
if (fieldDescriptions.containsKey(owner)) if (fieldDescriptions.containsKey(owner))
@ -212,7 +222,7 @@ public class FMLDeobfuscatingRemapper extends Remapper {
{ {
try try
{ {
byte[] classBytes = classLoader.getClassBytes(owner); byte[] classBytes = ClassPatchManager.INSTANCE.getPatchedResource(owner, map(owner).replace('/', '.'), classLoader);
if (classBytes == null) if (classBytes == null)
{ {
return 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; String result = classNameBiMap.containsKey(realType) ? classNameBiMap.get(realType) : mcpNameBiMap.containsKey(realType) ? mcpNameBiMap.get(realType) : realType;
result = dollarIdx > -1 ? result+"$"+subType : result; result = dollarIdx > -1 ? result+"$"+subType : result;
// System.out.printf("Mapping %s=>%s\n",typeName,result);
return 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; String result = classNameBiMap.containsValue(realType) ? classNameBiMap.inverse().get(realType) : mcpNameBiMap.containsValue(realType) ? mcpNameBiMap.inverse().get(realType) : realType;
result = dollarIdx > -1 ? result+"$"+subType : result; result = dollarIdx > -1 ? result+"$"+subType : result;
// System.out.printf("Unmapping %s=>%s\n",typeName,result);
return result; return result;
} }
@ -324,18 +332,36 @@ public class FMLDeobfuscatingRemapper extends Remapper {
private Map<String,String> getFieldMap(String className) private Map<String,String> getFieldMap(String className)
{ {
if (!fieldNameMaps.containsKey(className)) if (!fieldNameMaps.containsKey(className) && !negativeCacheFields.contains(className))
{ {
findAndMergeSuperMaps(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); return fieldNameMaps.get(className);
} }
private Map<String,String> getMethodMap(String className) private Map<String,String> getMethodMap(String className)
{ {
if (!methodNameMaps.containsKey(className)) if (!methodNameMaps.containsKey(className) && !negativeCacheMethods.contains(className))
{ {
findAndMergeSuperMaps(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); return methodNameMaps.get(className);
} }
@ -344,17 +370,14 @@ public class FMLDeobfuscatingRemapper extends Remapper {
{ {
try try
{ {
byte[] classBytes = classLoader.getClassBytes(name); String superName = null;
if (classBytes == null) String[] interfaces = new String[0];
byte[] classBytes = ClassPatchManager.INSTANCE.getPatchedResource(name, map(name), classLoader);
if (classBytes != null)
{ {
return;
}
ClassReader cr = new ClassReader(classBytes); ClassReader cr = new ClassReader(classBytes);
String superName = cr.getSuperName(); superName = cr.getSuperName();
String[] interfaces = cr.getInterfaces(); interfaces = cr.getInterfaces();
if (interfaces == null)
{
interfaces = new String[0];
} }
mergeSuperMaps(name, superName, interfaces); mergeSuperMaps(name, superName, interfaces);
} }

View File

@ -11,6 +11,7 @@ import java.security.CodeSource;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.jar.JarEntry; import java.util.jar.JarEntry;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import java.util.jar.JarInputStream; import java.util.jar.JarInputStream;
@ -19,6 +20,8 @@ import java.util.jar.Pack200;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import net.minecraft.launchwrapper.LaunchClassLoader;
import LZMA.LzmaInputStream; import LZMA.LzmaInputStream;
import com.google.common.base.Joiner; 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.base.Throwables;
import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap; import com.google.common.collect.ListMultimap;
import com.google.common.collect.Maps;
import com.google.common.hash.Hashing; import com.google.common.hash.Hashing;
import com.google.common.io.ByteArrayDataInput; import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
@ -44,6 +48,7 @@ public class ClassPatchManager {
private GDiffPatcher patcher = new GDiffPatcher(); private GDiffPatcher patcher = new GDiffPatcher();
private ListMultimap<String, ClassPatch> patches; private ListMultimap<String, ClassPatch> patches;
private Map<String,byte[]> patchedClasses = Maps.newHashMap();
private File tempDir; private File tempDir;
private ClassPatchManager() 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) public byte[] applyPatch(String name, String mappedName, byte[] inputData)
{ {
if (patches == null) if (patches == null)
{ {
return inputData; return inputData;
} }
if (patchedClasses.containsKey(name))
{
return patchedClasses.get(name);
}
List<ClassPatch> list = patches.get(name); List<ClassPatch> list = patches.get(name);
if (list.isEmpty()) 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" : ""); 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) 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); 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()); FMLRelaunchLog.log(Level.SEVERE, e, "Failed to write %s to %s", mappedName, tempDir.getAbsolutePath());
} }
} }
patchedClasses.put(name,inputData);
return inputData; return inputData;
} }
@ -185,6 +201,7 @@ public class ClassPatchManager {
} while (true); } while (true);
FMLRelaunchLog.fine("Read %d binary patches", patches.size()); FMLRelaunchLog.fine("Read %d binary patches", patches.size());
FMLRelaunchLog.fine("Patch list :\n\t%s", Joiner.on("\t\n").join(patches.asMap().entrySet())); FMLRelaunchLog.fine("Patch list :\n\t%s", Joiner.on("\t\n").join(patches.asMap().entrySet()));
patchedClasses.clear();
} }
private ClassPatch readPatch(JarEntry patchEntry, JarInputStream jis) private ClassPatch readPatch(JarEntry patchEntry, JarInputStream jis)

View File

@ -1,5 +0,0 @@
package cpw.mods.fml.common.patcher;
public class ClassPatchingTransformer {
}