/** * Creates the new instructions, inlining each instantiation of each * subroutine until the code is fully elaborated. */ private void emitCode() { LinkedList<Instantiation> worklist = new LinkedList<Instantiation>(); // Create an instantiation of the "root" subroutine, which is just the // main routine worklist.add(new Instantiation(null, mainSubroutine)); // Emit instantiations of each subroutine we encounter, including the // main subroutine InsnList newInstructions = new InsnList(); List<TryCatchBlockNode> newTryCatchBlocks = new ArrayList<TryCatchBlockNode>(); List<LocalVariableNode> newLocalVariables = new ArrayList<LocalVariableNode>(); while (!worklist.isEmpty()) { Instantiation inst = worklist.removeFirst(); emitSubroutine(inst, worklist, newInstructions, newTryCatchBlocks, newLocalVariables); } instructions = newInstructions; tryCatchBlocks = newTryCatchBlocks; localVariables = newLocalVariables; }
private static BitSet getEntryPoints(MethodNode asmNode, Map<AbstractInsnNode, int[]> exitPoints) { InsnList il = asmNode.instructions; BitSet entryPoints = new BitSet(il.size()); for (int[] eps : exitPoints.values()) { if (eps != null) { for (int ep : eps) entryPoints.set(ep); } } for (TryCatchBlockNode n : asmNode.tryCatchBlocks) { entryPoints.set(il.indexOf(n.handler)); } return entryPoints; }
@Override public void visitEnd() { // Compares TryCatchBlockNodes by the length of their "try" block. Comparator<TryCatchBlockNode> comp = new Comparator<TryCatchBlockNode>() { public int compare(TryCatchBlockNode t1, TryCatchBlockNode t2) { int len1 = blockLength(t1); int len2 = blockLength(t2); return len1 - len2; } private int blockLength(TryCatchBlockNode block) { int startidx = instructions.indexOf(block.start); int endidx = instructions.indexOf(block.end); return endidx - startidx; } }; Collections.sort(tryCatchBlocks, comp); // Updates the 'target' of each try catch block annotation. for (int i = 0; i < tryCatchBlocks.size(); ++i) { tryCatchBlocks.get(i).updateIndex(i); } if (mv != null) { accept(mv); } }
@SuppressWarnings(UNCHECKED) private void filterCatchVariables() { // on supprime les variables des blocs catchs (comme eclipse, etc...), // avant de supprimer les doublons car les blocs catchs provoquent parfois des variables de même index for (final TryCatchBlockNode tryCatchBlock : (List<TryCatchBlockNode>) methodNode.tryCatchBlocks) { // TODO est-ce qu'il y a un meilleur moyen d'identifier la variable de l'exception autrement que par son type ? final String type = tryCatchBlock.type; // type est null si finally if (type != null) { for (final Iterator<LocalVariableNode> it = localVariables.iterator(); it .hasNext();) { final LocalVariableNode localVariable = it.next(); final Type typeLocalVariable = Type.getType(localVariable.desc); if (typeLocalVariable.getSort() == Type.OBJECT && type.equals(typeLocalVariable.getInternalName())) { it.remove(); break; } } } } }
/** Adds an exception try block node to this graph */ protected void exception(@NonNull AbstractInsnNode from, @NonNull TryCatchBlockNode tcb) { // Add tcb's to all instructions in the range LabelNode start = tcb.start; LabelNode end = tcb.end; // exclusive // Add exception edges for all method calls in the range AbstractInsnNode curr = start; Node handlerNode = getNode(tcb.handler); while (curr != end && curr != null) { if (curr.getType() == AbstractInsnNode.METHOD_INSN) { // Method call; add exception edge to handler if (tcb.type == null) { // finally block: not an exception path getNode(curr).addSuccessor(handlerNode); } getNode(curr).addExceptionPath(handlerNode); } curr = curr.getNext(); } }
/** * Creates a new instance and initializes the manager * @param tryCatchBlocks list of {@link TryCatchBlockNode}s * @param stack expression stack, used for creation of label ids * @return initialized TryCatchManager */ public static TryCatchManager newInstance(List tryCatchBlocks, ExpressionStack stack) { TryCatchManager manager = new TryCatchManager(); List<Item> tryCatchItems = new ArrayList<>(); List<Item> catchBlockHandlers = new ArrayList<>(); if (tryCatchBlocks != null) { for (Object block : tryCatchBlocks) { TryCatchBlockNode node = (TryCatchBlockNode) block; Item item = new Item(stack.getLabelId(node.start.getLabel()), stack.getLabelId(node.end.getLabel()), stack.getLabelId(node.handler.getLabel()), node.type); addNewItemToList(tryCatchItems, catchBlockHandlers, item); } } manager.setItems(tryCatchItems); manager.setCatchBlockHandlers(catchBlockHandlers); return manager; }
private void addCatchBlock(LabelNode startNode, LabelNode endNode) { InsnList il = new InsnList(); LabelNode handlerNode = new LabelNode(); il.add(handlerNode); int exceptionVariablePosition = getFistAvailablePosition(); il.add(new VarInsnNode(Opcodes.ASTORE, exceptionVariablePosition)); this.methodOffset++; // Actualizamos el offset addGetCallback(il); il.add(new VarInsnNode(Opcodes.ALOAD, this.methodVarIndex)); il.add(new VarInsnNode(Opcodes.ALOAD, exceptionVariablePosition)); il.add(new VarInsnNode(Opcodes.ALOAD, this.executionIdIndex)); il.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "org/brutusin/instrumentation/Callback", "onThrowableUncatched", "(Ljava/lang/Object;Ljava/lang/Throwable;Ljava/lang/String;)V", false)); il.add(new VarInsnNode(Opcodes.ALOAD, exceptionVariablePosition)); il.add(new InsnNode(Opcodes.ATHROW)); TryCatchBlockNode blockNode = new TryCatchBlockNode(startNode, endNode, handlerNode, null); this.mn.tryCatchBlocks.add(blockNode); this.mn.instructions.add(il); }
@Override public void visitEnd() { // Compares TryCatchBlockNodes by the length of their "try" block. Comparator<TryCatchBlockNode> comp = new Comparator<TryCatchBlockNode>() { public int compare(TryCatchBlockNode t1, TryCatchBlockNode t2) { int len1 = blockLength(t1); int len2 = blockLength(t2); return len1 - len2; } private int blockLength(TryCatchBlockNode block) { int startidx = instructions.indexOf(block.start); int endidx = instructions.indexOf(block.end); return endidx - startidx; } }; Collections.sort(tryCatchBlocks, comp); if (mv != null) { accept(mv); } }
/** * Determines if the code contains handler that handles exception and * doesn't propagate some exception further. * * This has to be detected because it can cause stack inconsistency that has * to be handled in the weaver. */ private boolean containsHandledException(InsnList instructions, List<TryCatchBlockNode> tryCatchBlocks) { if (tryCatchBlocks.size() == 0) { return false; } // create control flow graph CtrlFlowGraph cfg = new CtrlFlowGraph(instructions, tryCatchBlocks); cfg.visit(instructions.getFirst()); // check if the control flow continues after exception handler // if it does, exception was handled for (int i = tryCatchBlocks.size() - 1; i >= 0; --i) { TryCatchBlockNode tcb = tryCatchBlocks.get(i); if (cfg.visit(tcb.handler).size() != 0) { return true; } } return false; }
/** * Constructs the Code structure. */ public Code(InsnList instructions, List<TryCatchBlockNode> tryCatchBlocks, Set<SyntheticLocalVar> referencedSLVs, Set<ThreadLocalVar> referencedTLVs, Set<StaticContextMethod> staticContexts, boolean usesDynamicContext, boolean usesClassContext, boolean containsHandledException) { super(); this.instructions = instructions; this.tryCatchBlocks = tryCatchBlocks; this.referencedSLVs = referencedSLVs; this.referencedTLVs = referencedTLVs; this.staticContexts = staticContexts; this.usesDynamicContext = usesDynamicContext; this.usesClassContext = usesClassContext; this.containsHandledException = containsHandledException; }
public void visitEnd() { // Compares TryCatchBlockNodes by the length of their "try" block. Comparator<TryCatchBlockNode> comp = new Comparator<TryCatchBlockNode>() { public int compare(TryCatchBlockNode t1, TryCatchBlockNode t2) { int len1 = blockLength(t1); int len2 = blockLength(t2); return len1 - len2; } private int blockLength(TryCatchBlockNode block) { int startidx = instructions.indexOf(Insns.FORWARD.firstRealInsn (block.start)); int endidx = instructions.indexOf(block.end); return endidx - startidx; } }; Collections.sort(tryCatchBlocks, comp); }
private boolean removeUnusedHandler() { CtrlFlowGraph cfg = CtrlFlowGraph.build(method); boolean isOptimized = false; for (final TryCatchBlockNode tcb : method.tryCatchBlocks) { // TCB start is inclusive, TCB end is exclusive. final AbstractInsnNode first = Insns.FORWARD.firstRealInsn (tcb.start); final AbstractInsnNode last = Insns.REVERSE.nextRealInsn (tcb.end); if (first == last) { method.tryCatchBlocks.remove(tcb); isOptimized |= removeUnusedBB(cfg); } } return isOptimized; }
public static int getMaxStack(InsnList ilist, List<TryCatchBlockNode> tryCatchBlocks) { CtrlFlowGraph cfg = CtrlFlowGraph.build(ilist, tryCatchBlocks); List<BasicBlock> unvisited = cfg.getNodes(); int maxStack = getMaxStack(0, cfg.getBB(ilist.getFirst()), unvisited); for (TryCatchBlockNode tcb : tryCatchBlocks) { maxStack = Math .max(getMaxStack(1, cfg.getBB(tcb.handler), unvisited), maxStack); } return maxStack; }
public ProcCode(InsnList instructions, List<TryCatchBlockNode> tryCatchBlocks, Set<SyntheticLocalVar> referencedSLV, Set<ThreadLocalVar> referencedTLV, boolean containsHandledException, Set<StaticContextMethod> staticContexts, boolean usesDynamicContext, boolean usesClassContext, boolean usesArgumentContext ) { super(instructions, tryCatchBlocks, referencedSLV, referencedTLV, staticContexts, usesDynamicContext, usesClassContext, containsHandledException); this.usesArgumentContext = usesArgumentContext; }
@Override public List<MarkedRegion> markWithDefaultWeavingReg(MethodNode method) { List<MarkedRegion> regions = new LinkedList<MarkedRegion>(); for (TryCatchBlockNode tcb : method.tryCatchBlocks) { AbstractInsnNode start = Insns.FORWARD.firstRealInsn (tcb.start); // RFC LB: Consider nextRealInsn, since TCB end is exclusive // This depends on the semantics of marked region AbstractInsnNode end = Insns.REVERSE.firstRealInsn (tcb.end); regions.add(new MarkedRegion(start, end)); } return regions; }
public SnippetCode(InsnList instructions, List<TryCatchBlockNode> tryCatchBlocks, Set<SyntheticLocalVar> referencedSLV, Set<ThreadLocalVar> referencedTLV, boolean containsHandledException, Set<StaticContextMethod> staticContexts, boolean usesDynamicContext, boolean usesClassContext, boolean usesProcessorContext, Map<Integer, ProcInvocation> invokedProcessors ) { super(instructions, tryCatchBlocks, referencedSLV, referencedTLV, staticContexts, usesDynamicContext, usesClassContext, containsHandledException); this.invokedProcessors = invokedProcessors; this.usesProcessorContext = usesProcessorContext; }
private static List <TryCatchBlockNode> __cloneTryCatchBlocks ( final List <TryCatchBlockNode> tryCatchBlocks, final Map <LabelNode, LabelNode> replacementLabels ) { final List <TryCatchBlockNode> result = new LinkedList <TryCatchBlockNode> (); for (final TryCatchBlockNode tcb : tryCatchBlocks) { final TryCatchBlockNode tcbClone = new TryCatchBlockNode ( replacementLabels.get (tcb.start), replacementLabels.get (tcb.end), replacementLabels.get (tcb.handler), tcb.type ); result.add (tcbClone); } return result; }
public void sort() { if (this.methodNode.tryCatchBlocks == null) { return; } Collections.sort(this.methodNode.tryCatchBlocks, new Comparator<TryCatchBlockNode>() { @Override public int compare(TryCatchBlockNode o1, TryCatchBlockNode o2) { return blockLength(o1) - blockLength(o2); } private int blockLength(TryCatchBlockNode block) { final int startidx = methodNode.instructions.indexOf(block.start); final int endidx = methodNode.instructions.indexOf(block.end); return endidx - startidx; } }); // Updates the 'target' of each try catch block annotation. for (int i = 0; i < this.methodNode.tryCatchBlocks.size(); i++) { this.methodNode.tryCatchBlocks.get(i).updateIndex(i); } }
public static void printMethod(PrintStream out, MethodNode method) { final Textifier textifier = new Textifier(); final TraceMethodVisitor mv = new TraceMethodVisitor(textifier); out.println(method.name + method.desc); for (int j = 0; j < method.instructions.size(); ++j) { method.instructions.get(j).accept(mv); final StringBuffer s = new StringBuffer(); while (s.length() < method.maxStack + method.maxLocals + 1) { s.append(' '); } out.print(Integer.toString(j + 100000).substring(1)); out.print(" " + s + " : " + textifier.text.get(j)); } for (int j = 0; j < method.tryCatchBlocks.size(); ++j) { ((TryCatchBlockNode) method.tryCatchBlocks.get(j)).accept(mv); out.print(" " + textifier.text.get(method.instructions.size()+j)); } out.println(" MAXSTACK " + method.maxStack); out.println(" MAXLOCALS " + method.maxLocals); out.println(); }
private List<TryCatchBlock> getPotentialTryHandlers(int offset) { List<TryCatchBlock> handlers = new ArrayList<>(); for (int i = 0; i < node.tryCatchBlocks.size(); i++) { TryCatchBlockNode tryBlock = (TryCatchBlockNode) node.tryCatchBlocks.get(i); if (tryBlockRelevant(tryBlock, offset)) { handlers.add(new TryCatchBlock(tryBlock, this)); } } return handlers; }
@SuppressWarnings("unchecked") private void splitTryCatch(FrameInfo fi) { for(int i=0 ; i<mn.tryCatchBlocks.size() ; i++) { TryCatchBlockNode tcb = (TryCatchBlockNode)mn.tryCatchBlocks.get(i); int start = getLabelIdx(tcb.start); int end = getLabelIdx(tcb.end); if(start <= fi.endInstruction && end >= fi.endInstruction) { //System.out.println("i="+i+" start="+start+" end="+end+" split="+splitIdx+ // " start="+mn.instructions.get(start)+" end="+mn.instructions.get(end)); // need to split try/catch around the suspendable call if(start == fi.endInstruction) { tcb.start = fi.createAfterLabel(); } else { if(end > fi.endInstruction) { TryCatchBlockNode tcb2 = new TryCatchBlockNode( fi.createAfterLabel(), tcb.end, tcb.handler, tcb.type); mn.tryCatchBlocks.add(i+1, tcb2); } tcb.end = fi.createBeforeLabel(); } } } }
private boolean doesTrapCatch(TryCatchBlockNode node, String... exceptions) { if (node.type == null) { return true; } if (node.type.equals("java/lang/Throwable")) { return true; } for (String exception : exceptions) { if (getDeobfuscator().isSubclass(node.type, exception)) { return true; } } return false; }
AsmMethodSource(int maxLocals, InsnList insns, List<LocalVariableNode> localVars, List<TryCatchBlockNode> tryCatchBlocks) { this.maxLocals = maxLocals; this.instructions = insns; this.localVars = localVars; this.tryCatchBlocks = tryCatchBlocks; }
@Override public void run() { if(mn.name.startsWith("<") && mn.name.endsWith(">")) // There are error if we are trying to add that try/catch in static return; ListIterator<AbstractInsnNode> iterator = mn.instructions.iterator(); AbstractInsnNode next; while(iterator.hasNext()) { next = iterator.next(); if(next.getOpcode() != GOTO && (next instanceof MethodInsnNode)) { tryStart = new LabelNode(); tryFinalStart = new LabelNode(); tryCatchStart = new LabelNode(); tryCatchEnd = new LabelNode(); iterator.previous(); iterator.add(tryStart); // Auto iterator.next() iterator.next(); iterator.add(tryFinalStart); { iterator.add ( new JumpInsnNode ( GOTO, tryCatchEnd ) ); } iterator.add(tryCatchStart); iterator.add ( new InsnNode ( ATHROW ) ); iterator.add(tryCatchEnd); mn.tryCatchBlocks.add(new TryCatchBlockNode(tryStart, tryFinalStart, tryCatchStart, "java/lang/Exception")); } } }