简单字符驱动程序崩溃
我正在制作一个简单的字符驱动程序,它假定写入到我的字符设备“/ dev/coffee_bean”中,读取时应显示字符串“Hi There!”。在控制台。我通过“cat/dev/coffee_bean”从设备读取,而是我的系统崩溃并重置。贝娄是我的源代码。感谢帮助。简单字符驱动程序崩溃
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/types.h>
#include <linux/completion.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/semaphore.h>
MODULE_LICENSE("Dual BSD/GPL");
#define DEVICE_NAME "coffee_grinds"
#define COUNT 4
#define FIRST_MINOR 0
#define CONST_QUANTUM 4000
#define CONST_QSET 4000
int test;
module_param(test, int, S_IRUGO);
struct my_char_structure{
struct cdev my_cdev;
struct semaphore sem;
unsigned int access_key;
unsigned long size;
};
static dev_t dev_num;
int dev_open(struct inode *in_node, struct file *filp){
struct my_char_structure *my_dev;
my_dev = container_of(in_node->i_cdev, struct my_char_structure, my_cdev);
filp->private_data = my_dev;
return 0;
}
int dev_release(struct inode *inode, struct file *filp){
return 0;
}
ssize_t dev_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp){
struct my_char_structure *my_dev = filp->private_data;
ssize_t retval = -ENOMEM; /* value used in "goto out" statements */
char *my_string;
int counting;
printk(KERN_ALERT "Write was accessed, Lol");
if (down_interruptible(&my_dev->sem))
return -ERESTARTSYS;
my_string = kmalloc(count,GFP_KERNEL);
counting = copy_from_user(my_string,buff,count);
printk(KERN_ALERT "You wrote %s",my_string);
kfree(my_string);
up(&my_dev->sem);
printk(KERN_ALERT "We wrote %d bytes",counting);
return retval;
// Here is some experimental code
}
ssize_t dev_read(struct file *filp, char __user *buff, size_t count, loff_t *offp){
struct my_char_structure *my_dev = filp->private_data;
ssize_t retval = 0;
char *my_string;
printk(KERN_ALERT "Read was accessed Lol");
if (down_interruptible(&my_dev->sem))
return -ERESTARTSYS;
my_string = "Hi there!";
copy_to_user(buff,my_string,10);
up(&my_dev->sem);
return retval;
}
struct file_operations fops = {
.owner = THIS_MODULE,
.read = dev_read,
.write = dev_write,
.open = dev_open,
.release= dev_release,
};
int start_mod(void){
//Because we are dealing with a fictitious device, I want
//the driver to create my two devices with arbitrarly
//assigned major numbers.
static struct my_char_structure Dev;
static struct my_char_structure *my_dev = &Dev;
int err;
alloc_chrdev_region(&dev_num, FIRST_MINOR, COUNT, DEVICE_NAME);
sema_init(&(my_dev->sem),1);
cdev_init(&(my_dev->my_cdev), &fops);
my_dev->my_cdev.owner = THIS_MODULE;
my_dev->my_cdev.ops = &fops;// fops is my file operations struct
err = cdev_add(&my_dev->my_cdev, dev_num, COUNT);
if(err)
printk(KERN_ALERT "There was an error %d.",err);
printk(KERN_ALERT " insmod to major number %d",MAJOR(dev_num));
return 0;
}
void end_mod(void){
unregister_chrdev_region(dev_num, COUNT);
}
module_init(start_mod);
module_exit(end_mod);
看着你现在发布的完整代码,我没有看到任何明显的崩溃原因。你正在做的事情在其他驱动程序中完成。
只是一些观察。
有很少的错误检查。这会咬你,因为成功执行下一件事通常取决于成功执行前一件事情的先决条件。
另外,如果确实读取函数的调用没有发生崩溃,您会发现它不会产生任何内容,因为您返回0
并且不会移动偏移量!大多数程序会将零回报解释为文件结束。
您必须遵守传入的缓冲区大小,否则会损坏用户空间。 cat
程序可能不会执行read(fd, buf, 5);
(注意,5小于您要复制到用户空间的10个字节),但可能会有一些。
顺便说一句,copy_to_user
和copy_from_user
是你必须测试失败也并返回-EFAULT
到用户空间,告诉它在一个坏区通过调用应用程序的功能。
要调试崩溃,有两种传统方法。一个是添加更多的printk语句。在没有分支的代码块中,并且打印没有被缓冲,如果一个print语句在崩溃之前产生输出,而另一个没有,则崩溃位于它们之间。
另一种技术是解释崩溃转储:机器寄存器,指令指针周围的字节,调用跟踪等。如果您从崩溃中获得该信息,则通常可以确定崩溃的位置,并通过查看机器代码和寄存器的值,你可以猜测C变量和数据结构在做什么。
祝你好运。
在达到dev_read
之前,事情可能会出错。你有没有在控制台上看到你的消息KERN_ALERT
?
显然这并不是所有的源代码,因为模块已初始化,字符设备已注册,并且还有其他功能,如打开例程。是什么让你认为这个错误在dev_read
之中,仅仅是因为从设备上读取设备会导致设备崩溃?
sizeof(my_string)
是sizeof(char *)
这是4或8.您正在使用指针的大小。如果你使用的是64位内核,那么当你进行调试的时候,你最多可以得到Hi there
而不是!
。 :)
I.e.很明显,您可能会从C基础知识中的教程中获益,例如数组和指针之间的区别。
哦,你是我在指针的大小之前犯过这个错误,我忘记了这一点。我会加入其他来源。 – 2012-03-13 01:24:12
只看代码就看不出来,你可以自己帮忙检查错误。在条件可能失败的所有地方,您可以使用KERN_ERR打印错误,并且可以添加goto OUT(其中OUT:返回-1),以便尽可能减少崩溃。这可以明确告诉您错误的位置。首先创建只写功能,并检查它是否正常工作,然后开始制作dev_read函数。
感谢Kaz,我调试了我的程序,崩溃是由于我为我的字符串分配内存的方式。设备不再崩溃,但是我得到了来自copy_to_user()函数的段错误。我怀疑我得到这个错误,因为我没有使用传递的count变量。感谢捆绑花时间看我的代码! – 2012-03-13 04:53:50
但你在写程序中有分配;你说它在阅读时崩溃了。写例程中的主要问题是'kmalloc'在它可以返回的块的大小方面非常有限。它返回物理上连续的页面(这是一个宝贵的资源)。但是,对“读”的争论可能非常大。即一般来说,使用用户空间中的值作为'kmalloc'大小(除了知道它在做什么的根特权服务器程序之外)并不是一个好主意。即使有很多内存,也要做好空回的准备。 – Kaz 2012-03-13 07:16:26
嗯,我只想打印出一些像“Hi There”这样的小东西,并用kmalloc分配字节,这样可以防止它崩溃。现在我不想寻找一个功能齐全的驱动程序来实现写入。我只是想先阅读才能工作。这是我写的第一个实现读/写的驱动程序。我在2周前才开始学习。 – 2012-03-13 20:11:34