dexlib2 - 分支覆盖检测
dexlib2 - Branch coverage instrumentation
我正在尝试使用 dexlib2 检测 smali 代码以测量分支
报道。特别是,我在每个分支(如果和相应的标签)基本上插入两条指令; const-string 为每个分支加载唯一的跟踪,invoke-static 调用静态方法。但是,有几个问题:
首先,我必须将寄存器的数量增加一个。这导致重新安排
某些指令的寄存器,这似乎有效(使用反射来增加寄存器编号,例如最初 p0 通过引入新的本地寄存器 v21 获得 v20)。但是,我注意到某些标签,例如.end local v15 也需要这种
修改,这似乎对 dexlib2 来说是不可能的,因为标签
不要跟踪此类信息或名称。我也不知道那些 .end/.restart./start 本地标签的 meaning/intention 是什么。是那些标签
对垃圾收集很有趣,或者对某些类型的信息也很有趣
对应的寄存器?
其次,某些指令只接受 v0-v15 作为参数。这就是为什么
我必须区分本地寄存器的数量是否超过 16 个。
在这种情况下,我基本上使用了两个额外的移动指令:
(在另一种情况下,检测要容易得多)
move-object/16 vNew, v0 #保存v0的值
(上面提到的两个指令)# 使用 v0 来保持跟踪
move-object/16 v0, vNew # 恢复 v0 的值
但是,最近我收到以下错误(以及类似的验证错误):
[0x25C] 'this' 参数 'Reference: java.lang.Object' 不是 'Reference: com.android.calendar.GeneralPreferences'
的实例
我观察到使用 move 和 move-object 之间有区别,但我不知道具体的区别。我会假设常数
是非对象,而其余的代表对象。如果有必要进行这种区分,我将不得不在每个分支上对 v0 的最后一个类型进行一些分析,这会使一切变得更加复杂。
第三,我注意到与分支相关的标签有点
在极少数情况下表现得很奇怪。整个smali都有分店
被检测两次的文件。调试显示查询
if 对其目标标签(另一个分支)的指令一次 returns
标签比其他时间更多。这就是为什么我现在使用的索引
目标标签 (instruction.getTarget().getLocation().getIndex()),但我仍然获得了一个分支,它被检测了两次。
我正在就该特定问题以及一般问题寻求任何帮助 hints/facts
我应该考虑。有没有更好的方法来获取有关的更详细信息
错误; logcat 的输出不是最好的,例如哪个特定指令
导致验证错误(被视为offest的十六进制值不
对我来说有任何意义)。
提前致谢。
我见过的处理您在增加寄存器计数时注意到的问题的最佳方法是添加一个序言,将所有 post-增加的参数寄存器移回其增加前的位置,然后使用最后的 register/registers 作为新的 "scratch" 寄存器。
例如如果参数为 v14-v20,并且将寄存器计数增加 1,则可以添加将 v15 移回 v14、v16 移回 v15 等的代码,并使用 v21 作为新的临时寄存器。
或者,您可以尝试不分配任何寄存器。例如创建一个新方法,并传入要检测的目标方法的值。您可以使用 invoke-*/range 传入任何单个寄存器。但在你的情况下,这似乎不太可行,因为你想传入一个额外的字符串来标识分支。理论上您可以为每个分支创建一个新方法,但您很快就会 运行 进入方法限制。
.end/.restart./start local 纯粹是为了调试信息。它们告诉调试器哪个寄存器与原始 java 代码中的哪个局部变量相关联。最简单的事情就是剥离它们。有关详细信息,请参阅 https://source.android.com/devices/tech/dalvik/dex-format#debug-info-item。
是的,move-object 必须用于引用类型,move-wide 用于基元longs/doubles,move 用于其他基元。另外,不要忘记宽类型占用 2 个寄存器。因此,如果您碰巧需要移动一个宽值(long 或 double 原语),则可能需要分配 2 个额外的临时寄存器
dexlib2 有一个 api 用于在需要时对寄存器执行类型分析。参见 https://github.com/JesusFreke/smali/blob/master/dexlib2/src/main/java/org/jf/dexlib2/analysis/MethodAnalyzer.java
我正在尝试使用 dexlib2 检测 smali 代码以测量分支 报道。特别是,我在每个分支(如果和相应的标签)基本上插入两条指令; const-string 为每个分支加载唯一的跟踪,invoke-static 调用静态方法。但是,有几个问题:
首先,我必须将寄存器的数量增加一个。这导致重新安排 某些指令的寄存器,这似乎有效(使用反射来增加寄存器编号,例如最初 p0 通过引入新的本地寄存器 v21 获得 v20)。但是,我注意到某些标签,例如.end local v15 也需要这种 修改,这似乎对 dexlib2 来说是不可能的,因为标签 不要跟踪此类信息或名称。我也不知道那些 .end/.restart./start 本地标签的 meaning/intention 是什么。是那些标签 对垃圾收集很有趣,或者对某些类型的信息也很有趣 对应的寄存器?
其次,某些指令只接受 v0-v15 作为参数。这就是为什么 我必须区分本地寄存器的数量是否超过 16 个。 在这种情况下,我基本上使用了两个额外的移动指令: (在另一种情况下,检测要容易得多)
move-object/16 vNew, v0 #保存v0的值
(上面提到的两个指令)# 使用 v0 来保持跟踪
move-object/16 v0, vNew # 恢复 v0 的值
但是,最近我收到以下错误(以及类似的验证错误):
[0x25C] 'this' 参数 'Reference: java.lang.Object' 不是 'Reference: com.android.calendar.GeneralPreferences'
的实例我观察到使用 move 和 move-object 之间有区别,但我不知道具体的区别。我会假设常数 是非对象,而其余的代表对象。如果有必要进行这种区分,我将不得不在每个分支上对 v0 的最后一个类型进行一些分析,这会使一切变得更加复杂。
第三,我注意到与分支相关的标签有点 在极少数情况下表现得很奇怪。整个smali都有分店 被检测两次的文件。调试显示查询 if 对其目标标签(另一个分支)的指令一次 returns 标签比其他时间更多。这就是为什么我现在使用的索引 目标标签 (instruction.getTarget().getLocation().getIndex()),但我仍然获得了一个分支,它被检测了两次。
我正在就该特定问题以及一般问题寻求任何帮助 hints/facts 我应该考虑。有没有更好的方法来获取有关的更详细信息 错误; logcat 的输出不是最好的,例如哪个特定指令 导致验证错误(被视为offest的十六进制值不 对我来说有任何意义)。
提前致谢。
我见过的处理您在增加寄存器计数时注意到的问题的最佳方法是添加一个序言,将所有 post-增加的参数寄存器移回其增加前的位置,然后使用最后的 register/registers 作为新的 "scratch" 寄存器。
例如如果参数为 v14-v20,并且将寄存器计数增加 1,则可以添加将 v15 移回 v14、v16 移回 v15 等的代码,并使用 v21 作为新的临时寄存器。
或者,您可以尝试不分配任何寄存器。例如创建一个新方法,并传入要检测的目标方法的值。您可以使用 invoke-*/range 传入任何单个寄存器。但在你的情况下,这似乎不太可行,因为你想传入一个额外的字符串来标识分支。理论上您可以为每个分支创建一个新方法,但您很快就会 运行 进入方法限制。
.end/.restart./start local 纯粹是为了调试信息。它们告诉调试器哪个寄存器与原始 java 代码中的哪个局部变量相关联。最简单的事情就是剥离它们。有关详细信息,请参阅 https://source.android.com/devices/tech/dalvik/dex-format#debug-info-item。
是的,move-object 必须用于引用类型,move-wide 用于基元longs/doubles,move 用于其他基元。另外,不要忘记宽类型占用 2 个寄存器。因此,如果您碰巧需要移动一个宽值(long 或 double 原语),则可能需要分配 2 个额外的临时寄存器
dexlib2 有一个 api 用于在需要时对寄存器执行类型分析。参见 https://github.com/JesusFreke/smali/blob/master/dexlib2/src/main/java/org/jf/dexlib2/analysis/MethodAnalyzer.java