简介
printk()是很多嵌入式开发者喜欢用的调试手段之一,但是,使用printk()每次都要重新编译内核,很不方便。使用动态输出在不需要重新编译内核的情况下,方便的打印出内核的debug信息。
要开启动态输出,内核需要添加CONFIG_DYNAMIC_DEBUG。开启宏之后,pr_debug(),dev_dbg() ,print_hex_dump_debug(),print_hex_dump_bytes()`所有信息都可以被动态打印出来。
动态输出支持的特性
动态输出在debugfs文件系统中对应的是control文件节点。control文件节点记录了系统中所有使用动态输出技术的文件名路径,输出语句所在的行号、模块名和将要输出的语句等。
你可以通过以下命令查看目前所有调试状态的行为配置:
cat/sys/kernel/debug/dynamic_debug/control
你也可以应用标准的Unix文本过滤命令来过滤这些数据, 例如:
grep-irdma/sys/kernel/debug/dynamic_debug/control|wc-l
在第三列显示了调试状态位的激活标志。如果无额外行为被激话, 为 "=_"。因此你可以通过下面的命令查看任何不是默认标志的状态位:
awk'$3!="=_"'/dynamic_debug/control
命令行使用方法
在语法层面上,一个命令由一系列的规格匹配组成,最后由一个标记来改变这规格。
command::=match-spec*flags-spec
match-spec常用来选择一个已知的dprintk()调用点的子集来套用flags-spec。把他们当做彼此之间的每对做隐式查询。注意,一个空的match_specs列表是有可能的,但不是非常有用,因为它不会匹配任何调用点的调试子句。
一个匹配规范由一个关键字组成,关键字控制被比较的调用点的属性和要比较的值。可能关键字是:
match-spec::='func'string| 'file'string| 'module'string| 'format'string| 'line'line-range
line-range::=lineno| '-'lineno| lineno'-'| lineno'-'lineno
注意:line-range不能包含空格,例如,“1-30”是有效的范围,但“1 - 30”就是无效的
每个关键字的含义如下:
func:给定的字符串会和每个调用点的函数名比较。例如:func svc_tcp_accept
file:给定的字符串会和每个调用点的源文件的全路径名或者相对名比较。例如:file svcsock.c, file /usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c
module:给定的字符串会和每个调用点的模块名进行比较。模块名是和在ls mod 里看到的字符串一样。例如,module sunrpc
format:给定的字符串会在动态调试格式字符串里查找。注意这字符串不需要匹配这个格式。空格和其他特殊字符能够用八进制字符语法来转义,例如空字符是�40。作为选择,这个字符串可以附上双引号(")或者是单引号(‘)。例如:
formatsvcrdma://NFS/RDMA服务器的dprintks formatreadahead//一些在预加载缓存里的dprintks formatnfsd:�40SETATTR//一个使用空格来匹配格式的方式 format"nfsd:SETATTR"//一个整齐的方法来用空格匹配格式 format'nfsd:SETATTR'//同样是一个用空格来匹配格式的方法和
line:给定的行号或者是行号范围会和每个dprintk()调用点的行号进行比较。例如:
line1603//准确定位到1603行 line1600-1605//1600行到1605行之间的6行 line-1605//从第一行到1605行之间的1605行 line1600-//从1600行到结尾的全部行
标记规范包含了一个由一个或多个标记字符跟随的变化操作。这变化操作如下所示:
-//移除给定的标记 +//加入给定的标记 =//设置标记到给定的标记上 f//包含已打印消息的函数名 l//包含已在打印消息的行号 m//包含已打印消息的模块名 p//产生一个printk()消息到显示系统启动日志 t//包含了不在中断上下文中产生的消息里的线程ID
传递启动参数给内核
在调试系统启动是时,像USB核心初始化等,这些代码在系统进入shell前已经初始化完毕,因此无法及时打开动态输出语句。这时可以在内核启动时传递参数给内核,在系统初始化时就打开它们。
例如,在内核命令行中添加 usbnet.dyndbg=+plft ,就可以在启动时打开 usbnet的动态输出。
在内核启动后,通过 dmesg | grep "usbnet" 即可看到输出的调试信息。
举例
打开文件svcsock.c 1603行动态输出语句
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 | grep XXX 。也可以使用 tail -f /var/log/dmesg来实时监控dmesg的日志输出。
审核编辑:汤梓红
-
嵌入式
+关注
关注
5068文章
19013浏览量
303064 -
内核
+关注
关注
3文章
1362浏览量
40220 -
字符串
+关注
关注
1文章
577浏览量
20485 -
DEBUG
+关注
关注
3文章
89浏览量
19879
原文标题:使用动态输出打印内核的DEBUG信息
文章出处:【微信号:嵌入式与Linux那些事,微信公众号:嵌入式与Linux那些事】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论