2013-09-20 6 views
3

Я пытаюсь поймать исключение во время выполнения через исключение. Я могу захватить обычный метод выхода из событий. Но контроль никогда не достигает opcode==Opcodes.ATHROW.Как уловить исключение во время выполнения в байткоде через ASM

Я думаю, что я делаю что-то неправильно при вызове событий.

Вот мой пример кода:

public void visitCode() { 
//   mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 
//   mv.visitLdcInsn("Entering method " + fQMethodName); 
//   mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream","println","(Ljava/lang/String;)V"); 
      } 


    @Override 
    public void visitInsn(int opcode) 
    { 



     if (opcode == Opcodes.ATHROW) 
     { 
          mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "err", "Ljava/io/PrintStream;"); 

      mv.visitLdcInsn("Exiting on exception ");   
      mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", 
        "(Ljava/lang/String;)V"); 
     } 


     super.visitInsn(opcode); 
    } 


     public void visitMethodInsn(int opcode, String owner, String name, 
        String desc) { 


        super.visitMethodInsn(opcode, owner, name, desc); 
        //     
        if (opcode == Opcodes.ATHROW) 
        { 
               mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "err", "Ljava/io/PrintStream;"); 

        mv.visitLdcInsn("Exiting on exception " + name);   
         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", 
          "(Ljava/lang/String;)V"); 
        } 
        else if (!name.equals("println") 
        && !name.equals("<init>") 
        && (opcode == Opcodes.INVOKEVIRTUAL || opcode == Opcodes.INVOKESPECIAL 
         || opcode == Opcodes.INVOKESTATIC || opcode == Opcodes.INVOKEDYNAMIC)) { 




         this.currentMethod = name; 

        onFinally(opcode); 
        } 
       } 

       private void onFinally(int opcode) { 
              mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "err", 
        "Ljava/io/PrintStream;"); 
        mv.visitLdcInsn("Returning to " + fQMethodName + " from " + currentMethod); 
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", 
        "(Ljava/lang/String;)V"); 
       } 

В то время исключения времени выполнения, существующий контент стек очищается, и только Throwable объект остается. Могу ли я получить элемент верхнего стека (например, в стеке) через ASM?

Спасибо в adavance.

EDIT:

Вот моя измененная программа после добавления попытки - поймать блок.

@ Хольгер: Благодарим за помощь. Действительно ценю это.

Итак, я пытаюсь вставить динамический блок try-catch в MethodVisitor ASM.

Вот мой код:

public void visitCode() 
    { 

     super.visitCode(); 

     this.visitTryCatchBlock(lblTryBlockStart, lblTryBlockEnd, lblCatchExceptionBlockStart, "java/lang/Exception"); 
     this.visitLabel(lblTryBlockStart); 

    } 



    public void visitMaxs(int maxStack, int maxLocals) 
    { 
     // visit try block end label 
     this.visitLabel(lblTryBlockEnd); 
     // visit normal execution exit block 
     this.visitJumpInsn(Opcodes.GOTO, exitBlock); 

     // visit catch exception block 
     this.visitLabel(lblCatchExceptionBlockStart); 
     // store the exception 
     this.visitVarInsn(Opcodes.ASTORE, 1); 
     // load the exception 
     this.visitVarInsn(Opcodes.ALOAD, 1); 
     // call printStackTrace() 
     //this.visitInsn(Opcodes.ATHROW); 
     this.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Exception", "printStackTrace", "()V"); 


     // exit from this dynamic block 
     this.visitLabel(exitBlock); 

     super.visitMaxs(maxStack+2, maxLocals+2); 

    } 

Мое намерение добавить динамическую попробовать - поймать блок, и если исключение, распечатать его.

+0

Вы знаете, где выдается фактическое исключение RuntimeException? Если он вызывается самой JRE, это не сработает с тех пор (я предполагаю), что вы не трансформируете классы в пакет java (чего вы не должны делать в любом случае). – Emiel

+0

Ваше последнее обновление работает? Я тоже хотел добавить try catch block в метод. Пожалуйста ответьте. – AKS

ответ

3

RuntimeException s не нужно вводить инструкцию athrow. Инструкция idiv или irem может выдать ArithmeticException, a getfield, putfield или invoke… инструкция может бросить NullPointerException, просто чтобы назвать некоторые примеры. Таким образом, вы не найдете инструктор в этих местах.

Единственный способ перехватить все из них - это ввести обработчик исключений, который обрабатывает ваш код, и перебрасывает исключение, если хотите.

+0

Я добавил заявления 'Label' и посетил их. И я также попробовал метод 'visitTryCatchBlock'. Но после этого я не смог продолжить дальше. Не могли бы вы помочь мне немного в этом? – DukeLover

+0

Правильно ли это? 'Mv.visitTryCatchBlock (lTryBlockStart, lTryBlockEnd, lCatchBlockStart,« java/lang/Exception »); \t \t super.visitMethodInsn (код операции, владелец, имя, desc); \t \t \t \t \t \t \t \t \t \t \t \t \t \t мв.visitLabel (lTryBlockEnd); \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t mv.visitJumpInsn (org.objectweb.asm.Opcodes.GOTO, lCatchBlockEnd); \t \t mv.visitLabel (lCatchBlockStart); \t \t mv.visitVarInsn (org.objectweb.asm.Opcodes.ASTORE, 1); \t \t mv.visitVarInsn (org.objectweb.asm.Opcodes.ALOAD, 1); \t \t mv.visitMethodInsn (org.objectweb.asm.Opcodes.INVOKEVIRTUAL, "java/lang/Exception", "printStackTrace", "() V"); \t \t mv.visitLabel (lCatchBlockEnd); \t \t \t} ' – DukeLover

+0

Это выходит за рамки комментариев; Я рекомендую открыть для этого новый вопрос. – Holger

Смежные вопросы