Android内存问题定位方法

将得不是很好,但是基本能够定位问题了

转自:http://leave001.blog.163.com/blog/static/1626912932011226105512484/

制造一个crash

为了演示的目的,我在libsensors的open_sensors_device中故意制造了一个crash:

static int open_sensors_device(const struct hw_module_t* module, const char* name,

struct hw_device_t** device)

{

int status = -EINVAL;

//if our sensor system is ready,commented next line

//return status;

char* ptr = 0;

*ptr = 0;

// ....

}

这里ptr指向0地址,但后面却往这个0地址写0,因此会crash。crash时,logcat可以看到android打印的backtrace:

I/SystemServer( 1046): Sensor Service

I/DEBUG ( 971): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

I/DEBUG ( 971): Build fingerprint: 'Questers/kylin/kylin/aspen168:2.2.1/FRG83/builder.20110307.131914:user/release-keys'

I/DEBUG ( 971): pid: 1046, tid: 1059 >>> system_server <<<

I/DEBUG ( 971): signal 11 (SIGSEGV), fault addr 00000000

I/DEBUG ( 971): r0 8150218c r1 81501250 r2 ae205500 r3 00000000

I/DEBUG ( 971): r4 ae203d5b r5 8150210c r6 43891f6c r7 42084eb0

I/DEBUG ( 971): r8 4a570b80 r9 42084ea8 10 42084e94 fp 0011f3e0

I/DEBUG ( 971): ip a7f0110c sp 4a570b50 lr ae203247 pc 815009ba cpsr a0000030

I/DEBUG ( 971): #00 pc 000009ba /system/lib/hw/sensors.default.so

I/DEBUG ( 971): #01 pc 00003244 /system/lib/libandroid_servers.so

I/DEBUG ( 971): #02 pc 00011cf4 /system/lib/libdvm.so

I/DEBUG ( 971): #03 pc 0003f194 /system/lib/libdvm.so

I/DEBUG ( 971): #04 pc 00016cb8 /system/lib/libdvm.so

I/DEBUG ( 971): #05 pc 0001d604 /system/lib/libdvm.so

I/DEBUG ( 971): #06 pc 0001c49c /system/lib/libdvm.so

I/DEBUG ( 971): #07 pc 00055374 /system/lib/libdvm.so

I/DEBUG ( 971): #08 pc 0005558a /system/lib/libdvm.so

I/DEBUG ( 971): #09 pc 00049672 /system/lib/libdvm.so

I/DEBUG ( 971): #10 pc 000113fc /system/lib/libc.so

I/DEBUG ( 971): #11 pc 00010ee0 /system/lib/libc.so

I/DEBUG ( 971):

I/DEBUG ( 971): code around pc:

I/DEBUG ( 971): 81500998 600b189b 46c04770 00001772 fffffef4

I/DEBUG ( 971): 815009a8 4d2bb5f0 492b1c0c b083447d 90012300

I/DEBUG ( 971): 815009b8 701b1869 1c161c20 efa8f7ff d11f1e07

I/DEBUG ( 971): 815009c8 f7ff205c 2100ef62 1c04225c ef92f7ff

I/DEBUG ( 971): 815009d8 21014821 6562424a 60676020 4a20491f

I/DEBUG ( 971):

I/DEBUG ( 971): code around lr:

I/DEBUG ( 971): ae203224 b082480e 1820447c f7fea901 2800eaf6

I/DEBUG ( 971): ae203234 9801d10f 4a0b490a 18616943 681b18a2

I/DEBUG ( 971): ae203244 28004798 9801d105 1d034669 47a06fdc

I/DEBUG ( 971): ae203254 2000e000 bd10b002 00001ee8 ffffec3f

I/DEBUG ( 971): ae203264 ffffec47 000003ec 4e3db5f0 4c3d1c05

I/DEBUG ( 971):

I/DEBUG ( 971): stack:

I/DEBUG ( 971): 4a570b10 4a570b80

I/DEBUG ( 971): 4a570b14 42084e74

I/DEBUG ( 971): 4a570b18 0027be10 [heap]

I/DEBUG ( 971): 4a570b1c 0011f3e0 [heap]

I/DEBUG ( 971): 4a570b20 00000001

I/DEBUG ( 971): 4a570b24 00000007

I/DEBUG ( 971): 4a570b28 00000000

I/DEBUG ( 971): 4a570b2c 00000000

I/DEBUG ( 971): 4a570b30 420ce5c0 /dev/ashmem/dalvik-LinearAlloc (deleted)

I/DEBUG ( 971): 4a570b34 0011f3e0 [heap]

I/DEBUG ( 971): 4a570b38 0027be10 [heap]

I/DEBUG ( 971): 4a570b3c 422962b0 /dev/ashmem/dalvik-LinearAlloc (deleted)

I/DEBUG ( 971): 4a570b40 4a570bb0

I/DEBUG ( 971): 4a570b44 000000d0

I/DEBUG ( 971): 4a570b48 df002777

I/DEBUG ( 971): 4a570b4c e3a070ad

I/DEBUG ( 971): #00 4a570b50 422962b0 /dev/ashmem/dalvik-LinearAlloc (deleted)

I/DEBUG ( 971): 4a570b54 8150218c /system/lib/hw/sensors.default.so

I/DEBUG ( 971): 4a570b58 45d7fd20 /dev/ashmem/mspace/dalvik-heap/2 (deleted)

I/DEBUG ( 971): 4a570b5c ae205114 /system/lib/libandroid_servers.so

I/DEBUG ( 971): 4a570b60 00000004

I/DEBUG ( 971): 4a570b64 43891f6c /data/dalvik-cache/system@framework@services.jar@classes.dex

I/DEBUG ( 971): 4a570b68 42084eb0

I/DEBUG ( 971): 4a570b6c ae203247 /system/lib/libandroid_servers.so

I/DEBUG ( 971): #01 4a570b70 438a922c /data/dalvik-cache/system@framework@services.jar@classes.dex

I/DEBUG ( 971): 4a570b74 8150218c /system/lib/hw/sensors.default.so

I/DEBUG ( 971): 4a570b78 4a570ba0

I/DEBUG ( 971): 4a570b7c aca11cf8 /system/lib/libdvm.so

D/Zygote ( 973): Process 1046 terminated by signal (11)

有用的信息

我们可以关注以下五处:

1. 哪个进程crash了

这里为/system/bin/system_server出了问题,它的pid为1046。

2. crash时cpu抛出的信号

比如这里是11(SEGV),表示段错误,一般为程序指令访问非法地址时产生。其它的信号的意义可以参考《Unix环境高级编程》。另外,这个数字和名字间的对应关系可以用kill -l列出:

# kill -l

1 HUP Hangup 17 CHLD Child exited

2 INT Interrupt 18 CONT Continue

3 QUIT Quit 19 STOP Stopped (signal)

4 ILL Illegal instruction 20 TSTP Stopped

5 TRAP Trap 21 TTIN Stopped (tty input)

6 ABRT Aborted 22 TTOU Stopper (tty output)

7 BUS Bus error 23 URG Urgent I/O condition

8 FPE Floating point exception 24 XCPU CPU time limit exceeded

9 KILL Killed 25 XFSZ File size limit exceeded

10 USR1 User signal 1 26 VTALRM Virtual timer expired

11 SEGV Segmentation fault 27 PROF Profiling timer expired

12 USR2 User signal 2 28 WINCH Window size changed

13 PIPE Broken pipe 29 IO I/O possible

14 ALRM Alarm clock 30 PWR Power failure

15 TERM Terminated 31 SYS Bad system call

16 STKFLT Stack fault


3. 发生错误的地址

如上面的log打印出的“fault addr 00000000",表示cpu对这个地址作读写操作除了异常。NULL(0)地址为OS预留的地址,作指针初始化用途,不允许程序进行读写。

4. PC指针

如上面打印出的

#00 pc 000009ba /system/lib/hw/sensors.default.so

#01 pc 00003244 /system/lib/libandroid_servers.so

表示出错时cpu的指令指针指向这个地址。可以用后面介绍的方法由地址找出代码位置。

5. 栈信息

android会dump出栈的内容。在unix/linux中,一般情况下栈会向低地址位置移动,android也不例外。在上面dump的信息中,越靠上(地址越小)表示这是栈顶位置,越往下表示栈底。

另外,dump的信息中有三列:

4a570b54 8150218c /system/lib/hw/sensors.default.so

第一列:表示栈空间的地址。这里为4a570b54

第二列:这个栈单元中的内容。这里为8150218c

第三列:表示该内容对应的代码。若无text信息,则此处显示为空。这里为/system/lib/hw/sensors.default.so

最后需要注意的是,这里显示的地址为完整形式,即基地址+偏移量。基地址可以从/proc/<pid>/maps中看出(<pid>为crash进程对应的pid):

cat /proc/1059/maps | grep "sensors.default.so"

81500000-81502000 r-xp 00000000 00:0f 953 /system/lib/hw/sensors.default.so

81502000-81503000 rwxp 00002000 00:0f 953 /system/lib/hw/sensors.default.so

这里上面一行(不可写)为sensors.default.so的文本段,下一行为数据段(可读写)。可以看到sensors.default.so被映射到了system_server进程的81500000~81503000地址空间中。将代码完整地址8150218c减去基地址81500000,可以得到libc.so中的偏移地址0000218c。另外注意到,8150218c映射到数据段,说明出问题时栈保存有 sensors.default.so中某一个函数中的局部变量。

由地址得到符号信息

给定一个地址,可以找出它对应的符号信息,以便分析。

找到大致的函数位置

guang@leave001:~/froyo_0308$ vendor/qsts/toolchain/arm-linux-4.1.1/bin/arm-linux-objdump -t out/target/product/kylin/symbols/system/lib/sensors.default.so | sort > list.txt

注意,这里需要找到out下symbols中的so文件,因为它的symbol信息没有被strip掉。list.txt中包含了按照地址排序的符号信息。根据sensors.default.so出错的地址000009ba,可以找到符号信息:

00000990 <sensors__get_sensors_list>:

000009a8 <open_sensors_device>:

00000a8c <pick_sensor>:

可以看到跟000009ba比较接近的地址为000009a8,因此可以判断出错的函数为open_sensors_device。

找出具体位置

objdump -t仅打印简单的信息。-S参数可以显示详细信息,输出中包含c和汇编代码:

guang@leave001:~/froyo_0308$ vendor/qsts/toolchain/arm-linux-4.1.1/bin/arm-linux-objdump -S out/target/product/kylin/symbols/system/lib/sensors.default.so > list.txt

在生成的list.txt中找到函数open_sensors_device,下面可以看到c代码和汇编:

static int open_sensors_device(const struct hw_module_t* module, const char* name,

struct hw_device_t** device)

{

9a8: b5f0 push {r4, r5, r6, r7, lr}

int status = -EINVAL;

//if our sensor system is ready,commented next line

//return status;

char* ptr = 0;

*ptr = 0;

if (!strcmp(name, SENSORS_HARDWARE_CONTROL)) {

9aa: 4d2b ldr r5, [pc, #172] (a58 <.text+0xc8>)

9ac: 1c0c adds r4, r1, #0

9ae: 492b ldr r1, [pc, #172] (a5c <.text+0xcc>)

9b0: 447d add r5, pc

9b2: b083 sub sp, #12

9b4: 2300 movs r3, #0

9b6: 9001 str r0, [sp, #4]

9b8: 1869 adds r1, r5, r1

9ba: 701b strb r3, [r3, #0]

9bc: 1c20 adds r0, r4, #0

9be: 1c16 adds r6, r2, #0

9c0: f7ff efa8 blx 914 <.text-0x7c>

9c4: 1e07 subs r7, r0, #0

9c6: d11f bne.n a08 <open_sensors_device+0x60>

出错的地址为09ba,这里的汇编代码为

9ba: 701b strb r3, r3, #0

r3, #0意思是把常数0往r3保存的地址传送,而r3在前面被初始化为0地址,因此可以判断出是上面的c代码出了问题。

不幸的是,对于c++生成的so,输出的汇编和c代码跟地址对不上,因此不容易找到具体位置。还有,有时出错的原因不容易从上面的方法分析出来,这时只能借助这个方法来缩小代码范围,通过打印和检视代码来慢慢分析。

更多相关文章

  1. Android 代码风格指南
  2. Android的一些网上开发资源链接地址
  3. Android Studio 官方最新版下载地址(支持国内下载)
  4. Android px和dip及sp的区别及转换代码
  5. Android 开发在Eclipse提示信息 This element neither has attac
  6. Android 源代码编译前后的目录结构
  7. Android有用代码片段(三)
  8. Android 通过代码实现控制数据网络的开关(仅适用于5.0以上)

随机推荐

  1. ArrayList动态删除 自定义Adapter (附源
  2. Activity的Intent Filter
  3. Android中JNI调用
  4. android系统进程简要分析
  5. Android仿淘宝添加商品时属性规格popupwi
  6. Android数据库升级,数据不丢失解决方案
  7. Android(安卓)安装apk时,报错 Failure [IN
  8. android数据库操作之直接读取db文件
  9. android input命令 模拟按键
  10. Eclipse proguard 代码混淆 微信第三方库