国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

內核調試利器printk的使用心得

Q4MP_gh_c472c21 ? 來源:嵌入式客棧 ? 作者:逸珺 ? 2021-11-08 17:31 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

[導讀] 剛剛開始做Linux相關開發工作時,深感Linux內核代碼龐大,要加些自己的驅動進內核代碼樹,常常深陷bug的泥沼難以自拔,今天來分享一下內核調試利器printk的使用心得。

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

printk初接觸

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

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

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

cat/dev/kmsg

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

/proc/kmsg

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

一個進程必須具有超級用戶特權才能讀取此文件,并且只有一個進程應讀取該文件。如果正在運行使用syslog(2)系統調用記錄內核消息的syslog進程,則不應讀取該文件。

這里補充說一點是,/proc文件系統本質上是偽文件系統,它提供了內核數據結構的接口。它一般掛載在/proc上。通常情況下,它是由系統自動掛載的的,但是也可以使用以下命令手動安裝:

mount-tprocproc/proc

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

/dev/kmsg

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

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

其代碼實現也可以簡單

printk使用

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

內核打印,界定了日志級別,其語法范式:

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

比如:

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

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

日志級別

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

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

格式化

下面內容來源于./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也不支持,%e, %f, %g, %a也不支持,如使用了會導致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還支持格式化打印塊設備名、IPv4、IPv6地址、網絡設備屬性、MAC/FDDI地址、UUID/GUID地址等等。如需要用到可查閱該文檔獲取更為詳細的信息。

修改控制臺打印級別

運行時修改

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

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

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

  • 當前控制臺日志級別
  • 默認日志級別
  • 最小日志級別
  • 啟動階段默認日志級別

使用下面命令可以當前控制臺printk日志級別:

echo6>/proc/sys/kernel/printk

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

echo8>/proc/sys/kernel/printk

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

klogd-o-f./kernel.msg

編譯修改

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

這里需要去看看你的內核模塊代碼是以何種方式去調用printk的,比如有的代碼這樣調用:

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其本質上也是調用的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

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

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

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

DEBUG=y

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

#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__)

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

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宏是內核打印的編譯開關,大概率是這個配置沒有使能。

總結一下

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

責任編輯:haq
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 內核
    +關注

    關注

    4

    文章

    1466

    瀏覽量

    42760
  • 驅動
    +關注

    關注

    12

    文章

    1942

    瀏覽量

    88471
  • Linux
    +關注

    關注

    88

    文章

    11746

    瀏覽量

    218846

原文標題:驅動調試神器printk你掌握了嗎?

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

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    (信息量有點大)基于RK3576深入解讀kernel-6.1/System.map:內核開發調試的“地址-功能”導航圖

    在 Linux 內核開發與調試場景中,你是否遇到過這些困惑?內核 panic 時打印的 pc: ffffffc00801c400 究竟對應哪個函數?編寫模塊時引用的foo 符號為何提示“未定義”?優化
    的頭像 發表于 02-04 16:18 ?486次閱讀
    (信息量有點大)基于RK3576深入解讀kernel-6.1/System.map:<b class='flag-5'>內核</b>開發<b class='flag-5'>調試</b>的“地址-功能”導航圖

    深入RK3588內核:rockchip_linux_defconfig的作用與調試價值

    編譯內核、適配硬件,還是調試復雜的內核故障,這個看似“平平無奇” 的配置文件,都扮演著 “基石” 般的角色。
    的頭像 發表于 02-03 15:56 ?1105次閱讀
    深入RK3588<b class='flag-5'>內核</b>:rockchip_linux_defconfig的作用與<b class='flag-5'>調試</b>價值

    探索DSC Multilink:調試利器的技術剖析

    探索DSC Multilink:調試利器的技術剖析 在嵌入式系統開發領域,高效的調試工具是節省開發時間、提升開發效率的關鍵。今天,我們就來深入了解一款功能強大的調試接口——DSC Mu
    的頭像 發表于 12-24 17:05 ?247次閱讀

    Linux內核日志玩明白了嗎?printk調試神器全解析

    前言:做Linux驅動開發或內核調試的朋友,一定對printk不陌生,但你真的會用它嗎?為什么同樣是調試RK3588內核,別人能精準捕捉關鍵
    的頭像 發表于 12-19 08:32 ?817次閱讀
    Linux<b class='flag-5'>內核</b>日志玩明白了嗎?<b class='flag-5'>printk</b><b class='flag-5'>調試</b>神器全解析

    CW32調試接口

    CW32F030 的內核為 ARM?Cortex?-M0+,內核內置 DAP 硬件調試模塊,支持 SWD 模式調試。硬件調試模塊可實現在取指
    發表于 12-15 06:18

    Linux驅動開發的必備知識

    的驅動框架進行開發。 6、調試技能: 掌握內核調試工具,如 KDB、KGDB、printk 等。 能夠分析內核日志,定位驅動程序中的問
    發表于 12-04 07:58

    GCC -O0?編譯內核調試黨的?“救命神器”,這些優勢?90%?開發者沒吃透!

    在?Linux?內核開發、驅動調試內核問題定位的場景中,“編譯優化等級”?是個容易被忽略卻影響巨大的選擇。GCC?的優化等級從?O0?到?O3、Os、Ofast?各有側重,而 O0(默認優化等級
    的頭像 發表于 12-03 07:05 ?466次閱讀
    GCC -O0?編譯<b class='flag-5'>內核</b>:<b class='flag-5'>調試</b>黨的?“救命神器”,這些優勢?90%?開發者沒吃透!

    Linux內核printk日志級別全解析:從參數解讀到實操配置

    ”——?它直接決定了?printk內核打印函數)的日志輸出行為。如果你是嵌入式開發者、內核調試工程師,或經常需要排查驅動?/?系統問題,理解這串數字和?
    的頭像 發表于 11-20 15:54 ?1635次閱讀
    Linux<b class='flag-5'>內核</b><b class='flag-5'>printk</b>日志級別全解析:從參數解讀到實操配置

    設備遠程調試利器:御控網關開啟PLC高效運維新時代

    御控網關,專為設備遠程調試,尤其是PLC(可編程邏輯控制器)的遠程調試服務,憑借其卓越性能與廣泛兼容性,支持絕大部分PLC遠程調試,成為工業領域運維人員的得力助手。
    的頭像 發表于 06-24 17:22 ?546次閱讀

    安森美WebDesigner+設計工具使用心得

    安森美(onsemi)近期推出的開發工具試用活動已圓滿收官,本次活動吸引了眾多工程師的積極參與,通過實際應用體驗安森美先進的開發工具,共同挖掘其在設計中的潛力。之前推文已分享過用WebDesigner+ 設計工具完成120W DC-DC隔離電源設計、通過Elite Power仿真工具,簡化125KW 儲能系統設計,今天分享的試用報告聚焦WebDesigner工具,一起來了解下。
    的頭像 發表于 05-16 15:19 ?882次閱讀
    安森美WebDesigner+設計工具使<b class='flag-5'>用心得</b>

    福祿克ST20MAX紅外測溫儀究竟有多好用

    “精準測量、智能預約、堅固耐用、貼心設計…” 小福帶著首批ST20MAX客戶試用心得來啦!ST20MAX 究竟有多好用?讓我們一探究竟!
    的頭像 發表于 04-10 13:55 ?804次閱讀

    嵌入式學習-飛凌嵌入式ElfBoard ELF 1板卡-內核空間與用戶空間的數據拷貝之獲取內核空間數據

    例程代碼路徑:ELF 1開發板資料包\\03-例程源碼\\03-2 驅動例程源碼\\03_內核空間與用戶空間的數據拷貝\\copy_to_user 在mydevice-auto.c源碼的基礎上
    發表于 03-21 14:00

    飛凌嵌入式ElfBoard ELF 1板卡-內核空間與用戶空間的數據拷貝之獲取內核空間數據

    本帖最后由 jf_13411809 于 2025-3-20 14:09 編輯 例程代碼路徑:ELF 1開發板資料包\\03-例程源碼\\03-2 驅動例程源碼\\03_內核空間與用戶空間的數據
    發表于 03-20 11:48

    恩智浦分享Zephyr調試技巧

    調試技巧 printk調試法 :通過使用prink來打印一些輔助調試信息,操作簡單,適合于基礎的profiling,但是可能會導致時序問題,尤其是針對在中斷上下文的處理中。還有針對于l
    的頭像 發表于 03-13 09:05 ?2306次閱讀

    聚焦離子束(FIB)技術:芯片調試利器

    FIB技術在芯片調試中的關鍵應用1.電路修改與修復在芯片設計和制造過程中,由于種種原因可能會出現設計錯誤或制造缺陷。FIB技術能夠對芯片電路進行精細的修改和修復。通過切斷錯誤的金屬連接線,并重
    的頭像 發表于 02-17 17:19 ?1227次閱讀
    聚焦離子束(FIB)技術:芯片<b class='flag-5'>調試</b>的<b class='flag-5'>利器</b>