模拟kernel panic并打印堆栈信息

在kernel中,有一个函数可以用来产生panic,就是panic()函数。
本文主要讲述如何模拟产生panic以及输出堆栈信息。


模拟kernel panic

以下两种方法可以产生kernel panic。

  • 方法1:使用panic()函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <linux/delay.h>

static int panic_test_init(void)
{
printk("in %s, line = %d starttttt\n", __func__, __LINE__);
panic("this code test panic");
printk("in %s, line = %d endddddddddd\n", __func__, __LINE__);
return 0;
}

static void panic_test_exit(void)
{
printk("exit panic_test\n");
}

module_init(panic_test_init);
module_exit(panic_test_exit);

MODULE_LICENSE ("GPL");
MODULE_AUTHOR("XXX Project");
MODULE_DESCRIPTION("panic test driver");
  • 方法2:使用sysrq-trigger来出发panic
    1
    # ehco c > /proc/sysrq-trigger

设定发生kernel panic后重启

当加载上述ko的时候,没有什么log输出,也不会重启。可以通过设定/proc/sys/kernel/panic的值为x,当产生panic后,经过x秒会重启。

关于这些文件的详细解释,可以参照:<Kernel_Dir>Documentation/sysctl/kernel.txt


产生backstrace

有时候发生panic,并没有堆栈信息输出,是由于kernel没有打开debug开关。
如果想要输出堆栈信息,必须打开CONFIG_DEBUG_BUGVERBOSE,如何打开这个宏,参照它的依赖关系:<Kernel_Dir>lib/Kconfig.debug

1
2
3
4
5
6
7
8
config DEBUG_BUGVERBOSE
bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EXPERT
depends on BUG && (GENERIC_BUG || HAVE_DEBUG_BUGVERBOSE)
default y
help
Say Y here to make BUG() panics output the file name and line number
of the BUG call as well as the EIP and oops trace. This aids
debugging but costs about 70-100K of memory.

必须设置CONFIG_BUG=y。当设置CONFIG_DEBUG_BUGVERBOSE=y之后,发生panic,打印出来的backtrace如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[   19.352682] in panic_test_init, line = 11 starttttt
[ 19.358702] Kernel panic - not syncing: this code test panic
[ 19.364715] CPU: 2 PID: 167 Comm: insmod Not tainted 4.1.15 #15
[ 19.370637] Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
[ 19.377166] Backtrace:
[ 19.379631] Function entered at [<40012e18>] from [<4001302c>]
[ 19.385466] r7:4059cba8 r6:4057edc4 r5:4057edc4 r4:00000000
[ 19.391185] Function entered at [<40013014>] from [<4045e4ec>]
[ 19.397020] Function entered at [<4045e460>] from [<4045d900>]
[ 19.402855] r7:4059cba8 r6:bcd7b140 r5:3f02a1e0 r4:4059cba8
[ 19.408573] Function entered at [<4045d85c>] from [<3f02a030>]
[ 19.414407] r3:00000000 r2:00000000 r1:00000002 r0:3f02a0ac
[ 19.420125] r7:3f02a124
[ 19.422675] Function entered at [<3f02a000>] from [<40009780>]
[ 19.428509] Function entered at [<40009674>] from [<4045dd20>]
[ 19.434343] r10:3f02a0dc r9:3f02a0e8 r8:00000000 r7:3f02a124 r6:bcd7b140 r5:3f02a1e0
[ 19.442248] r4:3f02a0dc
[ 19.444797] Function entered at [<4045dcbc>] from [<40095400>]
[ 19.450631] r6:bc73a0a8 r5:3f02a1e0 r4:bcc89f40
[ 19.455293] Function entered at [<40093ea8>] from [<400956d4>]
[ 19.461127] r10:00000000 r9:c0965a40 r8:3ebf7724 r7:bcc88000 r6:00f1f950 r5:00000000
[ 19.469033] r4:00000a40
[ 19.471581] Function entered at [<400955a0>] from [<4000f7e0>]
[ 19.477416] r9:bcc88000 r8:4000f984 r7:00000080 r6:00000a40 r5:00000003 r4:22384d14

这样看不出啥具体的内容,发现之所以这样打印,是因为没有设置CONFIG_KALLSYMS=y。参照如下:

1
2
3
4
5
6
7
8
9
10
11
12
//<Kernel_Dir>/arch/arm/kernel/traps.c
void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame)
{
#ifdef CONFIG_KALLSYMS
printk("[<%08lx>] (%ps) from [<%08lx>] (%pS)\n", where, (void *)where, from, (void *)from);
#else
printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from);
#endif

if (in_exception_text(where))
dump_mem("", "Exception stack", frame + 4, frame + 4 + sizeof(struct pt_regs));
}

关于这部分的信息,可以参照:http://tinylab.org/find-out-the-code-line-of-kernel-panic-address/

Title:模拟kernel panic并打印堆栈信息

Author:Victor Huang

Time:2019-03-17 / 16:03

Link:http://wowothink.com/5364ebaa/

License: Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0)