写应用程序时时常出现程序异常崩溃退出,这里总结Linux反汇编根据程序崩溃堆栈信息定位问题的方法。

程序崩溃堆栈信息

使用命令dmesg查看:

ifotond: unhandled page fault (11) at 0x00000000, code 0x017
pgd = c64e8000
[00000000] *pgd=864f1835, *pte=00000000, *ppte=00000000
CPU: 0 PID: 3327 Comm: ifotond Not tainted 4.9.11 #2
Hardware name: Freescale i.MX6 UltraLite (Device Tree)
task: c6fa0000 task.stack: c64ca000
PC is at 0xb6c26e64
LR is at 0x5c6ac
pc : [<b6c26e64>]    lr : [<0005c6ac>]    psr: 600d0030
sp : bedb2b90  ip : ffffffff  fp : bedb2c44
r10: 00074524  r9 : 0105e648  r8 : 00076b40
r7 : 0105e653  r6 : 00000000  r5 : bedb2bb4  r4 : 00000000
r3 : 00003030  r2 : 00000000  r1 : 00000000  r0 : fffffff8
Flags: nZCv  IRQs on  FIQs on  Mode USER_32  ISA Thumb  Segment user
Control: 10c53c7d  Table: 864e8059  DAC: 00000055
CPU: 0 PID: 3327 Comm: ifotond Not tainted 4.9.11 #2
Hardware name: Freescale i.MX6 UltraLite (Device Tree)
[<c010e540>] (unwind_backtrace) from [<c010b61c>] (show_stack+0x18/0x1c)
[<c010b61c>] (show_stack) from [<c0113300>] (__do_user_fault+0x84/0xcc)
[<c0113300>] (__do_user_fault) from [<c01135b8>] (do_page_fault+0x270/0x314)
[<c01135b8>] (do_page_fault) from [<c0101324>] (do_DataAbort+0x3c/0xbc)
[<c0101324>] (do_DataAbort) from [<c010c41c>] (__dabt_usr+0x3c/0x40)
Exception stack(0xc64cbfb0 to 0xc64cbff8)
bfa0:                                     fffffff8 00000000 00000000 00003030
bfc0: 00000000 bedb2bb4 00000000 0105e653 00076b40 0105e648 00074524 bedb2c44
bfe0: ffffffff bedb2b90 0005c6ac b6c26e64 600d0030 ffffffff

反汇编

arm-linux-gnueabihf-objdump -d ~/ifotond > ~/ifoton.s

 反汇编的可执行文件不能被strip掉,否则不能得到函数信息。【not stripped】

查看反汇编文件

0005c59c <config_ts>:
   5c59c:	e92d48f0 	push	{r4, r5, r6, r7, fp, lr}
   5c5a0:	e28db014 	add	fp, sp, #20
   5c5a4:	e24dd098 	sub	sp, sp, #152	; 0x98
   5c5a8:	e52de004 	push	{lr}		; (str lr, [sp, #-4]!)
   5c5ac:	fafed0f4 	blx	10984 <__gnu_mcount_nc>
   5c5b0:	e3500000 	cmp	r0, #0
   5c5b4:	e3a03000 	mov	r3, #0
   省略。。。。。。。。。
   5c698:	e24b008b 	sub	r0, fp, #139	; 0x8b
   5c69c:	ebfeb64f 	bl	9fe0 <_init+0x378>
   5c6a0:	e51b6094 	ldr	r6, [fp, #-148]	; 0x94
   5c6a4:	e1a00006 	mov	r0, r6
-> [5c6a8]:	ebfeb63a 	bl	9f98 <_init+0x330>
-> [5c6ac]:	e6ff1070 	uxth	r1, r0
   5c6b0:	e1a02004 	mov	r2, r4
   5c6b4:	e1a00006 	mov	r0, r6
   5c6b8:	ebffdbe2 	bl	53648 <param_setapn>
   5c6bc:	e55b0099 	ldrb	r0, [fp, #-153]	; 0x99
   5c6c0:	e1a01005 	mov	r1, r5

分析

PC is at 0xb6c26e64,由于反汇编文件中搜索不到,估计是已经被改,所以继续找到下一条指令LR is at 0x5c6ac,可以看到信息:5c6ac:    e6ff1070     uxth    r1, r0,查看r1和r0的信息:r1 : 00000000  r0 : fffffff8,怀疑应该是操作到空指针了。

5c6ac前面一句指令是bl    9f98 <_init+0x330>,由于没有函数名,推测是系统调用,所以这行汇编指令是系统调用,后面调用的是param_setapn函数,怀疑系统调用函数传入的参数有空指针。

找到0005c59c <config_ts>信息中的config_ts函数:

static inline int8_t config_ts(char *args)
{
    uint8_t idx;
    uint8_t *ip = NULL;
    char *apn = NULL;
    /* 2.解析参数
    *  idx,srvid,ip,port,apn
    */
    utils_mem_scannf(&args[4], strlen(args) - 4, "%d,%d,%s,%d,%s\n", \
        &idx, &tsp.srvid, &ip, &tsp.addr.port, &apn);

    if(NULL != ip)memcpy(tsp.addr.ip.data, ip, tsp.addr.ip.len);

    param_setapn(apn, strlen(apn), idx);

可以看到函数param_setapn前面的函数调用是strlen,strlen引起死机问题很大可能是传入的参数是空指针,下面验证。

可以看到系统调用memcpy中的ip是有判断NULL的,所以需要确认ip地址的长度是否越界,还需确认param_setapn函数参数apn是否为NULL。

通过添加查看代码和添加打印,由于代码需要5个参数,而在测试中只传入4个参数,导致了apn为NULL,但在使用时又没有判断NULL,导致了strlen访问到空指针引起程序崩溃。

总结

C语言的指针使用很频繁,且需要自己管理内存和指针,需要特别的注意,多做容错处理,多考虑异常情况,规范自己的代码风格防止写出BUG。

Logo

更多推荐