Open 724027069 opened 1 year ago
我想到一种解决方案:在qunar.tc.bistoury.instrument.client.debugger.DebuggerMethodVisitor中新增onMethodExit
方法,该方法继承自org.objectweb.asm.commons.AdviceAdapter,可以再目标方法返回值之前获取到返回值,由于每个方法都会插桩,所以我们需要记录断点所在方法名称(qunar.tc.bistoury.instrument.client.debugger.DebuggerMethodVisitor#methodUniqueName),用于后续比较,代码如下:
@Override
protected void onMethodExit(int opcode) {
if (opcode == RETURN) {
super.visitLdcInsn("void method");
} else if (opcode == ATHROW) {
super.visitLdcInsn("Exception happened");
} else if (opcode == ARETURN) {
// 复制操作数栈顶的1个数值,并将复制结果压入操作数栈顶,此时操作数栈上有2个连续相同的数值
// 复制的目的是,多出来的这个数值用来打印到控制台,原来栈顶的数值不受影响
dup();
} else if (opcode == LRETURN || opcode == DRETURN) {
// 因为double和long类型(64bit)占2个slot,所以要复制操作数栈顶的2个数值,并将其压入操作数栈顶
dup2();
// 对栈顶的数据按照返回值类型进行包装,并用包装好的值替换原来栈顶的这个数值
// double类型会用Double.valueOf()进行包装,long类型会用Long.valueOf()进行包装
box(Type.getReturnType(methodDesc));
} else {
dup();
// 这里排除上面几种返回值类型,这里的opcode应该是 FRETURN 和 IRETURN
// 对相应类型的数据进行Float.valueOf()或者Integer.valueOf()包装
box(Type.getReturnType(methodDesc));
}
boxingIfShould(methodDesc);
// 将methodName压入栈顶
super.visitLdcInsn(methodUniqueName);
// 所以要调用swap方法,将栈顶最顶端的两个数值互换
swap();
// 因为这里打印时,需要参数是Object类型,所以上面的2个box(getReturnType())必须有,目的是将基本数据类型转成包装类
// 否则打印时,传的是基本数据类型,不是Object一定会报错
super.visitMethodInsn(INVOKESTATIC, SPY_NAME, BistourySpys1.FILL_RETURN_OBJ,
"(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
DefaultSnapshotStore类中:
@Override
public void fillReturnObj(String breakpointId, String methodUniqueName, Object returnObj) {
Snapshot snapshot = snapshotCache.get(breakpointId);
if (snapshot == null) {
logger.debug("fill returnObj error, {}, breakpoint not exist now", breakpointId);
return;
}
if (Strings.isNullOrEmpty(snapshot.getMethodUniqueName()) || !snapshot.getMethodUniqueName().equals(methodUniqueName)) {
return;
}
logger.debug("start fill returnObj, {}", breakpointId);
String stacktraceRecord = DebugJsonWriter.write(returnObj);
snapshot.setReturnObj(stacktraceRecord);
logger.debug("end fill returnObj, {}, {}", breakpointId, stacktraceRecord);
}
bistoury这边是没有支持的,可以看下你这种方案是否可行。现在得到方法的调用方看方法返回值
这是来自QQ邮箱的自动回复邮件。 来信已经收到 感谢您的来信 付威