0x01 demo
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class EnterWorldScript {
//监控某一个方法的执行时间
@OnMethod(clazz = "a.b.c", method = "process", location=@Location(Kind.RETURN))
public static void printMethodRunTime(@ProbeClassName String probeClassName, @Duration long duration){
println(probeClassName + ", duration:" + duration / 1000000 + " ms");
}
}
1、从github的btrace repo中下载release版本。
2、解压缩,export BRACE_HOME=xxx
3、使用brace jpid EnterWorldScript.java
就可以看到a.b.c的process
方法的耗时了。
0x02 原理
使用jvmti在运行时attach到java进程上,启动javaagent
,使用Instrument
来动态的将代码注入到目标代码中。
btrace基本上只可以去打印一些调试信息、日志。下面列出的是btrace禁止的事情,会在remote server上启动的btrace-agent做校验(可以关闭这些校验,不过不安全)。
- 不能新建类、新建数组、 抛异常、 捕获异常,
- 不能调用实例方法以及静态方法(com.sun.btrace.BTraceUtils除外)
- 不能将目标程序和对象赋值给BTrace的实例和静态field
- 不能定义外部、 内部、匿名、本地类、不能实现接口、 不能扩展类
- 不能有同步块和方法
- 不能有循环
- 不能使用assert语句
- 不能使用class字面值
0x03 扩展
- 可以自己写个javaagent,存下Instrument的引用,使用这个引用就可以在运行时动态的修改任何代码了(但是不能对类签名、字段签名、方法签名进行修改,也无法添加字段和方法,这个是JVM TI的限制)。如果使用了这种方法,一定要搭配着iptables规则,最好还有权限校验,防止恶意注入。
- 阿里的JVM-SANDBOX计划调研下,看看是否可以作为热修复的备选方案。
- 在内网开发的时候btrace的用途并没有jdwp的用处大,内网开发的时候可以让开发有远程debug的能力,这样在开发效率上会比使用btrace的效率更高。
- btrace的wiki
- btrace不能用于howswap的原因