2016-03-21 10 views
1

Bir yöntem içinde varolan try/catch bloğunun catch bloğunun kod içeriğini değiştirmeye çalışıyorum.ASM Bytecode çerçevesini kullanarak yakalama blok kodu nasıl değiştirilir?

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

Amacım, catch bloğu içinde bir yöntem çağrısı eklemektir. Bir şey gibi

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

Not: Zaten MethodVisitor ait visitTryCatchBlock yöntemini geçersiz çalıştık. Ve etiketini birçok şekilde ziyaret ettiniz, ancak hiçbir şey yardımcı olmadı. Bunu, ağdaki herhangi bir belge/kılavuzda/örnekte bulamıyorum. Umarım herşeyi denedikten sonra bu soruyu yayınladığımı açıkça belirtmişimdir.

+0

Lütfen bu soruya oy verdikten sonra en azından yorum yazınız. – AKS

+1

Belki birisi, sorununun kendiniz çözmeniz için herhangi bir çaba göstermediğinden aşağıya düşüyor. Şu anda bir başkasının işini yapmasını istiyor. Şu ana kadar yaptığınız kodu gözden geçirin ve probleminizin nerede olduğunu netleştirin. – SubOptimal

+1

Başka seçeneğim olmadığında geldiğim yer burası. Kimse buraya gelmek istemiyor ve başka seçenekler açıksa ayrıntılı soru koyma gayretini almak istemiyor. Buraya gelmeden önce keşfettiğim seçenekleri koymalıyım. – AKS

cevap

0

Ağaç API'sini ASM'de kullanırsanız, sınıfın MethodNode'unu ve sonra MethodNode'un yönergelerini (InsnList) alabilirsiniz. InsnList'in toArray() yöntemini kullanarak, tek tek talimatlarla yineleyebilirsiniz. talimatlarını düzenlemek için böyle bir şey yapacağını:

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 
} 

Şahsen bu yöntem organları düzenlemek için en kolay yol bulmak.

0

Denemelerinizin açıklamasının doğru yön, visitTryCatchBlock ve visitLabel işaretleriyle karşılaştığınız gerçek engelin ne olduğu açık değil. İşte iş yapan bir müstakil örnektir:

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); 
    } 
} 

Gördüğünüz gibi, bu düz ileri ediyor, sadece visitTryCatchBlock istisna eylemcinin etiketini kaydetmek ve sağ visitLabel kod pozisyonunu karşılaşmadan sonra istediğiniz kodu enjekte . Gerisi, sınıf dosyasını okumak ve dönüştürmek ve sonucu test amacıyla yüklemek için toplu koddur.

+0

Çok teşekkürler! Bunu deneyeceğim ve güncellemeyi size bildireceğim. Kod enjekte etmek için ASM'yi nasıl kullanabilirim? Demek istediğim, bu şeyleri denemeye devam etmek ya da uygun bir rehber ya da dokümantasyon var. – AKS

+0

Ürünleri http://asm.ow2.org/ adresinde denediniz mi? – Holger

İlgili konular