打开驱动中的动态打印方法什么是动态打印动态打印跟 printk 的主要区别在于动态打印在进入系统后可以手动控制是否开启打印能具体到某个驱动甚至驱动中的某个函数的打印。如何使用调试驱动的时候有些中断中的打印用printk很容易造成内核崩溃但是有些人家已经加好的打印之前不知道怎么使用这次就介绍一下使用方法。在调试全志T717 openEuler内核的uart驱动的时候想看下串口接收到的数据人家驱动中(sunxi-uart.c)其实已经加好了打印了只需要咱们把他打开就能通过 “dmesg -w” 来看了先看下驱动源码中是怎么写的static unsigned int sw_uart_handle_rx(struct sw_uart_port *sw_uport, unsigned int lsr) { unsigned char ch 0; int max_count 256; char flag; /* * * */ //在这会通过SERIAL_DBG将收到的每个字符打印出来 SERIAL_DBG(sw_uport-port.dev, receive data 0x%x\n, ch); uart_insert_char(sw_uport-port, lsr, SUNXI_UART_LSR_OE, ch, flag); lsr serial_in(sw_uport-port, SUNXI_UART_LSR); return lsr; }然后看下 “SERIAL_DBG” 的宏定义#define SERIAL_DBG(dev, fmt, arg...) \ do { \ if (!sw_is_console_port(sw_uport-port)) \ sunxi_debug(dev, %s()%d - fmt, __func__, __LINE__, ##arg); \ } while (0) /* 再看下sunxi_debug宏定义 */ /* void sunxi_debug(struct device *dev, char *fmt, ...); */ #define sunxi_debug(dev, fmt, ...) \ do { if (dev) \ pr_debug(-%s:[DEBUG]: fmt, sunxi_log_dev_name(dev), ## __VA_ARGS__); \ else \ pr_debug(:[DEBUG]: fmt, ## __VA_ARGS__); \ } while (0) /* CONFIG_AW_LOG_VERBOSE */可以看到要想使用“sunxi_debug”这个宏要先打开CONFIG_AW_LOG_VERBOSE然后还要打开内核的动态打印功能所以一共需要在defconfig中添加三个宏定义# 打开全志的日志打印 CONFIG_AW_LOG_VERBOSEy #打开内核动态打印支持 CONFIG_DYNAMIC_DEBUGy CONFIG_DYNAMIC_DEBUG_COREy打开完了重新编译并烧录内核以后就可以在 /sys/kernel/debug/dynamic_debug/control 中查看动态打印都支持写什么打印了这个动态打印默认是关闭的需要手动去修改下 control 文件将打印打开打开方法如下# 打开bsp/drivers/uart/sunxi-uart.c 这个驱动中的所有动态打印echofile bsp/drivers/uart/sunxi-uart.c p/sys/kernel/debug/dynamic_debug/control# 修改下内核的打印登记直接拉满echo8/proc/sys/kernel/printk# 使用dmesg -w 动态更新打印这个就跟tail -F 一样的dmesg-w自己驱动中怎么使用debug这些打印的宏定义在 openeuler-kernel-t717/include/linux/printk.h 中其中pr_emerg() pr_alert() pr_crit() pr_err() pr_warn() pr_notice() pr_info()这些都是printk level 的封装如#define pr_err(fmt, ...) \ printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)只有pr_debug()会用到动态打印他的宏定义如下/* If you are writing a driver, please use dev_dbg instead */ #if defined(CONFIG_DYNAMIC_DEBUG) || \ (defined(CONFIG_DYNAMIC_DEBUG_CORE) defined(DYNAMIC_DEBUG_MODULE)) #include linux/dynamic_debug.h /** * pr_debug - Print a debug-level message conditionally * fmt: format string * ...: arguments for the format string * * This macro expands to dynamic_pr_debug() if CONFIG_DYNAMIC_DEBUG is * set. Otherwise, if DEBUG is defined, its equivalent to a printk with * KERN_DEBUG loglevel. If DEBUG is not defined it does nothing. * * It uses pr_fmt() to generate the format string (dynamic_pr_debug() uses * pr_fmt() internally). */ #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如果打开了CONFIG_DYNAMIC_DEBUG那么pr_debug()就会调用dynamic_pr_debug()否则如果定义了DEBUG宏那么pr_debug()就会调用printk()否则就会调用no_printk()。但是你看最开始一行写着如果你在写一个驱动请使用dev_dbg(),下面来看下dev_dbg()的宏定义openeuler-kernel-t717/include/linux/dev_printk.h#ifndef dev_fmt #define dev_fmt(fmt) fmt #endif #define dev_emerg(dev, fmt, ...) \ _dev_emerg(dev, dev_fmt(fmt), ##__VA_ARGS__) #define dev_crit(dev, fmt, ...) \ _dev_crit(dev, dev_fmt(fmt), ##__VA_ARGS__) #define dev_alert(dev, fmt, ...) \ _dev_alert(dev, dev_fmt(fmt), ##__VA_ARGS__) #define dev_err(dev, fmt, ...) \ _dev_err(dev, dev_fmt(fmt), ##__VA_ARGS__) #define dev_warn(dev, fmt, ...) \ _dev_warn(dev, dev_fmt(fmt), ##__VA_ARGS__) #define dev_notice(dev, fmt, ...) \ _dev_notice(dev, dev_fmt(fmt), ##__VA_ARGS__) #define dev_info(dev, fmt, ...) \ _dev_info(dev, dev_fmt(fmt), ##__VA_ARGS__) #if defined(CONFIG_DYNAMIC_DEBUG) || \ (defined(CONFIG_DYNAMIC_DEBUG_CORE) defined(DYNAMIC_DEBUG_MODULE)) #define dev_dbg(dev, fmt, ...) \ dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__) #elif defined(DEBUG) #define dev_dbg(dev, fmt, ...) \ dev_printk(KERN_DEBUG, dev, dev_fmt(fmt), ##__VA_ARGS__) #else #define dev_dbg(dev, fmt, ...) \ ({ \ if (0) \ dev_printk(KERN_DEBUG, dev, dev_fmt(fmt), ##__VA_ARGS__); \ }) #endifdev的打印会自动给加设备名会传入dev嘛就是struct device * 类型的设备指针这个会打印设备名所以在写驱动的时候优先使用这个。
Linux动态debug使用方法
打开驱动中的动态打印方法什么是动态打印动态打印跟 printk 的主要区别在于动态打印在进入系统后可以手动控制是否开启打印能具体到某个驱动甚至驱动中的某个函数的打印。如何使用调试驱动的时候有些中断中的打印用printk很容易造成内核崩溃但是有些人家已经加好的打印之前不知道怎么使用这次就介绍一下使用方法。在调试全志T717 openEuler内核的uart驱动的时候想看下串口接收到的数据人家驱动中(sunxi-uart.c)其实已经加好了打印了只需要咱们把他打开就能通过 “dmesg -w” 来看了先看下驱动源码中是怎么写的static unsigned int sw_uart_handle_rx(struct sw_uart_port *sw_uport, unsigned int lsr) { unsigned char ch 0; int max_count 256; char flag; /* * * */ //在这会通过SERIAL_DBG将收到的每个字符打印出来 SERIAL_DBG(sw_uport-port.dev, receive data 0x%x\n, ch); uart_insert_char(sw_uport-port, lsr, SUNXI_UART_LSR_OE, ch, flag); lsr serial_in(sw_uport-port, SUNXI_UART_LSR); return lsr; }然后看下 “SERIAL_DBG” 的宏定义#define SERIAL_DBG(dev, fmt, arg...) \ do { \ if (!sw_is_console_port(sw_uport-port)) \ sunxi_debug(dev, %s()%d - fmt, __func__, __LINE__, ##arg); \ } while (0) /* 再看下sunxi_debug宏定义 */ /* void sunxi_debug(struct device *dev, char *fmt, ...); */ #define sunxi_debug(dev, fmt, ...) \ do { if (dev) \ pr_debug(-%s:[DEBUG]: fmt, sunxi_log_dev_name(dev), ## __VA_ARGS__); \ else \ pr_debug(:[DEBUG]: fmt, ## __VA_ARGS__); \ } while (0) /* CONFIG_AW_LOG_VERBOSE */可以看到要想使用“sunxi_debug”这个宏要先打开CONFIG_AW_LOG_VERBOSE然后还要打开内核的动态打印功能所以一共需要在defconfig中添加三个宏定义# 打开全志的日志打印 CONFIG_AW_LOG_VERBOSEy #打开内核动态打印支持 CONFIG_DYNAMIC_DEBUGy CONFIG_DYNAMIC_DEBUG_COREy打开完了重新编译并烧录内核以后就可以在 /sys/kernel/debug/dynamic_debug/control 中查看动态打印都支持写什么打印了这个动态打印默认是关闭的需要手动去修改下 control 文件将打印打开打开方法如下# 打开bsp/drivers/uart/sunxi-uart.c 这个驱动中的所有动态打印echofile bsp/drivers/uart/sunxi-uart.c p/sys/kernel/debug/dynamic_debug/control# 修改下内核的打印登记直接拉满echo8/proc/sys/kernel/printk# 使用dmesg -w 动态更新打印这个就跟tail -F 一样的dmesg-w自己驱动中怎么使用debug这些打印的宏定义在 openeuler-kernel-t717/include/linux/printk.h 中其中pr_emerg() pr_alert() pr_crit() pr_err() pr_warn() pr_notice() pr_info()这些都是printk level 的封装如#define pr_err(fmt, ...) \ printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)只有pr_debug()会用到动态打印他的宏定义如下/* If you are writing a driver, please use dev_dbg instead */ #if defined(CONFIG_DYNAMIC_DEBUG) || \ (defined(CONFIG_DYNAMIC_DEBUG_CORE) defined(DYNAMIC_DEBUG_MODULE)) #include linux/dynamic_debug.h /** * pr_debug - Print a debug-level message conditionally * fmt: format string * ...: arguments for the format string * * This macro expands to dynamic_pr_debug() if CONFIG_DYNAMIC_DEBUG is * set. Otherwise, if DEBUG is defined, its equivalent to a printk with * KERN_DEBUG loglevel. If DEBUG is not defined it does nothing. * * It uses pr_fmt() to generate the format string (dynamic_pr_debug() uses * pr_fmt() internally). */ #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如果打开了CONFIG_DYNAMIC_DEBUG那么pr_debug()就会调用dynamic_pr_debug()否则如果定义了DEBUG宏那么pr_debug()就会调用printk()否则就会调用no_printk()。但是你看最开始一行写着如果你在写一个驱动请使用dev_dbg(),下面来看下dev_dbg()的宏定义openeuler-kernel-t717/include/linux/dev_printk.h#ifndef dev_fmt #define dev_fmt(fmt) fmt #endif #define dev_emerg(dev, fmt, ...) \ _dev_emerg(dev, dev_fmt(fmt), ##__VA_ARGS__) #define dev_crit(dev, fmt, ...) \ _dev_crit(dev, dev_fmt(fmt), ##__VA_ARGS__) #define dev_alert(dev, fmt, ...) \ _dev_alert(dev, dev_fmt(fmt), ##__VA_ARGS__) #define dev_err(dev, fmt, ...) \ _dev_err(dev, dev_fmt(fmt), ##__VA_ARGS__) #define dev_warn(dev, fmt, ...) \ _dev_warn(dev, dev_fmt(fmt), ##__VA_ARGS__) #define dev_notice(dev, fmt, ...) \ _dev_notice(dev, dev_fmt(fmt), ##__VA_ARGS__) #define dev_info(dev, fmt, ...) \ _dev_info(dev, dev_fmt(fmt), ##__VA_ARGS__) #if defined(CONFIG_DYNAMIC_DEBUG) || \ (defined(CONFIG_DYNAMIC_DEBUG_CORE) defined(DYNAMIC_DEBUG_MODULE)) #define dev_dbg(dev, fmt, ...) \ dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__) #elif defined(DEBUG) #define dev_dbg(dev, fmt, ...) \ dev_printk(KERN_DEBUG, dev, dev_fmt(fmt), ##__VA_ARGS__) #else #define dev_dbg(dev, fmt, ...) \ ({ \ if (0) \ dev_printk(KERN_DEBUG, dev, dev_fmt(fmt), ##__VA_ARGS__); \ }) #endifdev的打印会自动给加设备名会传入dev嘛就是struct device * 类型的设备指针这个会打印设备名所以在写驱动的时候优先使用这个。