Beispiel #1
0
 public static boolean isReturnBlocks(BlockNode b1, BlockNode b2) {
   if (!b1.isReturnBlock() || !b2.isReturnBlock()) {
     return false;
   }
   List<InsnNode> b1Insns = b1.getInstructions();
   List<InsnNode> b2Insns = b2.getInstructions();
   if (b1Insns.size() != 1 || b2Insns.size() != 1) {
     return false;
   }
   InsnNode i1 = b1Insns.get(0);
   InsnNode i2 = b2Insns.get(0);
   if (i1.getArgsCount() != i2.getArgsCount()) {
     return false;
   }
   return i1.getArgsCount() == 0 || i1.getArg(0).equals(i2.getArg(0));
 }
Beispiel #2
0
 private static void renameVar(MethodNode mth, SSAVar[] vars, int[] vers, BlockNode block) {
   SSAVar[] inputVars = Arrays.copyOf(vars, vars.length);
   for (InsnNode insn : block.getInstructions()) {
     if (insn.getType() != InsnType.PHI) {
       for (InsnArg arg : insn.getArguments()) {
         if (!arg.isRegister()) {
           continue;
         }
         RegisterArg reg = (RegisterArg) arg;
         int regNum = reg.getRegNum();
         SSAVar var = vars[regNum];
         if (var == null) {
           throw new JadxRuntimeException(
               "Not initialized variable reg: "
                   + regNum
                   + ", insn: "
                   + insn
                   + ", block:"
                   + block
                   + ", method: "
                   + mth);
         }
         var.use(reg);
       }
     }
     RegisterArg result = insn.getResult();
     if (result != null) {
       int regNum = result.getRegNum();
       vars[regNum] = mth.makeNewSVar(regNum, vers, result);
     }
   }
   for (BlockNode s : block.getSuccessors()) {
     PhiListAttr phiList = s.get(AType.PHI_LIST);
     if (phiList == null) {
       continue;
     }
     int j = s.getPredecessors().indexOf(block);
     if (j == -1) {
       throw new JadxRuntimeException("Can't find predecessor for " + block + " " + s);
     }
     for (PhiInsn phiInsn : phiList.getList()) {
       if (j >= phiInsn.getArgsCount()) {
         continue;
       }
       int regNum = phiInsn.getResult().getRegNum();
       SSAVar var = vars[regNum];
       if (var == null) {
         continue;
       }
       var.use(phiInsn.getArg(j));
       var.setUsedInPhi(phiInsn);
     }
   }
   for (BlockNode domOn : block.getDominatesOn()) {
     renameVar(mth, vars, vers, domOn);
   }
   System.arraycopy(inputVars, 0, vars, 0, vars.length);
 }
Beispiel #3
0
 private static void addPhi(BlockNode block, int regNum) {
   PhiListAttr phiList = block.get(AType.PHI_LIST);
   if (phiList == null) {
     phiList = new PhiListAttr();
     block.addAttr(phiList);
   }
   PhiInsn phiInsn = new PhiInsn(regNum, block.getPredecessors().size());
   phiList.getList().add(phiInsn);
   phiInsn.setOffset(block.getStartOffset());
   block.getInstructions().add(0, phiInsn);
 }
Beispiel #4
0
  /** Recursively traverse all blocks from 'block' until block from 'exits' */
  private BlockNode traverse(IRegion r, BlockNode block, RegionStack stack) {
    BlockNode next = null;
    boolean processed = false;

    List<LoopInfo> loops = block.getAll(AType.LOOP);
    int loopCount = loops.size();
    if (loopCount != 0 && block.contains(AFlag.LOOP_START)) {
      if (loopCount == 1) {
        next = processLoop(r, loops.get(0), stack);
        processed = true;
      } else {
        for (LoopInfo loop : loops) {
          if (loop.getStart() == block) {
            next = processLoop(r, loop, stack);
            processed = true;
            break;
          }
        }
      }
    }

    if (!processed && block.getInstructions().size() == 1) {
      InsnNode insn = block.getInstructions().get(0);
      switch (insn.getType()) {
        case IF:
          next = processIf(r, block, (IfNode) insn, stack);
          processed = true;
          break;

        case SWITCH:
          next = processSwitch(r, block, (SwitchNode) insn, stack);
          processed = true;
          break;

        case MONITOR_ENTER:
          next = processMonitorEnter(r, block, insn, stack);
          processed = true;
          break;

        default:
          break;
      }
    }
    if (!processed) {
      r.getSubBlocks().add(block);
      next = getNextBlock(block);
    }
    if (next != null && !stack.containsExit(block) && !stack.containsExit(next)) {
      return next;
    }
    return null;
  }
Beispiel #5
0
 /** Select loop exit and construct LoopRegion */
 private LoopRegion makeLoopRegion(IRegion curRegion, LoopInfo loop, List<BlockNode> exitBlocks) {
   for (BlockNode block : exitBlocks) {
     if (block.contains(AType.EXC_HANDLER)
         || block.getInstructions().size() != 1
         || block.getInstructions().get(0).getType() != InsnType.IF) {
       continue;
     }
     List<LoopInfo> loops = block.getAll(AType.LOOP);
     if (!loops.isEmpty() && loops.get(0) != loop) {
       // skip nested loop condition
       continue;
     }
     LoopRegion loopRegion = new LoopRegion(curRegion, loop, block, block == loop.getEnd());
     boolean found;
     if (block == loop.getStart()
         || block == loop.getEnd()
         || BlockUtils.isEmptySimplePath(loop.getStart(), block)) {
       found = true;
     } else if (block.getPredecessors().contains(loop.getStart())) {
       loopRegion.setPreCondition(loop.getStart());
       // if we can't merge pre-condition this is not correct header
       found = loopRegion.checkPreCondition();
     } else {
       found = false;
     }
     if (found) {
       List<LoopInfo> list = mth.getAllLoopsForBlock(block);
       if (list.size() >= 2) {
         // bad condition if successors going out of all loops
         boolean allOuter = true;
         for (BlockNode outerBlock : block.getCleanSuccessors()) {
           List<LoopInfo> outLoopList = mth.getAllLoopsForBlock(outerBlock);
           outLoopList.remove(loop);
           if (!outLoopList.isEmpty()) {
             // goes to outer loop
             allOuter = false;
             break;
           }
         }
         if (allOuter) {
           found = false;
         }
       }
     }
     if (found) {
       return loopRegion;
     }
   }
   // no exit found => endless loop
   return null;
 }
Beispiel #6
0
 private static void insertContinue(LoopInfo loop) {
   BlockNode loopEnd = loop.getEnd();
   List<BlockNode> predecessors = loopEnd.getPredecessors();
   if (predecessors.size() <= 1) {
     return;
   }
   Set<BlockNode> loopExitNodes = loop.getExitNodes();
   for (BlockNode pred : predecessors) {
     if (canInsertContinue(pred, predecessors, loopEnd, loopExitNodes)) {
       InsnNode cont = new InsnNode(InsnType.CONTINUE, 0);
       pred.getInstructions().add(cont);
     }
   }
 }
Beispiel #7
0
 private static void insertContinueInSwitch(BlockNode block, BlockNode out, BlockNode end) {
   int endId = end.getId();
   for (BlockNode s : block.getCleanSuccessors()) {
     if (s.getDomFrontier().get(endId) && s != out) {
       // search predecessor of loop end on path from this successor
       List<BlockNode> list = BlockUtils.collectBlocksDominatedBy(s, s);
       for (BlockNode p : end.getPredecessors()) {
         if (list.contains(p)) {
           if (p.isSynthetic()) {
             p.getInstructions().add(new InsnNode(InsnType.CONTINUE, 0));
           }
           break;
         }
       }
     }
   }
 }
Beispiel #8
0
 private boolean insertBreak(RegionStack stack, BlockNode loopExit, Edge exitEdge) {
   BlockNode exit = exitEdge.getTarget();
   BlockNode insertBlock = null;
   boolean confirm = false;
   // process special cases
   if (loopExit == exit) {
     // try/catch at loop end
     BlockNode source = exitEdge.getSource();
     if (source.contains(AType.CATCH_BLOCK) && source.getSuccessors().size() == 2) {
       BlockNode other = BlockUtils.selectOther(loopExit, source.getSuccessors());
       if (other != null) {
         other = BlockUtils.skipSyntheticSuccessor(other);
         if (other.contains(AType.EXC_HANDLER)) {
           insertBlock = source;
           confirm = true;
         }
       }
     }
   }
   if (!confirm) {
     while (exit != null) {
       if (insertBlock != null && isPathExists(loopExit, exit)) {
         // found cross
         if (canInsertBreak(insertBlock)) {
           confirm = true;
           break;
         }
         return false;
       }
       insertBlock = exit;
       List<BlockNode> cs = exit.getCleanSuccessors();
       exit = cs.size() == 1 ? cs.get(0) : null;
     }
   }
   if (!confirm) {
     return false;
   }
   InsnNode breakInsn = new InsnNode(InsnType.BREAK, 0);
   insertBlock.getInstructions().add(breakInsn);
   stack.addExit(exit);
   // add label to 'break' if needed
   addBreakLabel(exitEdge, exit, breakInsn);
   return true;
 }
Beispiel #9
0
 /** Traverse from monitor-enter thru successors and collect blocks contains monitor-exit */
 private static void traverseMonitorExits(
     SynchronizedRegion region,
     InsnArg arg,
     BlockNode block,
     Set<BlockNode> exits,
     Set<BlockNode> visited) {
   visited.add(block);
   for (InsnNode insn : block.getInstructions()) {
     if (insn.getType() == InsnType.MONITOR_EXIT && insn.getArg(0).equals(arg)) {
       exits.add(block);
       region.getExitInsns().add(insn);
       return;
     }
   }
   for (BlockNode node : block.getSuccessors()) {
     if (!visited.contains(node)) {
       traverseMonitorExits(region, arg, node, exits, visited);
     }
   }
 }
Beispiel #10
0
  private BlockNode processLoop(IRegion curRegion, LoopInfo loop, RegionStack stack) {
    BlockNode loopStart = loop.getStart();
    Set<BlockNode> exitBlocksSet = loop.getExitNodes();

    // set exit blocks scan order priority
    // this can help if loop have several exits (after using 'break' or 'return' in loop)
    List<BlockNode> exitBlocks = new ArrayList<BlockNode>(exitBlocksSet.size());
    BlockNode nextStart = getNextBlock(loopStart);
    if (nextStart != null && exitBlocksSet.remove(nextStart)) {
      exitBlocks.add(nextStart);
    }
    if (exitBlocksSet.remove(loopStart)) {
      exitBlocks.add(loopStart);
    }
    if (exitBlocksSet.remove(loop.getEnd())) {
      exitBlocks.add(loop.getEnd());
    }
    exitBlocks.addAll(exitBlocksSet);

    LoopRegion loopRegion = makeLoopRegion(curRegion, loop, exitBlocks);
    if (loopRegion == null) {
      BlockNode exit = makeEndlessLoop(curRegion, stack, loop, loopStart);
      insertContinue(loop);
      return exit;
    }
    curRegion.getSubBlocks().add(loopRegion);
    IRegion outerRegion = stack.peekRegion();
    stack.push(loopRegion);

    IfInfo condInfo = makeIfInfo(loopRegion.getHeader());
    condInfo = searchNestedIf(condInfo);
    confirmMerge(condInfo);
    if (!loop.getLoopBlocks().contains(condInfo.getThenBlock())) {
      // invert loop condition if 'then' points to exit
      condInfo = IfInfo.invert(condInfo);
    }
    loopRegion.setCondition(condInfo.getCondition());
    exitBlocks.removeAll(condInfo.getMergedBlocks());

    if (!exitBlocks.isEmpty()) {
      BlockNode loopExit = condInfo.getElseBlock();
      if (loopExit != null) {
        // add 'break' instruction before path cross between main loop exit and sub-exit
        for (Edge exitEdge : loop.getExitEdges()) {
          if (!exitBlocks.contains(exitEdge.getSource())) {
            continue;
          }
          insertBreak(stack, loopExit, exitEdge);
        }
      }
    }

    BlockNode out;
    if (loopRegion.isConditionAtEnd()) {
      BlockNode thenBlock = condInfo.getThenBlock();
      out = thenBlock == loopStart ? condInfo.getElseBlock() : thenBlock;
      loopStart.remove(AType.LOOP);
      loop.getEnd().add(AFlag.SKIP);
      stack.addExit(loop.getEnd());
      loopRegion.setBody(makeRegion(loopStart, stack));
      loopStart.addAttr(AType.LOOP, loop);
      loop.getEnd().remove(AFlag.SKIP);
    } else {
      out = condInfo.getElseBlock();
      if (outerRegion != null
          && out.contains(AFlag.LOOP_START)
          && !out.getAll(AType.LOOP).contains(loop)
          && RegionUtils.isRegionContainsBlock(outerRegion, out)) {
        // exit to already processed outer loop
        out = null;
      }
      stack.addExit(out);
      BlockNode loopBody = condInfo.getThenBlock();
      Region body = makeRegion(loopBody, stack);
      // add blocks from loop start to first condition block
      BlockNode conditionBlock = condInfo.getIfBlock();
      if (loopStart != conditionBlock) {
        Set<BlockNode> blocks = BlockUtils.getAllPathsBlocks(loopStart, conditionBlock);
        blocks.remove(conditionBlock);
        for (BlockNode block : blocks) {
          if (block.getInstructions().isEmpty()
              && !block.contains(AFlag.SKIP)
              && !RegionUtils.isRegionContainsBlock(body, block)) {
            body.add(block);
          }
        }
      }
      loopRegion.setBody(body);
    }
    stack.pop();
    insertContinue(loop);
    return out;
  }