2016-03-21 6 views
1

ändern Ich versuche, den Code-Inhalt von catch-Block des vorhandenen try/catch-Block in einer Methode zu ändern.Wie catch Block-Code mit ASM Bytecode Framework

public static void hello(Throwable throwable) { 
    try{ 
     System.out.println("in try"); 
    }catch(Exception e){ 
     System.out.println("in catch"); 
    } 
} 

Meine Absicht ist es, einen Methodenaufruf innerhalb catch-Block hinzuzufügen. So etwas wie,

public static void hello(Throwable throwable) { 
    try{ 
     System.out.println("in Try"); 
    }catch(Exception e){ 
     *passException(e);* 
     System.out.println("in catch"); 
    } 
} 

Hinweis: Ich habe bereits versucht, visitTryCatchBlock Methode von MethodVisitor außer Kraft zu setzen. Und experimentierte mit dem Besuch des Labels in vielerlei Hinsicht, aber nichts half. Ich kann das in keiner Dokumentation/Anleitung/Beispiele im Internet finden. Ich hoffe, ich habe klar erklärt, dass ich diese Frage stelle, nachdem ich alles versucht habe.

+0

Bitte geben Sie zumindest einen Kommentar, wenn Sie diese Frage abstimmen. – AKS

+1

Vielleicht jemand Downvote, weil Ihre Frage keine Anstrengung zeigt, das Problem selbst zu lösen. Momentan sieht es so aus, als ob jemand anderes deine Arbeit machen möchte. Hinter den Code, den Sie bisher gemacht haben, und klarstellen, wo Ihr Problem liegt. – SubOptimal

+1

Dies ist der Ort, wo ich komme, wenn ich keine andere Option habe. Niemand möchte hier her kommen und die Mühe machen, die detaillierte Frage zu stellen, wenn andere Möglichkeiten offen sind. Vielleicht sollte ich die Optionen setzen, die ich erforscht habe, bevor ich hierher kam. – AKS

Antwort

0

Wenn Sie die Baum-API in ASM verwenden, können Sie den MethodNode der Klasse und dann die Anweisungen des MethodNode (InsnList) abrufen. Mit der toArray() - Methode von InsnList können Sie einzelne Anweisungen durchlaufen. Um Anweisungen zu bearbeiten, würden Sie so etwas tun:

for (MethodNode method : classNode.methods) { 
    method.instructions.set(insn, otherInsn); // Sets the instruction to another one 
    method.instructions.remove(insn); //Removes a given instruction 
    method.instructions.add(insn); //Appends to end 
    method.instructions.insert(insn, otherInsn); // Inserts an instruction after the given insn 
    method.instructions.insertBefore(insn, otherInsn); // Inserts an instruction before the given insn 
} 

Persönlich finde ich dies die einfachste Möglichkeit, Methodenkörper zu bearbeiten.

0

Es ist nicht klar, welches tatsächliche Hindernis Sie konfrontiert sind, da Ihre Beschreibung Ihrer Versuche in die richtige Richtung zeigt, visitTryCatchBlock und visitLabel. Hier ist ein eigenständiges Beispiel, das die Arbeit erledigt:

import java.io.IOException; 
import java.lang.reflect.Method; 

import org.objectweb.asm.*; 

public class EnhanceExceptionHandler { 
    static class Victim { 
     public static void hello(boolean doThrow) { 
      try { 
       System.out.println("in try"); 
       if(doThrow) { 
        throw new Exception("just for demonstration"); 
       } 
      } catch(Exception e){ 
       System.out.println("in catch"); 
      } 
     } 
     static void passException(Exception e) { 
      System.out.println("passException(): "+e); 
     } 
    } 

    public static void main(String[] args) 
     throws IOException, ReflectiveOperationException { 

     Class<EnhanceExceptionHandler> outer = EnhanceExceptionHandler.class; 
     ClassReader classReader=new ClassReader(
      outer.getResourceAsStream("EnhanceExceptionHandler$Victim.class")); 
     ClassWriter classWriter=new ClassWriter(classReader,ClassWriter.COMPUTE_FRAMES); 
     classReader.accept(new ClassVisitor(Opcodes.ASM5, classWriter) { 
      private String className; 

      @Override 
      public void visit(int version, int access, String name, String signature, 
       String superName, String[] interfaces) { 

       className=name; 
       super.visit(version, access, name, signature, superName, interfaces); 
      } 

      @Override 
      public MethodVisitor visitMethod(int access, String name, String desc, 
       String signature, String[] exceptions) { 

       MethodVisitor visitor 
        = super.visitMethod(access, name, desc, signature, exceptions); 
       if(name.equals("hello")) { 
        visitor=new MethodVisitor(Opcodes.ASM5, visitor) { 
         Label exceptionHandler; 

         @Override 
         public void visitLabel(Label label) { 
          super.visitLabel(label); 
          if(label==exceptionHandler) { 
           super.visitInsn(Opcodes.DUP); 
           super.visitMethodInsn(Opcodes.INVOKESTATIC, className, 
            "passException", "(Ljava/lang/Exception;)V", false); 
          } 
         } 

         @Override 
         public void visitTryCatchBlock(
          Label start, Label end, Label handler, String type) { 

          exceptionHandler=handler; 
          super.visitTryCatchBlock(start, end, handler, type); 
         } 
        }; 
       } 
       return visitor; 
      } 
     }, ClassReader.SKIP_FRAMES|ClassReader.SKIP_DEBUG); 

     byte[] code=classWriter.toByteArray(); 
     Method def=ClassLoader.class.getDeclaredMethod(
      "defineClass", String.class, byte[].class, int.class, int.class); 
     def.setAccessible(true); 
     Class<?> instrumented=(Class<?>)def.invoke(
      outer.getClassLoader(), outer.getName()+"$Victim", code, 0, code.length); 
     Method hello=instrumented.getMethod("hello", boolean.class); 
     System.out.println("invoking "+hello+" with false"); 
     hello.invoke(null, false); 
     System.out.println("invoking "+hello+" with true"); 
     hello.invoke(null, true); 
    } 
} 

Wie Sie sehen können, ist es geradlinig, notieren Sie nur die Beschriftung des Exception-Handler in den visitTryCatchBlock und injiziert den gewünschten Code direkt nach der Codeposition in visitLabel Begegnung . Der Rest ist der Massencode zum Lesen und Transformieren der Klassendatei und zum Laden des Ergebnisses zu Testzwecken.

+0

Vielen Dank! Ich werde es versuchen und Sie das Update wissen lassen. Wie kann ich ASM verwenden, um Code zu injizieren? Ich meine, ist das einfach weiter experimentieren mit diesen Dingen oder es gibt einige richtige Anleitung oder Dokumentation. – AKS

+0

Haben Sie das Zeug auf http://asm.ow2.org/ getestet? – Holger