Linux内核调试之printk()变形 dev_info、dev_dbg、dev_err

目前在kernel驱动代码中,都不再建议直接使用printk直接添加打印信息,而是使用dev_info,dev_dbg,dev_err之类的函数代替。

注意:这三个函数声明于linux/include/linux/device.h

使用上述三个打印函数时打印信息格式如下

驱动模块的名字: + 具体的信息

如:在运行的linux系统设备上,插入鼠标,就会打印出鼠标的相关信息;

[ 402.134068] input: USB Optical Mouse as /devices/soc0/soc/2100000.aips-bus/2184000.usb/ci_hdrc.0/usb1/1-1/1-1:1.0/0003:0461:4D81.0003/input/input3
[ 402.149618] hid-generic 0003:0461:4D81.0003: input: USB HID v1.11 Mouse [USB Optical Mouse] on usb-ci_hdrc.0-1/input0

"input: " 是鼠标插入式,内核检测到,鼠标是输入设备,于是就把将鼠标与输入模块的驱动。
“hid-generic 0003:0461:4D81.0003” 是鼠标匹配的驱动是输入模块的hid-generic驱动。

其使用如下:

dev_info(dev,%s[%d] \n”, __func__, __LINE__);

这是第一个参数不同,后两个就是printk的参数相同,格式也相同。

第一个参数dev: 就是将这个设备的模块的名字等信息相同, 最终还是调用printk打印出来.

通常,dev第一个参数的打信息,是用两个函数从dev中获取信息。

const char *dev_driver_string(const struct device *dev)
{
        struct device_driver *drv;


        /* dev->driver can change to NULL underneath us because of unbinding,
         * so be careful about accessing it.  dev->bus and dev->class should
         * never change once they are set, so they don't need special care.
         */
        drv = ACCESS_ONCE(dev->driver);
        return drv ? drv->name :
                        (dev->bus ? dev->bus->name :
                        (dev->class ? dev->class->name : ""));

}

调用这个函数可以输出 "hid-generic"

static inline const char *dev_name(const struct device *dev)
{
        /* Use the init name until the kobject becomes available */
        if (dev->init_name)
                return dev->init_name;


        return kobject_name(&dev->kobj);

}
dev_name(&intf->dev)对应着DEV的四元组信息,可以用这个信息,来判断设备的具体位置,然后根据该信息,给设备固定名字。
调用这个函数,可以输出" 0003: ......"

dev_driver_string() / dev_name() 是内核调试打印信息中常用的输出函数

函数dev_err通过同一文件(drivers / base / core.c)中的define_dev_printk_level宏实现.

static void __dev_printk(const char *level, const struct device *dev,
			struct va_format *vaf)
{
	if (dev)
		dev_printk_emit(level[1] - '0', dev, "%s %s: %pV",
				dev_driver_string(dev), dev_name(dev), vaf);
	else
		printk("%s(NULL device *): %pV", level, vaf);
}

void dev_printk(const char *level, const struct device *dev,
		const char *fmt, ...)
{
	struct va_format vaf;
	va_list args;

	va_start(args, fmt);

	vaf.fmt = fmt;
	vaf.va = &args;

	__dev_printk(level, dev, &vaf);

	va_end(args);
}
EXPORT_SYMBOL(dev_printk);

#define define_dev_printk_level(func, kern_level)		\
void func(const struct device *dev, const char *fmt, ...)	\
{								\
	struct va_format vaf;					\
	va_list args;						\
								\
	va_start(args, fmt);					\
								\
	vaf.fmt = fmt;						\
	vaf.va = &args;						\
								\
	__dev_printk(kern_level, dev, &vaf);			\
								\
	va_end(args);						\
}								\
EXPORT_SYMBOL(func);

define_dev_printk_level(dev_emerg, KERN_EMERG);
define_dev_printk_level(dev_alert, KERN_ALERT);
define_dev_printk_level(dev_crit, KERN_CRIT);
define_dev_printk_level(dev_err, KERN_ERR);
define_dev_printk_level(dev_warn, KERN_WARNING);
define_dev_printk_level(dev_notice, KERN_NOTICE);
define_dev_printk_level(_dev_info, KERN_INFO);

#endif

这里利用宏 define_dev_printk_level 定义了 dev_emerg/dev_alert/dev_crit/dev_err/dev_warn/dev_notice/_dev_info 等几个函数。其实这几个函数归根结底都是函数调用__dev_printk。

另外在 include/linux/device.h 中

extern __printf(2, 3)
int dev_emerg(const struct device *dev, const char *fmt, ...);
extern __printf(2, 3)
int dev_alert(const struct device *dev, const char *fmt, ...);
extern __printf(2, 3)
int dev_crit(const struct device *dev, const char *fmt, ...);
extern __printf(2, 3)
int dev_err(const struct device *dev, const char *fmt, ...);
extern __printf(2, 3)
int dev_warn(const struct device *dev, const char *fmt, ...);
extern __printf(2, 3)
int dev_notice(const struct device *dev, const char *fmt, ...);
extern __printf(2, 3)
int _dev_info(const struct device *dev, const char *fmt, ...);

__printf(2, 3) 的定义见: include/linux/compiler-gcc.h

#define __printf(a, b)   __attribute__((format(printf, a, b)))

函数 dev_info 和 dev_dbg的实现

#define dev_info(dev, fmt, arg...) _dev_info(dev, fmt, ##arg)

#if defined(CONFIG_DYNAMIC_DEBUG)
#define dev_dbg(dev, format, ...)		     \
do {						     \
	dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \
} while (0)
#elif defined(DEBUG)
#define dev_dbg(dev, format, arg...)		\
	dev_printk(KERN_DEBUG, dev, format, ##arg)
#else
#define dev_dbg(dev, format, arg...)				\
({								\
	if (0)							\
		dev_printk(KERN_DEBUG, dev, format, ##arg);	\
})
#endif
  • 2
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值