服务器之家:专注于服务器技术及软件下载分享
分类导航

Linux|Centos|Ubuntu|系统进程|Fedora|注册表|Bios|Solaris|Windows7|Windows10|Windows11|windows server|

服务器之家 - 服务器系统 - Linux - Linux内核中dev_info、dev_dbg、dev_err及动态调试

Linux内核中dev_info、dev_dbg、dev_err及动态调试

2021-04-25 22:31一口Linux土豆居士 Linux

目前在kernel驱动代码中,都不再建议直接使用printk直接添加打印信息,而是使用dev_info,dev_dbg,dev_err之类的函数代替.

Linux内核中dev_info、dev_dbg、dev_err及动态调试

目前在kernel驱动代码中,都不再建议直接使用printk直接添加打印信息,而是使用dev_info,dev_dbg,dev_err之类的函数代替,虽然这些dev_xxx函数的本质还是使用printk打印的,但是相比起printk:

  • 支持打印模块信息、dev信息
  • 支持动态调试(dynamic debug)方式

下面简述下这几个dev_xxx函数的基本使用规则,以及动态调试使用方式。

  • dev_info():启动过程、或者模块加载过程等“通知类的”信息等,一般只会通知一次,例如probe函数;
  • dev_dbg():一般使用在普通错误,如-EINVAL、-ENOMEM等errno发生处,用于调试;
  • dev_err():一般使用在严重错误,尤其是用户无法得到errno的地方,或者程序员不容易猜测系统哪里出了问题的地方;

动态调试使用方法

 

  • 打开内核动态调试开关,make menuconfig选中CONFIG_DYNAMIC_DEBUG以及CONFIG_DEBUG_FS
  • Linux启动后,使用命令行挂载上dbgfs
  1. mkdir /mnt/dbg 
  2. mount -t debugfs none /mnt/dbg 
  • 使用下面方式控制你想输出dev_dbg()信息
  • 1.控制某个文件所有dev_dbg(),echo -n "file xxx.c +p" > /mnt/dbg/dynamic_debug/control
  • 2.控制某个函数所有dev_dbg(),echo -n "func xxx +p" > /mnt/dbg/dynamic_debug/control
  • 运行程序,使用dmesg则可以看到相应dev_dbg()的输出信息
  • 当调试结束,不再想输出dev_dbg()信息了,使用下面命令关闭即可
  • 1.echo -n "file xxx.c -p" > /mnt/dbg/dynamic_debug/control
  • 2.echo -n "func xxx -p" > /mnt/dbg/dynamic_debug/control

例子

  1. echo -n "file ca_dsc_core.c +p" > /mnt/dbg/dynamic_debug/control 则打印ca_dsc_core.c所有的dev_dbg()信息 
  2. echo -n "func ca_dsc_read +p" > /mnt/dbg/dynamic_debug/control 则打印ca_dsc_read()函数所有dev_dbg()信息 

动态打印调试的基本原理

 

当编译选项CONFIG_DYNAMIC_DEBUG打开的时候,在编译阶段,kernel会把所有使用dev_dbg()的信息记录在一个table中,这些信息我们可以从/mnt/dbg/dynamic_debug/control解析出来:

  1. # cat /mnt/dbg/dynamic_debug/control 
  2. ... ... 
  3. ... ... 
  4. drivers/alidrivers/modules/alidsc/ca_dsc_core.c:800 [alidsc]ca_dsc_probe_dt =_ "get dev-index error12" 
  5. drivers/alidrivers/modules/alidsc/ca_dsc_core.c:789 [alidsc]ca_dsc_probe_dt =_ "get clk error12" 
  6. drivers/alidrivers/modules/alidsc/ca_dsc_core.c:292 [alidsc]ca_dsc_read =p "read: session#%d read returned %d bytes12" 
  7. drivers/alidrivers/modules/alidsc/ca_dsc_core.c:234 [alidsc]ca_dsc_read =p "read: session#%d read request: %zd bytes12" 
  8. drivers/alidrivers/modules/alidsc/ca_dsc_core.c:435 [alidsc]ca_dsc_vm_fault =_ "dsc_vm_fault: buffer#%d release %d bytes for session#%d12" 
  9. drivers/alidrivers/modules/alidsc/ca_dsc_core.c:112 [alidsc]ca_dsc_open =_ "dsc_se: failed register se12" 
  10. drivers/alidrivers/modules/alidsc/ca_dsc_core.c:755 [alidsc]ca_dsc_splice_write =_ "splice_write: session#%d dsc_from_pipe %d bytes12" 
  11. drivers/alidrivers/modules/alidsc/ca_dsc_core.c:729 [alidsc]ca_dsc_splice_write =_ "splice_write: session#%d count %zd bytes12" 
  12. drivers/alidrivers/modules/alidsc/ca_dsc_core.c:619 [alidsc]ca_dsc_splice_read =_ "splice_read: session#%d ret %zd bytes12" 
  13. drivers/alidrivers/modules/alidsc/ca_dsc_core.c:532 [alidsc]ca_dsc_splice_read =_ "splice_read: session#%d request %zd bytes12" 
  14. drivers/alidrivers/modules/alidsc/ca_dsc_core.c:871 [alidsc]ca_dsc_probe =_ "Get DSC handler error!12" 
  15. drivers/alidrivers/modules/alidsc/ca_dsc_core.c:820 [alidsc]ca_dsc_probe =_ "Failed to parse DT12" 
  16. drivers/alidrivers/modules/alidsc/ca_dsc_core.c:923 [alidsc]ca_dsc_remove =_ "get clk error12" 
  17. drivers/alidrivers/modules/alidsc/ca_dsc_core.c:396 [alidsc]ca_dsc_write =_ "write: session#%d ret %zd12" 
  18. drivers/alidrivers/modules/alidsc/ca_dsc_core.c:325 [alidsc]ca_dsc_write =_ "write: session#%d count %zd12" 
  19. ... ... 
  20. ... ... 
  21. net/ipv4/ping.c:965 [ping]ping_rcv =_ "no socket, dropping12" 
  22. net/ipv4/ping.c:960 [ping]ping_rcv =_ "rcv on socket %p12" 
  23. net/ipv4/ping.c:953 [ping]ping_rcv =_ "ping_rcv(skb=%p,id=%04x,seq=%04x)12" 
  24. net/ipv4/ping.c:932 [ping]ping_queue_rcv_skb =_ "ping_queue_rcv_skb -> failed12" 
  25. net/ipv4/ping.c:929 [ping]ping_queue_rcv_skb =_ "ping_queue_rcv_skb(sk=%p,sk->num=%d,skb=%p)12" 
  26. net/ipv4/ping.c:921 [ping]ping_recvmsg =_ "ping_recvmsg -> %d12" 
  27. net/ipv4/ping.c:840 [ping]ping_recvmsg =_ "ping_recvmsg(sk=%p,sk->num=%u)12" 
  28. net/ipv4/ping.c:693 [ping]ping_v4_sendmsg =_ "ping_v4_sendmsg(sk=%p,sk->num=%u)12" 
  29. net/ipv4/ping.c:197 [ping]ping_lookup =_ "found: %p: num=%d, daddr=%pI4, dif=%d12" 
  30. net/ipv4/ping.c:189 [ping]ping_lookup =_ "iterate12" 
  31. net/ipv4/ping.c:176 [ping]ping_lookup =_ "try to find: num = %d, daddr = %pI4, dif = %d12" 
  32. net/ipv4/ping.c:505 [ping]ping_err =_ "err on socket %p12" 
  33. net/ipv4/ping.c:502 [ping]ping_err =_ "no socket, dropping12" 
  34. net/ipv4/ping.c:498 [ping]ping_err =_ "ping_err(proto=0x%x,type=%d,code=%d,id=%04x,seq=%04x)12" 
  35. net/ipv4/ping.c:304 [ping]ping_check_bind_addr =_ "ping_check_bind_addr(sk=%p,addr=%pI4,port=%d)12" 
  36. net/ipv4/ping.c:445 [ping]ping_bind =_ "ping_v4_bind -> %d12" 
  37. net/ipv4/ping.c:423 [ping]ping_bind =_ "after bind(): num = %d, dif = %d12" 
  38. net/ipv4/ping.c:286 [ping]ping_close =_ "isk->refcnt = %d12" 
  39. net/ipv4/ping.c:285 [ping]ping_close =_ "ping_close(sk=%p,sk->num=%u)12" 
  40. net/ipv4/ping.c:153 [ping]ping_unhash =_ "ping_unhash(isk=%p,isk->num=%u)12" 
  41. net/ipv4/ping.c:146 [ping]ping_hash =_ "ping_hash(sk->port=%u)12" 
  42. net/ipv4/ping.c:67 [ping]ping_hashfn =_ "hash(%d) = %d12" 
  43. net/ipv4/ping.c:130 [ping]ping_get_port =_ "was not hashed12" 
  44. net/ipv4/ping.c:127 [ping]ping_get_port =_ "found port/ident = %d12" 

以其中一条为例子:

  1. drivers/alidrivers/modules/alidsc/ca_dsc_core.c:800 [alidsc]ca_dsc_probe_dt =_ "get dev-index error12" 则不会打印 
  2. drivers/alidrivers/modules/alidsc/ca_dsc_core.c:800 [alidsc]ca_dsc_probe_dt =p "get dev-index error12" 则会打印 

所以在应用层,用户就可以通过使用echo来控制dynamic_debug/control文件,进而控制是否打印某个dev_dbg()信息!

  • dev_dbg()对于分析某些内核子系统或者驱动流程也十分有意义,例如,使能net/ipv4/ping.c的调试开关,则可以观测ping的运行原理。

代码分析

 

从代码角度,也很容易看出dev_dbg()的设计:

  1. include/linux/device.h include/linux/dynamic_debug.h lib/dynamic_debug.c 
  1. //使能CONFIG_DYNAMIC_DEBUG后则根据control信息动态打印 
  2. #if defined(CONFIG_DYNAMIC_DEBUG) 
  3.  #define dev_dbg(dev, format, ...)        
  4.  do {            
  5.   dynamic_dev_dbg(dev, format, ##__VA_ARGS__);  
  6.  } while (0) 
  7. //使能DEBUG,则打印整个kernel的dev_dbg信息 
  8. #elif defined(DEBUG) 
  9.  #define dev_dbg(dev, format, arg...)   
  10.   dev_printk(KERN_DEBUG, dev, format, ##arg) 
  11. //都不使能,dev_dbg不打印任何东西 
  12. #else 
  13.  #define dev_dbg(dev, format, arg...)     
  14.  ({         
  15.   if (0)        
  16.    dev_printk(KERN_DEBUG, dev, format, ##arg);  
  17.   0;        
  18.  }) 
  19. #endif 

下面的dynamic_dev_dbg()实现显然可以看出,打印是根据descriptor的标志位_DPRINTK_FLAGS_PRINT进行打印的,而标志位是可以通过dbgfs进行控制的。

  1. #define dynamic_dev_dbg(dev, fmt, ...)     
  2. do {         
  3.  DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt);   
  4.  if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT))  
  5.   __dynamic_dev_dbg(&descriptor, dev, fmt,  
  6.       ##__VA_ARGS__);   
  7. } while (0) 

好处

 

开发版本,打开CONFIG_DYNAMIC_DEBUG和CONFIG_DEBUG_FS,配合dbgfs动态观测和调试内核代码;

正式版本,关闭CONFIG_DYNAMIC_DEBUG和CONFIG_DEBUG_FS,所有dbgfs以及dev_dbg信息都从编译阶段自动移除;

原文地址:https://mp.weixin.qq.com/s/0qy8XkSoL-_keGo97aK2Cg

延伸 · 阅读

精彩推荐
  • LinuxLinux常用的日志文件和常用命令

    Linux常用的日志文件和常用命令

    成功地管理任何系统的关键之一,是要知道系统中正在发生什么事。 Linux 中提供了异常日志,并且日志的细节是可配置的。Linux 日志都以明文形式存储,所...

    Linux教程网2632020-04-18
  • LinuxLinux上设置用户通过SFTP访问目录的权限的方法

    Linux上设置用户通过SFTP访问目录的权限的方法

    这篇文章主要介绍了Linux上设置用户通过SFTP访问目录的权限的方法,SFTP可以理解为使用SSH协议进行FTP传输的协议,因而同时要对OpenSSH进行相关设置,需要的朋...

    OSChina10022019-06-19
  • Linux手把手教您在 Linux 上使用 GPG 加解密文件

    手把手教您在 Linux 上使用 GPG 加解密文件

    在本教程中,我将告诉你如何用 GPG 加密和解密文件。这是一个简单的教程,你可以在你的 Linux 系统上尝试所有的练习。这将帮助你练习 GPG 命令,并在你...

    Linux中国6962021-12-15
  • LinuxLinux中环境变量配置的步骤详解

    Linux中环境变量配置的步骤详解

    Linux中环境变量包括系统级和用户级,系统级的环境变量是每个登录到系统的用户都要读取的系统变量,而用户级的环境变量则是该用户使用系统时加载的...

    Myths7882022-02-10
  • Linuxlinux中rmdir命令使用详解(删除空目录)

    linux中rmdir命令使用详解(删除空目录)

    今天学习一下linux中命令: rmdir命令。rmdir是常用的命令,该命令的功能是删除空目录,一个目录被删除之前必须是空的 ...

    linux命令大全5372019-11-19
  • LinuxLinux lnmp下无法使用mail发邮件的两种解决方法

    Linux lnmp下无法使用mail发邮件的两种解决方法

    在配置了lnmp环境后,出现了mail函数不能发送邮件的问题,其实有两种方法,一是使用sendmail组件,而是使用postfix。下面为大家一一介绍下 ...

    Linux之家4042019-09-17
  • Linux确保Linux系统安全的前提条件 漏洞防护

    确保Linux系统安全的前提条件 漏洞防护

    Linux 作为开放式的操作系统受到很多程序员的喜爱,很多高级程序员都喜欢编写Linux操作系统的相关软件。这使得Linux操作系统有着丰富的软件支持,还有无...

    Linux之家2642020-04-11
  • Linux详解Linux系统下PXE服务器的部署过程

    详解Linux系统下PXE服务器的部署过程

    这篇文章主要介绍了Linux系统下PXE服务器的部署过程,包括对PXE的API架构作了一个基本的简介,需要的朋友可以参考下...

    运维之道9812019-07-04