printk 核心除錯 訊息級別
阿新 • • 發佈:2019-02-01
核心除錯相比於使用者程式除錯難度就要大很多。
LINUX 是 C 語言寫的,但不能使用 printf 來列印,原因很容易解釋,核心中不認識庫
檔案中的 printf 函式。
最普通的除錯技術是監視,即在應用程式中的適當地方呼叫 printf 顯示監視資訊,這
是針對普通應用程式而言,對於 linux 核心則是通過 printk 來完成相應工作,函式 printk 的
使用方法和 printf 相似。
1、訊息優先順序(loglevel)
printk 根據日誌級別(loglevel)對訊息進行分類。
日誌級別用巨集定義,日誌級別巨集展開為一個字串,在編譯時由前處理器將它和訊息
文字拼接成一個字串,因此 printk 函式中日誌級別巨集和格式字串間不能有逗號。
printk 的日誌級別定義如下(在 include/linux/printk.h 中):
#define KERN_EMERG "<0>" /*緊急事件訊息,系統崩潰之前提示,表示系統不可用*/
#define KERN_ALERT "<1>" /*報告訊息,表示必須立即採取措施*/
#define KERN_CRIT "<2>" /*臨界條件,通常涉及嚴重的硬體或軟體操作失敗*/
#define KERN_ERR "<3>" /*錯誤條件,驅動程式常用 KERN_ERR 來報告硬體的錯誤*/
#define KERN_WARNING "<4>" /*警告條件,對可能出現問題的情況進行警告*/
#define KERN_NOTICE "<5>" /*正常但又重要的條件,用於提醒。常用於與安全相關的訊息*/
#define KERN_INFO "<6>" /*提示資訊,如驅動程式啟動時,列印硬體資訊*/
#define KERN_DEBUG "<7>" /*除錯級別的訊息*/
日誌級別的範圍是 0~7,沒有指定日誌級別的 printk 語句預設採用的級別是
DEFAULT_ MESSAGE_LOGLEVEL,其定義列出如下:
/*沒有定義日誌級別的 printk 使用下面的預設級別*/
#define DEFAULT_MESSAGE_LOGLEVEL 4
/* KERN_WARNING 警告條件*/
核心設定了控制檯的日誌級別 console_loglevel。printk 日誌級別的作用是列印一定級別
的訊息,與之類似,控制檯只顯示一定級別的訊息。當日志級別小於 console_loglevel 時,
訊息才能顯示出來。控制檯相應的日誌級別定義如下:
/* 顯示比這個級別更重發的訊息*/
#define MINIMUM_CONSOLE_LOGLEVEL 1 /*可以使用的最小日誌級別*/
#define DEFAULT_CONSOLE_LOGLEVEL 7
/*比 KERN_DEBUG 更重要的訊息都被列印*/
int console_printk[4] = {
DEFAULT_CONSOLE_LOGLEVEL,
/*控制檯日誌級別,優先順序高於該值的訊息將在控制檯顯示*/
/*預設訊息日誌級別,printk 沒定義優先順序時,列印這個優先順序以上的訊息*/
DEFAULT_MESSAGE_LOGLEVEL,
/*最小控制檯日誌級別,控制檯日誌級別可被設定的最小值(最高優先順序)*/
MINIMUM_CONSOLE_LOGLEVEL,
DEFAULT_CONSOLE_LOGLEVEL,
/* 預設的控制檯日誌級別*/
};
通過讀寫/proc/sys/kernel/printk 檔案可讀取和修改控制檯的日誌級別。檢視這個檔案的
方法如下:
#cat /proc/sys/kernel/printk
6 4 1 7
上面顯示的 4 個數據分別對應控制檯日誌級別、預設的訊息日誌級別、最低的控制檯日
志級別和預設的控制檯日誌級別。
可用下面的命令設定當前日誌級別:
# echo 8 > /proc/sys/kernel/printk
通常,選用 KERN_INFO 和 KERN_DEBUG 作為除錯級別。
2、示例
printk(KERN_INFO "Resume: load_image: ret = %d.\n", ret);
printk(KERN_INFO "Resume:test output the point %p\n", ptr);
注意:在 KERN_DEBUG、 KERN_INFO 和後面的輸出語句之間沒有逗號!
3、檢視核心輸出
在核心中,函式 printk 將訊息列印到環形緩衝區__log_buf 中,並將訊息傳給控制檯進
行顯示。控制檯驅動程式根據控制檯的日誌級別顯示日誌訊息。
如果系統同時執行 klogd 和 syslogd,則無論 console_loglevel 為何值,核心訊息都會追
加到/var/log/messages 中(否則按 syslogd 的配置處理)。如果 klogd 沒有執行,則這些訊息
不會傳遞至使用者空間,這時只能檢視/proc/kmsg 檔案(使用 dmesg 命令即可)
實際使用過程中,通過 dmesg 資訊可以獲取核心輸出的訊息:
dmesg > xxxxx.log
#將核心訊息輸出到檔案中
另外,通過訪問/var/log/messages 檔案,可以檢視核心輸出的訊息,並且會保留多次的內容。
4、核心訊息解析
使用“/usr/src/linux-headers-3.2.0-32/scripts”下的 show_delta 指令碼,可以將 dmseg.log 內
容進行再整理,生成可顯示開機時間段的文件。
/usr/src/linux-headers-3.2.0-32-generic/scripts/show_delta xxxx.log > xxxx-time.log
LINUX 是 C 語言寫的,但不能使用 printf 來列印,原因很容易解釋,核心中不認識庫
檔案中的 printf 函式。
最普通的除錯技術是監視,即在應用程式中的適當地方呼叫 printf 顯示監視資訊,這
是針對普通應用程式而言,對於 linux 核心則是通過 printk 來完成相應工作,函式 printk 的
使用方法和 printf 相似。
1、訊息優先順序(loglevel)
printk 根據日誌級別(loglevel)對訊息進行分類。
日誌級別用巨集定義,日誌級別巨集展開為一個字串,在編譯時由前處理器將它和訊息
文字拼接成一個字串,因此 printk 函式中日誌級別巨集和格式字串間不能有逗號。
printk 的日誌級別定義如下(在 include/linux/printk.h 中):
#define KERN_EMERG "<0>" /*緊急事件訊息,系統崩潰之前提示,表示系統不可用*/
#define KERN_ALERT "<1>" /*報告訊息,表示必須立即採取措施*/
#define KERN_CRIT "<2>" /*臨界條件,通常涉及嚴重的硬體或軟體操作失敗*/
#define KERN_ERR "<3>" /*錯誤條件,驅動程式常用 KERN_ERR 來報告硬體的錯誤*/
#define KERN_WARNING "<4>" /*警告條件,對可能出現問題的情況進行警告*/
#define KERN_NOTICE "<5>" /*正常但又重要的條件,用於提醒。常用於與安全相關的訊息*/
#define KERN_INFO "<6>" /*提示資訊,如驅動程式啟動時,列印硬體資訊*/
#define KERN_DEBUG "<7>" /*除錯級別的訊息*/
日誌級別的範圍是 0~7,沒有指定日誌級別的 printk 語句預設採用的級別是
DEFAULT_ MESSAGE_LOGLEVEL,其定義列出如下:
/*沒有定義日誌級別的 printk 使用下面的預設級別*/
#define DEFAULT_MESSAGE_LOGLEVEL 4
/* KERN_WARNING 警告條件*/
核心設定了控制檯的日誌級別 console_loglevel。printk 日誌級別的作用是列印一定級別
的訊息,與之類似,控制檯只顯示一定級別的訊息。當日志級別小於 console_loglevel 時,
訊息才能顯示出來。控制檯相應的日誌級別定義如下:
/* 顯示比這個級別更重發的訊息*/
#define MINIMUM_CONSOLE_LOGLEVEL 1 /*可以使用的最小日誌級別*/
#define DEFAULT_CONSOLE_LOGLEVEL 7
/*比 KERN_DEBUG 更重要的訊息都被列印*/
int console_printk[4] = {
DEFAULT_CONSOLE_LOGLEVEL,
/*控制檯日誌級別,優先順序高於該值的訊息將在控制檯顯示*/
/*預設訊息日誌級別,printk 沒定義優先順序時,列印這個優先順序以上的訊息*/
DEFAULT_MESSAGE_LOGLEVEL,
/*最小控制檯日誌級別,控制檯日誌級別可被設定的最小值(最高優先順序)*/
MINIMUM_CONSOLE_LOGLEVEL,
DEFAULT_CONSOLE_LOGLEVEL,
/* 預設的控制檯日誌級別*/
};
通過讀寫/proc/sys/kernel/printk 檔案可讀取和修改控制檯的日誌級別。檢視這個檔案的
方法如下:
#cat /proc/sys/kernel/printk
6 4 1 7
上面顯示的 4 個數據分別對應控制檯日誌級別、預設的訊息日誌級別、最低的控制檯日
志級別和預設的控制檯日誌級別。
可用下面的命令設定當前日誌級別:
# echo 8 > /proc/sys/kernel/printk
通常,選用 KERN_INFO 和 KERN_DEBUG 作為除錯級別。
2、示例
printk(KERN_INFO "Resume: load_image: ret = %d.\n", ret);
printk(KERN_INFO "Resume:test output the point %p\n", ptr);
注意:在 KERN_DEBUG、 KERN_INFO 和後面的輸出語句之間沒有逗號!
3、檢視核心輸出
在核心中,函式 printk 將訊息列印到環形緩衝區__log_buf 中,並將訊息傳給控制檯進
行顯示。控制檯驅動程式根據控制檯的日誌級別顯示日誌訊息。
如果系統同時執行 klogd 和 syslogd,則無論 console_loglevel 為何值,核心訊息都會追
加到/var/log/messages 中(否則按 syslogd 的配置處理)。如果 klogd 沒有執行,則這些訊息
不會傳遞至使用者空間,這時只能檢視/proc/kmsg 檔案(使用 dmesg 命令即可)
實際使用過程中,通過 dmesg 資訊可以獲取核心輸出的訊息:
dmesg > xxxxx.log
#將核心訊息輸出到檔案中
另外,通過訪問/var/log/messages 檔案,可以檢視核心輸出的訊息,並且會保留多次的內容。
4、核心訊息解析
使用“/usr/src/linux-headers-3.2.0-32/scripts”下的 show_delta 指令碼,可以將 dmseg.log 內
容進行再整理,生成可顯示開機時間段的文件。
/usr/src/linux-headers-3.2.0-32-generic/scripts/show_delta xxxx.log > xxxx-time.log
同事wiki 帖出來 方便檢視