【问题标题】:Tracing method invocation arguments in bytecode using ASM使用 ASM 在字节码中跟踪方法调用参数
【发布时间】:2014-06-01 17:32:54
【问题描述】:

如何检查类的字节码(使用 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 将被调用 4 次,其值为 "foo""box""bar""baz"

【问题讨论】:

  • 通常你不能在不运行程序(或模拟它)的情况下做到这一点。这可以归结为停机问题。
  • @immibis - 我不太确定 - 输入清楚地编码在字节码中。它们可以跟随到最后的m3 调用。就像你可以通过查看上面的帖子来做到这一点一样,你可以通过检查字节码来做到这一点。我只是不清楚以编程方式解决此问题的最佳方法。
  • “一般”意味着对于声称这样做的任何程序,有一些输入程序要么使其产生不正确的输出,要么使其永远循环。仍然有一些算法适用于所有可能程序的某些子集。

标签: java java-bytecode-asm bytecode-manipulation


【解决方案1】:

使用 ASM,如果从其中调用同一类的另一个方法,理论上您可以跟踪每个方法。负责定义方法调用的访问者 API 的方法是 visitMethodIns。假设您的课程名为bar.Foo,您需要跟踪:

visitMethodIns(<any>, "bar.Foo", <any>, <any>)

然后,您需要构建相互调用的方法的传递关系,其中最后两个参数允许您构建这样的关系层次结构。此外,您需要跟踪这些方法调用的参数,这更棘手但并非不可能。

它更复杂的原因是可以将参数加载到操作数堆栈上的可能方式的数量。对于您的示例,您只需要注意 visitInsvisitLCDIns 回调。

在常量池值 (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");
}

不会被发现。正如 cmets 中所指出的,您基本上需要模拟 Java 虚拟机才能“运行”您的代码。

即使您实施了一个复杂的解决方案来跟踪这一切,您仍然无法确定您的结果。当我从实现中调用接口方法时会发生什么。还是子类的方法?由于方法的动态分派,您永远无法确定调用的目标。

【讨论】:

  • 反响很好。这应该是足够的信息来接近一个体面的解决方案,因为正如你所说,完美的解决方案基本上涉及模拟 JVM。
  • 嗨@JoshStone,你得到调用方法的参数了吗?如果是,您能否分享有关其解决方案的信息?我也面临同样的问题。我得到了调用方法的参数类型,但是我需要传递给被调用方法的值。
  • @Josh Stone 此处为 obj.methodName(account.getId) 示例,在此方法调用中,我需要 Account 对象的类型,但我得到的类型为 long(由 account.getId 返回的值)。你能帮我解决这个问题吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-30
  • 1970-01-01
  • 2018-07-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多