Linux內核基礎篇——動態輸出調試

動態輸出(dynamic print)是內核子系統開發者最喜歡的輸出技術之一。

上篇說到printk調試,但printk是全局的,只能設置輸出等級。而動態輸出可以動態選擇打開某個內核子系統的輸出,可以有選擇性地打開某些模塊的輸出。

配置內核編譯選項

要使用動態輸出,必須在配置內核時打開CONFIG_DYNAMIC_DEBUG宏。內核代碼裏使用大量pr_debug()/dev_dbg()函數來輸出信息,這些就使用了動態輸出。

需要打開的內核配置選項:

CONFIG_DEBUG_FS=y
CONFIG_DYNAMIC_DEBUG=y 

CONFIG_DYNAMIC_DEBUG是配置動態輸出,它依賴於CONFIG_DEBUG_FS,而CONFIG_DEBUG_FSdebugfs文件系統

打開內核配置後,我們還需要掛載debugfs文件系統

debugfs文件系統掛載

動態輸出在debugfs文件系統中有一個control文件節點,這個文件節點記錄了系統中所有使用動態輸出技術的文件名路徑、輸出所在的行號、模塊名字和要輸出的語句

debugfs默認會掛載到/sys/kernel/debug,如果沒有掛載,可以執行以下命令掛載:

# mount -t debugfs none /sys/kernel/debug/

掛載debugfs文件系統後,可以查看control節點內容:

# cat /sys/kernel/debug/dynamic_debug/control

動態輸出使用

打開svcsock.c文件中所有的動態輸出語句

# echo 'file svcsock.c +p' > /sys/kernel/debug/dynamic_debug/control

打開usbcore模塊中所有的動態輸出語句

# echo 'module usbcore +p' > /sys/kernel/debug/dynamic_debug/control

打開svc_process()函數中所有的動態輸出語句

# echo 'func svc_process() +p' > /sys/kernel/debug/dynamic_debug/control

打開文件路徑包含usb的文件裏所有的動態輸出語句

# echo -n '*usb* +p' > /sys/kernel/debug/dynamic_debug/control

打開系統所有的動態輸出語句

# echo -n '+p' > /sys/kernel/debug/dynamic_debug/control

上面是打開動態輸出語句的例子,除了能輸出pr_debug()/dev_dbg()函數中定義的輸出信息外,還能輸出一些額外信息,如函數名、行號、模塊名字以及線程ID等

  • p:打開動態輸出語句
  • f:輸出函數名
  • l:輸出行號
  • m:輸出模塊名字
  • t:輸出線程ID

另外,還可以在各個子系統的Makefile中添加ccflags來打開動態輸出語句

<../Makefile>

ccflags-y += -DDEBUG
ccflags-y += -DVERBOSE_DEBUG

實際案例

例如在一個led驅動中的open()、write()等函數開頭添加一句pr_debug(“%s enter\n”, __ func__);

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>

static int major = 0;
static char kernel_buf[1024];
static struct class *hello_class;

#define MIN(a, b) (a < b ? a : b)

static ssize_t hello_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
 int err;
 pr_debug("%s enter\n", __func__);

 err = copy_to_user(buf, kernel_buf, MIN(1024, size));
 return MIN(1024, size);
}

static ssize_t hello_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
 int err;
 pr_debug("%s enter\n", __func__);
 err = copy_from_user(kernel_buf, buf, MIN(1024, size));
 return MIN(1024, size);
}

static int hello_drv_open (struct inode *node, struct file *file)
{
 pr_debug("%s enter\n", __func__);
 return 0;
}

static int hello_drv_close (struct inode *node, struct file *file)
{
 pr_debug("%s enter\n", __func__);
 return 0;
}

/* 2. 定義自己的file_operations結構體                                              */
static struct file_operations hello_drv = {
 .owner  = THIS_MODULE,
 .open    = hello_drv_open,
 .read    = hello_drv_read,
 .write   = hello_drv_write,
 .release = hello_drv_close,
};

static int __init hello_init(void)
{
 int err;
 
 pr_debug("%s enter\n", __func__);
 major = register_chrdev(0, "hello", &hello_drv);  /* /dev/hello */

 hello_class = class_create(THIS_MODULE, "hello_class");
 err = PTR_ERR(hello_class);
 if (IS_ERR(hello_class)) {
  unregister_chrdev(major, "hello");
  return -1;
 }
 
 device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello"); /* /dev/hello */
 
 return 0;
}

static void __exit hello_exit(void)
{
 pr_debug("%s enter\n", __func__);
 device_destroy(hello_class, MKDEV(major, 0));
 class_destroy(hello_class);
 unregister_chrdev(major, "hello");
}

module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

爲了方面查看,先清除內核輸出:

# dmesg -c

然後加載驅動,執行dmesg查看是否有打印:

# insmod hello_drv.ko
# dmesg

此時沒有pr_debug()的打印。這時再使用動態輸出打開hello_drv模塊的動態輸出:

# echo 'module hello_drv +p' > /sys/kernel/debug/dynamic_debug/control

然後執行該驅動的應用層程序,使其調用到驅動的open、write、close函數,從而執行pr_debug():

# ./hello_drv_test -w 10

再查看demsg內容:

可以看到,當打開了hello_drv模塊的動態輸出後,驅動中的pr_debug()語句就可以正常打印了。

再看看debugfs的control節點:

# cat /sys/kernel/debug/dynamic_debug/control

control節點記錄了剛剛執行pr_debug()時的文件名、所在行號、模塊名、函數名和輸出語句(p表示動態輸出的語句)

 

原文:http://www.shouxieziti.cn/129489.html

 

 

 

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章