【zz】linux内核驱动模块的调试技术总结
原文: http://www.cnitblog.com/textbox/articles/61881.html
这些天来弄了一个简单的驱动模块,后发现系统只要一卸载模块系统就会死掉。到底是那里出了错?
如果你只是通过printk来调试, 而没有其他的方法去检测错误的。
也是这个原因促使我写驱动模块调试技术相关技术。要学好一个编程语言工具首先调试技术也一定同步。
(如果linux 也能做出一个类似windows 下的 Windbg 或 Soft-ICE 那就不必那么麻烦了)
这篇文章不是一气呵成的,只是我在学习内核调试的一个笔记。
调试技术有以下几种:
1.用打印调试
2.文件保存调试信息
3.truss、strace和ltrace命令输出信息来调试
4.调试器来调试
对于第一种 “用打印调试 ”
利用函数或命令把相应的信息输出到console或文件内
这些函数有 printk , STOCLINUX 等等
prink 的一般用法是定义成一个公用的宏
#undef PDEBUG /* undef it, just in case */
#ifdef SCULL_DEBUG
#ifdef __KERNEL__
/* This one if debugging is on, and kernel space */
#define PDEBUG(fmt, args) printk( KERN_DEBUG " scull: " fmt, ## args)
# else
/* This one for user space */
#define PDEBUG(fmt, args) fprintf(stderr, fmt, ## args)
#endif
#else
#define PDEBUG(fmt, args) /* not debugging: nothing */
#endif
#undef PDEBUGG
#define PDEBUGG(fmt, args) /* nothing: it's a placeholder */ 在makefile 里面添加
这样定义的宏可以在内核模式和用户模式在 Debug 版本下输出调试信息,而在release版本编译时候去掉调试输出的函数代码。
并可以通过设置makefile就可以是否输出调试信息, 缺点是修改makefile还需要重新编译一次。
想法,如果能给模块一个配置文件 (*.conf)那就修改配置文件就不用重新编译,只需要卸载安装模块就实现调试信息的输出,
缺点是影响系统的性能。
对於第二种 “文件保存调试信息 ”
内核模式下可以使用 /proc文件系统 或者 seq_file 来记录调试信息。创建自己的/proc文件系统的文件 或 seq_file 文件 并记录相应的调试信息,用于查询。
seq_file 操作可以参考 http://blog.chinaunix.net/u/12313/showart_172686.html;
还有 用ioctl 命令。这些命令可以从驱动模块拷贝相关的数据结构到用户空间, 用于查询它们,缺点是需要用另外的程序来发出和显示调试信息,并增加模块的体积 。优点是比/proc块
oops消息 ,通常消息发生于引用了 NULL 指针或者使用其他不正确指针值。
调试器
使用 gdb
优点:比较适用于用户模式下调试程序,linux自带无需重新安装
缺点:不适合内核模块的调试(也可以内核调试,利用它的远程调试功能。需要两台电脑)
主要步骤是
1.执行 #gdb program
2.执行到mian():#start
3.设置断点
4.调试
具体命令使用: 参考 http://baike.baidu.com/view/639266.htm
使用kdb
优点:不需要远程调试
缺点:不支持源代码级别上的调试只能使用汇编级别的调试,需要重新下载安装包,安装需要重新编译内核激活kdb
使用 kgdb
优点:可以对内核进行全方面的调试 (感觉有点类似 windows 下的WinDdg)
缺点:需要两台电脑,配置复杂 ,更新慢,到目前位置最高只能支持2.6.15.5 版本的内核
使用Linux Trace Toolkit
使用Dynamic Probes ( DProbes )
使用 SkyEye
优点: ARM Simulator很好地结合在了一起 主要用于嵌入式驱动开发领域
缺点:配置文件设置复杂
使用 UML (虚拟机类似)
优点: UML适合于调试那些处理与硬件无关的驱动程序
缺点: UML并不适合于调试那些处理实际硬件的驱动程序
使用 JTAG- based debuggers
优点: The JTAG (Joint Test Action Group) based debuggers are hardware assisted and powerful tools
缺点: but are expensive.
这些天来弄了一个简单的驱动模块,后发现系统只要一卸载模块系统就会死掉。到底是那里出了错?
如果你只是通过printk来调试, 而没有其他的方法去检测错误的。
也是这个原因促使我写驱动模块调试技术相关技术。要学好一个编程语言工具首先调试技术也一定同步。
(如果linux 也能做出一个类似windows 下的 Windbg 或 Soft-ICE 那就不必那么麻烦了)
这篇文章不是一气呵成的,只是我在学习内核调试的一个笔记。
调试技术有以下几种:
1.用打印调试
2.文件保存调试信息
3.truss、strace和ltrace命令输出信息来调试
4.调试器来调试
对于第一种 “用打印调试 ”
利用函数或命令把相应的信息输出到console或文件内
这些函数有 printk , STOCLINUX 等等
prink 的一般用法是定义成一个公用的宏
#undef PDEBUG /* undef it, just in case */
#ifdef SCULL_DEBUG
#ifdef __KERNEL__
/* This one if debugging is on, and kernel space */
#define PDEBUG(fmt, args) printk( KERN_DEBUG " scull: " fmt, ## args)
# else
/* This one for user space */
#define PDEBUG(fmt, args) fprintf(stderr, fmt, ## args)
#endif
#else
#define PDEBUG(fmt, args) /* not debugging: nothing */
#endif
#undef PDEBUGG
#define PDEBUGG(fmt, args) /* nothing: it's a placeholder */
DEBUG
=
y
# Add your debugging flag (or not) to CFLAGS
ifeq ($(DEBUG),y)
DEBFLAGS = - O - g - D SCULL_DEBUG # " -O " is needed to expand inlines
else
DEBFLAGS = - O2
endif
CFLAGS += $(DEBFLAGS)
# Add your debugging flag (or not) to CFLAGS
ifeq ($(DEBUG),y)
DEBFLAGS = - O - g - D SCULL_DEBUG # " -O " is needed to expand inlines
else
DEBFLAGS = - O2
endif
CFLAGS += $(DEBFLAGS)
这样定义的宏可以在内核模式和用户模式在 Debug 版本下输出调试信息,而在release版本编译时候去掉调试输出的函数代码。
并可以通过设置makefile就可以是否输出调试信息, 缺点是修改makefile还需要重新编译一次。
想法,如果能给模块一个配置文件 (*.conf)那就修改配置文件就不用重新编译,只需要卸载安装模块就实现调试信息的输出,
缺点是影响系统的性能。
对於第二种 “文件保存调试信息 ”
内核模式下可以使用 /proc文件系统 或者 seq_file 来记录调试信息。创建自己的/proc文件系统的文件 或 seq_file 文件 并记录相应的调试信息,用于查询。
seq_file 操作可以参考 http://blog.chinaunix.net/u/12313/showart_172686.html;
还有 用ioctl 命令。这些命令可以从驱动模块拷贝相关的数据结构到用户空间, 用于查询它们,缺点是需要用另外的程序来发出和显示调试信息,并增加模块的体积 。优点是比/proc块
oops消息 ,通常消息发生于引用了 NULL 指针或者使用其他不正确指针值。
调试器
使用 gdb
优点:比较适用于用户模式下调试程序,linux自带无需重新安装
缺点:不适合内核模块的调试(也可以内核调试,利用它的远程调试功能。需要两台电脑)
主要步骤是
1.执行 #gdb program
2.执行到mian():#start
3.设置断点
4.调试
具体命令使用: 参考 http://baike.baidu.com/view/639266.htm
使用kdb
优点:不需要远程调试
缺点:不支持源代码级别上的调试只能使用汇编级别的调试,需要重新下载安装包,安装需要重新编译内核激活kdb
使用 kgdb
优点:可以对内核进行全方面的调试 (感觉有点类似 windows 下的WinDdg)
缺点:需要两台电脑,配置复杂 ,更新慢,到目前位置最高只能支持2.6.15.5 版本的内核
使用Linux Trace Toolkit
使用Dynamic Probes ( DProbes )
使用 SkyEye
优点: ARM Simulator很好地结合在了一起 主要用于嵌入式驱动开发领域
缺点:配置文件设置复杂
使用 UML (虚拟机类似)
优点: UML适合于调试那些处理与硬件无关的驱动程序
缺点: UML并不适合于调试那些处理实际硬件的驱动程序
使用 JTAG- based debuggers
优点: The JTAG (Joint Test Action Group) based debuggers are hardware assisted and powerful tools
缺点: but are expensive.