最近在给一个Linux的显卡驱动debug。该驱动比较复杂,且涉及Xserver的东东,不时需要跳到不同的地方去看代码。粗略数了一下,内核驱动+Xserver驱动+Xorg server,代码量在二十万行以上。这样的东东,要在短时间内就开始debug,显然不可能先读完代码、详细理清楚逻辑再开始动手。
??
因为不了解细节,很多时候只能猜测问题所在,然后就尝试,失败了继续猜。
??
我不用kgdb,只喜欢通过printk输出调试信息,然后通过看日志来分析流程。printk虽然简单,但是有几个功能非常好用:
??
1、设定消息优先级。因为printk的每条信息都是有级别的,所以可以在/etc/syslog.conf里面设置相应优先级的消息的目标输出文件。比如要把KERN_ERR这一级别的消息输出到/var/log/kerr.log,则在/etc/syslog.conf里面添加"kern.err /var/log/keer.log"即可。同时如果有"kern.* /var/log/kern.log"这样的记录,则同时所有的printk输出,包括KERN_ERR的,都又输出到kern.log里面,这样就可以很方便地根据需要查看不同类型的调试信息了。
??
这是printk比printf强大的地方。
??
2、在printk输出的信息里添加行号和函数名,用__LINE__和__FUNCTION__这两个宏即可,前者用%d输出,后者用%s输出。与之类似的还有__FILE__,不过我不太用它。这其实不是printk的特殊功能,好像是C语言内建的宏,或者是gcc的扩展,反正普通用户空间程序里用printf也照样可以输出。
??
有时候日志会非常多,看不过来。而且因为不知道问题出在哪里,所以需要打出很多日志信息,广撒网。这时候可以通过比较正常运行时的日志和出错时的日志来找问题,对比两者的差异就会比较容易发现问题所在。一般可以用diff对日志做比较,也可以用Emacs里面的ediff,或者vimdiff,或者windows下面的beyondcompare等工具。为了制造差异,往往还需要对代码做一些改动,比如在某些条件测试处改变分支的走向,从而引发bug出现(或者暂时性消除bug)。
??
如果某个bug是原先没有,在新版本的代码里才出现的,那么可以比较好的旧版本和有bug的新版本的代码差异。同样用diff或ediff、vimdiff等工具来比较代码。我最近在用git做版本控制,这个工具是Linus开发的,相当好,个人觉得比svn强那么一点点。git可以直接比较任意两个版本之间的差异,用git diff v1..v2即可,还可以进行二分法查找bug,可以参考git bisect命令的手册去详细了解。
??
暂时只想到这些,欢迎大家也来分享一下自己的经验心得。