diff options
Diffstat (limited to 'src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java')
| -rw-r--r-- | src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java | 157 |
1 files changed, 0 insertions, 157 deletions
diff --git a/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java b/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java deleted file mode 100644 index dc3f553..0000000 --- a/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java +++ /dev/null | |||
| @@ -1,157 +0,0 @@ | |||
| 1 | package cuchaz.enigma.analysis; | ||
| 2 | |||
| 3 | import cuchaz.enigma.api.EnigmaPlugin; | ||
| 4 | import cuchaz.enigma.api.EnigmaPluginContext; | ||
| 5 | import cuchaz.enigma.api.service.JarIndexerService; | ||
| 6 | import cuchaz.enigma.api.service.NameProposalService; | ||
| 7 | import cuchaz.enigma.source.DecompilerService; | ||
| 8 | import cuchaz.enigma.source.Decompilers; | ||
| 9 | import cuchaz.enigma.source.procyon.ProcyonDecompiler; | ||
| 10 | import cuchaz.enigma.translation.representation.TypeDescriptor; | ||
| 11 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | ||
| 12 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 13 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | ||
| 14 | import cuchaz.enigma.utils.Pair; | ||
| 15 | import cuchaz.enigma.utils.Utils; | ||
| 16 | import org.objectweb.asm.ClassReader; | ||
| 17 | import org.objectweb.asm.ClassVisitor; | ||
| 18 | import org.objectweb.asm.FieldVisitor; | ||
| 19 | import org.objectweb.asm.MethodVisitor; | ||
| 20 | import org.objectweb.asm.Opcodes; | ||
| 21 | import org.objectweb.asm.tree.AbstractInsnNode; | ||
| 22 | import org.objectweb.asm.tree.FieldInsnNode; | ||
| 23 | import org.objectweb.asm.tree.InsnList; | ||
| 24 | import org.objectweb.asm.tree.LdcInsnNode; | ||
| 25 | import org.objectweb.asm.tree.MethodInsnNode; | ||
| 26 | import org.objectweb.asm.tree.MethodNode; | ||
| 27 | import org.objectweb.asm.tree.analysis.Analyzer; | ||
| 28 | import org.objectweb.asm.tree.analysis.Frame; | ||
| 29 | import org.objectweb.asm.tree.analysis.SourceInterpreter; | ||
| 30 | import org.objectweb.asm.tree.analysis.SourceValue; | ||
| 31 | |||
| 32 | import java.util.ArrayList; | ||
| 33 | import java.util.HashMap; | ||
| 34 | import java.util.HashSet; | ||
| 35 | import java.util.List; | ||
| 36 | import java.util.Map; | ||
| 37 | import java.util.Optional; | ||
| 38 | import java.util.Set; | ||
| 39 | |||
| 40 | public final class BuiltinPlugin implements EnigmaPlugin { | ||
| 41 | |||
| 42 | public BuiltinPlugin() { | ||
| 43 | } | ||
| 44 | |||
| 45 | @Override | ||
| 46 | public void init(EnigmaPluginContext ctx) { | ||
| 47 | registerEnumNamingService(ctx); | ||
| 48 | registerDecompilerServices(ctx); | ||
| 49 | } | ||
| 50 | |||
| 51 | private void registerEnumNamingService(EnigmaPluginContext ctx) { | ||
| 52 | final Map<Entry<?>, String> names = new HashMap<>(); | ||
| 53 | final EnumFieldNameFindingVisitor visitor = new EnumFieldNameFindingVisitor(names); | ||
| 54 | |||
| 55 | ctx.registerService("enigma:enum_initializer_indexer", JarIndexerService.TYPE, ctx1 -> (classCache, jarIndex) -> classCache.visit(() -> visitor, ClassReader.SKIP_FRAMES)); | ||
| 56 | ctx.registerService("enigma:enum_name_proposer", NameProposalService.TYPE, ctx1 -> (obfEntry, remapper) -> Optional.ofNullable(names.get(obfEntry))); | ||
| 57 | } | ||
| 58 | |||
| 59 | private void registerDecompilerServices(EnigmaPluginContext ctx) { | ||
| 60 | ctx.registerService("enigma:procyon", DecompilerService.TYPE, ctx1 -> Decompilers.PROCYON); | ||
| 61 | ctx.registerService("enigma:cfr", DecompilerService.TYPE, ctx1 -> Decompilers.CFR); | ||
| 62 | } | ||
| 63 | |||
| 64 | private static final class EnumFieldNameFindingVisitor extends ClassVisitor { | ||
| 65 | |||
| 66 | private ClassEntry clazz; | ||
| 67 | private String className; | ||
| 68 | private final Map<Entry<?>, String> mappings; | ||
| 69 | private final Set<Pair<String, String>> enumFields = new HashSet<>(); | ||
| 70 | private final List<MethodNode> classInits = new ArrayList<>(); | ||
| 71 | |||
| 72 | EnumFieldNameFindingVisitor(Map<Entry<?>, String> mappings) { | ||
| 73 | super(Utils.ASM_VERSION); | ||
| 74 | this.mappings = mappings; | ||
| 75 | } | ||
| 76 | |||
| 77 | @Override | ||
| 78 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { | ||
| 79 | super.visit(version, access, name, signature, superName, interfaces); | ||
| 80 | this.className = name; | ||
| 81 | this.clazz = new ClassEntry(name); | ||
| 82 | this.enumFields.clear(); | ||
| 83 | this.classInits.clear(); | ||
| 84 | } | ||
| 85 | |||
| 86 | @Override | ||
| 87 | public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { | ||
| 88 | if ((access & Opcodes.ACC_ENUM) != 0) { | ||
| 89 | if (!enumFields.add(new Pair<>(name, descriptor))) { | ||
| 90 | throw new IllegalArgumentException("Found two enum fields with the same name \"" + name + "\" and desc \"" + descriptor + "\"!"); | ||
| 91 | } | ||
| 92 | } | ||
| 93 | return super.visitField(access, name, descriptor, signature, value); | ||
| 94 | } | ||
| 95 | |||
| 96 | @Override | ||
| 97 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { | ||
| 98 | if ("<clinit>".equals(name)) { | ||
| 99 | MethodNode node = new MethodNode(api, access, name, descriptor, signature, exceptions); | ||
| 100 | classInits.add(node); | ||
| 101 | return node; | ||
| 102 | } | ||
| 103 | return super.visitMethod(access, name, descriptor, signature, exceptions); | ||
| 104 | } | ||
| 105 | |||
| 106 | @Override | ||
| 107 | public void visitEnd() { | ||
| 108 | super.visitEnd(); | ||
| 109 | try { | ||
| 110 | collectResults(); | ||
| 111 | } catch (Exception ex) { | ||
| 112 | throw new RuntimeException(ex); | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | private void collectResults() throws Exception { | ||
| 117 | String owner = className; | ||
| 118 | Analyzer<SourceValue> analyzer = new Analyzer<>(new SourceInterpreter()); | ||
| 119 | |||
| 120 | for (MethodNode mn : classInits) { | ||
| 121 | Frame<SourceValue>[] frames = analyzer.analyze(className, mn); | ||
| 122 | |||
| 123 | InsnList instrs = mn.instructions; | ||
| 124 | for (int i = 1; i < instrs.size(); i++) { | ||
| 125 | AbstractInsnNode instr1 = instrs.get(i - 1); | ||
| 126 | AbstractInsnNode instr2 = instrs.get(i); | ||
| 127 | String s = null; | ||
| 128 | |||
| 129 | if (instr2.getOpcode() == Opcodes.PUTSTATIC | ||
| 130 | && ((FieldInsnNode) instr2).owner.equals(owner) | ||
| 131 | && enumFields.contains(new Pair<>(((FieldInsnNode) instr2).name, ((FieldInsnNode) instr2).desc)) | ||
| 132 | && instr1.getOpcode() == Opcodes.INVOKESPECIAL | ||
| 133 | && "<init>".equals(((MethodInsnNode) instr1).name)) { | ||
| 134 | |||
| 135 | for (int j = 0; j < frames[i - 1].getStackSize(); j++) { | ||
| 136 | SourceValue sv = frames[i - 1].getStack(j); | ||
| 137 | for (AbstractInsnNode ci : sv.insns) { | ||
| 138 | if (ci instanceof LdcInsnNode && ((LdcInsnNode) ci).cst instanceof String) { | ||
| 139 | //if (s == null || !s.equals(((LdcInsnNode) ci).cst)) { | ||
| 140 | if (s == null) { | ||
| 141 | s = (String) (((LdcInsnNode) ci).cst); | ||
| 142 | // stringsFound++; | ||
| 143 | } | ||
| 144 | } | ||
| 145 | } | ||
| 146 | } | ||
| 147 | } | ||
| 148 | |||
| 149 | if (s != null) { | ||
| 150 | mappings.put(new FieldEntry(clazz, ((FieldInsnNode) instr2).name, new TypeDescriptor(((FieldInsnNode) instr2).desc)), s); | ||
| 151 | } | ||
| 152 | // report otherwise? | ||
| 153 | } | ||
| 154 | } | ||
| 155 | } | ||
| 156 | } | ||
| 157 | } | ||