1 21 package proguard.classfile.util; 22 23 import proguard.classfile.*; 24 import proguard.classfile.attribute.CodeAttribute; 25 import proguard.classfile.constant.*; 26 import proguard.classfile.constant.visitor.ConstantVisitor; 27 import proguard.classfile.instruction.*; 28 import proguard.classfile.instruction.visitor.InstructionVisitor; 29 30 37 public class InstructionSequenceMatcher 38 extends SimplifiedVisitor 39 implements InstructionVisitor, 40 ConstantVisitor 41 { 42 private static final boolean DEBUG = false; 43 public static boolean DEBUG_MORE = false; 45 48 49 public static final int X = 0x40000000; 50 public static final int Y = 0x40000001; 51 public static final int Z = 0x40000002; 52 53 public static final int A = 0x40000003; 54 public static final int B = 0x40000004; 55 public static final int C = 0x40000005; 56 public static final int D = 0x40000006; 57 58 59 private Constant[] patternConstants; 60 private Instruction[] patternInstructions; 61 62 private boolean matching; 63 private int patternInstructionIndex; 64 private int[] matchedInstructionOffsets; 65 private int matchedArgumentFlags; 66 private int[] matchedArguments = new int[7]; 67 private int matchedConstantFlags; 68 private int[] matchedConstantIndices; 69 70 private Constant patternConstant; 72 private boolean matchingConstant; 73 74 75 81 public InstructionSequenceMatcher(Constant[] patternConstants, 82 Instruction[] patternInstructions) 83 { 84 this.patternConstants = patternConstants; 85 this.patternInstructions = patternInstructions; 86 87 matchedInstructionOffsets = new int[patternInstructions.length]; 88 matchedConstantIndices = new int[patternConstants.length]; 89 } 90 91 92 95 public void reset() 96 { 97 patternInstructionIndex = 0; 98 matchedArgumentFlags = 0; 99 matchedConstantFlags = 0; 100 } 101 102 103 public boolean isMatching() 104 { 105 return matching; 106 } 107 108 109 public int instructionCount() 110 { 111 return patternInstructions.length; 112 } 113 114 115 public int matchedInstructionOffset(int index) 116 { 117 return matchedInstructionOffsets[index]; 118 } 119 120 121 public int matchedArgument(int argument) 122 { 123 int argumentIndex = argument - X; 124 return argumentIndex < 0 ? 125 argument : 126 matchedArguments[argumentIndex]; 127 } 128 129 130 public int[] matchedArguments(int[] arguments) 131 { 132 int[] matchedArguments = new int[arguments.length]; 133 134 for (int index = 0; index < arguments.length; index++) 135 { 136 matchedArguments[index] = matchedArgument(arguments[index]); 137 } 138 139 return matchedArguments; 140 } 141 142 143 public int matchedConstantIndex(int constantIndex) 144 { 145 int argumentIndex = constantIndex - X; 146 return argumentIndex < 0 ? 147 matchedConstantIndices[constantIndex] : 148 matchedArguments[argumentIndex]; 149 } 150 151 152 public int matchedBranchOffset(int offset, int branchOffset) 153 { 154 int argumentIndex = branchOffset - X; 155 return argumentIndex < 0 ? 156 branchOffset : 157 matchedArguments[argumentIndex] - offset; 158 } 159 160 161 public int[] matchedJumpOffsets(int offset, int[] jumpOffsets) 162 { 163 int[] matchedJumpOffsets = new int[jumpOffsets.length]; 164 165 for (int index = 0; index < jumpOffsets.length; index++) 166 { 167 matchedJumpOffsets[index] = matchedBranchOffset(offset, 168 jumpOffsets[index]); 169 } 170 171 return matchedJumpOffsets; 172 } 173 174 175 177 public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) 178 { 179 Instruction patternInstruction = patternInstructions[patternInstructionIndex]; 180 181 boolean condition = 183 matchingOpcodes(simpleInstruction, patternInstruction) && 184 matchingArguments(simpleInstruction.constant, 185 ((SimpleInstruction)patternInstruction).constant); 186 187 checkMatch(condition, 189 clazz, 190 method, 191 codeAttribute, 192 offset, 193 simpleInstruction); 194 } 195 196 197 public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) 198 { 199 Instruction patternInstruction = patternInstructions[patternInstructionIndex]; 200 201 boolean condition = 203 matchingOpcodes(variableInstruction, patternInstruction) && 204 matchingArguments(variableInstruction.variableIndex, 205 ((VariableInstruction)patternInstruction).variableIndex) && 206 matchingArguments(variableInstruction.constant, 207 ((VariableInstruction)patternInstruction).constant); 208 209 checkMatch(condition, 211 clazz, 212 method, 213 codeAttribute, 214 offset, 215 variableInstruction); 216 } 217 218 219 public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) 220 { 221 Instruction patternInstruction = patternInstructions[patternInstructionIndex]; 222 223 boolean condition = 225 matchingOpcodes(constantInstruction, patternInstruction) && 226 matchingConstantIndices(clazz, 227 constantInstruction.constantIndex, 228 ((ConstantInstruction)patternInstruction).constantIndex) && 229 matchingArguments(constantInstruction.constant, 230 ((ConstantInstruction)patternInstruction).constant); 231 232 checkMatch(condition, 234 clazz, 235 method, 236 codeAttribute, 237 offset, 238 constantInstruction); 239 } 240 241 242 public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) 243 { 244 Instruction patternInstruction = patternInstructions[patternInstructionIndex]; 245 246 boolean condition = 249 matchingOpcodes(branchInstruction, patternInstruction) && 250 matchingBranchOffsets(offset, 251 branchInstruction.branchOffset, 252 ((BranchInstruction)patternInstruction).branchOffset); 253 254 checkMatch(condition, 256 clazz, 257 method, 258 codeAttribute, 259 offset, 260 branchInstruction); 261 } 262 263 264 public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction) 265 { 266 Instruction patternInstruction = patternInstructions[patternInstructionIndex]; 267 268 boolean condition = 270 matchingOpcodes(tableSwitchInstruction, patternInstruction) && 271 matchingArguments(offset + tableSwitchInstruction.defaultOffset, 272 ((TableSwitchInstruction)patternInstruction).defaultOffset) && 273 matchingArguments(tableSwitchInstruction.lowCase, 274 ((TableSwitchInstruction)patternInstruction).lowCase) && 275 matchingArguments(tableSwitchInstruction.highCase, 276 ((TableSwitchInstruction)patternInstruction).highCase) && 277 matchingJumpOffsets(offset, 278 tableSwitchInstruction.jumpOffsets, 279 ((TableSwitchInstruction)patternInstruction).jumpOffsets); 280 281 checkMatch(condition, 283 clazz, 284 method, 285 codeAttribute, 286 offset, 287 tableSwitchInstruction); 288 } 289 290 291 public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) 292 { 293 Instruction patternInstruction = patternInstructions[patternInstructionIndex]; 294 295 boolean condition = 297 matchingOpcodes(lookUpSwitchInstruction, patternInstruction) && 298 matchingArguments(lookUpSwitchInstruction.defaultOffset, 299 ((LookUpSwitchInstruction)patternInstruction).defaultOffset) && 300 matchingArguments(lookUpSwitchInstruction.cases, 301 ((LookUpSwitchInstruction)patternInstruction).cases) && 302 matchingJumpOffsets(offset, 303 lookUpSwitchInstruction.jumpOffsets, 304 ((LookUpSwitchInstruction)patternInstruction).jumpOffsets); 305 306 checkMatch(condition, 308 clazz, 309 method, 310 codeAttribute, 311 offset, 312 lookUpSwitchInstruction); 313 } 314 315 316 318 public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) 319 { 320 IntegerConstant integerPatternConstant = (IntegerConstant)patternConstant; 321 322 matchingConstant = integerConstant.getValue() == 324 integerPatternConstant.getValue(); 325 } 326 327 328 public void visitLongConstant(Clazz clazz, LongConstant longConstant) 329 { 330 LongConstant longPatternConstant = (LongConstant)patternConstant; 331 332 matchingConstant = longConstant.getValue() == 334 longPatternConstant.getValue(); 335 } 336 337 338 public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) 339 { 340 FloatConstant floatPatternConstant = (FloatConstant)patternConstant; 341 342 matchingConstant = floatConstant.getValue() == 344 floatPatternConstant.getValue(); 345 } 346 347 348 public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) 349 { 350 DoubleConstant doublePatternConstant = (DoubleConstant)patternConstant; 351 352 matchingConstant = doubleConstant.getValue() == 354 doublePatternConstant.getValue(); 355 } 356 357 358 public void visitStringConstant(Clazz clazz, StringConstant stringConstant) 359 { 360 StringConstant stringPatternConstant = (StringConstant)patternConstant; 361 362 matchingConstant = 364 matchingConstantIndices(clazz, 365 stringConstant.u2stringIndex, 366 stringPatternConstant.u2stringIndex); 367 } 368 369 370 public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) 371 { 372 Utf8Constant utf8PatternConstant = (Utf8Constant)patternConstant; 373 374 matchingConstant = utf8Constant.getString().equals( 376 utf8PatternConstant.getString()); 377 } 378 379 380 public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) 381 { 382 RefConstant refPatternConstant = (RefConstant)patternConstant; 383 384 matchingConstant = 386 matchingConstantIndices(clazz, 387 refConstant.getClassIndex(), 388 refPatternConstant.getClassIndex()) && 389 matchingConstantIndices(clazz, 390 refConstant.getNameAndTypeIndex(), 391 refPatternConstant.getNameAndTypeIndex()); 392 } 393 394 395 public void visitClassConstant(Clazz clazz, ClassConstant classConstant) 396 { 397 ClassConstant classPatternConstant = (ClassConstant)patternConstant; 398 399 matchingConstant = 401 matchingConstantIndices(clazz, 402 classConstant.u2nameIndex, 403 classPatternConstant.u2nameIndex); 404 } 405 406 407 public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) 408 { 409 NameAndTypeConstant typePatternConstant = (NameAndTypeConstant)patternConstant; 410 411 matchingConstant = 413 matchingConstantIndices(clazz, 414 nameAndTypeConstant.u2nameIndex, 415 typePatternConstant.u2nameIndex) && 416 matchingConstantIndices(clazz, 417 nameAndTypeConstant.u2descriptorIndex, 418 typePatternConstant.u2descriptorIndex); 419 } 420 421 422 424 private boolean matchingOpcodes(Instruction instruction1, 425 Instruction instruction2) 426 { 427 return instruction1.opcode == instruction2.opcode || 429 instruction1.canonicalOpcode() == instruction2.opcode; 430 } 431 432 433 private boolean matchingArguments(int argument1, 434 int argument2) 435 { 436 int argumentIndex = argument2 - X; 437 if (argumentIndex < 0) 438 { 439 return argument1 == argument2; 441 } 442 else if ((matchedArgumentFlags & (1 << argumentIndex)) == 0) 443 { 444 matchedArguments[argumentIndex] = argument1; 446 matchedArgumentFlags |= 1 << argumentIndex; 447 448 return true; 449 } 450 else 451 { 452 return matchedArguments[argumentIndex] == argument1; 454 } 455 } 456 457 458 private boolean matchingArguments(int[] arguments1, 459 int[] arguments2) 460 { 461 if (arguments1.length != arguments2.length) 462 { 463 return false; 464 } 465 466 for (int index = 0; index < arguments1.length; index++) 467 { 468 if (!matchingArguments(arguments1[index], arguments2[index])) 469 { 470 return false; 471 } 472 } 473 474 return true; 475 } 476 477 478 private boolean matchingConstantIndices(Clazz clazz, 479 int constantIndex1, 480 int constantIndex2) 481 { 482 if (constantIndex2 >= X) 483 { 484 return matchingArguments(constantIndex1, constantIndex2); 486 } 487 else if ((matchedConstantFlags & (1 << constantIndex2)) == 0) 488 { 489 matchingConstant = false; 491 patternConstant = patternConstants[constantIndex2]; 492 493 if (clazz.getTag(constantIndex1) == patternConstant.getTag()) 494 { 495 clazz.constantPoolEntryAccept(constantIndex1, this); 496 497 if (matchingConstant) 498 { 499 matchedConstantIndices[constantIndex2] = constantIndex1; 501 matchedConstantFlags |= 1 << constantIndex2; 502 } 503 } 504 505 return matchingConstant; 506 } 507 else 508 { 509 return matchedConstantIndices[constantIndex2] == constantIndex1; 511 } 512 } 513 514 515 private boolean matchingBranchOffsets(int offset, 516 int branchOffset1, 517 int branchOffset2) 518 { 519 int argumentIndex = branchOffset2 - X; 520 if (argumentIndex < 0) 521 { 522 return branchOffset1 == branchOffset2; 524 } 525 else if ((matchedArgumentFlags & (1 << argumentIndex)) == 0) 526 { 527 matchedArguments[argumentIndex] = offset + branchOffset1; 529 matchedArgumentFlags |= 1 << argumentIndex; 530 531 return true; 532 } 533 else 534 { 535 return matchedArguments[argumentIndex] == offset + branchOffset1; 537 } 538 } 539 540 541 private boolean matchingJumpOffsets(int offset, 542 int[] jumpOffsets1, 543 int[] jumpOffsets2) 544 { 545 if (jumpOffsets1.length != jumpOffsets2.length) 546 { 547 return false; 548 } 549 550 for (int index = 0; index < jumpOffsets1.length; index++) 551 { 552 if (!matchingBranchOffsets(offset, 553 jumpOffsets1[index], 554 jumpOffsets2[index])) 555 { 556 return false; 557 } 558 } 559 560 return true; 561 } 562 563 564 private void checkMatch(boolean condition, 565 Clazz clazz, 566 Method method, 567 CodeAttribute codeAttribute, 568 int offset, 569 Instruction instruction) 570 { 571 if (DEBUG_MORE) 572 { 573 System.out.println("InstructionSequenceMatcher: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]: "+patternInstructions[patternInstructionIndex].toString(patternInstructionIndex)+(condition?"\t== ":"\t ")+instruction.toString(offset)); 574 } 575 576 if (condition) 578 { 579 matchedInstructionOffsets[patternInstructionIndex] = offset; 581 582 patternInstructionIndex++; 584 585 matching = patternInstructionIndex == patternInstructions.length; 587 588 if (matching) 589 { 590 if (DEBUG) 591 { 592 System.out.println("InstructionSequenceMatcher: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]"); 593 for (int index = 0; index < patternInstructionIndex; index++) 594 { 595 System.out.println(" "+InstructionFactory.create(codeAttribute.code, matchedInstructionOffsets[index]).toString(matchedInstructionOffsets[index])); 596 } 597 } 598 599 reset(); 601 } 602 } 603 else 604 { 605 matching = false; 607 608 boolean retry = patternInstructionIndex == 1; 610 611 reset(); 613 614 if (retry) 616 { 617 instruction.accept(clazz, method, codeAttribute, offset, this); 618 } 619 } 620 } 621 } 622 | Popular Tags |