0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

內(nèi)核調(diào)試?yán)鱬rintk的使用心得

Q4MP_gh_c472c21 ? 來源:嵌入式客棧 ? 作者:逸珺 ? 2021-11-08 17:31 ? 次閱讀

[導(dǎo)讀] 剛剛開始做Linux相關(guān)開發(fā)工作時,深感Linux內(nèi)核代碼龐大,要加些自己的驅(qū)動進(jìn)內(nèi)核代碼樹,常常深陷bug的泥沼難以自拔,今天來分享一下內(nèi)核調(diào)試?yán)鱬rintk的使用心得。

前面一段時間很忙,后期更文頻率會漸漸回歸正常頻率,盡量會保證每周一到兩更。感謝各位朋友的關(guān)注而沒有棄我而去,我定不負(fù)厚愛,會持續(xù)輸出些日常技術(shù)工作中的心得體會,如對朋友們有些許幫助,也煩請幫忙點個贊或者在看(這并不會對各位有何不利的影響哈~~~),這也是對我堅持持續(xù)輸出的大大激勵!

printk初接觸

Linux內(nèi)核啟動之后常會看見很多信息打印出來,這在底層是printk子系統(tǒng)實現(xiàn)的,其實現(xiàn)代碼在./kernel/printk/中實現(xiàn)的。

一個小小的打印,對于內(nèi)核而言也需要考慮很多方面,需要考慮到多核、中斷、緩沖以及用戶空間接口。對于用戶空間接口很多朋友或許會很疑惑。

其中/dev/kmsg字符設(shè)備就是printk子系統(tǒng)實現(xiàn)的內(nèi)核打印字符設(shè)備。如果利用文件操作寫這個設(shè)備就最終會以printk形式輸出,如果讀這個設(shè)備最終就會返回printk歷史,你如不信不妨用這個命令試試:

cat/dev/kmsg

看到這里或許有朋友會問,為啥有的文章提到用/proc/kmsg去讀取內(nèi)核打印緩沖區(qū)的日志用以調(diào)試。來分析一下:

/proc/kmsg

/proc/kmsg僅為root用戶提供內(nèi)核日志緩沖區(qū)的只讀操作。等效于通過SYSLOG_ACTION_READ操作調(diào)用[syslog(2)]。

一個進(jìn)程必須具有超級用戶特權(quán)才能讀取此文件,并且只有一個進(jìn)程應(yīng)讀取該文件。如果正在運行使用syslog(2)系統(tǒng)調(diào)用記錄內(nèi)核消息的syslog進(jìn)程,則不應(yīng)讀取該文件。

這里補(bǔ)充說一點是,/proc文件系統(tǒng)本質(zhì)上是偽文件系統(tǒng),它提供了內(nèi)核數(shù)據(jù)結(jié)構(gòu)的接口。它一般掛載在/proc上。通常情況下,它是由系統(tǒng)自動掛載的的,但是也可以使用以下命令手動安裝:

mount-tprocproc/proc

大部分位于/proc下的文件屬于只讀特性,但也有少部分是可寫的。但是對于/proc/kmsg而言則是只讀的。

/dev/kmsg

/dev/kmsg提供對同一內(nèi)核日志緩沖區(qū)的訪問,但以一種更易于使用的方式。每次打開都會對讀取進(jìn)行跟蹤,因此可以并行讀取多個進(jìn)程,并且在讀取條目時不會將其從緩沖區(qū)中刪除。/dev/kmsg還提供對日志緩沖區(qū)的寫訪問權(quán),因此可用于將條目添加到日志緩沖區(qū)。

那么為什么兩者都存在,以及為什么一個存在于/proc中和而另一個存在于/dev中,/proc/kmsg是歷史設(shè)計,而/dev/kmsg是較新引入的,被設(shè)計為日志緩沖區(qū)的可用接口。該接口也實現(xiàn)了用戶空間添加記錄進(jìn)內(nèi)核日志系統(tǒng)的可能。

其代碼實現(xiàn)也可以簡單

printk使用

printk怎么打印的呢?想必做嵌入式開發(fā)的一定熟悉printf函數(shù),那么從范式上printk也比較類似,但也有很多不同。且看:

內(nèi)核打印,界定了日志級別,其語法范式:

printk([KERN_LOG_LEVEL]"Message:%s
",arg);

比如:

printk(KERN_DEBUG“Hereis:%s:%i
”,__FILE__,__LINE__);

那么有哪些日志級別,又各有何區(qū)別呢?

日志級別

級別 宏名 描述
0 KERN_EMERG 最高級別,系統(tǒng)遇到緊急狀況,嚴(yán)重時可能掛機(jī)了
1 KERN_ALERT 告警級別,需要立即關(guān)注或處置
2 KERN_CRIT critical 情況,比較緊急
3 KERN_ERR 當(dāng)系統(tǒng)檢測到某個錯誤
4 KERN_WARNING warning中文也會翻譯成警告,但是緊急程度級別比Alert低,
5 KERN_NOTICE 正常操作但或許需要注意的一些操作
6 KERN_INFO 信息提示級別,比如驅(qū)動指示一下做了什么操作
7 KERN_DEBUG 調(diào)試信息

對于這個表,或許剛使用時會不知所措,這么多級別到底該傳入什么級別呢?我的理解如果是自己定義的驅(qū)動按照字面意思理解,靈活使用即可。唯一需要注意的時候,不同的級別打印或許在控制臺會有不同的體現(xiàn),這取決于控制臺打印的配置。

格式化

下面內(nèi)容來源于./Documentation/printk-formats.txt,整理于此方便使用:

  • 基本變量
類型 格式化
int %d 或 %x
unsigned int %u 或 %x
long %ld 或 %lx
unsigned long %lu 或 %lx
long long %lld 或 %llx
unsigned long long %llu 或 %llx
size_t %zu 或 %zx
ssize_t %zd 或 %zx
s32 %d 或 %x
u32 %u 或 %x
s64 %lld 或 %llx
u64 %llu 或 %llx

注意:內(nèi)核打印不支持浮點,%n也不支持,%e, %f, %g, %a也不支持,如使用了會導(dǎo)致WARN。

  • 指針
類型 格式化
%p 打印基本指針
%pF versatile_init+0x0/0x110
%pf versatile_init
%pS versatile_init+0x0/0x110
%pSR versatile_init+0x9/0x110
%ps versatile_init
%pB prev_fn_of_versatile_init+0x88/0x88

除上面描述的這些格式化,printk還支持格式化打印塊設(shè)備名、IPv4、IPv6地址、網(wǎng)絡(luò)設(shè)備屬性、MAC/FDDI地址、UUID/GUID地址等等。如需要用到可查閱該文檔獲取更為詳細(xì)的信息。

修改控制臺打印級別

運行時修改

在調(diào)試過程中,或許會發(fā)現(xiàn)有的printk信息沒有打印出來,那么肯定是默認(rèn)運行中內(nèi)核控制臺printk打印級別低于代碼中使用的級別,那么如果不想重新編譯內(nèi)核,有沒有辦法動態(tài)修改呢?來看看怎么修改:

a7ea0a54-3f78-11ec-9195-dac502259ad0.png

在/proc/sys/kernel/printk文件中,有4個屬性分別對應(yīng):

  • 當(dāng)前控制臺日志級別
  • 默認(rèn)日志級別
  • 最小日志級別
  • 啟動階段默認(rèn)日志級別

使用下面命令可以當(dāng)前控制臺printk日志級別:

echo6>/proc/sys/kernel/printk

這里傳入6,表示小于6級別的打印都將會被打印出來。這里可以根據(jù)需要傳入不同的值。取值參見前表<日志級別>。如想將所有的信息都打印出來,傳入8即可,如:

echo8>/proc/sys/kernel/printk

如果你想將這些打印記錄進(jìn)一個文件,則可以使用klogd進(jìn)行重定向,比如:

klogd-o-f./kernel.msg

編譯修改

如果你想將某一模塊的內(nèi)核打印在編譯時使能,這樣做的好處是在模塊加載過程中的所有的信息在控制臺都可以看到,你還可以增加你感興趣的代碼添加打印信息,用以輔助調(diào)試。這怎么實現(xiàn)呢?

這里需要去看看你的內(nèi)核模塊代碼是以何種方式去調(diào)用printk的,比如有的代碼這樣調(diào)用:

staticinttea5764_i2c_probe(structi2c_client*client,
conststructi2c_device_id*id)
{
structtea5764_device*radio;
structv4l2_device*v4l2_dev;
structv4l2_ctrl_handler*hdl;
structtea5764_regs*r;
intret;

PDEBUG("probe");
.....

這里的PDEBUG其實就是printk的一種宏重包裝:

#definePINFO(format,...)
printk(KERN_INFOKBUILD_MODNAME":"
DRIVER_VERSION":"format"
",##__VA_ARGS__)
#definePWARN(format,...)
printk(KERN_WARNINGKBUILD_MODNAME":"
DRIVER_VERSION":"format"
",##__VA_ARGS__)
#definePDEBUG(format,...)
printk(KERN_DEBUGKBUILD_MODNAME":"
DRIVER_VERSION":"format"
",##__VA_ARGS__)

還有的是這樣:

staticintad9467_spi_read(structspi_device*spi,unsignedreg)
{
unsignedcharbuf[3];
intret;

if(spi){
buf[0]=0x80|(reg>>8);
buf[1]=reg&0xFF;

ret=spi_write_then_read(spi,&buf[0],2,&buf[2],1);

dev_dbg(&spi->dev,"%s:REG:0x%XVAL:0x%X(%d)
",
__func__,reg,buf[2],ret);

if(retdev,"spi_write_then_readfailed%s:REG:0x%XVAL:0x%X(%d)
",
__func__,reg,buf[2],ret);
returnret;
}


returnbuf[2];
}
return-ENODEV;
}

dev_dbg其本質(zhì)上也是調(diào)用的printk,來看看,在./include/linux/device.h中

#ifdefined(CONFIG_DYNAMIC_DEBUG)
#definedev_dbg(dev,fmt,...)
dynamic_dev_dbg(dev,dev_fmt(fmt),##__VA_ARGS__)
#elifdefined(DEBUG)
#definedev_dbg(dev,fmt,...)
dev_printk(KERN_DEBUG,dev,dev_fmt(fmt),##__VA_ARGS__)
#else
#definedev_dbg(dev,fmt,...)
({
if(0)
dev_printk(KERN_DEBUG,dev,dev_fmt(fmt),##__VA_ARGS__);
})
#endif

要把這些調(diào)試信息從控制臺給打印出來,可以這樣做:

  • 修改一下默認(rèn)打印機(jī)別,在./inlcude/linux/printk.h中,直接修改其默認(rèn)值,8表示全放出來。
#defineCONSOLE_LOGLEVEL_DEFAULT8//CONFIG_CONSOLE_LOGLEVEL_DEFAULT
#defineCONSOLE_LOGLEVEL_QUIETCONFIG_CONSOLE_LOGLEVEL_QUIET
  • 在模塊頂端添加宏定義
/*添加宏定義DEBUG開關(guān)*/
#defineDEBUG
#include
#include
#include

當(dāng)然,你也可以通過makefile來定義這個宏,找到你模塊所在的模塊,添加如下語句:

DEBUG=y

推薦使用device.h中的定義的一系列宏,對應(yīng)了不同日志級別。

#definedev_emerg(dev,fmt,...)
_dev_emerg(dev,dev_fmt(fmt),##__VA_ARGS__)
#definedev_crit(dev,fmt,...)
_dev_crit(dev,dev_fmt(fmt),##__VA_ARGS__)
#definedev_alert(dev,fmt,...)
_dev_alert(dev,dev_fmt(fmt),##__VA_ARGS__)
#definedev_err(dev,fmt,...)
_dev_err(dev,dev_fmt(fmt),##__VA_ARGS__)
#definedev_warn(dev,fmt,...)
_dev_warn(dev,dev_fmt(fmt),##__VA_ARGS__)
#definedev_notice(dev,fmt,...)
_dev_notice(dev,dev_fmt(fmt),##__VA_ARGS__)
#definedev_info(dev,fmt,...)
_dev_info(dev,dev_fmt(fmt),##__VA_ARGS__)

這有什么好處呢,因為這樣可以將模塊的設(shè)備名給打印出來。比如我在調(diào)試一個IIO設(shè)備時,其關(guān)聯(lián)的SPI控制接口到底發(fā)了些什么控制命令,通過這種方式就可以非常清楚的看到驅(qū)動調(diào)用了什么設(shè)備,寫了哪些寄存器,寫的什么值。

ad9467spi1.0:ad9467_spi_write:REG:0x5VAL:0x1(0)
ad9467spi1.0:ad9467_spi_write:REG:0xDVAL:0x0(0)
ad9467spi1.0:ad9467_spi_write:REG:0x5VAL:0x3(0)
ad9467spi1.0:ad9467_spi_write:REG:0xFFVAL:0x1(0)
ad9467spi1.0:ad9467_spi_write:REG:0xFFVAL:0x0(0)
ad9467spi1.0:ad9467_spi_write:REG:0x5VAL:0x2(0)
ad9467spi1.0:ad9467_spi_write:REG:0xDVAL:0x0(0)
ad9467spi1.0:ad9467_spi_write:REG:0x5VAL:0x3(0)
ad9467spi1.0:ad9467_spi_write:REG:0xFFVAL:0x1(0)

仍然沒有看到?

如果你配了這些,甚至編譯了,可是你還是沒有看到打印信息,那么可能printk沒有使能,在哪里使能呢?

CONFIG_PRINTK宏是內(nèi)核打印的編譯開關(guān),大概率是這個配置沒有使能。

總結(jié)一下

內(nèi)核模塊的調(diào)試還有很多其他的手段,printk則是一個非常高效的調(diào)試手段,所有如何比較好的利用printk進(jìn)行打印調(diào)試,是做內(nèi)核模塊調(diào)試一個必要掌握的手段,至于printk的內(nèi)部實現(xiàn)其實也較為復(fù)雜,這塊代碼則沒有必要深究,當(dāng)然如果從學(xué)習(xí)的角度去分析分析其代碼如何實現(xiàn)的,也是不錯的。好了,本期就分享到這里,咱們下期見~

責(zé)任編輯:haq
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 內(nèi)核
    +關(guān)注

    關(guān)注

    3

    文章

    1360

    瀏覽量

    40185
  • 驅(qū)動
    +關(guān)注

    關(guān)注

    12

    文章

    1818

    瀏覽量

    85110
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11209

    瀏覽量

    208721

原文標(biāo)題:驅(qū)動調(diào)試神器printk你掌握了嗎?

文章出處:【微信號:gh_c472c2199c88,微信公眾號:嵌入式微處理器】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    微軟Copilot:與OpenAI ChatGPT類似的AI助手

    科技媒體Windows Latest今日發(fā)表文章,詳細(xì)介紹了Copilot應(yīng)用的使用心得,指出其設(shè)計理念與OpenAI的ChatGPT頗為相似。
    的頭像 發(fā)表于 05-23 14:36 ?591次閱讀

    嵌入式學(xué)習(xí)-飛凌嵌入式ElfBoard ELF 1板卡-如何在內(nèi)核開啟時間戳

    1.進(jìn)入內(nèi)核源碼目錄,執(zhí)行環(huán)境變量。elf@ubuntu:~/work/linux-4.1.15-elf1$ . /opt/fsl-imx-x11/4.1.15-2.0.0
    發(fā)表于 05-08 09:49

    飛凌嵌入式ElfBoard ELF 1板卡-如何在內(nèi)核開啟時間戳

    1.進(jìn)入內(nèi)核源碼目錄,執(zhí)行環(huán)境變量。elf@ubuntu:~/work/linux-4.1.15-elf1$ . /opt/fsl-imx-x11/4.1.15-2.0.0
    發(fā)表于 05-08 09:44

    國產(chǎn)FPGA應(yīng)用專題--易靈思Efinity軟件使用心得

    做為FPGA的集成開發(fā)環(huán)境,不同的廠家其實大同小異。很多國產(chǎn)廠家,如安路,高云,會在軟件上貼近Xilinx和Intel,以節(jié)省客戶的軟件使用成本。而國產(chǎn)廠商的易靈思的集成開發(fā)環(huán)境Efinity似乎并不像大廠,顯得差異更大一些。但經(jīng)過一段時間的使用,我個人認(rèn)為并不需要因為差異大些就過于排斥,Efinity在使用上并不會麻煩。 接下來我們來聊一下Efinity的一些功能及個人使用感受。主要包括以下幾個方面: (1)軟件安裝; (2)軟件界面; (3)控制面板;
    的頭像 發(fā)表于 04-23 15:38 ?1966次閱讀
    國產(chǎn)FPGA應(yīng)用專題--易靈思Efinity軟件使<b class='flag-5'>用心得</b>

    手機(jī)信號放大器:優(yōu)化通信質(zhì)量的利器

    深圳特信屏蔽器|手機(jī)信號放大器:優(yōu)化通信質(zhì)量的利器
    的頭像 發(fā)表于 04-02 09:05 ?642次閱讀

    EMI濾波器:電磁干擾過濾的利器?|深圳比創(chuàng)達(dá)電子EMC

    EMI濾波器:電磁干擾過濾的利器?|深圳比創(chuàng)達(dá)電子EMC
    的頭像 發(fā)表于 01-29 10:13 ?473次閱讀
    EMI濾波器:電磁干擾過濾的<b class='flag-5'>利器</b>?|深圳比創(chuàng)達(dá)電子EMC

    1-2B參數(shù)規(guī)模大模型的使用心得

    大模型時代,根據(jù)大模型縮放定律,大家通常都在追求模型的參數(shù)規(guī)模更大、訓(xùn)練的數(shù)據(jù)更多,從而使得大模型涌現(xiàn)出更多的智能。但是,模型參數(shù)越大部署壓力就越大。即使有g(shù)ptq、fastllm、vllm等推理加速方法,但如果GPU資源不夠也很難保證高并發(fā)。
    的頭像 發(fā)表于 12-28 11:47 ?898次閱讀
    1-2B參數(shù)規(guī)模大模型的使<b class='flag-5'>用心得</b>

    五軸按鍵測試機(jī):精準(zhǔn)評估按鍵性能的利器

    五軸按鍵測試機(jī):精準(zhǔn)評估按鍵性能的利器
    的頭像 發(fā)表于 12-26 09:15 ?501次閱讀
    五軸按鍵測試機(jī):精準(zhǔn)評估按鍵性能的<b class='flag-5'>利器</b>

    探秘四軸按鍵測試機(jī):提高生產(chǎn)效率的利器

    探秘四軸按鍵測試機(jī):提高生產(chǎn)效率的利器?|深圳磐石
    的頭像 發(fā)表于 12-25 09:11 ?563次閱讀
    探秘四軸按鍵測試機(jī):提高生產(chǎn)效率的<b class='flag-5'>利器</b>

    窺探材料性能的利器:平行擠壓測試儀解析

    窺探材料性能的利器:平行擠壓測試儀解析
    的頭像 發(fā)表于 12-11 09:09 ?461次閱讀
    窺探材料性能的<b class='flag-5'>利器</b>:平行擠壓測試儀解析

    關(guān)于PCB板ESD設(shè)計的實用心得

    在做ESD放電測試時通常采用兩種方法:接觸放電和空氣放電。接觸放電就是直接對待測設(shè)備進(jìn)行放電;空氣放電也稱為間接放電,是強(qiáng)磁場對鄰近電流環(huán)路耦合產(chǎn)生。這兩種測試的測試電壓一般為2KV-8KV,不同地區(qū)要求不一樣,因此在設(shè)計之前,先要弄清楚產(chǎn)品針對的市場。
    發(fā)表于 12-08 15:26 ?361次閱讀

    【收藏】大牛總結(jié)的30個PCB布局的細(xì)節(jié)與心得

    【收藏】大??偨Y(jié)的30個PCB布局的細(xì)節(jié)與心得
    的頭像 發(fā)表于 12-06 15:17 ?581次閱讀

    HT for Web (Hightopo) 使用心得(5)- 動畫的實現(xiàn)

    其實,在 HT for Web 中,有多種手段可以用來實現(xiàn)動畫。我們這里仍然用直升機(jī)為例,只是更換了場景。增加了巡游過程。 使用 HT 開發(fā)的一個簡單網(wǎng)頁直升機(jī)巡邏動畫(Hightopo 使用心得
    的頭像 發(fā)表于 11-29 11:04 ?728次閱讀
    HT for Web (Hightopo) 使<b class='flag-5'>用心得</b>(5)- 動畫的實現(xiàn)

    ADI電源管理芯片使用歷程及心得

    本次與大家分享的是世健和ADI聯(lián)合舉辦的《在ADI電源產(chǎn)品的花園里“挖呀挖”》主題活動的三等獎文章:《ADI電源管理芯片使用歷程及心得》及作者獲獎感言。獲獎感言ADI電源管理芯片使用歷程及心得
    的頭像 發(fā)表于 11-18 08:23 ?2300次閱讀
    ADI電源管理芯片使用歷程及<b class='flag-5'>心得</b>

    四種獲取內(nèi)核函數(shù)地址的方法

    內(nèi)核調(diào)試中,經(jīng)常需要知道某個函數(shù)的地址,或者根據(jù)函數(shù)地址找到對應(yīng)的函數(shù),從而進(jìn)行更深一步的debug。
    的頭像 發(fā)表于 11-17 16:58 ?1218次閱讀
    四種獲取<b class='flag-5'>內(nèi)核</b>函數(shù)地址的方法