Linux中,在客户环境中诊断问题的一个非常有用的命令就是strace,可以利用其查看程序执行过程中的系统调用,调用库,每一个系统调用的时间,以及接收到的信号等等,在这里就不详细阐述strace的功能了。
最近刚好遇到一个棘手的问题,在一个客户的环境中,应用程序调用系统调用ioctl与产品的内核模块交互总是失败。然后通过strace查看进程的执行过程中的ioctl系统调用是否有异常。查看到如下信息:
ioctl(3, CDROMREADTOCHDR, 0xffd92af0) = -1 EINVAL (Invalid argument) <0.000025>
ioctl第二个参数为与驱动交互的命令,是一个数值。奇怪的问题刚好就产生在这里,产品应用程序中的调用的ioctl的第二个参数为"SIOCXXXXXXX" ("SIOCXXXXXXX" 为产品内核模块实现的一个命令)。再查看"SIOCXXXXXXX"的值为0x40105305,而"CDROMREADTOCHDR"的值为0x5305,虽然低2位字节相同,可他们的数值毕竟不同啊。难道是ioctl会去截断高位2个字节?通过实验,在产品内核模块中收到的命令也为"SIOCXXXXXXX" (即0x40105305)。
经过诸多尝试,最后一个猜想,莫非strace打印出来的"CDROMREADTOCHDR"有误?仔细通过man查看了strace的解释,找到了一个参数描述:
-e raw=set Print raw, undecoded arguments for the specified set of system calls. This option has the effect of causing all arguments to be printed in hexadecimal.
This is mostly useful if you don’t trust the decoding or you need to know the actual numeric value of an argument.
简单来说,就是strace会根据系统调用参数的值进行decode,即转换为一些我们常见的宏名字,便于阅读。通过上面的最后一句,也可以看出,strace的decode也不一定是完全正确的。比如我不相信其对ioctl的decode结果,可以使用参数"-e raw=ioctl"去显示ioctl系统调用时参数的具体数值。