linux驱动调试和开发的区别,Linux下驱动开发调试技术(二)

三、利用strace

有时小问题可以通过监视程序监控用户应用程序的行为来追踪,同时监视程序也有助于建立对驱动正确工作的信心。例如,在看了它的读实现如何响应不同数量数据的读请求之后,我们能够对scull正在正确运行感到有信心。

有几个方法来监视用户空间程序运行。你可以运行一个调试器来单步过它的函数,增加打印语句,或者在 strace 下运行程序。这里,我们将讨论最后一个技术,因为当真正目的是检查内核代码时,它是最有用的。

strace 命令是一个有力工具,它能显示所有的用户空间程序发出的系统调用。它不仅显示调用,还以符号形式显示调用的参数和返回值。当一个系统调用失败, 错误的符号值(例如, ENOMEM)和对应的字串(Out of memory) 都显示。strace 有很多命令行选项,其中最有用的是 -t 来显示每个调用执行的时间,-T 来显示调用中花费的时间,-e 来限制被跟踪调用的类型(例如strace –eread,write ls表示只监控read和write调用),以及-o 来重定向输出到一个文件。缺省情况下,strace 打印调用信息到 stderr。

strace 从内核自身获取信息。这意味着可以跟踪一个程序,不管它是否带有调试支持编译(对 gcc 是 -g 选项)以及不管它是否被strip过。此外,你也可以追踪一个正在运行中的进程,这类似于调试器连接到一个运行中的进程并控制它。

跟踪信息常用来支持发给应用程序开发者的故障报告,但是对内核程序员也是很有价值的。我们已经看到驱动代码运行如何响应系统调用,strace 允许我们检查每个调用的输入和输出数据的一致性。

例如,运行命令 strace ls /dev > /dev/scull0 将会在屏幕上显示如下的内容:

[code language=”c”]

open("/dev", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY) = 3

fstat64(3, {st_mode=S_IFDIR|0755, st_size=24576, …}) = 0

fcntl64(3, F_SETFD, FD_CLOEXEC) = 0

getdents64(3, , 4096) = 4088

[…]

getdents64(3, , 4096) = 0

close(3) = 0

[…]

fstat64(1, {st_mode=S_IFCHR|0664, st_rdev=makedev(254, 0), …}) = 0

write(1, "MAKEDEV\nadmmidi0\nadmmidi1\nadmmid"…, 4096) = 4000

write(1, "b\nptywc\nptywd\nptywe\nptywf\nptyx0\n"…, 96) = 96

write(1, "b\nptyxc\nptyxd\nptyxe\nptyxf\nptyy0\n"…, 4096) = 3904

write(1, "s17\nvcs18\nvcs19\nvcs2\nvcs20\nvcs21"…, 192) = 192

write(1, "\nvcs47\nvcs48\nvcs49\nvcs5\nvcs50\nvc"…, 673) = 673

close(1) = 0

exit_group(0) = ?

[/code]

从第一个 write 调用看, 明显地, 在 ls 结束查看目标目录后,它试图写 4KB。但奇怪的是,只有 4000 字节被成功写入, 并且操作被重复。但当我们查看scull 中的写实现,发现它一次最多只允许写一个quantum(共4000字节),可见驱动本来就是期望部分写。几步之后, 所有东西清空, 程序成功退出。正是通过strace的输出,使我们确信驱动的部分写功能运行正确。

作为另一个例子, 让我们读取 scull 设备(使用 wc scull0 命令):

[code language=”c”]

[…]

open("/dev/scull0", O_RDONLY|O_LARGEFILE) = 3

fstat64(3, {st_mode=S_IFCHR|0664, st_rdev=makedev(254, 0), …}) = 0

read(3, "MAKEDEV\nadmmidi0\nadmmidi1\nadmmid"…, 16384) = 4000

read(3, "b\nptywc\nptywd\nptywe\nptywf\nptyx0\n"…, 16384) = 4000

read(3, "s17\nvcs18\nvcs19\nvcs2\nvcs20\nvcs21"…, 16384) = 865

read(3, "", 16384) = 0

fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), …}) = 0

write(1, "8865 /dev/scull0\n", 17) = 17

close(3) = 0

exit_group(0) = ?

[/code]

如同期望的, read 一次只能获取 4000 字节,但是数据总量等同于前个例子写入的。这个例子,意外的收获是:可以肯定,wc 为快速读进行了优化,它因此绕过了标准库(没有使用fscanf),而是直接一个系统调用以读取更多数据。这一点,可从跟踪到的读的行里看到wc一次试图读取16 KB的数据而确认。

四、利用ioctl方法

由于驱动中的ioctl函数可以将驱动的一些信息返回给用户程序,也可以让用户程序通过ioctl系统调用设置一些驱动的参数。所以在驱动的开发过程中,可以扩展一些ioctl的命令用于传递和设置调试驱动时所需各种信息和参数,以达到调试驱动的目的。

五、利用/proc 文件系统

/proc文件系统用于内核向用户空间暴露一些内核的信息。因此出于调试的目的,我们可以在驱动代码中增加向/proc文件系统导出有助于监视驱动的信息的代码。这样一来,我们就可以通过查看/proc中的相关信息来监视和调试驱动。如何在驱动中实现向/proc文件系统导出信息,请参见《Linux Device Driver》的4.3节。

六、使用kgdb

kgdb是在内核源码中打用于调试内核的补丁,然后通过相应的硬件和软件,就可以像gdb单步调试应用程序一样来调试内核(当然包括驱动)。至于kgdb如何使用,就请你google吧,实在不行,百度一下也可以。

本文链接:http://www.yunweipai.com/3808.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值