測試環境:linux
運行環境:ubuntu-20.04git
內核版本:5.10.0github
1、接口簡介ubuntu
在系統運行過程當中,維護者能夠經過控制 pr_debug 的開關來動態的配置某個模塊中的調試信息是否輸出,相對於 printk 來講,它顯然是更加靈活。測試
2、使用方法ui
如內核 printk.h 文件中定義:spa
1 /* If you are writing a driver, please use dev_dbg instead */
2 #if defined(CONFIG_DYNAMIC_DEBUG) || \
3 (defined(CONFIG_DYNAMIC_DEBUG_CORE) && defined(DYNAMIC_DEBUG_MODULE)) 4 #include <linux/dynamic_debug.h>
5
6 /** 7 * pr_debug - Print a debug-level message conditionally 8 * @fmt: format string 9 * @...: arguments for the format string 10 * 11 * This macro expands to dynamic_pr_debug() if CONFIG_DYNAMIC_DEBUG is 12 * set. Otherwise, if DEBUG is defined, it's equivalent to a printk with 13 * KERN_DEBUG loglevel. If DEBUG is not defined it does nothing. 14 * 15 * It uses pr_fmt() to generate the format string (dynamic_pr_debug() uses 16 * pr_fmt() internally). 17 */
18 #define pr_debug(fmt, ...) \
19 dynamic_pr_debug(fmt, ##__VA_ARGS__) 20 #elif defined(DEBUG)
21 #define pr_debug(fmt, ...) \
22 printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) 23 #else
24 #define pr_debug(fmt, ...) \
25 no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) 26 #endif
能夠看到經過配置能夠分別實現有三種功能: debug
1)只有當 CONFIG_DYNAMIC_DEBUG 等宏已定義時,動態輸出功能纔會真正的啓用,其核心是靠 dynamic_pr_debug 來實現,大概是經過將描述信息插入到 section("__dyndbg") 段內來進一步實現;調試
2)在引用到 pr_debug 接口的某個文件或某個模塊中,經過自定義一個 DEBUG 來配置它的第二種實現,這時候你們能夠發現它就等同於 printk,很直觀;code
3)若是前兩種配置都不成立,那麼好了, pr_debug 將不會有任何的輸出。
3、實例測試
測試源碼:
【 pr_dbg.c 】
1 #include <linux/kernel.h>
2 #include <linux/module.h>
3 #include <linux/init.h>
4 #include <linux/timer.h>
5 #include <linux/printk.h>
6
7 static struct timer_list timer = {0}; 8
9 void timer_handler(struct timer_list *t) 10 { 11 pr_debug("pr_dbg: This is pr_init func.\n"); 12 mod_timer(&timer, jiffies+msecs_to_jiffies(5000)); 13 } 14
15 static int pr_test_init(void) 16 { 17 timer_setup(&timer, timer_handler, 0); 18 timer.expires = jiffies + 5 * HZ; 19 add_timer(&timer); 20
21 return 0; 22 } 23
24 static int pr_init(void) 25 { 26 pr_test_init(); 27 printk("pr_init exec finished.\n"); 28
29 return 0; 30 } 31
32 static void pr_exit(void) 33 { 34 del_timer(&timer); 35 } 36
37 module_init(pr_init); 38 module_exit(pr_exit); 39 MODULE_LICENSE("GPL"); 40 MODULE_AUTHOR("Zackary.Liu");
【 Makefile 】 :
1 kernel_path := /root/github/linux 2
3 all: 4 make -C ${kernel_path} M=`pwd` modules 5 #KCFLAGS=-DDEBUG 6
7 clean: 8 make -C ${kernel_path} M=`pwd` clean 9
10 obj-m += pr_dbg.o
1)先測試第二種配置吧,比較簡單一些,如上面說過的只要定義一個 DEBUG 便可以實現,那麼咱們直接就在 Makefile 中加入好,
將編譯指令改成: make -C ${kernel_path} M=`pwd` modules KCFLAGS+=-DDEBUG 便可。
將模塊編譯好並安裝,能夠看到有 pr_dbg: This is pr_init func. 信息輸出。
2)配置爲動態輸出,首先須要打開內核相關配置,並編譯替換爲新內核:
藉助 debugfs 下的 control 接口,寫入相應的指令便可控制動態輸出的開關,開關默認是關閉的:
/* 先查找對應信息 */
/ # cat /sys/kernel/debug/dynamic_debug/control | grep pr_dbg /root/kernel_modules/01-dev_dbg/pr_dbg.c:11 [pr_dbg]timer_handler =_ "pr_dbg: This is pr_init func.\012"
/* 打開信息輸出開關 */
/ # echo "file pr_dbg.c +p" > /sys/kernel/debug/dynamic_debug/control
你們有沒有想過,若是動態動態輸出的宏與 DEBUG 宏都定義了,那麼會產生什麼效果呢?
對應源碼的話不難發現,走的仍是動態輸出的流程,只不過默認就是輸出調試信息了。
4、原理分析
動態輸出原理分析,暫時留白。