addr2line死机问题定位

死机问题在程序开发过程中是经常遇到的问题,本文介绍通过addr2line工具解析堆栈来定位死机问题

使用addr2line定位死机问题

在某个C应用程序挂掉后,会生成堆栈信息,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
F/libc    (21866): Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1)
W/ (21866): [SkCanvas* DrawSurface::lockCanvas(const android::Rect&)]-----[76]
I/DEBUG ( 944): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
I/DEBUG ( 944): Build fingerprint: 'full_godbox/godbox:4.0.3/8841C/84125002:eng/ test-keys'
I/DEBUG ( 944): pid: 21866, tid: 21866 >>> demo_cmd <<<
I/DEBUG ( 944): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000
I/DEBUG ( 944): r0 00000003 r1 00000000 r2 000010b0 r3 0000001f
I/DEBUG ( 944): r4 41334124 r5 00000000 r6 beae2f94 r7 00000046
I/DEBUG ( 944): r8 beae2f08 r9 00000010 10 00000bb8 fp beae3024
I/DEBUG ( 944): ip 400c6108 sp beae2f00 lr 41331d13 pc 41331d42 cpsr 00000030
I/DEBUG ( 944): d0 0000000000000000 d1 0000000000000000
I/DEBUG ( 944): d2 0000000000000000 d3 c1859800408ca000
I/DEBUG ( 944): d4 4125f000c1981600 d5 43ff000041200000
I/DEBUG ( 944): d6 0000000000000000 d7 0000000000000000
I/DEBUG ( 944): d8 0000000000000000 d9 0000000000000000
I/DEBUG ( 944): d10 0000000000000000 d11 0000000000000000
I/DEBUG ( 944): d12 0000000000000000 d13 0000000000000000
I/DEBUG ( 944): d14 0000000000000000 d15 0000000000000000
I/DEBUG ( 944): scr 60000010
I/DEBUG ( 944):
I/DEBUG ( 944): #00 pc 00002d42 /system/lib/libtest.so (std_ping)
I/DEBUG ( 944): #01 pc 0000f466 /system/bin/demo_cmd
I/DEBUG ( 944):
I/DEBUG ( 944): code around pc:

这种情况下就可以通过addr2line命令定位出死在了哪一行代码:

1
2
addr2line -e libtest.so 00002d42
addr2line -e demo_cmd 0000f466

注意:我们机顶盒上的so库或者可执行程序,一般都是被stripped的,是无法使用addr2line命令定位死机位置的。这种情况下,则需要找到对应的not stripped的同名文件。这两个文件必须是同一次编译生成的。
  可以使用file命令查看strip状态,如下:

1
2
3
4
$ file system/bin/demo_cmd
system/bin/demo_cmd: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked (uses shared libs), stripped
$ file symbols/system/bin/demo_cmd
symbols/system/bin/demo_cmd: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked (uses shared libs), not stripped

备注:

  • 本文介绍的所有命令,都是在Linux主机上执行的命令;
  • addr2line解析的文件必须是”not stripped“的文件。如果是android sdk,一般放在out的symbols目录下,比如:out/target/product/xxx/symbols/
  • 如果是Android机顶盒,应用程序挂掉后在/data/tombstones/目录下面会生成墓碑文件tombstone_*。在这些文件中就会有堆栈信息。

Android墓碑文件tombstone

Android logcat打印的日志可以显示堆栈信息,但堆栈信息同时会保存到墓碑文件中。

当一个动态库(native 程序)开始执行时,系统会注册一些连接到 debuggerd 的 signal handlers,当系统 crash 的时候,会保存一个 tombstone 文件到/data/tombstones目录下(Logcat中也会有相应的信息),文件的确就像墓碑一样记录了死亡了的进程的基本信息(例如进程的进程号,线程号),死亡的地址(在哪个地址上发生了 Crash),死亡时的现场是什么样的(记录了一系列的堆栈调用信息)等等。
注意:有些Android设备默认是不会产生墓碑文件的,需要手动创建文件/data/tombstones/tombstone_00

1
2
3
mkdir /data/tombstones/
touch /data/tombstones/tombstone_00
chmod 777 /data/tombstones/tombstone_00

系统发生一次段错误后,会把堆栈信息写入tombstone_0x文件,tombstone_0x文件需要从0~9循环使用,需要通过文件更新时间确认最新的一次段错误是哪个墓碑文件。

参考文章