【发布时间】:2013-03-01 20:31:20
【问题描述】:
我正在 Android 1.6 模拟器上调试一个没有符号的程序。在加载 SO 库期间出现崩溃(信号),我正在尝试追踪它。崩溃发生在库启动代码的某个地方,我知道的很多。在控制从加载程序转到 SO 之前,我知道 SO 加载程序代码中的安全位置。我可以在那里设置一个断点,然后一直到 BLX 进入库。加载程序的代码是 Thumb。库启动代码是ARM。
由于没有符号,我使用set arm force-mode xxx 让GDB 知道。在启动导致加载程序停止的序列之前,我将模式设置为 Thumb。
但问题是,当我来到 BLX 指令并尝试单步执行 (si) 时,调试器不会在下一条指令处停止 - 它一直到信号.即使我在 BLX 上执行 si 之前先执行 set arm force-mode arm,似乎也无所谓。
在库启动代码中设置断点也无济于事。我不确定 GDB 究竟是如何设置断点的,但看起来当前执行代码的模式与预期的断点目标模式之间的不匹配是一个障碍。
编辑:我什至尝试对正在运行的代码进行猴子修补,以便在正确的位置使用 BKPT 命令 - GDB 仍然没有中断。
EDIT2:猴子修补代码部分似乎不起作用。不过,我可以将数据部分的一部分用作暂存区。尽管如此,BKPT 不会导致 GDB 崩溃...
EDIT3:对三行代码 sn-p 使用暂存数据区域,我可以切换出 Thumb 并在信号中返回 GDB。但是,现在我处于 ARM 模式,GDB 由于某种原因无法设置断点。
BLX 进入库命令如下所示:blx r2。 r2 的值为 0x80601b60 - 这是库启动例程。
当我停止使用 BLX 时,我会这样做。我在数据部分有一个暂存区。我将以下 ARM 命令放在那里:
mov r12, 0 ; the value of r12 will be soon ruined by the code anyway
ldr r12, [r12] ; Provoke a SIGSEGV to stop GDB in ARM mode
mov pc, r2 ; To resume back into the library
然后我将r2的值强行设置为我的暂存区,将GDB模式设置为ARM并继续。划痕区的一个 SIGSEGV 自然被抛出。
我在这里,处于 ARM 模式(CPU 和 GDB 的强制模式)。我在 0x80601b60 - 库入口点设置了一个断点。我将 r2 的值改回 0x80601b60 以便第三条命令跳转到那里。我将 r12 的值更改为有效读取地址,以便在重试时不会重新抛出信号。然后我发出signal 0 命令在没有信号的情况下继续。
我预计控制会转到 0x80601b60 并且会遇到断点。它不是。为什么不? mov 的语义在分配给 pc 时是否有所不同(就像 ldr rx, [pc] 一样)?
在mov pc, r2 上设置断点也不起作用。在信号模式停止时在 GDB 中设置断点是否有问题?但即使我在信号之前设置断点(在 Thumb 模式下),它也不起作用。
更奇怪的是,我遇到了控制越过mov pc, r2 的情况,就好像它根本没有执行一样。但是,一旦我修复了 r12,就会执行上一条指令 。
signal 0 有单步模拟吗?
【问题讨论】:
-
试试
set arm force-mode auto和set arm fallback-mode auto。这应该检查 CPSR。 BLX 的问题是,GDB通常会将illegal指令放在下一个执行点到单步。如果它对模式感到困惑,那么它可能会编写一个illegalARM vs Thumb 指令。由于 ICACHE/DCACHE 等原因,补丁代码有问题。我不知道猴子补丁是什么意思,但您需要遵循 SMC 程序。见:en.wikipedia.org/wiki/Self-modifying_code -
不,仍然失败:(
-
确实如此,但 Android 上的每个代码部分也是如此。在
maps中标记为r-xp。 -
你能否通过写入 PC/LR/CPSR 然后告诉 GCC 它处于 ARM 模式来“手动模拟”BLX 指令?
-
不,也不行。
标签: linux debugging android-ndk gdb arm