在编写Linux驱动程序时,通常都使用 printk 函数打印相应的提示信息从而对驱动进行调试,除了printk 函数之外,还有其他的方式来调试驱动呢。
一、dump_stack 函数
作用:打印内核调用堆栈,并打印函数的调用关系。
这里以最简单的 helloworld 驱动为例进行 dump_stack 函数演示,实验代码如下所示:
#include <linux/module.h>
#include <linux/kernel.h>
static int __init helloworld_init(void)
{
printk(KERN_EMERG "helloworld_init\r\n");
dump_stack();
return 0;
}
static void __exit helloworld_exit(void)
{
printk(KERN_EMERG "helloworld_exit\r\n");
}
module_init(helloworld_init);
module_exit(helloworld_exit);
驱动加载之后打印信息如下所示:
可以看到 helloworld_init 函数的调用关系就都打印了出来。
二、WARN_ON(condition)函数
WARN_ON (condition)函数作用:在括号中的条件成立时,内核会抛出栈回溯,打印函数的调用关系。通常用于内核抛出一个警告,暗示某种不太合理的事情发生了。
WARN_ON 实际上也是调用 dump_stack,只是多了参数condition 判断条件是否成立,例如 WARN_ON (1)则条件判断成功,函数会成功执行。
这里仍然以最简单的 helloworld 驱动为例进行 WARN_ON 函数演示,代码如下所示:
#include <linux/module.h>
#include <linux/kernel.h>
static int __init helloworld_init(void)
{
printk(KERN_EMERG "helloworld_init\r\n");
WARN_ON(1);
return 0;
}
static void __exit helloworld_exit(void)
{
printk(KERN_EMERG "helloworld_exit\r\n");
}
module_init(helloworld_init);
module_exit(helloworld_exit);
驱动加载之后打印信息
可以看到 helloworld_init 函数的调用关系以及寄存器值就都打印了出来。
三、BUG_ON (condition)函数
内核中有许多地方调用类似 BUG_ON()的语句,它非常像一个内核运行时的断言,意味着本来不该执行到 BUG_ON()这条语句,一旦 BUG_ON()执行内核就会立刻抛出oops,导致栈的回溯和错误信息的打印。大部分体系结构把 BUG()和 BUG_ON()定义成某种非法操作,这样自然会产生需要的 oops。参数 condition 判断条件是否成立,例如BUG_ON(1)则条件判断成功,函数会成功执行。
这里仍然以最简单的 helloworld 驱动为例进行 BUGON 函数演示,实验代码如下所示:
#include <linux/module.h>
#include <linux/kernel.h>
static int __init helloworld_init(void)
{
printk(KERN_EMERG "helloworld_init\r\n");
BUGON(1);
return 0;
}
static void __exit helloworld_exit(void)
{
printk(KERN_EMERG "helloworld_exit\r\n");
}
module_init(helloworld_init);
module_exit(helloworld_exit);
驱动加载之后打印信息如下
可以看到 helloworld_init 函数的调用关系以及寄存器值就都打印了出来。
四、panic (fmt…)函数
panic (fmt…)函数:输出打印会造成系统死机并将函数的调用关系以及寄存器值就都打印了出来。
#include <linux/module.h>
#include <linux/kernel.h>
static int __init helloworld_init(void)
{
printk(KERN_EMERG "helloworld_init\r\n");
panic("!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
return 0;
}
static void __exit helloworld_exit(void)
{
printk(KERN_EMERG "helloworld_exit\r\n");
}
module_init(helloworld_init);
module_exit(helloworld_exit);
驱动加载之后打印信息如下
可以看到 helloworld_init 函数的调用关系以及寄存器值就都打印了出来,信息打印完成之后会发现系统已经崩溃了,终端已经无法再进行输入。