什么是Oops
Oops在字面上的意思就是“哎呀,不小心”表示把事情搞砸了,所以当内核发出这个消息的时候就表示内核出了一些问题了。
Oops有何用
内核打印出的Oops信息能够帮助我们很快得追查到错误得源头。
不过需要我们配置内核得时候打开相应的配置,这样就能打开函数的调用栈回溯信息,不过如果没有这个信息我们提供Oops其它信息也能找到源头,不过就是没那么直观了。
要让内核出错时能够打印栈回溯信息,编译内核时要增加“-fno-omit-frame-pointer”选项,这可以通过配置 CONFIG_FRAME_POINTER 来实现。查看内核目录下的配置文件.config,确保 CONFIG_FRAME_POINTER 已经被定义,如果没有,执行“make menuconfig”命令重新配置内核。CONFIG_FRAME_POINTER 有可能被其他配置项自动选上。
示例
我们通过在内核中指针的解引用来引起Oops
driver.c
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/tty.h>
#include <linux/ratelimit.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/serial_8250.h>
#include <linux/nmi.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/pm_runtime.h>
#include <linux/io.h>
#include <linux/fs.h>//新字符设备驱动编写步骤
/*1.module_init,module_exit3.alloc_chrdev_region4.创建fops,cdev_init5.cdev_add6.创建类7.创建设备节点
*/struct new_struct{dev_t devid; /* 设备号 */struct cdev cdev; /* cdev */struct class *class; /* 类 */struct device *device; /* 设备 */int major;int minor;
};
struct new_struct new;wait_queue_head_t rwq,wwq;
int havedata=0;int new_open (struct inode *inode, struct file *file)
{//调试Oopschar *Oops = NULL;*Oops = "Oops";printk("-----------%s-----------%s-------------%d-----------\n",__FILE__,__FUNCTION__,__LINE__);return 0;
}
ssize_t new_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{printk("-----------%s-----------%s-------------%d-----------\n",__FILE__,__FUNCTION__,__LINE__);return 0;
}int new_release (struct inode *inode, struct file *file)
{printk("-----------%s-----------%s-------------%d-----------\n",__FILE__,__FUNCTION__,__LINE__);return 0;
}static struct file_operations new_ops={.open = new_open,.release = new_release,.read = new_read,.owner = THIS_MODULE,
};
static int __init new_init(void)
{int i;printk("-----------%s-----------%s-------------%d-----------\n",__FILE__,__FUNCTION__,__LINE__);alloc_chrdev_region(&new.devid , 0, 1, "new");//获得主设备号new.major = MAJOR(new.devid);cdev_init(&new.cdev,&new_ops);cdev_add(&new.cdev, new.devid, 1);new.class = class_create(THIS_MODULE, "new_cls");if (IS_ERR(new.class)) {return PTR_ERR(new.class);}new.device = device_create(new.class, NULL, MKDEV(new.major,i), NULL, "new%d",1);//创建DEVICE_NUM个设备节点if (IS_ERR(new.device)) {return PTR_ERR(new.device);}return 0;
}//创建主设备号
/*一个driver对应一个主设备号,device资源中的每一项对应一个节点
*/
static void __exit new_exit(void)
{int i;printk("-----------%s-----------%s-------------%d-----------\n",__FILE__,__FUNCTION__,__LINE__);device_destroy(new.class,MKDEV(new.major,1));//销毁DEVICE_NUM个设备节点class_destroy(new.class);cdev_del(&new.cdev);unregister_chrdev_region(new.devid,1);
}module_init(new_init);
module_exit(new_exit);MODULE_LICENSE("GPL");
test.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>int main(int argc, char **argv)
{int fd;char *buf;char status = 0;if(argc!=2){printf("error!\r\n");return -1;}fd = open(argv[1],O_RDWR);if(fd<0){printf("open error!\n");return -1;}read(fd,&status,sizeof(status));close(fd);
}
当insmod之后再用test打开对应设备,就会触发Oops(因为是再open中解引用)
对应Oops信息:
[85302.059107] Oops: 0002 [#1] SMP NOPTI
[85302.059109] Modules linked in: driver(OE) nls_utf8 isofs rfcomm vmw_vsock_vmci_transport vsock bnep snd_ens1371 snd_ac97_codec crct10dif_pclmul crc32_pclmul gameport ac97_bus ghash_clmulni_intel snd_pcm pcbc aesni_intel aes_x86_64 snd_seq_midi vmw_balloon btusb crypto_simd btrtl btbcm glue_helper btintel snd_seq_midi_event bluetooth snd_rawmidi cryptd snd_seq snd_seq_device snd_timer ecdh_generic joydev snd input_leds serio_raw soundcore vmw_vmci i2c_piix4 shpchp binfmt_misc mac_hid parport_pc ppdev nfsd auth_rpcgss nfs_acl lockd grace sunrpc lp parport autofs4 hid_generic usbhid hid vmwgfx mptspi mptscsih ttm mptbase drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops ahci psmouse libahci scsi_transport_spi e1000 drm pata_acpi
[85302.059140] CPU: 2 PID: 10427 Comm: test Tainted: G OE 4.15.0-142-generic #146~16.04.1-Ubuntu
[85302.059141] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 11/12/2020
[85302.059143] RIP: 0010:new_open+0x12/0x40 [driver]
[85302.059144] RSP: 0018:ffffbacd4067bbd0 EFLAGS: 00010286
[85302.059145] RAX: ffffffffc089d024 RBX: ffffffffc089e000 RCX: 0000000000000034
[85302.059145] RDX: 0000000000000001 RSI: ffff9b4930b4a600 RDI: ffff9b489fc7f3b8
[85302.059146] RBP: ffffbacd4067bc20 R08: 0000000000000000 R09: 0000000000000000
[85302.059147] R10: 00000000000000f3 R11: ffff9b4865cd8578 R12: ffffffffc089e4a8
[85302.059147] R13: ffff9b489fc7f3b8 R14: ffff9b4930b4a600 R15: ffffffffac8c9d00
[85302.059150] FS: 00007fe71a249700(0000) GS:ffff9b4939680000(0000) knlGS:0000000000000000
[85302.059151] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[85302.059152] CR2: 0000000000000000 CR3: 0000000134290000 CR4: 0000000000340ee0
[85302.059153] Call Trace:
[85302.059161] ? chrdev_open+0xc2/0x1b0
[85302.059163] do_dentry_open+0x25a/0x390
[85302.059165] ? cdev_put+0x30/0x30
[85302.059166] vfs_open+0x4f/0x80
[85302.059167] path_openat+0x305/0x1570
[85302.059169] ? unlock_page_memcg+0x12/0x20
[85302.059172] ? page_add_file_rmap+0x5a/0x220
[85302.059175] ? filemap_map_pages+0x3dc/0x3f0
[85302.059176] do_filp_open+0x99/0x110
[85302.059177] ? __check_object_size+0x114/0x1a0
[85302.059179] ? __alloc_fd+0x46/0x170
[85302.059181] do_sys_open+0x12d/0x290
[85302.059182] ? do_sys_open+0x12d/0x290
[85302.059183] SyS_open+0x1e/0x20
[85302.059186] do_syscall_64+0x73/0x130
[85302.059189] entry_SYSCALL_64_after_hwframe+0x41/0xa6
[85302.059190] RIP: 0033:0x7fe719d71140
[85302.059191] RSP: 002b:00007ffcdf74cb28 EFLAGS: 00000246 ORIG_RAX: 0000000000000002
[85302.059192] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fe719d71140
[85302.059193] RDX: 00007ffcdf74cc50 RSI: 0000000000000002 RDI: 00007ffcdf74d1e0
[85302.059193] RBP: 00007ffcdf74cb50 R08: 0000000000400790 R09: 00007fe71a054af0
[85302.059194] R10: 000000000000069d R11: 0000000000000246 R12: 0000000000400570
[85302.059195] R13: 00007ffcdf74cc30 R14: 0000000000000000 R15: 0000000000000000
[85302.059196] Code: <88> 04 25 00 00 00 00 48 c7 c2 f8 d0 89 c0 48 c7 c6 40 d0 89 c0 48
[85302.059203] RIP: new_open+0x12/0x40 [driver] RSP: ffffbacd4067bbd0
[85302.059204] CR2: 0000000000000000
[85302.059206] ---[ end trace 998a993bf62d1b33 ]---
其中Call Trace:下的就是调用栈。
也可以从RIP: 0010:new_open+0x12/0x40 [driver]直接看出是哪个函数发生错误。