如何打開pr_debug調試信息


轉載:http://blog.csdn.net/helloanthea/article/details/25330809

以DMA的調試為例,先來看看一個pr_debug函數調用

       pr_debug("%s: %s (%s)\n",
                 __func__,
                 chan ? "success" : "fail",
                 chan ? dma_chan_name(chan) : NULL);

在include/linux/printk.h里找到pr_debug的定義

/* If you are writing a driver, please use dev_dbg instead */
#if defined(CONFIG_DYNAMIC_DEBUG)
/* dynamic_pr_debug() uses pr_fmt() internally so we don't need it here */
#define pr_debug(fmt, ...) \
        dynamic_pr_debug(fmt, ##__VA_ARGS__)
#elif defined(DEBUG)
#define pr_debug(fmt, ...) \
        printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#else
#define pr_debug(fmt, ...) \
        no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#endif


三個判斷條件決定pr_debug的用法
1.如果定義了CONFIG_DYNAMIC_DEBUG,就使用動態debug機制dynamic_pr_debug();
2.如果定義了DEBUG,就使用printk(KERN_DEBUG...)
3.默認情況下,不打印。

那么要想讓kernel乖乖的打印調試信息,就只有兩條路可選了:要么動態debug,要么定義DEBUG宏。

先說一下如何定義DEBUG宏
其實在kernel中很多driver已經定義好了這樣的選項
例如,我們經常可以看到這樣的配置選項和宏定義:
(1)DMA Engine debugging(CONFIG_DMADEVICES_DEBUG )
(2)Power Management Debug Support(CONFIG_PM_DEBUG)
(3)Enable debug for the B2C2 FlexCop drivers(CONFIG_PCI_DEBUG)

以DMA為例,在drivers/dma/Makefile中定義了編譯選項
ccflags-$(CONFIG_DMADEVICES_DEBUG)  := -DDEBUG
其作用相當於在drivers/dma/所有子文件定義了宏#define DEBUG

小伙伴們趕緊把CONFIG_DEBUG選項選上吧,然后重新編譯kernel。先別急,這樣還不夠,
默認的console級別是7(在kernel/printk/printk.c中定義了#define DEFAULT_CONSOLE_LOGLEVEL 7)
只有那些級別“小於7”的調試信息才能打印出來,而printk(KERN_DEBUG...)的級別是7,那就還需要提高console打印級別
如果要查看dma初始化的debug信息,那就直接改代碼
#define DEFAULT_CONSOLE_LOGLEVEL 8
如果是runtime,可以直接通過printk的sys接口調整打印級別

$cat /proc/sys/kernel/printk
7       4       1       7
$echo 8 > /proc/sys/kernel/printk
$cat /proc/sys/kernel/printk
8       4       1       7

 

ok,大功告成!

ps:如果一些driver沒有現成的宏可用,開發人員可以自己仿照上述方法,也可以直接在源文件中定義DEBUG宏

#define DEBUG(宏的作用范圍相信我就不用多說了吧,就是從宏定義開始到源文件的末尾結束)

 

下面再簡單說一下kernel的動態調試
打開Enable dynamic printk() support(DYNAMIC_DEBUG),那么所有的 pr_debug()/dev_debug() 之類的函數在runtime就可以動態地使用了。
kernel動態調試提供一個debugfs接口: <debugfs>/dynamic_debug/control
這個文件可以用來獲取已完成的調試信息列表
例如你要顯示文件'svcsock.c'的1603行內容,你可以這樣做:

nullarbor:~ # echo 'file svcsock.c line 1603 +p' >
                <debugfs>/dynamic_debug/control  

// 提供文件svcsock.c所有信息
nullarbor:~ # echo -n 'file svcsock.c +p' >
                <debugfs>/dynamic_debug/control

如果你想執行多個命令,你需要為每個加入“echo”分割,像這樣:

nullarbor:~ # echo 'file svcsock.c line 1603 +p' > /proc/dprintk ;\
> echo 'file svcsock.c line 1563 +p' > /proc/dprintk

或者甚至是這樣:

nullarbor:~ # (
> echo 'file svcsock.c line 1603 +p' ;\
> echo 'file svcsock.c line 1563 +p' ;\
> ) > /proc/dprintk

file可以替換成module,format等匹配方式,具體用法請參考Documentation/dynamic-debug-howto.txt
好了,enjoy你的debug之旅吧!

下面是一個范例

Makefile:

ifneq ($(KERNELRELEASE),)
    ccflags-y += -DDEBUG
    obj-m := debug_driver.o
    obj-m += debug_device.o
else
    KERNELDIR ?= /root/work/latest_codes/linux-stable
    PWD := $(shell pwd)
default:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

clean:
    @rm -rf *.o *.mod.c *.mod.o *.ko *.order *.symvers .*.cmd .tmp_versions
endif

 

debug_device.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/mm.h>

MODULE_LICENSE("GPL");

static void demo_release (struct device *dev) {

}

static struct platform_device demo_dev = {
    .name        = "demo_debug",
    .id        = -1,
    .dev = {
        .release = demo_release,
    },
};

static int demo_init(void)
{
    platform_device_register(&demo_dev);

    return 0;
}

 

debug_driver.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/types.h>

static struct device *dev = NULL;

static int debug_demo_open (struct inode *inode, struct file *file) {

    pr_debug("pr_debug: \n");
    dev_dbg(dev, "dev_dbg test.\n");

    return 0;
}

static int debug_demo_close (struct inode *inode, struct file *file) {

    printk("%s enter.\n", __func__);
    return 0;
}

static ssize_t debug_demo_write (struct file *file, const char __user *buf, size_t size, loff_t *offset) {

    printk("%s enter, size: %d\n", __func__, size);
    return size;
}

static struct file_operations debug_demo_fops = {
    .owner        = THIS_MODULE,
    .open        = debug_demo_open,
    .write        = debug_demo_write,
    .release    = debug_demo_close,
};

static struct miscdevice debug_demo_miscdev = {
    MISC_DYNAMIC_MINOR,
    "debug_demo",
    &debug_demo_fops
};

static int demo_probe(struct platform_device *device) {
    int ret;

    printk("%s enter.\n", __func__);

    dev = &device->dev;

    ret = misc_register(&debug_demo_miscdev);
    printk("ret: %d\n", ret);
    if (ret < 0)
        return ret;

    return 0;
}

static struct platform_driver demo_driver = {
    .probe = demo_probe,
    .driver = {
        .name = "demo_debug",
        .owner = THIS_MODULE,
    },
};

static int demo_init(void)
{
    platform_driver_register(&demo_driver);
    printk(KERN_ALERT "demo World.\n");
    return 0;
}

static void demo_exit(void)
{
    platform_driver_unregister(&demo_driver);
    misc_deregister(&debug_demo_miscdev);
    printk(KERN_ALERT "GoodBye, cruel world.\n");
}

MODULE_LICENSE("GPL");
module_init(demo_init);
module_exit(demo_exit);

完。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM