如何使用GDB分析KE问题
文摘 无标签 2020-02-8 阅读:6283[DESCRIPTION]
有些模块类KE,需要由对应模块owner处理,但是有时从程序流程可能看不出具体原因,这时就需要掌握简单的KE分析基础。
gdb是开源调试工具,可以在网上搜到很多信息,在此列出Windows环境下分析KE必要步骤,仅供参考。
[SOLUTION]
1.安装Windows调试环境,最好从MOL上下载GAT工具,再从网上下载python环境。
打开GAT安装路径下的prebuiltpythonbinaarch64-linux-android-gdb.exe调试64 bit kernel。
如果要调试32bit kernel则使用arm-linux-androideabi-gdb.exe
2.准备好KE.dbg和对应版本的vmlinux。
【KE.dbg路径如下:】
data/aee_exp ; mtklog/aee_exp ; mtklog/aee_expbackup
注意:如果开不了机,从uart log中发现有KE问题导致的重启,需要回读expdb分区,提供给MTK。参考[FAQ19639] How to readback expdb。
【vmlinux路径如下:】
alps/out/target/product/$Projectname/obj/KERNEL_OBJ/vmlinux
注意:要同一次编译生成,参考[FAQ06985]KE发生后如何判断vmlinux和log是否匹配。
3.在打开的gdb调试窗口中输入下述命令,做好调试前的加载工作:
(1)cd 解开的DB路径,如fatal.00.KE.dbg.DEC
(2)file vmlinux所在路径
(3)core SYS_MINI_DUMP所在路径,在(1)中已经cd过,所以就是当前路径
(gdb) cd D:\fatal.00.KE.dbg.DEC
Working directory D:\fatal.00.KE.dbg.DEC.
(gdb) file symbols/vmlinux
Reading symbols from symbols/vmlinux...done.
(gdb) core SYS_MINI_RDUMP
warning: core file may not match specified executable file.
Core was generated by `console=tty0 console=ttyMT0,921600n1 root=/dev/ram vmalloc=496M androidboot.har'.
#0 slab_alloc_node (addr=<optimized out>, node=<optimized out>, gfpflags=<optimized out>, s=<optimized out>)
at /mnt/one/bak/PROJECT/MT6753/F2_TMCELL_0208/kernel-3.18/mm/slub.c:2512
2512 /mnt/one/bak/PROJECT/MT6753/F2_TMCELL_0208/kernel-3.18/mm/slub.c: No such file or directory.
[Current thread is 1 (LWP 101)]
4.接下来是一些简单必要的调试命令,大家可以从公开网站查询具体含义与使用方法
主要思路如下:
(1)查看KE backtrace调用关系是否正常,有些backtrace存在明显的不对应关系。
一方面怀疑是客制化code,一方面怀疑可能是函数跳转地址异常。这里会用到命令:bt。
(gdb) bt
#0 slab_alloc_node (addr=<optimized out>, node=<optimized out>, gfpflags=<optimized out>, s=<optimized out>)
at /mnt/one/bak/PROJECT/MT6753/F2_TMCELL_0208/kernel-3.18/mm/slub.c:2512
#1 slab_alloc (addr=<optimized out>, gfpflags=<optimized out>, s=<optimized out>)
at /mnt/one/bak/PROJECT/MT6753/F2_TMCELL_0208/kernel-3.18/mm/slub.c:2560
#2 kmem_cache_alloc (s=0x1 <__vectors_start>, gfpflags=3233115096)
at /mnt/one/bak/PROJECT/MT6753/F2_TMCELL_0208/kernel-3.18/mm/slub.c:2565
#3 0xc0813bc8 in kmem_cache_alloc_node (node=<optimized out>, flags=<optimized out>, s=<optimized out>)
at /mnt/one/bak/PROJECT/MT6753/F2_TMCELL_0208/kernel-3.18/include/linux/slab.h:304
(2)从最后一帧异常地址所在的汇编查看异常地址来源是访问了哪个寄存器?这里会用到命令:f 0和disas。
(gdb) f 0
#0 slab_alloc_node (addr=<optimized out>, node=<optimized out>, gfpflags=<optimized out>, s=<optimized out>)
at /mnt/one/bak/PROJECT/MT6753/F2_TMCELL_0208/kernel-3.18/mm/slub.c:2512
2512 in /mnt/one/bak/PROJECT/MT6753/F2_TMCELL_0208/kernel-3.18/mm/slub.c
(gdb) disas
Dump of assembler code for function kmem_cache_alloc:
0xc01396e4 <+0>: mov r12, sp
0xc01396e8 <+4>: push {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr, pc}
0xc01396ec <+8>: sub r11, r12, #4
0xc01396f0 <+12>: sub sp, sp, #28
0xc01396f4 <+16>: mov r12, sp
0xc01396f8 <+20>: bic r12, r12, #8128 ; 0x1fc0
0xc01396fc <+24>: movw r8, #18296 ; 0x4778
0xc0139700 <+28>: bic r9, r12, #63 ; 0x3f
0xc0139704 <+32>: movt r8, #49369 ; 0xc0d9
0xc0139708 <+36>: mov r7, lr
0xc013970c <+40>: mov r6, r0
0xc0139710 <+44>: mov r5, r1
0xc0139714 <+48>: str r12, [r11, #-48] ; 0xffffffd0
0xc0139718 <+52>: mov r0, #1
0xc013971c <+56>: bl 0xc004df08 <preempt_count_add>
0xc0139720 <+60>: ldr r4, [r6]
0xc0139724 <+64>: bl 0xc02a3a14 <debug_smp_processor_id>
0xc0139728 <+68>: ldr r10, [r8, r0, lsl #2]
0xc013972c <+72>: add r3, r4, r10
=> 0xc0139730 <+76>: ldr r3, [r3, #4]; 程序挂在这里
(3)查看此时寄存器的值到底是多少?这里会用到命令:i reg或i reg $指定寄存器。
(gdb) i reg //查看所有寄存器值
r0 0x1 1
r1 0xc0b56bd8 3233115096
r2 0xc0813bc8 3229694920
r3 0xa0d14a00 2698070528
r4 0xc0d6ea00 3235310080
r5 0x4d0 1232
r6 0xdb401e00 3678412288
r7 0xc0813bc8 3229694920
r8 0xc0d94778 3235465080
r9 0xd92f0000 3643736064
r10 0xdffa6000 3757727744
r11 0xd92f1ccc 3643743436
r12 0x1 1
sp 0xd92f1c88 0xd92f1c88
lr 0xc02a3a34 3223992884
pc 0xc0139730 0xc0139730 <kmem_cache_alloc+76>
cpsr 0x200f0013 537853971
(gdb) i reg $r3 $r4 //只看r3和r4
r3 0xa0d14a00 2698070528
r4 0xc0d6ea00 3235310080
(4)看到异常地址来源后,需要往前追汇编,看是谁给异常寄存器赋值的。
此时结合C code和汇编找出异常寄存器对应的变量,然后查看变量值。这里会用到命令:p 变量名。
(5)如果是传进来的函数参数本身就已经异常,就要看上一帧参数当时的值,这是需要切换当前调试帧。这里会用到命令:up。
(gdb) p s //查看C code中的s变量的值,可惜被编译器优化看不到了。
$1 = <optimized out>
(gdb) up //因此查看上一帧(也可以用f 1来指定当前帧),看传下来s是多少,一直往前追踪
#1 slab_alloc (addr=<optimized out>, gfpflags=<optimized out>, s=<optimized out>)
at /mnt/one/bak/PROJECT/MT6753/F2_TMCELL_0208/kernel-3.18/mm/slub.c:2560
2560 in /mnt/one/bak/PROJECT/MT6753/F2_TMCELL_0208/kernel-3.18/mm/slub.c
(6)重复(2)~(5)直到追踪到异常来源。