gpt4 book ai didi

java - 使用 ASM 读取方法退出处的异常

转载 作者:行者123 更新时间:2023-11-30 05:54:51 25 4
gpt4 key购买 nike

我正在编写一个小java工具,它使用ASM 5.2记录所有方法入口和导出。下面是运行良好的程序。该程序基本上使用了 try 和finally(没有 catch) block 。 onMethodEnter() 它记录方法入口。由于整个方法都放在try/finally中,所以finally block 中记录了方法的退出。

import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.commons.AdviceAdapter;

public class SGMethodAdapter extends AdviceAdapter {

private String entry;
private String exit;
private Label startFinally = new Label();

public SGMethodAdapter(int api, MethodVisitor mv, int access, String name, String desc, String className) {
super(api, mv, access, name, desc);
entry = ">" + className + ";" + name;
exit = "<" + className + ";" + name;
}

public void visitCode() {
super.visitCode();
mv.visitLabel(startFinally);
}

public void visitMaxs(int maxStack, int maxLocals) {
Label endFinally = new Label();
mv.visitTryCatchBlock(startFinally, endFinally, endFinally, null);
mv.visitLabel(endFinally);
onFinally(ATHROW);
mv.visitInsn(ATHROW);
mv.visitMaxs(maxStack, maxLocals);
}

private void onFinally(int opcode) {
try {
mv.visitLdcInsn(exit);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/test/MethodEntryExitRecorder", "methodExit",
"(Ljava/lang/String;)V", false);
} catch (Throwable t) {
t.printStackTrace();
}
}

protected void onMethodEnter() {
try {
super.visitLdcInsn(entry);
super.visitMethodInsn(Opcodes.INVOKESTATIC, "com/test/MethodEntryExitRecorder", "methodEntry",
"(Ljava/lang/String;)V", false);
} catch (Throwable t) {
t.printStackTrace();
}
}

protected void onMethodExit(int opcode) {
if (opcode != ATHROW) {
onFinally(opcode);
}
}
}

现在我希望这个程序在退出之前也能读取任何方法抛出的异常(只是读取,而不是捕获)。如果没有抛出异常,我只想记录正常的方法退出。如果方法抛出异常,JVM 保证在方法退出时异常对象在堆栈顶部可用。下面是我调整以添加此行为的相同程序。问题是,这只是读取了少数异常(exception)情况,而不是全部。无法理解哪些异常被读取,哪些异常未被读取。不确定代码中的错误在哪里...非常感谢任何帮助...

private void onFinally(int opcode) {
if(opcode == ATHROW) {
try {
mv.visitInsn(DUP);
mv.visitLdcInsn(exit);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/test/MethodEntryExitRecorder", "methodExitWithException",
"(Ljava/lang/Throwable;Ljava/lang/String;)V", false);
} catch (Throwable t) {
t.printStackTrace();
}
} else {
try {
mv.visitLdcInsn(exit);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/test/MethodEntryExitRecorder", "methodExit",
"(Ljava/lang/String;)V", false);
} catch (Throwable t) {
t.printStackTrace();
}
}
}

protected void onMethodEnter() {
try {
super.visitLdcInsn(entry);
super.visitMethodInsn(Opcodes.INVOKESTATIC, "com/test/MethodEntryExitRecorder", "methodEntry",
"(Ljava/lang/String;)V", false);
} catch (Throwable t) {
t.printStackTrace();
}
}

protected void onMethodExit(int opcode) {
onFinally(opcode);
}

更新:更好地解释问题

看来我对问题的解释不清楚。

就是这里。

1)我正在开发一个java工具,它记录所有java方法的入口和导出(基本上在应用程序运行时生成动态调用图)

2)为此我不想更改应用程序代码。该工具应该可以在不改变应用程序行为的情况下工作

3)为了实现这一点,我正在使用 ASM 进行字节码检测

4)该工具需要在方法体开始和结束处将字节代码注入(inject)到java应用程序的每个方法中

5) 由于一个方法中可以有多个退出/返回点,因此在方法体结束处注入(inject)记录代码是不够的,因为如果方法在方法体中途返回,则不会记录方法退出

6)为了克服这个问题,我将整个应用程序方法体放在 try/finally 中(使用检测)而不使用 catch(因为应用程序需要捕获异常,而不是这个工具)

7) 上面的第一个程序是 ASM 的 AdviceAdapter,它将在类加载时将字节代码注入(inject)到应用程序的所有方法中

8) onMethodEnter() 将注入(inject)记录代码,该代码将记录在运行时调用时输入的应用程序方法

9) onMethodExit() 将在新注入(inject)的finally block 中注入(inject)记录代码,以记录应用程序在运行时退出的方法(位于finally中可确保该代码块始终被执行)

到目前为止,效果很好。它正确生成动态调用图。

现在,对于上面的第一个程序,我想注入(inject)额外的代码,这些代码还将读取应用程序/方法抛出的异常(类型和堆栈跟踪)。还是那句话,只阅读不捕捉。为此,我在上面的第二个程序中添加了这个附加代码。问题是第二个程序只读取少数异常,而不是全部。不确定代码中的错误在哪里。非常感谢任何帮助。

谢谢

斯里尼瓦斯

最佳答案

您的要求反射(reflect)了我的要求,我正在使用下面的代码来记录特定 java 方法引发的异常 - 仅当这些异常未通过使用 try...catch...block 捕获时才记录异常。

package com.abc.agent.adapter;

import java.util.Map;
import com.abc.tm.Constants;
import com.abc.org.objectweb.asm.Label;
import com.abc.org.objectweb.asm.MethodVisitor;
import com.abc.org.objectweb.asm.Opcodes;
import com.abc.org.objectweb.asm.Type;
import com.abc.org.objectweb.asm.commons.AdviceAdapter;

public class PojoMethodAdviceAdapter extends AdviceAdapter {

private String methodName;
private String className;
private String description;
private int okFlag = newLocal(Type.BOOLEAN_TYPE);

Label startFinally = new Label();

public PojoMethodAdviceAdapter(int access , MethodVisitor mv , String methodName, String description, String className , int classFileVersion, boolean learning, int lineNumber, Map pendingMethod){
super(Opcodes.ASM5 , mv, access, methodName, description);
this.className = className;
this.methodName = methodName;
this.description = description;
}

public void visitCode() {
super.visitCode();
mv.visitLabel(startFinally);
}

protected void onMethodEnter(){
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(ISTORE, okFlag);
mv.visitLdcInsn(className);
mv.visitLdcInsn(methodName);
mv.visitLdcInsn(description);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, Constants.RootTracer, Constants.pojoMethodBegin, Constants.pojoMethodBeginDesc, false);
mv.visitVarInsn(ISTORE, okFlag);
}

protected void onMethodExit(int opcode){
if(opcode!=ATHROW) {
onFinally(opcode);
}
}

public void visitMaxs(int maxStack, int maxLocals){
Label endFinally = new Label();
mv.visitTryCatchBlock(startFinally, endFinally, endFinally, null);
mv.visitLabel(endFinally);
onFinally(ATHROW);
mv.visitInsn(ATHROW);
mv.visitMaxs(maxStack+4, maxLocals);
}

private void onFinally(int opcode){
if(opcode == ATHROW){
mv.visitInsn(Opcodes.DUP);
mv.visitLdcInsn(className);
mv.visitLdcInsn(methodName);
mv.visitLdcInsn(description);
mv.visitVarInsn(ILOAD, okFlag);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, Constants.RootTracer, Constants.recordPOJOException, Constants.recordPOJOExceptionDesc, false);
}
mv.visitLdcInsn(className);
mv.visitLdcInsn(methodName);
mv.visitLdcInsn(description);
mv.visitVarInsn(ILOAD, okFlag);
mv.visitLdcInsn(opcode);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, Constants.RootTracer, Constants.pojoMethodEnd, Constants.pojoMethodEndDesc, false);
}

}

关于java - 使用 ASM 读取方法退出处的异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53348684/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com