linux 内核 printk 使用
在linux 中,內核打印語句 printk() 會將內核信息輸出到內核信息緩沖區中。內核信息緩沖區是一個環形緩沖區(ring buffer),因此,如果插入的信息過多,就會將之前的信息沖刷掉。
printk() 定義了8個消息級別,分為級別0 ~ 7,級別越低(數值越大)的消息越不重要,第0級是緊急事件,
第7級是調試級,在內核中 include/linux/printk.h 中的定義如下:
#define KERN_EMERG ? ?"<0>" ? ?/* system is unusable ? ? ? ? ? ?*/
#define KERN_ALERT ? ?"<1>" ? ?/* action must be taken immediately ? ?*/
#define KERN_CRIT ? ?"<2>" ? ?/* critical conditions ? ? ? ? ? ?*/
#define KERN_ERR ? ?"<3>" ? ?/* error conditions ? ? ? ? ? ?*/
#define KERN_WARNING ? ?"<4>" ? ?/* warning conditions ? ? ? ? ? ?*/
#define KERN_NOTICE ? ?"<5>" ? ?/* normal but significant condition ? ?*/
#define KERN_INFO ? ?"<6>" ? ?/* informational ? ? ? ? ? ?*/
#define KERN_DEBUG ? ?"<7>" ? ?/* debug-level messages ? ?*/
0級,代表緊急事件,一般是系統崩潰之前提示的消息
1級,必須立即采取行動
2級,臨界狀態,通常涉及嚴重的硬件或軟件操作失敗
3級,用于報告錯誤狀態,設備驅動程序會經常使用KERN_ERR 報告來自硬件的問題
4級,對可能出現問題的情況進行警告,這類情況通常不會對系統造成嚴重問題
5級,有必要進行提示的正常情況,許多與安全相關的狀況用這個級別進行提示
6級,內核提示性信息,很多驅動程序在啟動的時候用這個級別打印出它們找到的硬件信息
7級,用于調試信息
調試時,通常使用封裝了 printk 的更高級的宏,其中可替代 printk 的宏如下:
#define pr_emerg(fmt, ...) \
? ? printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)
#define pr_alert(fmt, ...) \
? ? printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
#define pr_crit(fmt, ...) \
? ? printk(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
#define pr_err(fmt, ...) \
? ? printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warning(fmt, ...) \
? ? printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warn pr_warning
#define pr_notice(fmt, ...) \
? ? printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
#define pr_info(fmt, ...) \
? ? printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
#define pr_cont(fmt, ...) \
? ? printk(KERN_CONT fmt, ##__VA_ARGS__)
/* pr_devel() should produce zero code unless DEBUG is defined */
#ifdef DEBUG
#define pr_devel(fmt, ...) \
? ? printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#else
#define pr_devel(fmt, ...) \
? ? no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#endif
在打印信息時,如果要打印所出其所在函數,可以使用 __FUNCTION__,
printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION, irq, devname);
對于做Linux內核開發的人來說,printk實在是再熟悉不過了。內核啟動時顯示的各種信息大部分都是通過她來實現的,在做內核驅動調試的時候大部分 時候使用她就足矣。她之所以用得如此廣泛,一個是由于她使用方便,還有一個重要的原因是她的健壯性。它使用范圍很廣,幾乎是內核的任何地方都能調用它。你既可以在中斷上下文、進程上下中調用她,也可以在任何持有鎖時調用她,更可以在SMP系統中調用她,且調用時連鎖都不必使用。這樣好的適應性來源于她的設計,一個由三個指針控制的簡單“ring buffer”。
注意上面說到的是:“幾乎”在內核的任何地方都可以使用。那什么地方使用會有“問題”?那就是在系統啟動過程的早期,終端初始化之前的某些地方雖然可以使用,但是在終端和控制臺被初始化之前所有信息都被緩存在printk的簡單的ring buffer(環形緩沖區)中,直到終端和控制臺被初始化之后,所有緩存信息都被一并輸出。
如果你要調試的是啟動過程最開始的部分(如setup_arch()),可以依靠此時能夠工作的硬件設備(如串口)與外界通信,使用printk()的變體early_printk()函數。她在啟動過程初期就具有在終端上打印的能力,功能與prink()類似,區別在于:
(1)函數名
(2)能夠更早地工作(輸出信息)
(3)她有自己的小緩存(一般為512B)
(4)一次性輸出到硬件設備,不再以ring buffer的形式保留信息。
但該函數在一些構架上無法實現,所以這種辦法缺少可移植性。(大多數構架都可以,包括x86和arm)。
所以,除非要在啟動初期在終端上輸出,否則我們認為printk()在任何情況下都能工作。這點從內核的啟動代碼中就可以看出,在已進入start_kernel不久就通過printk打印內核版本信息了。
總結
以上是生活随笔為你收集整理的linux 内核 printk 使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 批处理检查电脑是否中了冰河木马
- 下一篇: 首次使用Windbg调试dNet程序