如何检查类的字节码(使用ASM之类的东西)来了解哪些初始值传递给方法?
例如:给定一些将值互相传递的方法:
void m1(Object o) {
Object v = o;
m2(v);
m2("box");
}
void m2(Object o) {
Object v = o;
m3(x);
}
void m3(Object o) {
}
一些方法调用,都在同一个类中定义:
{
Object foo = "foo";
m1(foo);
m2("bar");
m3("baz");
}
我如何检查班级'字节码,了解m3
将使用值"foo"
,"box"
,"bar"
和"baz"
进行4次调用?
答案 0 :(得分:5)
使用ASM,理论上可以跟踪每个方法,如果从其中调用同一个类的另一个方法。负责定义方法调用的访问者API方法是visitMethodIns
。假设您的类名为bar.Foo
,则需要跟踪:
visitMethodIns(<any>, "bar.Foo", <any>, <any>)
然后,您需要构建一个相互调用的方法的传递关系,其中最后两个参数允许您构建这样的关系层次结构。另外,您需要跟踪这些方法调用的参数,更棘手但也不是不可能。
它更复杂的原因是参数可以加载到操作数堆栈的可能方式的数量。对于您的示例,您只需要关注visitIns和visitLCDIns回调。
在常量池值(LCD)上调用方法时,参数的分辨率相当微不足道。但是,在调用方法学习局部变量赋值之前,您需要跟踪整个指令链,以便知道您正在调用方法参数上的方法。因此,你可以找到
ALOAD_0 / ASTORE_1 / ALOAD_1 => ALOAD_0
是从方法局部变量数组读取/写入序列的有效结果。
通过这一切,通过解析字节代码,您将了解以下调用转换:
m1(Ljava/lang/Object)V -> m2(Ljava/lang/Object)V [ALOAD 0]
-> m2(Ljava/lang/Object)V [LCD "box"]
m2(Ljava/lang/Object)V -> m3(Ljava/lang/Object)V [ALOAD 0]
然后,您可以使用这些结果来解析您发现这些方法调用及其含义的块。然而,你会创建一个非常脆弱的解决方案,其中包括:
{
Foo foo = this;
foo.m1("bar");
}
不会被发现。正如评论中指出的那样,您基本上需要模拟Java虚拟机以便运行&#34;运行&#34;你的代码。
即使您实施了一个复杂的解决方案来追踪所有这些,您仍然无法确定您的结果。当我从实现中调用接口方法时会发生什么。还是一个子类的方法?由于动态调度方法,您永远无法确定被调用的目标。