堆栈跟踪停在叶子寄存器(lr)

时间:2011-06-23 20:17:20

标签: c++ arm android-ndk

我常常看到以#{1}}指针终止的ARM堆栈跟踪(读取:Android NDK堆栈跟踪),如下所示:

lr

我知道 #00 pc 001c6c20 /data/data/com.audia.dev.qt/lib/libQtGui.so #01 lr 80a356cc /data/data/com.audia.dev.rta/lib/librta.so 代表ARM和其他架构上的lr,并且它是存储返回地址的快捷方式,但我不明白为什么它似乎总是存储无用的地址。在此示例中,link register无法使用80a356ccaddr2line映射到任何代码。

有没有办法获得更多信息?为什么跟踪必须在gdb地址处停止?

2 个答案:

答案 0 :(得分:2)

最后偶然发现了答案。我只需要更加敏锐。查看以下短堆栈跟踪及其后面的信息:

         #00  pc 000099d6  /system/lib/libandroid.so
         #01  lr 80b6c17c  /data/data/com.audia.dev.rta/lib/librta.so

code around pc:
a9d899b4 bf00bd0e 2102b507 aa016d43 28004798 
a9d899c4 9801bfa8 bf00bd0e 460eb573 93004615 
a9d899d4 6d842105 462b4632 200047a0 bf00bd7c 
a9d899e4 b100b510 f7fe3808 2800edf4 f04fbf14 
a9d899f4 200030ff bf00bd10 b097b5f0 4614af01 

code around lr:
80b6c15c e51b3078 e5933038 e5932024 e51b302c 
80b6c16c e1a00002 e3a01000 e3a02000 ebfeee5c 
80b6c17c e1a03000 e50b303c e51b303c e1a03fa3 
80b6c18c e6ef3073 e3530000 0a000005 e59f34fc 
80b6c19c e08f3003 e1a00003 e51b103c ebfeebe6 

现在lr地址仍然是80xxxxxx地址,对我们没用。

它从pc打印的地址为000099d6,但请查看下一部分code around pc。第一列是地址列表(您可以从每次递增16的事实中得知。)这些地址都不像pc地址,除非您切掉前16位。然后你会注意到a9d899d4必须对应000099d4,并且程序停止的代码是两个字节。

Android的堆栈跟踪似乎已经“切断”pc地址的前2个字节,但无论出于何种原因,它都不会对叶子寄存器中的地址执行此操作。这让我们找到了解决方案:

简而言之,我能够80b6c17c地址中删除前16位以使其成为0000c17c,到目前为止,它已经为我提供了有效的代码每次我都可以使用gdbaddr2line查询。 (编辑:我发现它实际上通常 前12位或前3位十六进制数字。您可以通过查看来自行决定堆栈跟踪输出,如上所述。)我可以确认它也是正确的代码地址。这肯定使调试变得更容易了!

答案 1 :(得分:1)

您是否拥有所有调试信息(-g3)?

Gcc喜欢使用lr作为普通注册。请记住,非叶函数看起来像

push {lr}
; .. setup args here etc.
bl foo  ; call a function foo
; .. work with function results
pop {pc}

一旦将lr推入堆栈,编译器几乎可以自由地使用它 - lr将仅被函数调用覆盖。因此lr中很可能存在任何中间值。

这应该在编译器生成的调试信息中说明,以便让调试器知道它必须查看堆栈值而不是lr