這里強烈推薦驅動開發者用這種方式輸出log。linux kernel space中有pr_debug及dev_dbg來使用dynamic debug。可以看到當用戶define DEBUG后,prdebug和dev_dbg就等於printk的KERN_DEBUG級別輸出了;否則什么也不打印。
一. 開啟dynamic debug功能
要使用dynamic_debug需要在kernel的defconfig中開啟
CONFIG_DEBUG_FS=y CONFIG_DYNAMIC_DEBUG=y
用menuconfig去配置的話如下圖:
二 dynamic debug功能使用
1. 編譯好image后,需要掛載debugfs(不掛載的話將不會創建debugfs,那么/sys/kernel/debug/下是空的)。
修改etc/fstab文件,追加下面這段字符。
nodev /sys/kernel/debug debugfs defaults 0 0
2. 可以用cat /sys/kernel/debug/dynamic_debug/control | grep xxx.c來查看自己想要查看的log所在文件有沒有包含進去。
那這里可以看到該文件所有用dev_dbg()打印出的訊息。
那如果不開啟CONFIG_DYNAMIC_DEBUG,將不會產生/sys/kernel/debug/dynamic_debug目錄, 是不能進行動態打印的。
開啟dynamic debug:
①echo "module cvi_mipi_rx +p" > /sys/kernel/debug/dynamic_debug/control ②echo "file cvi_vip_cif.c +p" >/sys/kernel/debug/dynamic_debug/control
這兩種方式都是開dynamic debug,第一種是對模塊開啟,第二種只對文件開啟。下面舉一個栗子:
開啟之后,可以看到dev_dbg()打印的log都會輸出。
反之,關閉dynamic debug:
①echo "module cvi_mipi_rx -p" > /sys/kernel/debug/dynamic_debug/control ②echo "file cvi_vip_cif.c -p" >/sys/kernel/debug/dynamic_debug/control
那除了上面的兩種方式還有一種可以只開啟某個function:
echo "func _init_resource +p" > /sys/kernel/debug/dynamic_debug/control
不過一般不太推薦使用這種做法,因為很多functions都是相同名字但屬於不同modules的。
三 dev_err/dev_info/dev_warn系列函數
在Linux驅動代碼中,有大量的調試信息,那么推薦使用dev_err/dev_info/dev_warn這一系列函數族。這一系列函數族定義在include/linux/device.h.
其實這些函數族本質上和下面printk.h中的定義也是完全一致的。
#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__)
下圖是示例,可以看到err級別以下的log沒有打印,那么設置printk的控制台級別可以把對應的log輸出到console(如何設置printk console level可以看上一篇1. printk & dmesg)。
四 可變參數宏(##__VA_ARGS__)
##__VA_ARGS__表示可變參數宏,可以用來傳遞多個參數,如:
#define my_dbg(fmt, ...) \ do { \ printf("[%s] [%d] " fmt, __func__, __LINE__, ##__VA_ARGS__);\ } while(0)
#define my_dbg(fmt...) \
do { \
printf("[%s] [%d] ", __func__, __LINE__); \
printf(fmt); \
} while(0)
char *name = "robin"; int age = 18; my_dbg("this is a test. name:%s, age:%d\n", name, age);
結果如下:
那和下面這種寫法呢本質上是完全一樣的。