LINUX KERNEL OOPS调试及实例分析(GDB OBJDUMP指令)
LINUX KERNEL OOPS调试及实例分析(GDB OBJDUMP指令)
内核模块文件OOPS.C
-
-
-
-
-
static void create_oops(void)
-
{
-
*(int *)0 = 0;
-
}
-
static int __init my_oops_init(void)
-
{
-
printk("oops from the module\n");
-
create_oops();
-
return (0);
-
}
-
static void __exit my_oops_exit(void)
-
{
-
printk("Goodbye world\n");
-
}
-
module_init(my_oops_init);
-
module_exit(my_oops_exit);
-
MODULE_LICENSE("GPL");
编译内核模块MAKEFILE
-
EXTRA_CFLAGS += -g
-
obj-m += oops.o
-
-
all:
-
$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD)
-
clean:
-
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
-
rm -f modules.order Module.symvers Module.markers
备注:
Makefile中EXTRA_CFLAGS += -g需要增加
编译内核模拟OOPS
安装模块INSMOD OOPS.KO,出现KILLED,由于故障不严重,未导致系统死机重启
DMESG查看信息可以看到OOPS信息如下
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
-
[
问题分析
OOPS信息分析
[ 933.023624] Oops: 0002 [#1] SMP PTI
0002 :是错误码
#1 :Oops发生的次数
This is the error code value in hex. Each bit has a significance of its own:
bit 0
== 0 means no page found, 1 means a protection faultbit 1
== 0 means read, 1 means writebit 2
== 0 means kernel, 1 means user-mode[#1]
— this value is the number of times the Oops occurred. Multiple Oops can be triggered as a cascading effect of the first one.
[ 933.023642] CPU: 1 PID: 4198 Comm: insmod Tainted: G OE 4.15.0-123-generic #126~16.04.1-Ubuntu
这个表示Oops是发生在CPU1上,当运行进程4198 insmod的时候出现的问题
关键信息如下,这里提示在操作函数my_oops_init的时候出现异常,偏移地址0x15
[ 933.023621] IP: my_oops_init+0x15/0x1000 [oops]
问题定位
从以上分析可以看出,最关键信息如下:
-
[
-
[
由此可以看出内核执行到my_oops_init+0x15/0x1000这个地址的时候出现异常,我们只需要找到这个地址对应的代码即可
格式为 +偏移/长度
my_oops_init指示了实在my_oops_init中出现的异常
0x15表示出错的偏移位置
0x1000表示my_oops_init函数的大小
方法一:GDB直接查看异常代码
由于是驱动出现的问题, 那么gdb直接调试驱动的 ko
文件, 如果是源内核出现的 OOPS
, 那么只能用 gdb
对 vmlinux(内核根目录下)
文件进行调试
-
gdb oops.ko或者gdb oops.o
-
l*(my_oops_init+0x15)
-
-
格式:
-
l*(函数名+偏移地址)或者(函数入口地址+偏移地址)
备注:
ko文件一定要是和报错的是ko是同一个,如果编译到内核可以使用.o文件,如下所示
可以看到gdb提示是第7行代码异常,此方法也适合内核Oops,只需要将ko文件替换为vmlinux文件即可
方法二:GDB反汇编代码获取地址直接转化对应源码
对于驱动来说, 可以从/sys/module/对应驱动名称/sections/.init.text
查找到对应的地址信息
-
cat /sys/module/oops/sections/.init.text
-
0xffffffffc0648000
-
gdb oops.ko
-
#加符号文件添加到调试器
-
add-symbol-file oops.o 0xffffffffc0648000
-
#将my_oops_init函数反汇编得到虚拟地址信息
-
disassemble my_oops_init
-
#列出对应代码信息
-
l*(函数名+偏移地址)
方法三:OBJDUMP反汇编
objdump -S oops.o
从报错log可以找到出错的机器码如下:
[ 933.023714] Code: <c7> 04 25 00 00 00 00 00 00 00 00 31 c0 5d c3 00 00 00 00 00 00 00
参考资料
https://cloud.tencent.com/developer/article/1463579
https://kernel.blog.csdn.net/article/details/73715860
本公司成本价甩卖工控主板,欢迎大家选购:
PCIE总线转八串口卡,PCIE总线转IO卡,瑞芯微3568板卡,寒武纪CE3226摄像头板卡,龙芯3A4000工控板卡,龙芯3A5000工控板卡,海光3250工控板卡,飞腾FT-2000/4板卡
联系方式:
电话、微信:15918785568 罗生
Email:13279654@qq.com
公众号:开发之美