当前位置: 首页 > 科技观察

使用动态输出打印内核的DEBUG信息

时间:2023-03-15 00:27:31 科技观察

简介printk()是很多嵌入式开发者喜欢使用的调试方式之一,但是每次都要用printk()重新编译内核,非常不方便。使用动态输出可以方便的打印出内核的调试信息,无需重新编译内核。要启用动态输出,内核需要添加CONFIG_DYNAMIC_DEBUG。启用该宏后,可以动态打印出pr_debug()、dev_dbg()、print_hex_dump_debug()、print_hex_dump_bytes()的所有信息。动态输出支持的特性动态输出对应于debugfs文件系统中的控制文件节点。控制文件节点记录了系统中所有使用动态输出技术的文件名和路径、输出语句所在的行号、模块名和要输出的语句等,可以使用如下命令查看当前所有调试状态的行为配置:cat/sys/kernel/debug/dynamic_debug/control你也可以应用标准的Unix文本过滤命令来过滤这些数据,例如:grep-irdma/sys/kernel/debug/dynamic_debug/control|wc-l在第三列中显示调试状态位的活动标志。"=_"如果没有激活其他操作。因此,您可以使用以下命令查看任何不是默认标志的状态位:awk'$3!="=_"'/dynamic_debug/controlcommandlineusage在语法级别,一个命令由一系列匹配的specifications组成,最后由一个flag来改变这个specification。命令::=match-spec*flags-specmatch-spec用于选择已知dprintk()调用站点的子集以应用flags-spec。将它们视为每对彼此的隐式查询。请注意,一个空的match_specs列表是可能的,但不是很有用,因为它不会匹配调用站点的任何调试子句。一个匹配规范由一个关键字组成,该关键字控制被比较的调用点的属性和被比较的值。可能的关键字是:match-spec::='func'string|'文件'字符串|'模块'字符串|'格式'字符串|'line'line-rangeline-range::=lineno|'-'线号|lineno'-'|lineno'-'lineno注意:line-range不能包含空格,例如"1-30"是有效范围,但是"1-30"是无效的每个关键字的含义如下:func:给指定的字符串与每个调用站点的函数名称进行比较。例如:funcsvc_tcp_acceptfile:给定的字符串将在每个调用站点与源文件的完整路径名或相对名称进行比较。例如:文件svcsock.c,文件/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.cmodule:给定的字符串将与每个调用站点的模块名称进行比较。模块名称与lsmod中看到的字符串相同。例如,模块sunrpcformat:将在动态调试格式字符串中查找给定的字符串。请注意,字符串不需要匹配此模式。可以使用八进制字符语法对空格和其他特殊字符进行转义,例如空字符为\040。或者,字符串可以用双引号(")或单引号(')括起来。例如:formatsvcrdma://dprintksformatreadaheadforNFS/RDMAservers//somedprintksformatnfsdinthepreloadcache:\040SETATTR//一种用空格匹配格式的方法format"nfsd:SETATTR"//一种用空格匹配格式的巧妙方法format'nfsd:SETATTR'//也是一种用空格匹配格式的方法和行:给定的行号或范围行号与每个dprintk()调用站点的行号进行比较。例如:line1603//准确定位line1603line1600-1605//line1600和line1605之间的6行line-1605//line1605从line1到line1605line1600-//fromalllinemarkerspecificationsfromline1600到末尾包含一个更改操作,后跟一个或多个标记字符。更改操作如下:-//移除给定的标记+//添加给定的标记=//将标记设置为给定的标记f//包含打印消息的函数名l//包含已经在的打印消息的行号m//包含打印消息的模块名p//生成一条printk()消息来显示系统启动日志t//包含消息中的线程ID不是在中断上下文中生成并通过启动参数到内核开始调试系统的时候,比如USB核心初始化等,这些代码在系统进入shell之前就已经初始化好了,所以不能及时打开动态输出语句。这时候可以在内核启动的时候给内核传递参数,在系统初始化的时候开启。例如,在内核命令行中加入usbnet.dyndbg=+plft,即可在开机时开启usbnet的动态输出。内核启动后,通过dmesg|可以看到输出的调试信息grep“usbnet”。例如打开文件svcsock.cline1603动态输出语句echo-n'filesvcsock.cline1603+p'>/sys/kernel/debug/dynamic_debug/control打开文件svcsock.c所有动态输出语句echo-n'filesvcsock.c+p'>/sys/kernel/debug/dynamic_debug/control打开NFS服务模块的所有动态输出语句echo-n'modulenfsd+p'>/sys/kernel/debug/dynamic_debug/control开启函数svc_process()的所有动态输出语句echo-n'funcsvc_process+p'>/sys/kernel/debug/dynamic_debug/control关闭函数svc_process()的所有动态输出语句echo-n'funcsvc_process-p'>/sys/kernel/debug/dynamic_debug/control打开所有NFS调用READ开头的信息。echo-n'format"nfsd:READ"+p'>/sys/kernel/debug/dynamic_debug/control查看输出信息,可以使用dmesg|grepXXX。也可以使用tail-f/var/log/dmesg来实时监控dmesg的日志输出。本文参考dynamic-debug-howto.txt《奔跑吧Linux内核》