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

在Linux内核中,dev_info、dev_dbg、dev_err和动态调试

时间:2023-03-17 10:00:32 科技观察

目前都在内核驱动代码中。不再推荐使用printk直接添加打印信息,而是改用dev_info、dev_dbg、dev_err等函数,虽然这些dev_xxx函数的本质是使用printk进行打印,但是与printk相比:支持打印的模块information,dev信息支持动态调试(dynamicdebug)模式下面简单介绍dev_xxx这几个函数的基本使用规则和动态调试的使用方法。dev_info():启动过程,或者模块加载过程等“通知”信息,一般只通知一次,比如probe函数;dev_dbg():一般在出现-EINVAL、-ENOMEM等errno等常见错误时使用,用于调试;dev_err():一般用于严重错误,尤其是用户无法得到errno,或者程序员不容易猜到系统哪里出了问题;动态调试方法是打开内核动态调试开关,makemenuconfig选择CONFIG_DYNAMIC_DEBUG和CONFIG_DEBUG_FSLinux启动后,使用命令行挂载dbgfsmkdir/mnt/dbgmount-tdebugfsnone/mnt/dbg使用如下方法控制dev_dbg()你要输出的信息1.控制一个文件中所有的dev_dbg(),echo-n"filexxx.c+p">/mnt/dbg/dynamic_debug/control2.控制一个函数的所有dev_dbg(),echo-n"funcxxx+p">/mnt/dbg/dynamic_debug/control运行程序,使用dmesg可以看到对应dev_dbg()的输出信息,当调试结束后,不再希望输出dev_dbg()信息,只需使用以下命令关闭它1.echo-n"filexxx.c-p">/mnt/dbg/dynamic_debug/control2.echo-n"funcxxx-p">/mnt/dbg/dynamic_debug/control示例echo-n"fileca_dsc_core.c+p">/mnt/dbg/dynamic_debug/control然后打印所有ca_dsc_core.c的dev_dbg()信息echo-n"funcca_dsc_read+p">/mnt/dbg/dynamic_debug/control将打印ca_dsc_read()函数的所有dev_dbg()信息动态打印调试的基本原理当编译选项CONFIG_DYNAMIC_DEBUG打开时,在编译阶段,内核会将使用dev_dbg()的所有信息记录在一个表中,我们可以从/mnt/中获取这些信息dbg/dynamic_debug/控件解析:#cat/mnt/dbg/dynamic_debug/control.......drivers/alidrivers/modules/alidsc/ca_dsc_core.c:800[alidsc]ca_dsc_probe_dt=_"getdev-indexerror12"drivers/alidrivers/modules/alidsc/ca_dsc_core.c:789[alidsc]ca_dsc_probe_dt=_"getclkerror12"drivers/alidrivers/modules/alidsc/ca_dsc_core.c:292[alidsc]ca_dsc_read=p"read:session#%dreadreturned%dbytes12"drivers/alidrivers/modules/alidsc/ca_dsc_core.c:234[alidsc]ca_dsc_read=p"read:session#%dreadrequest:%zdbytes12"drivers/alidrivers/modules/alidsc/ca_dsc_core.c:435[alidsc]ca_dsc_vm_fault=_"dsc_vm_fault:buffer#%drelease%dbytesforsession#%d12"drivers/alidrivers/modules/alidsc/ca_dsc_core.c:112[alidsc]ca_dsc_open=_"dsc_se:failedregisterse12“驱动程序/alidrivers/modules/alidsc/ca_dsc_core.c:755[alidsc]ca_dsc_splice_write=_"splice_write:session#%ddsc_from_pipe%dbytes12"drivers/alidrivers/modules/alidsc/ca_dsc_core.c:729[alidsc]ca_dsc_splice_write=_"splice_write:session#%dcount%zdbytes12"drivers/alidrivers/modules/alidsc/ca_dsc_core.c:619[alidsc]ca_dsc_splice_read=_"splice_read:session#%dret%zdbytes12"drivers/alidrivers/modules/alidsc/ca_dsc_core.c:532[alidsc]ca_dsc_splice_read=_"splice_read:session#%drequest%zdbytes12"驱动程序/alidrivers/modules/alidsc/ca_dsc_core.c:871[alidsc]ca_dsc_probe=_"GetDSChandlererror!12"drivers/alidrivers/modules/alidsc/ca_dsc_core.c:820[alidsc]ca_dsc_probe=_"FailedtoparseDT12"drivers/alidrivers/modules/alidsc/ca_dsc_core.c:923[alidsc]ca_dsc_remove=_"getclkerror12"drivers/alidrivers/modules/alidsc/ca_dsc_core.c:396[alidsc]ca_dsc_write=_"write:session#%dret%zd12"drivers/alidrivers/modules/alidsc/ca_dsc_core.c:325[alidsc]ca_dsc_write=_"write:session#%dcount%zd12".................net/ipv4/ping.c:965[ping]ping_rcv=_"nosocket,dropping12"net/ipv4/ping.c:960[ping]ping_rcv=_"rcvonsocket%p12"net/ipv4/ping.c:953[ping]ping_rcv=_"ping_rcv(skb=%p,id=%04x,seq=%04x)12"net/ipv4/ping.c:932[ping]ping_queue_rcv_skb=_"ping_queue_rcv_skb->failed12"net/ipv4/ping.c:929[ping]ping_queue_rcv_skb=_"ping_queue_rcv_skb(sk=%p,sk->num=%d,skb=%p)12"net/ipv4/ping.c:921[ping]ping_recvmsg=_"ping_recvmsg->%d12"net/ipv4/ping.c:840[ping]ping_recvmsg=_"ping_recvmsg(sk=%p,sk->num=%u)12"net/ipv4/ping.c:693[ping]ping_v4_sendmsg=_"ping_v4_sendmsg(sk=%p,sk->num=%u)12"net/ipv4/ping.c:197[ping]ping_lookup=_"found:%p:num=%d,daddr=%pI4,dif=%d12"net/ipv4/ping.c:189[ping]ping_lookup=_"iterate12"net/ipv4/ping.c:176[ping]ping_lookup=_"trytofind:num=%d,daddr=%pI4,dif=%d12"net/ipv4/ping.c:505[ping]ping_err=_"erronsocket%p12"net/ipv4/ping.c:502[ping]ping_err=_"nosocket,dropping12"net/ipv4/ping.c:498[ping]ping_err=_"ping_err(proto=0x%x,type=%d,code=%d,id=%04x,seq=%04x)12"net/ipv4/ping.c:304[ping]ping_check_bind_addr=_"ping_check_bind_addr(sk=%p,addr=%pI4,port=%d)12"net/ipv4/ping.c:445[ping]ping_bind=_"ping_v4_bind->%d12"net/ipv4/ping.c:423[ping]ping_bind=_"afterbind():num=%d,dif=%d12"net/ipv4/ping.c:286[ping]ping_close=_"isk->refcnt=%d12"net/ipv4/ping.c:285[ping]ping_close=_"ping_close(sk=%p,sk->num=%u)12"net/ipv4/ping.c:153[ping]ping_unhash=_"ping_unhash(isk=%p,isk->num=%u)12"net/ipv4/ping.c:146[ping]ping_hash=_"ping_hash(sk->port=%u)12"net/ipv4/ping.c:67[ping]ping_hashfn=_"hash(%d)=%d12"net/ipv4/ping.c:130[ping]ping_get_port=_"wasnothashed12"net/ipv4/ping.c:127[ping]ping_get_port=_"foundport/ident=%d12"以其中一条为示例:drivers/alidrivers/modules/alidsc/ca_dsc_core.c:800[alidsc]ca_dsc_probe_dt=_"getdev-indexerror12"不会打印drivers/alidrivers/modules/alidsc/ca_dsc_core.c:800[alidsc]ca_dsc_probe_dt=p"getdev-indexerror12"它会打印,所以在应用层,用户可以通过echo来控制dynamic_debug/control文件,进而控制是否打印某个dev_dbg()信息!dev_dbg()对于分析某些内核子系统或者驱动进程也非常有意义,比如打开net/ipv4/ping.c的debug开关,可以观察到ping的运行原理代码分析从代码的角度,很容易看出dev_dbg()的设计:include/linux/device.hinclude/linux/dynamic_debug.hlib/dynamic_debug.c//启用CONFIG_DYNAMIC_DEBUG后,会根据控制信息动态打印#ifdefined(CONFIG_DYNAMIC_DEBUG)#definedev_dbg(dev,format,...)do{dynamic_dev_dbg(dev,format,##__VA_ARGS__);}while(0)//开启DEBUG,然后打印整个内核的dev_dbg信息#elifdefined(DEBUG)#definedev_dbg(dev,format,arg...)dev_printk(KERN_DEBUG,dev,format,##arg)//没有启用,dev_dbg不打印任何东西#else#definedev_dbg(dev,format,arg...)(下面的{if(0)dev_printk(KERN_DEBUG,dev,format,##arg);0;})#endifdynamic_dev_dbg()从实现中可以明显看出打印是ac根据描述符的标志位_DPRINTK_FLAGS_PRINT,可以通过dbgfs控制标志位。#definedynamic_dev_dbg(dev,fmt,...)do{DEFINE_DYNAMIC_DEBUG_METADATA(descriptor,fmt);if(不太可能(descriptor.flags&_DPRINTK_FLAGS_PRINT))__dynamic_dev_dbg(&descriptor,dev,fmt,##__VA_ARGS__);}while(0)有利于开发版本,开启CONFIG_DYNAMIC_DEBUG和CONFIG_DEBUG_FS,配合dbgfs动态观察和调试内核代码;正式版中,关闭CONFIG_DYNAMIC_DEBUG和CONFIG_DEBUG_FS,所有dbgfs和dev_dbg信息会自动从编译阶段移除;