高通Android 7.1遇到cnss-daemo进程崩溃,分析过程如下:
Log信息:(红色是关键信息)
pid: 6577, tid: 6577, name: cnss-daemon >>> /system/bin/cnss-daemon <<<
signal 6 (SIGABRT) , code -6 (SI_TKILL), fault addr --------
x0 0000000000000000 x1 00000000000019b1 x2 0000000000000006 x3 0000000000000008
x4 000000000000006e x5 0000000000800000 x6 0000007fb7736000 x7 0000000000000000
......
backtrace:
#00 pc 000000000006b790 /system/lib64/libc.so (tgkill+8)
#01 pc 0000000000068c14 /system/lib64/libc.so (pthread_kill+64)
#02 pc 0000000000024180 /system/lib64/libc.so (raise+24)
#03 pc 000000000001cbec /system/lib64/libc.so (abort+52)
#04 pc 0000000000002a4c /system/bin/cnss-daemon
#05 pc 00000000000004dc [vdso:0000007fb7737000]
#06 pc 0000000000002730 /system/bin/cnss-daemon
#07 pc 0000000000002058 /system/bin/cnss-daemon
#08 pc 000000000001a7d8 /system/lib64/libc.so (__libc_init+88)
#09 pc 0000000000001e40 /system/bin/cnss-daemon
1、addr2line找问题代码行:
addr2line -e cnss-daemon -f (pc地址)
执行命令
prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android-addr2line -e out/target/product/msm8953_64_box3/obj/EXECUTABLES/cnss-daemon_intermediates/PACKED/cnss-daemon -f 0000000000002a4c
wsvc_debug_init
/proc/self/cwd/vendor/qcom/proprietary/wlan/cnss-daemon/debug.c:139
定位代码在文件debug.c,函数wsvc_debug_init的139行。
debug.c文件
static void wsvc_debug_sigsegv_handler(int signum)
{
wsvc_printf_err("SIGSEGV Crashed! %d\n", signum);
abort(); // 139行
return;
}
cnss-daemon截取了signal,看不到真正崩溃的位置,拿掉signal截取部分,复现问题,获取tombstone。
tombstone片段:
Fatal signal 11 (SIGSEGV), code 1,
fault addr 0x8015912764 in tid 19936 (cnss-daemon)
继续使用addr2line找崩溃的代码行。
nl_loop_process_msg
vendor/qcom/proprietary/wlan/cnss-daemon/nl_loop.c:261
(图:修改前后对比差异)
崩溃在函数NLMSG_OK:
宏NLMSG_OK(nlh,len)用于判断消息是否有len这么长。
#define NLMSG_OK(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(sizeof(struct nlmsghdr)))
从函数NLMSG_OK 判断nlh指向非法内存地址,nlh从NLMSG_NEXT取到。宏NLMSG_NEXT(nlh,len)用于得到下一个消息的首地址,同时len也减少为剩余消息的总长度。
#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
(struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
当len<=(nlh)->nlmsg_len,获取nlh指向非法地址。
获取nlh前比较len和nlh->nlmsg_len。
if (u_len <= NLMSG_ALIGN(nlh->nlmsg_len)) {
wsvc_printf_err("%s: no enough message, len: %u, nlmsg_len: %u",
__func__,
u_len, nlh->nlmsg_len);
break;
}
nlh = NLMSG_NEXT(nlh, u_len);