首页
社区
课程
招聘
[原创][原创]在调试器下看Panic机制及oops信息分析
2021-7-26 17:42 5108

[原创][原创]在调试器下看Panic机制及oops信息分析

2021-7-26 17:42
5108

    穷理者,因其所已知而及其所未知,因其所已达而及其所未达。人之良知,本所固有。然不能穷理者,只是足于已知已达,而不能穷其未知未达,故见得一截,又不曾见得一截,此其所以于理未精也。然仍须功夫日日增加。今日既格得一物,明日又格得一物,工夫更不住地做。如左脚进得一步,右脚又进一步;右脚进得一步,左脚又进,接续不已,自然贯通。

 

借钟馗与GDK7之合力捉”鬼“,保佑代码平安顺利、风调雨顺,再无”鬼怪出现“。

oops

    当你见到oops这个单词时,第一时间想到的或许就是“哎呦*****“;同样的当你在Linux内核中碰到oops时,你也会第一时间说出“哎呦*****”,因为此时你很清楚的明白Linux内核陷入到了一场不算小的意外当中。

    Linux内核发生异常后会输出的oops信息(异常相关的信息),oops信息可以辅助我们进行调试,从而找出导致Linux内核出现异常的问题所在。

    oops信息内没有源代码信息,因为oops信息的产生不依赖dwarf符号,所以不能产生源代码信息。

    oops-tracing.txt:介绍oops信息的格式;oops-tracing.txt可以在内核源代码文件夹中的Documentation文件夹内找到,如图下图所示。

Panic机制与oops的关系

Linux内核碰到某些不严重的oops后,内核仍然可以正常运行,但是如果Linux内核碰到一些比较严重的oops后,内核将无法继续运行,同时Linux内核会进入Panic机制,而Panic机制会使系统重启。

Panic机制的关系与oops的关系如下图所示。

调试Panic

1号CPU的状况

    将附件中的llaolao.zip复制到GDK7当中,并解压文件(具体位置无要求);进入解压得到的llaolao文件夹(cd /......),然后编译模块(make)。

//llaolao模块:模拟内核态栈溢出,无限递归。


    将GDK7中llaolao.ko复制到调试主机(与vmlinux处于同一文件夹下),通过Nano Code将GDK7断下来,并加载符号文件(.sympath ......)及源代码文件(.srcpath ......);然后手动加载一下llaolao模块,输入.reload,并查看llaolao模块是否存在;让GDK7重新跑起来。


    在GDK7端进入管理员模式(sudo su),在命令行内输入echo 200 > /sys/kernel/debug/llaolao/age,如果发现光标停在下一行不动(如果等待一段时间,会发现GDK7越来越不正常,异常卡顿直到最后直接动不了了)则代表执行成功,并且LInux内核进入到Panic机制当中。


    在Nano Code中断GDK7(此时为0号CPU)。


    切换到1号CPU下查看栈回溯(如下图所示);但切换到1号CPU之后printk.c会自动打开(猜测一下,就是1号CPU在执行llaolao吗?);继续查看栈回溯,此时我们可以很清楚的知道llaolao在无限递归的过程中不断调用printk,使Linux内核陷入到了Panic机制当中。

//切换CPU:~Xs;X为CPU的号数,如果是2号CPU,则X=2。

     由于等待内核栈空间耗完的时间过长,因此我将GDK7重启,并选择使用触发空指针的形式来使Linux内核陷入Panic机制。


    重启后,断下GDK7并加载符号及源代码;给panic函数设置断点(bp);恢复GDK7。


    在GDK7端的命令行内输入在GDK7端进入管理员模式(sudo su),在命令行内输入echo nullp > /proc/llaolao;如果输入后没有任何输出,则按下方步骤设置内核选项后再重新输入echo nullp > /proc/llaolao。

//1.gedu@gdk:/proc/sys/kernel$ sudo su

//2.root@gdk:/proc/sys/kernel# echo 1 > panic_on_oops


    如果echo nullp > /proc/llaolao命令执行成功,则此时GDK7端会立刻卡死,转头看看Nano Code,果不其然断点命中,panic.c自动打开,此时是0号CPU正在执行,如下图所示。

    查看栈回溯,如下图所示。

Child-SP          RetAddr           Call Site
ffffac05`c28efb78 ffffffff`9b8337ba lk!panic+0x28 [/build/linux-hwe-zHO4ZF/linux-hwe-5.0.0/kernel/panic.c @ 162]
ffffac05`c28efb78 00000000`00000880 lk!oops_end+0xda [/build/linux-hwe-zHO4ZF/linux-hwe-5.0.0/arch/x86/kernel/dumpstack.c @ 354]

0、2及3号CPU的状况(重启前)

    在0号CPU下查看栈回溯(如下图所示);很可惜并没有捕捉到相应的栈回溯,显然不是0号CPU在执行llaolao。

    切换到2号CPU下查看栈回溯(如下图所示);如0号CPU一样并没有捕捉到相应的栈回溯,显然不是2号CPU在执行llaolao。

    切换到3号CPU下查看栈回溯(如下图所示);当切换到3号CPU之后会自动弹出common.c,同时查看栈回溯,不难看出此时3号CPU正在执行系统调用,因此自然也就不是3号CPU在执行llaolao。

oops信息分析

第1部分:概要介绍

[  192.174205] reboot: Restarting system
[    0.000000] tsc: Fast TSC calibration failed
[    0.878127] BUG: unable to handle kernel NULL pointer dereference at 00000008
[    0.881181] IP: [<c155b954>] kallsym_init+0x134/0x260
[    0.882117] *pdpt = 0000000000000000 *pde = f000ff53f000ff53
[    0.883045] Oops: 0000 [#1] SMP
[    0.885233] Modules linked in:
[    0.885703] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.11.0gedu #9
[    0.890017] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
[    0.894979] task: df480000 ti: df44a000 task.ti: df44a000
[    0.898298] EIP: 0060:[<c155b954>] EFLAGS: 00010246 CPU: 0
[    0.903263] EIP is at kallsym_init+0x134/0x260
[    0.909127] EAX: 00000000 EBX: c17f6ab8 ECX: 00000009 EDX: 00000000
[    0.911950] ESI: c17f626c EDI: c17f672c EBP: df44beac ESP: df44be90
[    0.916195]  DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
[    0.916973] CR0: 8005003b CR2: 00000008 CR3: 01a62000 CR4: 000406f0
[    0.917816] DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
[    0.920026] DR6: fffe0ff0 DR7: 00000400

 

    行1:代表在192.174205秒时,重启系统。

    行2:日志信息;快速tsc校准失败

//tsc是一种高精度的cpu时钟

    行3:Bug信息;不能访问空指针,空指针的地址为00000008。

//空指针不可以访问;0及小于一定数值的地址都是是空指针;故00000008也是空指针。

    行4:IP信息;显示做非法访问的函数的所在位置信息。

    行5:页表信息。

    行6:oops信息;SMP-对称多处理。

    行7-8:模块信息;显示做非法访问的函数的所在模块及进程的相关信息。

    行9:硬件信息。

    行10:task指针的地址信息。

    行11:显示做非法访问的函数的所在位置信息(与IP信息内的内容一致)及寄存器信息。

    行12:显示符号信息(由做非法访问的函数的所在位置信息翻译得到)。

    行13-18:寄存器信息;特别注意CR2,因为CR2存有CPU访问错误地址时的地址信息。

//如果启用调试选项输出CR2,CR2的数值可能改变。

第2部分:重要的栈回溯

    CPU想要运行一定要有栈空间,而栈空间里则会记录函数返回地址信息(线程的执行轨迹)、参数信息及局部变量信息等内容。

    输出oops信息时,内核会自动寻找栈空间内的函数返回地址信息,并会尝试翻译地址信息为函数名。

    函数名前的问号代表内核无法不能确定此函数是否执行过,需要进一步的分析;代码如下所示。

void printk_address(unsigned long address, int reliable)
{
pr_cont(" [<%p>] %s%pB\n",
(void *)address, reliable ? "" : "? ", (void *)address);
}
[    0.924014] Stack:
[    0.926206]  c18655ce 00012fa6 c16c22d8 c170e174 00000000 00000105 c1a39cd4df44bef8
[    0.929478]  c19ceb1e c1864976 00000060 000080d0 00000301 de3a15a0 de3a15a000000000
[    0.935932]  df44bee8 c13fd5bb c1b3b23c 00000000 00000105 c1a39cd0 df44bef0c1551769
[    0.940598] Call Trace:
[    0.945476]  [<c19ceb1e>] fedcore_init+0x15/0x350
[    0.946233]  [<c13fd5bb>] ? __class_create+0x4b/0x70
[    0.946993]  [<c1551769>] ? create_extcon_class.part.2+0x19/0x30
[    0.949370]  [<c19ceb07>] ? extcon_class_init+0x13/0x15
[    0.950123]  [<c10020fc>] do_one_initcall+0xdc/0x1b0
[    0.956222]  [<c11c5583>] ? __proc_create+0xa3/0xe0
[    0.956953]  [<c19ceb09>] ? extcon_class_init+0x15/0x15
[    0.957707]  [<c1071243>] ? parse_args+0x283/0x480
[    0.960365]  [<c197dbe3>] kernel_init_freeable+0x11c/0x1b9
[    0.961339]  [<c197d514>] ? do_early_param+0x74/0x74
[    0.962062]  [<c1638eb0>] kernel_init+0x10/0xd0
[    0.963534]  [<c164f0f7>] ret_from_kernel_thread+0x1b/0x28
[    0.967251]  [<c1638ea0>] ? rest_init+0x70/0x70

第3部分:汇编指令

    显示出问题的汇编指令附件的机器码信息;根据出问题的指针地址信息得到。。

    <a1>:尖括号代表出问题的指针地址的机器码信息。

[    0.969798] Code: be 03 e8 10 f6 ff ff 85 c0 74 14 83 c3 01 0f be 03 e8 01 f6 ff ff 85 c0 75 f1 83 c3 01 eb e0 89 d8 83 e0 03 74 05 29 c3 83 c3 04 <a1> 08 00 00 00 89 1d 3c e5 b4 c1 89 5c 24 0c 31 db 89 7c 24 08
[    0.984078] EIP: [<c155b954>] kallsym_init+0x134/0x260 SS:ESP 0068:df44be90
[    0.987013] CR2: 0000000000000008

第4部分:结束标志

    oops信息的结束标志如下所示。

[    0.988500] ---[ end trace 27c8b114d5190fc5 ]---
[    0.989411] ata2.00: ATAPI: VBOX CD-ROM, 1.0, max UDMA/133
[    0.990510] ata2.00: configured for UDMA/33
[    0.992419] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000009
[    0.992419]
[    0.999444] atkbd serio0: Spurious ACK on isa0060/serio0. Some program might be trying to access hardware directly.

GDK7的介绍

GDK7通过专用调试电缆与调试目标进行连接,二者通过DCI协议进行通信,也不需要专用的ITP硬件就可以实现JTAG调试和系统追踪。

GDK7提供了一个完整的被调试目标系统,大大减少准备调试环境所需的时间,省去各种因为软件和硬件不兼容所带来的烦恼。与传统的ITP/XDP硬件调试器相比,GDK7的传输速度高达5Gbps,比XDPITP提高了10倍还多;可以把GDK7中的数据实时传输到调试主机内,让全量分析多线程软件的执行轨迹成为可能,当然GDK7的强大功能不局限于此。

其他说明

    若您有问题咨询及出现链接失效等其他情况请联系邮箱:birdring_NULL@outlook.com



[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

最后于 2021-7-28 16:52 被birdring编辑 ,原因: 更新调试Panic的部分
上传的附件:
收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回