第38章 驱动调试方法实验

在之前编写的驱动程序中,通常都使用printk函数打印相应的提示信息从而对驱动进行调试,那有没有其他的方式来调试驱动呢,答案是肯定的,在本章节中将对不同驱动调试方法进行学习。

38.1 方法1:dump_stack函数

作用:打印内核调用堆栈,并打印函数的调用关系。

这里以最简单的helloworld驱动为例进行dump_stack函数演示,实验代码如下所示:

#include 
#include  
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);   
MODULE_LICENSE("GPL v2");    
MODULE_AUTHOR("topeet");

和原helloworld驱动程序相比,在第6行添加了dump_stack(),驱动加载之后打印信息如下(图 38-1)所示:

第38章 驱动调试方法实验_第1张图片

图 38-1

可以看到helloworld_init函数的调用关系就都打印了出来。

至此关于dump_stack函数的测试就完成了。

38.2 方法2:WARN_ON(condition)函数

WARN_ON (condition)函数作用:在括号中的条件成立时,内核会抛出栈回溯,打印函数的调用关系。通常用于内核抛出一个警告,暗示某种不太合理的事情发生了。

WARN_ON实际上也是调用dump_stack,只是多了参数condition判断条件是否成立,例如WARN_ON (1)则条件判断成功,函数会成功执行。

这里仍然以最简单的helloworld驱动为例进行WARN_ON函数演示,实验代码如下所示:

#include 
#include  
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);   
MODULE_LICENSE("GPL v2");    
MODULE_AUTHOR("topeet");

和原helloworld驱动程序相比,在第6行添加了WARN_ON(1),驱动加载之后打印信息如下(图 38-2)所示:

第38章 驱动调试方法实验_第2张图片

图 38-2

可以看到helloworld_init函数的调用关系以及寄存器值就都打印了出来。

至此关于WARN_ON函数的测试就完成了。

38.3 方法3:BUG_ON (condition)函数

内核中有许多地方调用类似BUG_ON()的语句,它非常像一个内核运行时的断言,意味着本来不该执行到BUG_ON()这条语句,一旦BUG_ON()执行内核就会立刻抛出oops,导致栈的回溯和错误信息的打印。大部分体系结构把BUG()和BUG_ON()定义成某种非法操作,这样自然会产生需要的oops。参数condition判断条件是否成立,例如BUG_ON (1)则条件判断成功,函数会成功执行。

这里仍然以最简单的helloworld驱动为例进行BUGON函数演示,实验代码如下所示:

#include 
#include  
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);   
MODULE_LICENSE("GPL v2");    
MODULE_AUTHOR("topeet");

和原helloworld驱动程序相比,在第6行添加了BUGON(1),驱动加载之后打印信息如下(图 38-3)所示:

第38章 驱动调试方法实验_第3张图片

图 38-3

可以看到helloworld_init函数的调用关系以及寄存器值就都打印了出来。

至此关于BUGON(1)函数的测试就完成了。

38.4 方法4:panic (fmt…)函数

panic (fmt…)函数:输出打印会造成系统死机并将函数的调用关系以及寄存器值就都打印了出来。

这里仍然以最简单的helloworld驱动为例进行panic 函数的演示,实验代码如下所示:

#include 
#include  
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);   
MODULE_LICENSE("GPL v2");    
MODULE_AUTHOR("topeet");

和原helloworld驱动程序相比,在第6行添加了panic(“!!!”),驱动加载之后打印信息如下(图 38-4)所示:

第38章 驱动调试方法实验_第4张图片

图 38-4

可以看到helloworld_init函数的调用关系以及寄存器值就都打印了出来,信息打印完成之后会发现系统已经崩溃了,终端已经无法再进行输入。

至此关于panic函数的测试就完成了。

【最新驱动资料(文档+例程)】

链接 https://pan.baidu.com/s/1M4smUG2vw_hnn0Hye-tkog

提取码:hbh6

【B 站配套视频】

https://b23.tv/XqYa6Hm

【RK3568 购买链接】

https://item.taobao.com/item.htm?spm=a1z10.5-c-s.w4002-2245

aidu.com/s/1M4smUG2vw_hnn0Hye-tkog

提取码:hbh6

【B 站配套视频】

https://b23.tv/XqYa6Hm

【RK3568 购买链接】

https://item.taobao.com/item.htm?spm=a1z10.5-c-s.w4002-2245

2452613.11.2fec74a6elWNeA&id=669939423234

你可能感兴趣的:(linux,服务器,算法,驱动开发)