溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Linux內(nèi)核中dev_info、dev_dbg、dev_err及動(dòng)態(tài)調(diào)試是怎樣的

發(fā)布時(shí)間:2021-09-27 16:49:21 來源:億速云 閱讀:277 作者:柒染 欄目:系統(tǒng)運(yùn)維

Linux內(nèi)核中dev_info、dev_dbg、dev_err及動(dòng)態(tài)調(diào)試是怎樣的,相信很多沒有經(jīng)驗(yàn)的人對(duì)此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個(gè)問題。

目前在kernel驅(qū)動(dòng)代碼中,都不再建議直接使用printk直接添加打印信息,而是使用dev_info,dev_dbg,dev_err之類的函數(shù)代替,雖然這些dev_xxx函數(shù)的本質(zhì)還是使用printk打印的,但是相比起printk:

  • 支持打印模塊信息、dev信息

  • 支持動(dòng)態(tài)調(diào)試(dynamic debug)方式

下面簡述下這幾個(gè)dev_xxx函數(shù)的基本使用規(guī)則,以及動(dòng)態(tài)調(diào)試使用方式。

  • dev_info():啟動(dòng)過程、或者模塊加載過程等“通知類的”信息等,一般只會(huì)通知一次,例如probe函數(shù);

  • dev_dbg():一般使用在普通錯(cuò)誤,如-EINVAL、-ENOMEM等errno發(fā)生處,用于調(diào)試;

  • dev_err():一般使用在嚴(yán)重錯(cuò)誤,尤其是用戶無法得到errno的地方,或者程序員不容易猜測系統(tǒng)哪里出了問題的地方;

動(dòng)態(tài)調(diào)試使用方法

  • 打開內(nèi)核動(dòng)態(tài)調(diào)試開關(guān),make menuconfig選中CONFIG_DYNAMIC_DEBUG以及CONFIG_DEBUG_FS

  • Linux啟動(dòng)后,使用命令行掛載上dbgfs

mkdir /mnt/dbg mount -t debugfs none /mnt/dbg
  • 使用下面方式控制你想輸出dev_dbg()信息

  • 1.控制某個(gè)文件所有dev_dbg(),echo -n "file xxx.c +p" >  /mnt/dbg/dynamic_debug/control

  • 2.控制某個(gè)函數(shù)所有dev_dbg(),echo -n "func xxx +p" >  /mnt/dbg/dynamic_debug/control

  • 運(yùn)行程序,使用dmesg則可以看到相應(yīng)dev_dbg()的輸出信息

  • 當(dāng)調(diào)試結(jié)束,不再想輸出dev_dbg()信息了,使用下面命令關(guān)閉即可

  • 1.echo -n "file xxx.c -p" > /mnt/dbg/dynamic_debug/control

  • 2.echo -n "func xxx -p" > /mnt/dbg/dynamic_debug/control

例子

echo -n "file ca_dsc_core.c +p" > /mnt/dbg/dynamic_debug/control 則打印ca_dsc_core.c所有的dev_dbg()信息 echo -n "func ca_dsc_read +p" > /mnt/dbg/dynamic_debug/control 則打印ca_dsc_read()函數(shù)所有dev_dbg()信息

動(dòng)態(tài)打印調(diào)試的基本原理

當(dāng)編譯選項(xiàng)CONFIG_DYNAMIC_DEBUG打開的時(shí)候,在編譯階段,kernel會(huì)把所有使用dev_dbg()的信息記錄在一個(gè)table中,這些信息我們可以從/mnt/dbg/dynamic_debug/control解析出來:

# cat /mnt/dbg/dynamic_debug/control ... ... ... ... drivers/alidrivers/modules/alidsc/ca_dsc_core.c:800 [alidsc]ca_dsc_probe_dt =_ "get dev-index error12" drivers/alidrivers/modules/alidsc/ca_dsc_core.c:789 [alidsc]ca_dsc_probe_dt =_ "get clk error12" drivers/alidrivers/modules/alidsc/ca_dsc_core.c:292 [alidsc]ca_dsc_read =p "read: session#%d read returned %d bytes12" drivers/alidrivers/modules/alidsc/ca_dsc_core.c:234 [alidsc]ca_dsc_read =p "read: session#%d read request: %zd bytes12" 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" drivers/alidrivers/modules/alidsc/ca_dsc_core.c:112 [alidsc]ca_dsc_open =_ "dsc_se: failed register se12" drivers/alidrivers/modules/alidsc/ca_dsc_core.c:755 [alidsc]ca_dsc_splice_write =_ "splice_write: session#%d dsc_from_pipe %d bytes12" drivers/alidrivers/modules/alidsc/ca_dsc_core.c:729 [alidsc]ca_dsc_splice_write =_ "splice_write: session#%d count %zd bytes12" drivers/alidrivers/modules/alidsc/ca_dsc_core.c:619 [alidsc]ca_dsc_splice_read =_ "splice_read: session#%d ret %zd bytes12" drivers/alidrivers/modules/alidsc/ca_dsc_core.c:532 [alidsc]ca_dsc_splice_read =_ "splice_read: session#%d request %zd bytes12" drivers/alidrivers/modules/alidsc/ca_dsc_core.c:871 [alidsc]ca_dsc_probe =_ "Get DSC handler error!12" drivers/alidrivers/modules/alidsc/ca_dsc_core.c:820 [alidsc]ca_dsc_probe =_ "Failed to parse DT12" drivers/alidrivers/modules/alidsc/ca_dsc_core.c:923 [alidsc]ca_dsc_remove =_ "get clk error12" drivers/alidrivers/modules/alidsc/ca_dsc_core.c:396 [alidsc]ca_dsc_write =_ "write: session#%d ret %zd12" drivers/alidrivers/modules/alidsc/ca_dsc_core.c:325 [alidsc]ca_dsc_write =_ "write: session#%d count %zd12" ... ... ... ... net/ipv4/ping.c:965 [ping]ping_rcv =_ "no socket, dropping12" net/ipv4/ping.c:960 [ping]ping_rcv =_ "rcv on socket %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 =_ "try to find: num = %d, daddr = %pI4, dif = %d12" net/ipv4/ping.c:505 [ping]ping_err =_ "err on socket %p12" net/ipv4/ping.c:502 [ping]ping_err =_ "no socket, 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 =_ "after bind(): 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 =_ "was not hashed12" net/ipv4/ping.c:127 [ping]ping_get_port =_ "found port/ident = %d12"

以其中一條為例子:

drivers/alidrivers/modules/alidsc/ca_dsc_core.c:800 [alidsc]ca_dsc_probe_dt =_ "get dev-index error12" 則不會(huì)打印 drivers/alidrivers/modules/alidsc/ca_dsc_core.c:800 [alidsc]ca_dsc_probe_dt =p "get dev-index error12" 則會(huì)打印

所以在應(yīng)用層,用戶就可以通過使用echo來控制dynamic_debug/control文件,進(jìn)而控制是否打印某個(gè)dev_dbg()信息!

  • dev_dbg()對(duì)于分析某些內(nèi)核子系統(tǒng)或者驅(qū)動(dòng)流程也十分有意義,例如,使能net/ipv4/ping.c的調(diào)試開關(guān),則可以觀測ping的運(yùn)行原理。

代碼分析

從代碼角度,也很容易看出dev_dbg()的設(shè)計(jì):

include/linux/device.h include/linux/dynamic_debug.h lib/dynamic_debug.c
//使能CONFIG_DYNAMIC_DEBUG后則根據(jù)control信息動(dòng)態(tài)打印 #if defined(CONFIG_DYNAMIC_DEBUG)  #define dev_dbg(dev, format, ...)         do {              dynamic_dev_dbg(dev, format, ##__VA_ARGS__);   } while (0) //使能DEBUG,則打印整個(gè)kernel的dev_dbg信息 #elif defined(DEBUG)  #define dev_dbg(dev, format, arg...)     dev_printk(KERN_DEBUG, dev, format, ##arg) //都不使能,dev_dbg不打印任何東西 #else  #define dev_dbg(dev, format, arg...)      ({           if (0)           dev_printk(KERN_DEBUG, dev, format, ##arg);    0;         }) #endif

下面的dynamic_dev_dbg()實(shí)現(xiàn)顯然可以看出,打印是根據(jù)descriptor的標(biāo)志位_DPRINTK_FLAGS_PRINT進(jìn)行打印的,而標(biāo)志位是可以通過dbgfs進(jìn)行控制的。

#define dynamic_dev_dbg(dev, fmt, ...)     do {          DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt);    if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT))    __dynamic_dev_dbg(&descriptor, dev, fmt,        ##__VA_ARGS__);   } while (0)

看完上述內(nèi)容,你們掌握Linux內(nèi)核中dev_info、dev_dbg、dev_err及動(dòng)態(tài)調(diào)試是怎樣的的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI