我正在编写Dalvik字节码的工具,它为各种方法调用条目执行一些日志记录.具体来说,在各种方法调用站点,我将插入一组指令,收集参数,将它们放在Object []数组中,然后将其传递给日志记录函数.
这一切都很好,我已经实现并通过了大多数应用程序的所有kludges.但是我遇到了一个特别难以理解的Dalvik验证错误:
java.lang.VerifyError: Verifier rejected class io.a.a.g: void io.a.a.g.r()
failed to verify: void io.a.a.g.r(): [0x570] register v5 has type Reference:
java.lang.Object but expected Precise Reference: java.lang.String
我查看了我的仪器生成的代码,我正在做的就是将寄存器v5放在一个对象数组中.
我在这里有几个问题:
>什么是精确的参考,为什么它与参考不兼容?
>这里的偏移是什么意思? [0x570]指向字节码指令的中间,因此它没有清楚地映射到任何指令:周围的指令不涉及v5.
>我将如何进行调试?理想情况下,我想知道验证者认为应该发生什么并解决这个问题.
编辑:
这是我正在谈论的方法的字节码的转储. https://gist.github.com/kmicinski/c8382f0521b19643bb24379d91c47d36正如您所看到的,0x570不是指令的开头,并且(据我所知),没有任何地方r5与应该是对象的String冲突.
解决方法:
如果仔细查看错误,它会告诉您正在传递一个Object,其中需要一个String.无论如何,除非你发布导致问题的实际字节码,否则没有更多可以说的.
你确定0x570指向指令的中间吗?它不应该.无论如何,你要调试它的方法是查看相关的指令,并找出为什么r5是一个Object,当它应该是一个String时.或者您可以发布字节码,以便我可以看看.
编辑:现在您已经发布了代码,实际上有一条路径导致v5成为Object,但它有点微妙
异常处理程序
.catch JSONException {:5D8 ..:938}:BDE跳转到:BDE
异常处理程序的代码将捕获的异常存储在v5中,这意味着此时v5不再是String.然后跳到:162
:BDE
00000BDE move-exception v5
00000BE0 const v0, 0x00488B36
00000BE6 invoke-static Logger->logBasicBlockEntry(I)V, v0
00000BEC goto/16 :162
:162在另一个异常处理程序的范围内:.catch ClassNotFoundException {:2E ..:594}:BF0
:Bf0离开v5不动,跳到:A28
:BF0
00000BF0 move-exception v6
00000BF2 const v0, 0x00488B3E
00000BF8 invoke-static Logger->logBasicBlockEntry(I)V, v0
00000BFE goto/16 :A28
:A28是代码块的开头,它假定v5是String.特别是,在指令上:AE0,v5被传递给一个带字符串的函数.
00000AE0 invoke-virtual StringBuilder->append(String)StringBuilder, v7, v5
0xAE0正好是0x570的两倍,这解释了错误中显示的偏移,一旦你按照JesusFreke的建议调整代码单位.
请注意,这不一定是唯一损坏的代码路径,它只是我在查看代码时找到的第一个路径.但是,一条坏路径足以将v5的类型与JSONException统一起来,因此将其转换为Object.