某个c文件,某个函数含有pr_debug。默认是不会打印的
/* If you are writing a driver, please use dev_dbg instead */ #if defined(CONFIG_DYNAMIC_DEBUG) #include/* 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
在没有开启DYNAMIC_DEBUG的情况下和DEBUG的定义下是不会打印的。这里假设不开启DYNAMIC_DEBUG,如果要打印pr_debug可以在对应c文件同级目录的Makefile中添加
CFLAGS_[filename].o := -DDEBUG
然后重新编译内核。
这是针对一个文件,如果针对该目录下所有文件,则可以在Makefile中添加
ccflags-y := -DDEBUG
一般都有config控制比如 i2c
ccflags-$(CONFIG_I2C_DEBUG_CORE) := -DDEBUG
动态打印:
如果内核编译时候没有定义DEBUG,但是定义了DYNAMIC_DEBUG。可以使用动态打印
Dynamic debug — The Linux Kernel documentation
主要操作control节点。这个方便现场调试。
举例usb xhci调试。一般我会在host/Makefile 和core/Makefile 加上ccflags-y += -DDEBUG。使用dynamic后如下echo效果一致,省去了编译时间和换image时间。缺点就是,reboot后需要重写,不适合开机调试
echo -n "file drivers/usb/host/* +p" > /sys/kernel/debug/dynamic_debug/control
echo -n "file drivers/usb/core/* +p" > /sys/kernel/debug/dynamic_debug/control
你要是问我有没有一劳永逸的,当然有,在cmdline添加。reboot后自始至终生效
dyndbg="file drivers/usb/host/* +p"
dyndbg="file drivers/usb/core/* +p"
其他的模块也适用,具体看 control 节点是否给你暴露出该文件的调试信息。
dev_vdbg打印。这个没办法像上面那样在Makefile里修改
#ifdef VERBOSE_DEBUG #define dev_vdbg dev_dbg #else #define dev_vdbg(dev, fmt, ...) \ ({ \ if (0) \ dev_printk(KERN_DEBUG, dev, dev_fmt(fmt), ##__VA_ARGS__); \ }) #endif
使用方法在目标c文件加上。第一个可以打印dev_dbg,第二个可以打印dev_vdbg
#define DEBUG #define VERBOSE_DEBUG
调试函数为pm_pr_dbg,开启了需要开启CONFIG_PM_SLEEP_DEBUG
开启后还是不能用
void __pm_pr_dbg(bool defer, const char *fmt, ...) { struct va_format vaf; va_list args; if (!pm_debug_messages_on) //默认这里返回 return; va_start(args, fmt); vaf.fmt = fmt; vaf.va = &args; if (defer) printk_deferred(KERN_DEBUG "PM: %pV", &vaf); else printk(KERN_DEBUG "PM: %pV", &vaf); va_end(args); }
所以需要pm_debug_messages_on置1才能打印。置1方法
echo 1 > /sys/power/pm_debug_messages
原理如下:
static ssize_t pm_debug_messages_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "%d\n", pm_debug_messages_on); } static ssize_t pm_debug_messages_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n) { unsigned long val; if (kstrtoul(buf, 10, &val)) return -EINVAL; if (val > 1) return -EINVAL; pm_debug_messages_on = !!val; return n; }
这种方法很常见,所以多需要关注一下节点中是否有可写的节点用于开启打印。
当然在高版本,直接在cmdline中添加pm_debug_messages_on就可以开启开关了。
注意可以配合no_console_suspend来获取状态执行时的log,这个参数保证了串口是工作的。
#define memblock_dbg(fmt, ...) \ if (memblock_debug) printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
开启该打印需要memblock_debug置1
static int __init early_memblock(char *p) { if (p && strstr(p, "debug")) //memblock带debug参数则置1 memblock_debug = 1; return 0; } early_param("memblock", early_memblock);
所以实现方法,在command line中添加memblock=debug