codeattributeeditor.java

来自「proguard 一个java的混淆器」· Java 代码 · 共 981 行 · 第 1/3 页

JAVA
981
字号
/* * ProGuard -- shrinking, optimization, obfuscation, and preverification *             of Java bytecode. * * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */package proguard.classfile.editor;import proguard.classfile.*;import proguard.classfile.attribute.*;import proguard.classfile.attribute.preverification.*;import proguard.classfile.attribute.preverification.visitor.*;import proguard.classfile.attribute.visitor.*;import proguard.classfile.instruction.*;import proguard.classfile.instruction.visitor.InstructionVisitor;import proguard.classfile.util.SimplifiedVisitor;/** * This AttributeVisitor accumulates specified changes to code, and then applies * these accumulated changes to the code attributes that it visits. * * @author Eric Lafortune */public class CodeAttributeEditorextends      SimplifiedVisitorimplements   AttributeVisitor,             InstructionVisitor,             ExceptionInfoVisitor,             StackMapFrameVisitor,             VerificationTypeVisitor,             LineNumberInfoVisitor,             LocalVariableInfoVisitor,             LocalVariableTypeInfoVisitor{    //*    private static final boolean DEBUG = false;    /*/    private static       boolean DEBUG = true;    //*/    private int     codeLength;    private boolean modified;    private boolean simple;    /*private*/public Instruction[]    preInsertions  = new Instruction[ClassConstants.TYPICAL_CODE_LENGTH];    /*private*/public Instruction[]    replacements   = new Instruction[ClassConstants.TYPICAL_CODE_LENGTH];    /*private*/public Instruction[]    postInsertions = new Instruction[ClassConstants.TYPICAL_CODE_LENGTH];    private boolean[]        deleted = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];    private int[]   instructionOffsetMap = new int[ClassConstants.TYPICAL_CODE_LENGTH];    private int     newOffset;    private boolean lengthIncreased;    private int expectedStackMapFrameOffset;    private final StackSizeUpdater    stackSizeUpdater    = new StackSizeUpdater();    private final VariableSizeUpdater variableSizeUpdater = new VariableSizeUpdater();    private final InstructionWriter   instructionWriter   = new InstructionWriter();    /**     * Resets the accumulated code changes.     * @param codeLength the length of the code that will be edited next.     */    public void reset(int codeLength)    {        this.codeLength = codeLength;        // Try to reuse the previous arrays.        if (preInsertions.length < codeLength)        {            preInsertions  = new Instruction[codeLength];            replacements   = new Instruction[codeLength];            postInsertions = new Instruction[codeLength];            deleted        = new boolean[codeLength];        }        else        {            for (int index = 0; index < codeLength; index++)            {                preInsertions[index]  = null;                replacements[index]   = null;                postInsertions[index] = null;                deleted[index]        = false;            }        }        modified = false;        simple   = true;    }    /**     * Remembers to place the given instruction right before the instruction     * at the given offset.     * @param instructionOffset the offset of the instruction.     * @param instruction       the new instruction.     */    public void insertBeforeInstruction(int instructionOffset, Instruction instruction)    {        if (DEBUG)        {            System.out.println("Inserting instruction before ["+instructionOffset+"]: "+instruction);        }        if (instructionOffset < 0 ||            instructionOffset >= codeLength)        {            throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");        }        preInsertions[instructionOffset] = instruction;        modified = true;        simple   = false;    }    /**     * Remembers to replace the instruction at the given offset by the given     * instruction.     * @param instructionOffset the offset of the instruction to be replaced.     * @param instruction       the new instruction.     */    public void replaceInstruction(int instructionOffset, Instruction instruction)    {        if (instructionOffset < 0 ||            instructionOffset >= codeLength)        {            throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");        }        replacements[instructionOffset] = instruction;        modified = true;    }    /**     * Remembers to place the given instruction right after the instruction     * at the given offset.     * @param instructionOffset the offset of the instruction.     * @param instruction       the new instruction.     */    public void insertAfterInstruction(int instructionOffset, Instruction instruction)    {        if (instructionOffset < 0 ||            instructionOffset >= codeLength)        {            throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");        }        postInsertions[instructionOffset] = instruction;        modified = true;        simple   = false;    }    /**     * Remembers to delete the instruction at the given offset.     * @param instructionOffset the offset of the instruction to be deleted.     */    public void deleteInstruction(int instructionOffset)    {        if (instructionOffset < 0 ||            instructionOffset >= codeLength)        {            throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");        }        deleted[instructionOffset] = true;        modified = true;        simple   = false;    }    /**     * Remembers not to delete the instruction at the given offset.     * @param instructionOffset the offset of the instruction not to be deleted.     */    public void undeleteInstruction(int instructionOffset)    {        if (instructionOffset < 0 ||            instructionOffset >= codeLength)        {            throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");        }        deleted[instructionOffset] = false;    }    /**     * Returns whether the instruction at the given offset has been modified     * in any way.     */    public boolean isModified(int instructionOffset)    {        return preInsertions[instructionOffset]  != null ||               replacements[instructionOffset]   != null ||               postInsertions[instructionOffset] != null ||               deleted[instructionOffset];    }    // Implementations for AttributeVisitor.    public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}    public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)    {//        DEBUG =//            clazz.getName().equals("abc/Def") &&//            method.getName(clazz).equals("abc");        // TODO: Remove this when the code has stabilized.        // Catch any unexpected exceptions from the actual visiting method.        try        {            // Process the code.            visitCodeAttribute0(clazz, method, codeAttribute);        }        catch (RuntimeException ex)        {            System.err.println("Unexpected error while editing code:");            System.err.println("  Class       = ["+clazz.getName()+"]");            System.err.println("  Method      = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]");            System.err.println("  Exception   = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")");            throw ex;        }    }    public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute)    {        if (DEBUG)        {            System.out.println("CodeAttributeEditor: ["+clazz.getName()+"."+method.getName(clazz)+"]");        }        // Avoid doing any work if nothing is changing anyway.        if (!modified)        {            return;        }        // Check if we can perform a faster simple replacement of instructions.        if (canPerformSimpleReplacements(codeAttribute))        {            // Simply overwrite the instructions.            performSimpleReplacements(codeAttribute);            // Update the maximum stack size and local variable frame size.            stackSizeUpdater.visitCodeAttribute(clazz, method, codeAttribute);            variableSizeUpdater.visitCodeAttribute(clazz, method, codeAttribute);        }        else        {            // Move and remap the instructions.            codeAttribute.u4codeLength =                updateInstructions(clazz, method, codeAttribute);            // Remap the exception table.            codeAttribute.exceptionsAccept(clazz, method, this);            // Remove exceptions with empty code blocks.            codeAttribute.u2exceptionTableLength =                removeEmptyExceptions(codeAttribute.exceptionTable,                                      codeAttribute.u2exceptionTableLength);            // Update the maximum stack size and local variable frame size.            stackSizeUpdater.visitCodeAttribute(clazz, method, codeAttribute);            variableSizeUpdater.visitCodeAttribute(clazz, method, codeAttribute);            // Remap the line number table and the local variable table.            codeAttribute.attributesAccept(clazz, method, this);            // Make sure instructions are widened if necessary.            instructionWriter.visitCodeAttribute(clazz, method, codeAttribute);        }    }    public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute)    {        // Remap all stack map entries.        expectedStackMapFrameOffset = -1;        stackMapAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this);    }    public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute)    {        // Remap all stack map table entries.        expectedStackMapFrameOffset = 0;        stackMapTableAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this);    }    public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute)    {        // Remap all line number table entries.        lineNumberTableAttribute.lineNumbersAccept(clazz, method, codeAttribute, this);        // Remove line numbers with empty code blocks.        lineNumberTableAttribute.u2lineNumberTableLength =

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?