Linux下驱动开发调试技术(二)
有时小问题可以通过监视程序监控用户应用程序的行为来追踪,同时监视程序也有助于建立对驱动正确工作的信心。例如,在看了它的读实现如何响应不同数量数据的读请求之后,我们能够对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节。
六、使用kgdbkgdb是在内核源码中打用于调试内核的补丁,然后通过相应的硬件和软件,就可以像gdb单步调试应用程序一样来调试内核(当然包括驱动)。至于kgdb如何使用,就请你google吧,实在不行,百度一下也可以。
本文链接:http://www.yunweipai.com/3808.html
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/53217.html
googlejavalinux程序员相关文章
- Linux库安装:快速进入安全世界(linux库安装)
- 深入解析Linux驱动开发(linux驱动电子书)
- 安装安装Linux驱动,接入USB网卡(usb网卡linux驱动)
- Linux动态库调试实战:秒杀难题!(linux动态库调试)
- Linux开启新纪元:全新存储系统来袭(linux存储系统)
- Linux系统告警日志分析(linux告警日志)
- 快速掌握嵌入式Linux驱动开发(嵌入式linux驱动开发)
- Linux支持LCD驱动: 让你畅享可视化环境(lcd驱动linux)
- Linux下实现串口调试的方法(串口调试工具linux)
- 优化Linux:简化系统下载(精简linux系统下载)
- Linux查看驱动的简单方法(linux怎么看驱动)
- Linux系统开机启动设置指南(linux开机启动设置)
- Linux中的字符串加密策略与实现(linux字符串加密)
- Linux驱动:构建环境的基础(linux驱动环境)
- GPIO在Linux中的应用:编写驱动程序实现控制(gpio驱动linux)
- 路由器与Linux系统联动提升网络性能(路由器与linux系统)
- Linux双系统:跨分区访问新世界(linux双系统分区)
- 教你快速安装U盘Linux系统(u盘linux安装教程)
- Linux下调试串口的技巧分享(linux调试串口)
- 如何在Linux系统中快速安装显卡驱动(linux装显卡驱动)
- Linux的精彩:从冒号到精彩的世界(linux 冒号)
- Linux下开发PCI驱动:提升系统性能(linux的pci驱动)
- Linux驱动快速下载指南(linux 驱动 下载)
- 实践Linux驱动开发入门实践:指引你走上成功之路(linux驱动开发 入门)
- Linux 与 MySQL之间的动力驱动(linux的mysql)
- Linux下的俄罗斯方块:让你爱不释手(俄罗斯方块linux)