我正在编写一个简单的可写字符设备驱动程序(2.6.32-358.el6.x86_64,在VirtualBox下),由于它尚未成熟,它往往会崩溃/冻结(段错误,无限循环)。
我正在测试它:$> echo "some data" > /dev/my_dev
,如果发生崩溃/冻结,整个系统(VirtualBox)会冻结。我试图将所有工作转移到另一个内核线程,以避免系统范围内的冻结,但它没有帮助。
是否有可能“隔离”这样的崩溃/冻结,以便我能够终止内核模块运行的进程?
答案 0 :(得分:3)
模块在内核上下文中运行。这就是为什么调试它很困难,而且错误很容易导致系统崩溃。无限循环不是一个真正的问题,因为它只会减慢系统速度,但不会导致崩溃。然而写入错误的记忆区域是致命的。
如果你很幸运,你会在冻结前获得内核oops。如果您在其中一个TTY而不是GUI中测试代码,那么您可能会立即在屏幕上看到可以学习的oops(内核BUG日志)和might be helpful to you。
根据我的经验,最好在用户空间中编写和测试与内核无关的代码,可能使用模拟函数并对其进行大量测试,在其上运行valgrind
,并确保它没有错误。然后在内核空间中使用它。您会惊讶于内核模块的代码实际上根本不需要内核上下文。当然,这在很大程度上取决于内核模块的功能。
要实际调试内核空间中的代码,有一些我从未使用过的工具,例如kgdb。我自己做的通常是printk
和二分搜索的混合。也就是说,如果崩溃严重到根本没有显示内核oops。首先,我在不同的地方放置printk
(可能会有延迟)以查看在oops之前到达代码的哪些部分。 tail -f /var/log/messages
派上用场。然后,我做二分搜索;禁用一半代码以查看是否发生崩溃。如果没有,可能问题出在后半部分。如果它发生,问题肯定是在上半年。重复!
编写无错内核模块的最终方法是编写首先没有错误的代码。当然,这很少可能,但是如果你编写干净且未定义行为的C代码并编写非常简洁的函数,其正确性是显而易见的并且你注意数组的边界,那就不那么难了。