1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.bcel.util;
18
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.HashMap;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Locale;
25 import java.util.Map;
26 import java.util.regex.Matcher;
27 import java.util.regex.Pattern;
28
29 import org.apache.bcel.Const;
30 import org.apache.bcel.generic.ClassGenException;
31 import org.apache.bcel.generic.InstructionHandle;
32 import org.apache.bcel.generic.InstructionList;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 public class InstructionFinder {
64
65
66
67
68
69 public interface CodeConstraint {
70
71
72
73
74
75 boolean checkCode(InstructionHandle[] match);
76 }
77
78 private static final int OFFSET = 32767;
79 private static final int NO_OPCODES = 256;
80 private static final Map<String, String> map = new HashMap<>();
81
82
83 static {
84 map.put("arithmeticinstruction",
85 "(irem|lrem|iand|ior|ineg|isub|lneg|fneg|fmul|ldiv|fadd|lxor|frem|idiv|land|ixor|ishr|fsub|lshl|fdiv|iadd|lor|dmul|lsub|ishl|imul|lmul|lushr|dneg|iushr|lshr|ddiv|drem|dadd|ladd|dsub)");
86 map.put("invokeinstruction", "(invokevirtual|invokeinterface|invokestatic|invokespecial|invokedynamic)");
87 map.put("arrayinstruction",
88 "(baload|aastore|saload|caload|fastore|lastore|iaload|castore|iastore|aaload|bastore|sastore|faload|laload|daload|dastore)");
89 map.put("gotoinstruction", "(goto|goto_w)");
90 map.put("conversioninstruction", "(d2l|l2d|i2s|d2i|l2i|i2b|l2f|d2f|f2i|i2d|i2l|f2d|i2c|f2l|i2f)");
91 map.put("localvariableinstruction", "(fstore|iinc|lload|dstore|dload|iload|aload|astore|istore|fload|lstore)");
92 map.put("loadinstruction", "(fload|dload|lload|iload|aload)");
93 map.put("fieldinstruction", "(getfield|putstatic|getstatic|putfield)");
94 map.put("cpinstruction",
95 "(ldc2_w|invokeinterface|invokedynamic|multianewarray|putstatic|instanceof|getstatic|checkcast|getfield|invokespecial|ldc_w|invokestatic|invokevirtual|putfield|ldc|new|anewarray)");
96 map.put("stackinstruction", "(dup2|swap|dup2_x2|pop|pop2|dup|dup2_x1|dup_x2|dup_x1)");
97 map.put("branchinstruction",
98 "(ifle|if_acmpne|if_icmpeq|if_acmpeq|ifnonnull|goto_w|iflt|ifnull|if_icmpne|tableswitch|if_icmple|ifeq|if_icmplt|jsr_w|if_icmpgt|ifgt|jsr|goto|ifne|ifge|lookupswitch|if_icmpge)");
99 map.put("returninstruction", "(lreturn|ireturn|freturn|dreturn|areturn|return)");
100 map.put("storeinstruction", "(istore|fstore|dstore|astore|lstore)");
101 map.put("select", "(tableswitch|lookupswitch)");
102 map.put("ifinstruction",
103 "(ifeq|ifgt|if_icmpne|if_icmpeq|ifge|ifnull|ifne|if_icmple|if_icmpge|if_acmpeq|if_icmplt|if_acmpne|ifnonnull|iflt|if_icmpgt|ifle)");
104 map.put("jsrinstruction", "(jsr|jsr_w)");
105 map.put("variablelengthinstruction", "(tableswitch|jsr|goto|lookupswitch)");
106 map.put("unconditionalbranch", "(goto|jsr|jsr_w|athrow|goto_w)");
107 map.put("constantpushinstruction", "(dconst|bipush|sipush|fconst|iconst|lconst)");
108 map.put("typedinstruction",
109 "(imul|lsub|aload|fload|lor|new|aaload|fcmpg|iand|iaload|lrem|idiv|d2l|isub|dcmpg|dastore|ret|f2d|f2i|drem|iinc|i2c|checkcast|frem|lreturn|astore|lushr|daload|dneg|fastore|istore|lshl|ldiv|lstore|areturn|ishr|ldc_w|invokeinterface|invokedynamic|aastore|lxor|ishl|l2d|i2f|return|faload|sipush|iushr|caload|instanceof|invokespecial|putfield|fmul|ireturn|laload|d2f|lneg|ixor|i2l|fdiv|lastore|multianewarray|i2b|getstatic|i2d|putstatic|fcmpl|saload|ladd|irem|dload|jsr_w|dconst|dcmpl|fsub|freturn|ldc|aconst_null|castore|lmul|ldc2_w|dadd|iconst|f2l|ddiv|dstore|land|jsr|anewarray|dmul|bipush|dsub|sastore|d2i|i2s|lshr|iadd|l2i|lload|bastore|fstore|fneg|iload|fadd|baload|fconst|ior|ineg|dreturn|l2f|lconst|getfield|invokevirtual|invokestatic|iastore)");
110 map.put("popinstruction", "(fstore|dstore|pop|pop2|astore|putstatic|istore|lstore)");
111 map.put("allocationinstruction", "(multianewarray|new|anewarray|newarray)");
112 map.put("indexedinstruction",
113 "(lload|lstore|fload|ldc2_w|invokeinterface|invokedynamic|multianewarray|astore|dload|putstatic|instanceof|getstatic|checkcast|getfield|invokespecial|dstore|istore|iinc|ldc_w|ret|fstore|invokestatic|iload|putfield|invokevirtual|ldc|new|aload|anewarray)");
114 map.put("pushinstruction", "(dup|lload|dup2|bipush|fload|ldc2_w|sipush|lconst|fconst|dload|getstatic|ldc_w|aconst_null|dconst|iload|ldc|iconst|aload)");
115 map.put("stackproducer",
116 "(imul|lsub|aload|fload|lor|new|aaload|fcmpg|iand|iaload|lrem|idiv|d2l|isub|dcmpg|dup|f2d|f2i|drem|i2c|checkcast|frem|lushr|daload|dneg|lshl|ldiv|ishr|ldc_w|invokeinterface|invokedynamic|lxor|ishl|l2d|i2f|faload|sipush|iushr|caload|instanceof|invokespecial|fmul|laload|d2f|lneg|ixor|i2l|fdiv|getstatic|i2b|swap|i2d|dup2|fcmpl|saload|ladd|irem|dload|jsr_w|dconst|dcmpl|fsub|ldc|arraylength|aconst_null|tableswitch|lmul|ldc2_w|iconst|dadd|f2l|ddiv|land|jsr|anewarray|dmul|bipush|dsub|d2i|newarray|i2s|lshr|iadd|lload|l2i|fneg|iload|fadd|baload|fconst|lookupswitch|ior|ineg|lconst|l2f|getfield|invokevirtual|invokestatic)");
117 map.put("stackconsumer",
118 "(imul|lsub|lor|iflt|fcmpg|if_icmpgt|iand|ifeq|if_icmplt|lrem|ifnonnull|idiv|d2l|isub|dcmpg|dastore|if_icmpeq|f2d|f2i|drem|i2c|checkcast|frem|lreturn|astore|lushr|pop2|monitorexit|dneg|fastore|istore|lshl|ldiv|lstore|areturn|if_icmpge|ishr|monitorenter|invokeinterface|invokedynamic|aastore|lxor|ishl|l2d|i2f|return|iushr|instanceof|invokespecial|fmul|ireturn|d2f|lneg|ixor|pop|i2l|ifnull|fdiv|lastore|i2b|if_acmpeq|ifge|swap|i2d|putstatic|fcmpl|ladd|irem|dcmpl|fsub|freturn|ifgt|castore|lmul|dadd|f2l|ddiv|dstore|land|if_icmpne|if_acmpne|dmul|dsub|sastore|ifle|d2i|i2s|lshr|iadd|l2i|bastore|fstore|fneg|fadd|ior|ineg|ifne|dreturn|l2f|if_icmple|getfield|invokevirtual|invokestatic|iastore)");
119 map.put("exceptionthrower",
120 "(irem|lrem|laload|putstatic|baload|dastore|areturn|getstatic|ldiv|anewarray|iastore|castore|idiv|saload|lastore|fastore|putfield|lreturn|caload|getfield|return|aastore|freturn|newarray|instanceof|multianewarray|athrow|faload|iaload|aaload|dreturn|monitorenter|checkcast|bastore|arraylength|new|invokevirtual|sastore|ldc_w|ireturn|invokespecial|monitorexit|invokeinterface|invokedynamic|ldc|invokestatic|daload)");
121 map.put("loadclass",
122 "(multianewarray|invokeinterface|invokedynamic|instanceof|invokespecial|putfield|checkcast|putstatic|invokevirtual|new|getstatic|invokestatic|getfield|anewarray)");
123 map.put("instructiontargeter",
124 "(ifle|if_acmpne|if_icmpeq|if_acmpeq|ifnonnull|goto_w|iflt|ifnull|if_icmpne|tableswitch|if_icmple|ifeq|if_icmplt|jsr_w|if_icmpgt|ifgt|jsr|goto|ifne|ifge|lookupswitch|if_icmpge)");
125
126 map.put("if_icmp", "(if_icmpne|if_icmpeq|if_icmple|if_icmpge|if_icmplt|if_icmpgt)");
127 map.put("if_acmp", "(if_acmpeq|if_acmpne)");
128 map.put("if", "(ifeq|ifne|iflt|ifge|ifgt|ifle)");
129
130 map.put("iconst", precompile(Const.ICONST_0, Const.ICONST_5, Const.ICONST_M1));
131 map.put("lconst", new String(new char[] {'(', makeChar(Const.LCONST_0), '|', makeChar(Const.LCONST_1), ')'}));
132 map.put("dconst", new String(new char[] {'(', makeChar(Const.DCONST_0), '|', makeChar(Const.DCONST_1), ')'}));
133 map.put("fconst", new String(new char[] {'(', makeChar(Const.FCONST_0), '|', makeChar(Const.FCONST_1), '|', makeChar(Const.FCONST_2), ')'}));
134 map.put("lload", precompile(Const.LLOAD_0, Const.LLOAD_3, Const.LLOAD));
135 map.put("iload", precompile(Const.ILOAD_0, Const.ILOAD_3, Const.ILOAD));
136 map.put("dload", precompile(Const.DLOAD_0, Const.DLOAD_3, Const.DLOAD));
137 map.put("fload", precompile(Const.FLOAD_0, Const.FLOAD_3, Const.FLOAD));
138 map.put("aload", precompile(Const.ALOAD_0, Const.ALOAD_3, Const.ALOAD));
139 map.put("lstore", precompile(Const.LSTORE_0, Const.LSTORE_3, Const.LSTORE));
140 map.put("istore", precompile(Const.ISTORE_0, Const.ISTORE_3, Const.ISTORE));
141 map.put("dstore", precompile(Const.DSTORE_0, Const.DSTORE_3, Const.DSTORE));
142 map.put("fstore", precompile(Const.FSTORE_0, Const.FSTORE_3, Const.FSTORE));
143 map.put("astore", precompile(Const.ASTORE_0, Const.ASTORE_3, Const.ASTORE));
144
145 map.forEach((key, value) -> {
146 final char ch = value.charAt(1);
147 if (ch < OFFSET) {
148 map.put(key, compilePattern(value));
149 }
150 });
151
152 final StringBuilder buf = new StringBuilder("(");
153 for (short i = 0; i < NO_OPCODES; i++) {
154 if (Const.getNoOfOperands(i) != Const.UNDEFINED) {
155 buf.append(makeChar(i));
156 if (i < NO_OPCODES - 1) {
157 buf.append('|');
158 }
159 }
160 }
161 buf.append(')');
162 map.put("instruction", buf.toString());
163 }
164
165
166
167
168
169
170
171
172 private static String compilePattern(final String pattern) {
173
174 final String lower = pattern.toLowerCase(Locale.ENGLISH);
175 final StringBuilder buf = new StringBuilder();
176 final int size = pattern.length();
177 for (int i = 0; i < size; i++) {
178 char ch = lower.charAt(i);
179 if (Character.isLetterOrDigit(ch)) {
180 final StringBuilder name = new StringBuilder();
181 while ((Character.isLetterOrDigit(ch) || ch == '_') && i < size) {
182 name.append(ch);
183 if (++i >= size) {
184 break;
185 }
186 ch = lower.charAt(i);
187 }
188 i--;
189 buf.append(mapName(name.toString()));
190 } else if (!Character.isWhitespace(ch)) {
191 buf.append(ch);
192 }
193 }
194 return buf.toString();
195 }
196
197
198
199
200 private static char makeChar(final short opcode) {
201 return (char) (opcode + OFFSET);
202 }
203
204
205
206
207
208
209
210 private static String mapName(final String pattern) {
211 final String result = map.get(pattern);
212 if (result != null) {
213 return result;
214 }
215 for (short i = 0; i < NO_OPCODES; i++) {
216 if (pattern.equals(Const.getOpcodeName(i))) {
217 return String.valueOf(makeChar(i));
218 }
219 }
220 throw new IllegalArgumentException("Instruction unknown: " + pattern);
221 }
222
223 private static String precompile(final short from, final short to, final short extra) {
224 final StringBuilder buf = new StringBuilder("(");
225 for (short i = from; i <= to; i++) {
226 buf.append(makeChar(i));
227 buf.append('|');
228 }
229 buf.append(makeChar(extra));
230 buf.append(")");
231 return buf.toString();
232 }
233
234 private final InstructionList il;
235
236 private String ilString;
237
238 private InstructionHandle[] handles;
239
240
241
242
243
244 public InstructionFinder(final InstructionList il) {
245 this.il = il;
246 reread();
247 }
248
249
250
251
252 public final InstructionList getInstructionList() {
253 return il;
254 }
255
256
257
258
259 private InstructionHandle[] getMatch(final int matchedFrom, final int matchLength) {
260 return Arrays.copyOfRange(handles, matchedFrom, matchedFrom + matchLength);
261 }
262
263
264
265
266 public final void reread() {
267 final int size = il.getLength();
268 final char[] buf = new char[size];
269 handles = il.getInstructionHandles();
270
271 for (int i = 0; i < size; i++) {
272 buf[i] = makeChar(handles[i].getInstruction().getOpcode());
273 }
274 ilString = new String(buf);
275 }
276
277
278
279
280
281
282
283 public final Iterator<InstructionHandle[]> search(final String pattern) {
284 return search(pattern, il.getStart(), null);
285 }
286
287
288
289
290
291
292
293
294 public final Iterator<InstructionHandle[]> search(final String pattern, final CodeConstraint constraint) {
295 return search(pattern, il.getStart(), constraint);
296 }
297
298
299
300
301
302
303
304
305 public final Iterator<InstructionHandle[]> search(final String pattern, final InstructionHandle from) {
306 return search(pattern, from, null);
307 }
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335 public final Iterator<InstructionHandle[]> search(final String pattern, final InstructionHandle from, final CodeConstraint constraint) {
336 final String search = compilePattern(pattern);
337 int start = -1;
338 for (int i = 0; i < handles.length; i++) {
339 if (handles[i] == from) {
340 start = i;
341 break;
342 }
343 }
344 if (start == -1) {
345 throw new ClassGenException("Instruction handle " + from + " not found in instruction list.");
346 }
347 final Pattern regex = Pattern.compile(search);
348 final List<InstructionHandle[]> matches = new ArrayList<>();
349 final Matcher matcher = regex.matcher(ilString);
350 while (start < ilString.length() && matcher.find(start)) {
351 final int startExpr = matcher.start();
352 final int endExpr = matcher.end();
353 final int lenExpr = endExpr - startExpr;
354 final InstructionHandle[] match = getMatch(startExpr, lenExpr);
355 if (constraint == null || constraint.checkCode(match)) {
356 matches.add(match);
357 }
358 start = endExpr;
359 }
360 return matches.iterator();
361 }
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386 }