当前位置:首页 » Android开发技术

Android Native Crash调试方法

2013-04-18 14:21 本站整理 浏览(8)
Native调试方法, 一个tombstome文件如下
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'sprd/sprdroid_base/hsdroid:2.3.5/MocorDroid2.3.5/W13.08_20130218.033702:eng/test-keys'
pid: 151, tid: 23358  >>> /system/bin/mediaserver <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 80c1e0c8
 r0 00086b34  r1 68000010  r2 00000000  r3 80c1e0bc
 r4 00000000  r5 00000000  r6 0005adc8  r7 00066830
 r8 80b09015  r9 00083c38  10 00008000  fp 00000001
 ip a39ad7ec  sp 41627e60  lr a3928d5d  pc a3928d64  cpsr 40800030
 d0  6f6365443a3a4f41  d1  614d687469576564
 d2  6e45692072656b72  d3  6165727453666f64
 d4  9f9f9f9f9f9f9f9f  d5  a1a1a1a1a1a1a1a1
 d6  a2a2a2a2a2a2a2a2  d7  a2a2a2a2a2a2a2a2
 d8  7979797979797979  d9  7979797979797979
 d10 0101010101010101  d11 0000000000000000
 d12 01e701e701e701e7  d13 01e701e701e701e7
 d14 7878787878787878  d15 7979797979797979
 d16 000000000019e100  d17 a5a5a5a5a5a5a5a5
 d18 a5a5a5a5a5a5a5a5  d19 a5a5a5a5a5a5a5a5
 d20 a5a5a5a5a5a5a5a5  d21 a4a4a4a4a4a4a4a4
 d22 a4a4a4a4a4a4a4a4  d23 a2a2a2a2a2a2a2a2
 d24 016d016d016d016d  d25 016d016d016d016d
 d26 7a7a7a7a7a7a7a7a  d27 7a7a7a7a7a7a7a7a
 d28 00f200f200f200f2  d29 00f200f200f200f2
 d30 00f400f400f400f4  d31 00f400f400f400f4
 scr 68000010

         #00  pc 00028d64  /system/lib/libopencore_common.so
         #01  pc 00028f8c  /system/lib/libopencore_common.so
         #02  pc 000292f0  /system/lib/libopencore_common.so
         #03  pc 00008f66  /system/lib/libomx_sharedlibrary.so
         #04  pc 00009064  /system/lib/libomx_sharedlibrary.so
         #05  pc 00011d4c  /system/lib/libc.so
         #06  pc 00011910  /system/lib/libc.so

code around pc:
a3928d44 e0594788 68319e06 5ca0f501 4000f8dc 
a3928d54 2004eb01 e9daf7f8 b9204604 68039804 
a3928d64 479068da f1b0e005 bf063fff 684c9906 
a3928d74 98062400 ffa8f00b d03d2c00 68089904 
a3928d84 46086883 47984621 28004604 9d05d034 

code around lr:
a3928d3c 46289d04 68d9682b e0594788 68319e06 
a3928d4c 5ca0f501 4000f8dc 2004eb01 e9daf7f8 
a3928d5c b9204604 68039804 479068da f1b0e005 
a3928d6c bf063fff 684c9906 98062400 ffa8f00b 
a3928d7c d03d2c00 68089904 46086883 47984621 

stack:
    41627e20  0005a808  
    41627e24  0000000a  
    41627e28  80b084d9  /system/lib/libomx_sharedlibrary.so
    41627e2c  00000001  
    41627e30  00066890  
    41627e34  00066894  
    41627e38  00066898  
    41627e3c  00000000  
    41627e40  00000003  
    41627e44  00066830  
    41627e48  00000000  
    41627e4c  00000000  
    41627e50  0005adc8  
    41627e54  afd0d00c  /system/lib/libc.so
    41627e58  df002777  
    41627e5c  e3a070ad  
#00 41627e60  00066844  
    41627e64  a392a451  /system/lib/libopencore_common.so
    41627e68  00000000  
    41627e6c  000667e8  
    41627e70  00086b34  
    41627e74  000667e8  
    41627e78  0005adc8  
    41627e7c  a39ad7b0  
    41627e80  000667e8  
    41627e84  00000000  
    41627e88  00000001  
    41627e8c  a3928f91  /system/lib/libopencore_common.so
#01 41627e90  00000000  
    41627e94  80b09015  /system/lib/libomx_sharedlibrary.so
    41627e98  00083c38  
    41627e9c  00000078  
    41627ea0  80b09015  /system/lib/libomx_sharedlibrary.so
    41627ea4  a39292f5  /system/lib/libopencore_common.so
#02 41627ea8  0005adc8  
    41627eac  000667e8  
    41627eb0  00000000  
    41627eb4  80b08f69  /system/lib/libomx_sharedlibrary.so
#03 41627eb8  41627f00  
    41627ebc  00083c38  
    41627ec0  41627f00  
    41627ec4  0005adc8  
    41627ec8  0005adc8  
    41627ecc  00083c3c  
    41627ed0  00000000  
    41627ed4  00000000  
    41627ed8  41627f00  
    41627edc  80b09069  /system/lib/libomx_sharedlibrary.so
#04 41627ee0  00083c38  
    41627ee4  0005adc8  
    41627ee8  00000000  
    41627eec  afd11d50  /system/lib/libc.so
#05 41627ef0  41627f00  
    41627ef4  0005ad50  
    41627ef8  418a0c08  
    41627efc  afd11914  /system/lib/libc.so
#06 41627f00  41627f00  
    41627f04  0005ad50  
    41627f08  00000002  
    41627f0c  00000000  
    41627f10  00000000  
    41627f14  00000000  
    41627f18  0005ad90  
    41627f1c  00000000  
    41627f20  00000000  
    41627f24  00000000  
    41627f28  00000000  
    41627f2c  00000000  
    41627f30  00000000  
    41627f34  00000000  
    41627f38  00000000  
    41627f3c  00000000  
    41627f40  00000000  
    41627f44  00000000  
这个可以使用stacktrace工具来查看
./stacktrace --symbols-dir=符号表目录   tombstome_file
另外还可以用core dump进行调试
core dump需要一下几个步骤,对android,可以在开机的时候在init.rc里去执行
在init.rc里加上
   setrlimit 4 -1 -1
     write /proc/sys/kernel/core_pattern "/local/log/core-%e-%p-%t"

(1)使用ulimit命令开启coredump功能。
(2)修改coredump文件生成位置与名称
(3)gdb的使用方法

【3】实践
(1)adb连接手机,开启coredump
# ulimit -a
ulimit -a
time(seconds)        unlimited
file(blocks)         unlimited
data(kbytes)         unlimited
stack(kbytes)        8192
coredump(blocks)     unlimited  //这里coredump是开启的,大小为不限制,可以用ulimit -c unlimited修改成不限制大小
memory(kbytes)       unlimited
locked memory(kbytes) 64
process(processes)   4096
nofiles(descriptors) 1024
(2)配置coredump文件生成位置与名称
#echo "1" > /proc/sys/kernel/core_uses_pid       //允许文件名后加pid
#echo "/local/log/core-%e-%p" > /proc/sys/kernel/core_pattern
#echo 1 > /proc/sys/fs/suid_dumpable
把dump文件存放目录改到local/log下。
(3)示例程序
foo.c
#include <stdio.h>
static void sub(void);
int main(void)
{
      sub();
     return 0;
}
static void sub(void)
{
     int *p = NULL;
    printf("%d",*p);
}
然后编译,android会生成两种版本的文件,一种是带符号信息的,
out/target/product/generic/symbols/system/bin/foo
另一种是不带符号信息的(即strip过的)
out/target/product/generic/system/bin/foo
不带符号信息的会做到system.img中去,带符号信息的我们需要保存住,以备后续调试用。
上面第二个log信息就是此程序运行的结果。
(4)运行
我们把generic/system/bin/foo文件拷贝到手机中,比如local目录下,修改权限(chmod 777 foo),执行,结果如下。
#./foo
[1] + Stopped (signal)        ./foo
#
[1]   Segmentation fault (core dumped) ./foo
#
然后可以看到/local/log目录下多了一个coredump文件, 进程id位1673
core-foo-1673 

拿gdb调试
将core-foo-1673与generic/symbols/system/bin/foo(这个必须是带符号的)拷贝到相同目录下
运行gdb进行调试,注意这里要运行的gdb是android自带的,我这里的名称叫arm-eabi-gdb
$arm-eabi-gdb ./foo
GNU gdb 6.6
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
The GDB was configured as "--host=i686-unknown-linux-gnu --target=arm-elf-linux"...
(gdb)
输入core-file文件,回车
(gdb) core-file core-foo-1672
warning: core file may not match specified executable file.
Error while mapping shared library sections:
/system/bin/linker: No such file or directory.
Error while mapping shared library sections:
libc.so: Success.
Error while mapping shared library sections:
libstdc++.so: Success.
Error while mapping shared library sections:
libm.so: Success.
Symbol file not found for /system/bin/linker
Symbol file not found for libc.so
Symbol file not found for libstdc++.so
Symbol file not found for libm.so
warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.
Core was generated by `./foo'.
Program terminated with signal 11, Segmentation fault.
#0 0x0000836a in main () at external/coredump/foo.c:15 ==》看到这种信息知道该知道哪出错了把
15   printf("%d",*p)
(gdb)
如果函数调用关系比较复杂,可试试bt(backtrace)指令

附录:在PC机上做的实验
linux 上core dump及应用
【1】core dump 概念http://en.wikipedia.org.nyud.net:8080/wiki/Core_dump 【2】示例:在Linux下产生并调试core文件
参考http://www.zedware.org/code/code-coredump.html
$ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
max locked memory (kbytes, -l) 4
max memory size (kbytes, -m) unlimited
open files (-n) 2048
pipe size (512 bytes, -p) 8
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 7168
virtual memory (kbytes, -v) unlimited
写个简单的程序,看看core文件是不是会被产生。创建foo.c,使内容如下。
$ more foo.c
#include <stdio.h>
static void sub(void);
int main(void)
{
     sub();
     return 0;
}
static void sub(void)
{
     int *p = NULL;
     /* derefernce a null pointer, expect core dump. */
     printf("%d", *p);
}
$ gcc -Wall -g foo.c   【-Wall :[Warning all] 显示所有常用的编译警告信息。 -g选项,将调试信息加入到目标文件或可执行文件中。】
$ ./a.out
Segmentation fault   【所谓的Segmentation Fault(段错误)就是指访问的内存超出了系统所给这个程序的内存空间】
$ ls -l core*
ls: core*: No such file or directory
没有找到core文件,我们改改ulimit的设置,让它产生,1024是随便取的,也可以使用ulimit -c unlimited不限制大小。
$ ulimit -c 1024
$ ulimit -a
core file size (blocks, -c) 1024
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
max locked memory (kbytes, -l) 4
max memory size (kbytes, -m) unlimited
open files (-n) 2048
pipe size (512 bytes, -p) 8
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 7168
virtual memory (kbytes, -v) unlimited
$ ./a.out
Segmentation fault (core dumped)
$ ls -l core*
-rw------- 1 uniware uniware 53248 Jun 30 17:10 core.9128 【此处也可能是名称为core的文件】
注意看上述的输出信息,多了个(core dumped)。确实产生了一个core文件,9128是该进程的PID。我们用GDB来看看这个core。
$ gdb --core=core.9128
GNU gdb Asianux (6.0post-0.20040223.17.1AX)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This was configured as "i386-asianux-linux-gnu".
Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
#0 0x08048373 in ?? ()
(gdb) bt
#0 0x08048373 in ?? ()
#1 0xbfffd8f8 in ?? ()
#2 0x0804839e in ?? ()
#3 0xb74cc6b3 in ?? ()
#4 0x00000000 in ?? ()

此时用bt看不到backtrace,也就是调用堆栈,原来GDB还不知道符号信息在哪里。我们告诉它一下:
(gdb) file ./a.out
Reading symbols from ./a.out...done.
Using host libthread_db library "/lib/tls/libthread_db.so.1".
(gdb) bt
#0 0x08048373 in sub () at foo.c:17
#1 0x08048359 in main () at foo.c:8

此时backtrace出来了。
(gdb) l   (此处是“L”的小写,不是数字“1”)
8         sub();
9         return 0;
10     }
11
12      static void sub(void)
13      {
14          int *p = NULL;
15
16          /* derefernce a null pointer, expect core dump. */
17          printf("%d", *p);
(gdb)
【3】总结
参考http://blog.csdn.net/shaovey/archive/2008/07/31/2744487.aspx
在程序不寻常退出时,内核会在当前工作目录下生成一个core文件(是一个内存映像,同时加上调试信息)。使用gdb来查看core文件,可以指示出导致程序出错的代码所在文件和行数。

1.core文件的生成开关和大小限制
1)使用ulimit -c命令可查看core文件的生成开关。若结果为0,则表示关闭了此功能,不会生成core文件。
2)使用ulimit -c filesize命令,可以限制core文件的大小(filesize的单位为kbyte)。如果生成的信息超过此大小,将会被裁剪,最终生成一个不完整的core文件。在调试此core文件的时候,gdb会提示错误。若ulimit -c unlimited,则表示core文件的大小不受限制。ulimit -c 0关闭该功能。
PS: ulimit使用方法见http://www.ibm.com/developerworks/cn/linux/l-cn-ulimit/

2.core文件的名称和生成路径
core文件生成路径:输入可执行文件运行命令的同一路径下。
若系统生成的core文件不带其它任何扩展名称,则全部命名为core。新的core文件生成将覆盖原来的core文件。
1)/proc/sys/kernel/core_uses_pid可以控制core文件的文件名中是否添加pid作为扩展。文件内容为1,表示添加pid作为扩展名,生成的core文件格式为core.xxxx;为0则表示生成的core文件同一命名为core。
可通过以下命令修改此文件:
echo "1" > /proc/sys/kernel/core_uses_pid
2)proc/sys/kernel/core_pattern可以控制core文件保存位置和文件名格式。
可通过以下命令修改此文件:
echo "/corefile/core-%e-%p-%t" > core_pattern,可以将core文件统一生成到/corefile目录下,产生的文件名为core-命令名-pid-时间戳
以下是参数列表:
    %p - insert pid into filename 添加pid
    %u - insert current uid into filename 添加当前uid
    %g - insert current gid into filename 添加当前gid
    %s - insert signal that caused the coredump into the filename 添加导致产生core的信号
    %t - insert UNIX time that the coredump occurred into filename 添加core文件生成时的unix时间
    %h - insert hostname where the coredump happened into filename 添加主机名
    %e - insert coredumping executable name into filename 添加命令名

3.core文件的查看
core文件需要使用gdb来查看。
gdb ./a.out
core-file core.xxxx
使用bt命令即可看到程序出错的地方。 
以下两种命令方式具有相同的效果,但是在有些环境下不生效,所以推荐使用上面的命令。 
1)gdb -core=core.xxxx
file ./a.out
bt 
2)gdb -c core.xxxx
file ./a.out
bt