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