目录
Android上如何用debuggerd拿到死机堆栈
拿到死机堆栈后如何分析
分析backtrace文件
反汇编分析.so文件
反汇编分析.o文件
相关附件
关于debuggerd的原理,在这里就不赘述了。
需要注意两点:
1,确保要调试的进程中没有重写信号处理函数。
在我们的中间件中,libqin_buslib.so中,重写了信号处理函数,这样会覆盖系统默认的信号处理函数,导致debuggerd无法捕获信号。
修改方法:
common_lib/buslib/src/bus_main.c,将bus_ctrl_init()函数内的如下一行代码注释掉:
bus_ctrl_init() {
...
//bus_ctrl_ShutdownInit();
... }
然后重新编译common_lib仓库,将新的libqin_buslib.so放入机顶盒内的相关路径中。
2,确保 /data/tombstones/目录已存在。
如果该目录不存在,那么debuggred无法将堆栈写入tombstone文件。
必要时手动创建:
mkdir /data/tombstones
死机后的堆栈信息,将被debuggerd写入 /data/tombstones/中
我们知道,只要拿到的backtrace中有函数信息,我们就可以找到死机对应的大体位置,通过添加多行打印的方法,来一点点逼近死机位置。
但是,这种方法也有他的局限性:
因此,拿到第一次backtrace后就能精准定位死机位置的方法,才是高大上的方法。
backtrace-05的死机堆栈:
backtrace:
#00 pc 00000d3c /system/lib/libqin_playerportbc.so
#01 pc 00001a94 /system/lib/libqin_playerportbc.so (istb_porting_player_open+1180)
当前函数#00的PC是0xd3c,外层调用函数#01的pc是1a94(返回地址是1a98),因此,0xd3c和0x1a94处到底指的是哪一行源码,是我们要求证的终极目标。
先来分析so库的反汇编信息:
00000ca8
: ca8: e59f0004 ldr r0, [pc, #4] ; cb4
cac: e08f0000 add r0, pc, r0
......
d10: e92d4800 push {fp, lr}
d14: e28db004 add fp, sp, #4
d18: e24dd020 sub sp, sp, #32
d1c: e50b0010 str r0, [fp, #-16]
d20: e50b1014 str r1, [fp, #-20] ; 0xffffffec
d24: e59f3098 ldr r3, [pc, #152] ; dc4
d28: e08f3003 add r3, pc, r3
d2c: e5933000 ldr r3, [r3]
d30: e50b3008 str r3, [fp, #-8]
d34: ea00000b b d68
d38: e51b3008 ldr r3, [fp, #-8]
d3c: e5932000 ldr r2, [r3]
0xd3c处的指令 ldr r2,[r3] 表示的含义是,将寄存器r3的值所表示的内存地址处的数据,读入寄存器r2。
而我们从backtrace-05.txt中可知,r3=00000010
因此,ldr r2,[r3],相当于C语言代码:int r2 = *(long)0x00000010
而0x00000010显然是个不可访问的非法地址,因此触发了signal 11.
但此指令属于哪一个函数的哪一行呢?
我们看到0xd3c的基准地址入口是
我们知道,静态函数只在当前源文件内有效,因此链接器不会浪费PLT资源来寻址静态函数,只需要用段内相对寻址就完全可以了,
我们再看函数#01的PC 0x1a94和返回地址0x1a98,
000015f8
: ......
1a94: ebfffc9d bl d10
1a98: e59f3148 ldr r3, [pc, #328] ; 1be8
0x1a94处是istb_porting_player_open函数内的指令,含义是跳转到0xd10地址处执行,完成后返回;
因此,0xd10应该是函数#00的入口。
我们看0xd10处指令,
push {fp, lr}
含义是将fp和lr寄存器压栈,这是典型的函数入口指令,从objdump文件中可以看出,所有其他函数的入口都是这一条指令。
因此,这证实了0xd10是函数#00的入口。
由于本人能力有限,从对.so的objdump文件中,只能分析到这一步,结论是:
1,死机的最内层函数的入口地址是0xd10(相对于so文件的.text段的偏移);
2,死机指令的地址是0xd3c,它相对于函数入口的偏移量是 0xd3c - 0xd10 = 0x2c ;
3,死机的第二层函数是istb_porting_player_open函数,#00的返回地址是0x1a98,它在函数#01中的偏移量是 0x1a98 - 0x15f8 = 0x4a0
至于#00到底是哪一个函数,0xd3c到底是对应的是函数#00内的哪一行代码,从so的objdump文件中无法继续分析了。
我们知道,从.o目标文件链接生成.so动态库文件的过程中,动态连接器虽然对所有.o文件进行了section合并、GOT生成、指令地址修正等大量处理,但是,.o中某条指令相对于该函数入口的偏移地址并没有被改变,它和.so中是一样的。
因此,我们可以对.o文件进行反汇编,编译.o时,一定要加-g选项,这样才能生成源码和汇编对应的调试信息;
arm-linux-androideabi-objdump -S player_porting_bus_client.o > backtrace-05-player_porting_bus_client.o.objdump.txt
其中,-S表示反汇编时,同时保留对应的源码,这正是我们想要的信息。
下面分析backtrace-05-player_porting_bus_client.o.objdump.txt。
我们先看#00的返回地址(#01入口+ 0x4a0), 0x914 + 0x4a0 = 0xdb4,
00000914
: ......
d94: ebfffffe bl 0 <__android_log_print>
set_signatureCode(iFuncId,*pAVHandle);
d98: e51b3010 ldr r3, [fp, #-16]
d9c: e1a02003 mov r2, r3
da0: e51b3028 ldr r3, [fp, #-40] ; 0xffffffd8
da4: e5933000 ldr r3, [r3]
da8: e1a00002 mov r0, r2
dac: e1a01003 mov r1, r3
db0: ebfffc9d bl 2c
LOGD("<%s,%d> after set_signatureCode\n", __FUNCTION__, __LINE__);
db4: e59f3148 ldr r3, [pc, #328] ; f04
从上述汇编可以看出,0xdb4处代表的是源码是
LOGD("<%s,%d> after set_signatureCode\n", __FUNCTION__, __LINE__);
并且上一条指令是死机时当前函数的pc:
db0: ebfffc9d bl 2c
因此,我们得出#00函数便是set_signatureCode,这正是一个静态函数。
然后我们看set_signatureCode的汇编:
0000002c
: static void set_signatureCode(ITI_U32 mFuncID,ITI_S32 mCode)
{
2c: e92d4800 push {fp, lr}
30: e28db004 add fp, sp, #4
34: e24dd020 sub sp, sp, #32
38: e50b0010 str r0, [fp, #-16]
3c: e50b1014 str r1, [fp, #-20] ; 0xffffffec
bus_CBInfo_s *pCur = gCallBack;
40: e59f3098 ldr r3, [pc, #152] ; e0
44: e08f3003 add r3, pc, r3
48: e5933000 ldr r3, [r3]
4c: e50b3008 str r3, [fp, #-8]
while (NULL != pCur)
50: ea00000b b 84
{
if (pCur->iFuncID == mFuncID )
54: e51b3008 ldr r3, [fp, #-8]
58: e5932000 ldr r2, [r3]
5c: e51b3010 ldr r3, [fp, #-16]
60: e1520003 cmp r2, r3
64: 1a000003 bne 78
我们已经知道,死机指令相对于该函数的偏移地址是0x2c,因此,死机位于:0x2c + 0x2c = 0x58,
因此死机指令是:
58: e5932000 ldr r2, [r3]
这恰好就是我们从so的反汇编分析中得到的死机指令。
死机指令对应的源代码:
if (pCur->iFuncID == mFuncID )
很明显,r3寄存器目前存的就是pCur变量的值,0x00000010,pCur是一个指针,0x00000010这个值对于指针来说显然是非法的。
我咋找不到在哪添加附件?
http://note.youdao.com/noteshare?id=b7fbbdd8ffb423740719972efdcc5644