From 6046e132892c55081229b795f9ba68d32b681d82 Mon Sep 17 00:00:00 2001 From: liach Date: Sat, 3 Jul 2021 05:34:39 -0500 Subject: Update cfr and fixes a few related issues (#414) * Update cfr and fixes a few related issues fixes #368 context for token references, missing some field and method references * Prevent crash when cfr fails to decompile a lambda and creates a fallback Signed-off-by: liach * Fix issue with parameters incorrectly spilling into other methods Signed-off-by: liach * try improve performance of cfr source Co-authored-by: liach --- .../cuchaz/enigma/source/cfr/CfrDecompiler.java | 3 +- .../java/cuchaz/enigma/source/cfr/CfrSource.java | 33 +++++++++++------ .../cuchaz/enigma/source/cfr/EnigmaDumper.java | 43 ++++++++++++++-------- 3 files changed, 50 insertions(+), 29 deletions(-) (limited to 'enigma/src/main/java') diff --git a/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java b/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java index ffc4788..91fd5a2 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java +++ b/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java @@ -24,7 +24,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.objectweb.asm.tree.ClassNode; import java.util.Collection; -import java.util.HashMap; import java.util.Map; public class CfrDecompiler implements Decompiler { @@ -33,7 +32,7 @@ public class CfrDecompiler implements Decompiler { private final SourceSettings settings; public CfrDecompiler(ClassProvider classProvider, SourceSettings sourceSettings) { - Map options = new HashMap<>(); + Map options = Map.of("trackbytecodeloc", "true"); state = new DCCommonState(OptionsImpl.getFactory().create(options), new ClassFileSource2() { @Override diff --git a/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrSource.java b/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrSource.java index ba831d7..7c63afc 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrSource.java +++ b/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrSource.java @@ -13,11 +13,12 @@ import org.checkerframework.checker.nullness.qual.Nullable; public class CfrSource implements Source { private final SourceSettings settings; private final ClassFile tree; - private final SourceIndex index; - private final String string; private final DCCommonState state; private final TypeUsageInformation typeUsage; private final Options options; + private final EntryRemapper mapper; + + private SourceIndex index; public CfrSource(SourceSettings settings, ClassFile tree, DCCommonState state, TypeUsageInformation typeUsage, Options options, @Nullable EntryRemapper mapper) { this.settings = settings; @@ -25,16 +26,7 @@ public class CfrSource implements Source { this.state = state; this.typeUsage = typeUsage; this.options = options; - - EnigmaDumper dumper = new EnigmaDumper(new StringBuilder(), settings, typeUsage, options, mapper); - tree.dump(state.getObfuscationMapping().wrap(dumper)); - index = dumper.getIndex(); - string = dumper.getString(); - } - - @Override - public String asString() { - return string; + this.mapper = mapper; } @Override @@ -44,6 +36,23 @@ public class CfrSource implements Source { @Override public SourceIndex index() { + ensureDecompiled(); return index; } + + @Override + public String asString() { + ensureDecompiled(); + return index.getSource(); + } + + private synchronized void ensureDecompiled() { + if (index != null) { + return; + } + + EnigmaDumper dumper = new EnigmaDumper(new StringBuilder(), settings, typeUsage, options, mapper); + tree.dump(state.getObfuscationMapping().wrap(dumper)); + index = dumper.getIndex(); + } } diff --git a/enigma/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java b/enigma/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java index d0734c5..b85851f 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java +++ b/enigma/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java @@ -12,17 +12,16 @@ import cuchaz.enigma.translation.representation.entry.Entry; import cuchaz.enigma.translation.representation.entry.FieldEntry; import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; import cuchaz.enigma.translation.representation.entry.MethodEntry; -import org.benf.cfr.reader.bytecode.analysis.types.JavaArrayTypeInstance; -import org.benf.cfr.reader.bytecode.analysis.types.JavaGenericBaseInstance; +import org.benf.cfr.reader.bytecode.analysis.loc.HasByteCodeLoc; import org.benf.cfr.reader.bytecode.analysis.types.JavaRefTypeInstance; import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; import org.benf.cfr.reader.bytecode.analysis.types.MethodPrototype; -import org.benf.cfr.reader.bytecode.analysis.types.RawJavaType; import org.benf.cfr.reader.bytecode.analysis.variables.NamedVariable; import org.benf.cfr.reader.entities.AccessFlag; import org.benf.cfr.reader.entities.ClassFile; import org.benf.cfr.reader.entities.ClassFileField; import org.benf.cfr.reader.entities.Field; +import org.benf.cfr.reader.entities.Method; import org.benf.cfr.reader.state.TypeUsageInformation; import org.benf.cfr.reader.util.getopt.Options; import org.benf.cfr.reader.util.output.Dumper; @@ -49,6 +48,7 @@ public class EnigmaDumper extends StringStreamDumper { private final TypeUsageInformation typeUsage; private final MovableDumperContext dumperContext; private boolean muteLine = false; + private MethodEntry contextMethod = null; public EnigmaDumper(StringBuilder sb, SourceSettings sourceSettings, TypeUsageInformation typeUsage, Options options, @Nullable EntryRemapper mapper) { @@ -68,18 +68,19 @@ public class EnigmaDumper extends StringStreamDumper { } private MethodEntry getMethodEntry(MethodPrototype method) { - if (method == null || method.getClassType() == null) { + if (method == null || method.getOwner() == null) { return null; } MethodDescriptor desc = new MethodDescriptor(method.getOriginalDescriptor()); - return new MethodEntry(getClassEntry(method.getClassType()), method.getName(), desc); + return new MethodEntry(getClassEntry(method.getOwner()), method.getName(), desc); } private LocalVariableEntry getParameterEntry(MethodPrototype method, int parameterIndex, String name) { MethodEntry owner = getMethodEntry(method); - if (owner == null) { + // params may be not computed if cfr creates a lambda expression fallback, e.g. in PointOfInterestSet + if (owner == null || !method.parametersComputed()) { return null; } @@ -253,7 +254,7 @@ public class EnigmaDumper extends StringStreamDumper { if (defines) { index.addDeclaration(token, entry); // override as cfr reuses local vars } else { - index.addReference(token, entry, null); + index.addReference(token, entry, contextMethod); } } @@ -276,7 +277,7 @@ public class EnigmaDumper extends StringStreamDumper { if (defines) { this.index.addDeclaration(token, entry); } else { - this.index.addReference(token, entry, null); + this.index.addReference(token, entry, contextMethod); } } @@ -293,27 +294,31 @@ public class EnigmaDumper extends StringStreamDumper { public Dumper identifier(String name, Object ref, boolean defines) { super.identifier(name, ref, defines); Entry entry; + if (defines) { + refs.remove(ref); + return this; + } if ((entry = refs.get(ref)) == null) { return this; } int now = sb.length(); Token token = new Token(now - name.length(), now, name); - index.addReference(token, entry, null); + index.addReference(token, entry, contextMethod); return this; } @Override - public Dumper fieldName(String name, Field field, JavaTypeInstance owner, boolean hiddenDeclaration, boolean defines) { - super.fieldName(name, field, owner, hiddenDeclaration, defines); + public Dumper fieldName(String name, String descriptor, JavaTypeInstance owner, boolean hiddenDeclaration, boolean isStatic, boolean defines) { + super.fieldName(name, descriptor, owner, hiddenDeclaration, isStatic, defines); int now = sb.length(); Token token = new Token(now - name.length(), now, name); - Entry entry = field == null ? null : getFieldEntry(owner, name, field.getDescriptor()); + if (descriptor != null) { + Entry entry = getFieldEntry(owner, name, descriptor); - if (entry != null) { if (defines) { index.addDeclaration(token, entry); } else { - index.addReference(token, entry, null); + index.addReference(token, entry, contextMethod); } } @@ -348,7 +353,7 @@ public class EnigmaDumper extends StringStreamDumper { if (defines) { index.addDeclaration(token, getClassEntry(type)); } else { - index.addReference(token, getClassEntry(type), null); + index.addReference(token, getClassEntry(type), contextMethod); } return; } @@ -367,6 +372,14 @@ public class EnigmaDumper extends StringStreamDumper { return new EnigmaDumper(this.sb, sourceSettings, innerclassTypeUsageInformation, options, mapper, index, dumperContext); } + @Override + public void informBytecodeLoc(HasByteCodeLoc loc) { + Collection methods = loc.getLoc().getMethods(); + if (!methods.isEmpty()) { + this.contextMethod = getMethodEntry(methods.iterator().next().getMethodPrototype()); + } + } + public SourceIndex getIndex() { index.setSource(getString()); return index; -- cgit v1.2.3