news 2026/5/22 6:52:16

Linux动态debug使用方法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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_VERBOSE=y #打开内核动态打印支持 CONFIG_DYNAMIC_DEBUG=y CONFIG_DYNAMIC_DEBUG_CORE=y

打开完了重新编译并烧录内核以后就可以在 /sys/kernel/debug/dynamic_debug/control 中查看动态打印都支持写什么打印了,
这个动态打印默认是关闭的,需要手动去修改下 control 文件,将打印打开,打开方法如下:

# 打开bsp/drivers/uart/sunxi-uart.c 这个驱动中的所有动态打印echo'file 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, it's 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__); \ }) #endif

dev的打印会自动给加设备名,会传入dev嘛,就是struct device * 类型的设备指针,
这个会打印设备名,所以在写驱动的时候优先使用这个。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/22 6:51:04

淘宝任务自动化:基于Auto.js的淘金币脚本技术解析与实战指南

淘宝任务自动化&#xff1a;基于Auto.js的淘金币脚本技术解析与实战指南 【免费下载链接】taojinbi 淘宝淘金币自动执行脚本&#xff0c;包含蚂蚁森林收取能量&#xff0c;芭芭农场全任务&#xff0c;解放你的双手 项目地址: https://gitcode.com/gh_mirrors/ta/taojinbi …

作者头像 李华
网站建设 2026/5/22 6:50:17

C++友元函数与友元类

C友元函数与友元类友元机制允许特定的函数或类访问另一个类的私有和保护成员。虽然友元打破了封装性&#xff0c;但在某些场景下可以提供更清晰的接口设计。友元函数可以访问类的私有成员&#xff0c;常用于运算符重载。#include #includeclass Vector2D { double x_, y_;publi…

作者头像 李华
网站建设 2026/5/22 6:46:28

如何使用代理保护电子邮件营销?如何保护您的收件箱

电子邮件仍然是企业和个人最广泛使用的沟通渠道之一&#xff0c;同时也是网络犯罪分子最常攻击的目标之一。从网络钓鱼和垃圾邮件泛滥到凭证窃取和未经授权的账户访问&#xff0c;电子邮件收件箱时刻面临风险。据行业报告显示&#xff0c;电子邮件仍然是超过 90% 网络攻击的主要…

作者头像 李华
网站建设 2026/5/22 6:41:13

2026年必看:六款热门AI编程工具横评,Trae与Cursor怎么选

2026年必看&#xff1a;六款热门AI编程工具横评&#xff0c;Trae与Cursor怎么选AI编程工具正从辅助插件进化为全流程开发核心&#xff0c;2026年市场进入智能体协作新阶段。本文精选6款主流AI编程工具&#xff0c;从核心功能、协作模式、适配场景等维度深度解析&#xff0c;帮开…

作者头像 李华
网站建设 2026/5/22 6:39:26

Token聚合平台 vs 传统云 vs AI原生云,AI推理应用怎么选?

在大模型能力深度融入生产环境的当下&#xff0c;后端 AI 架构的选择往往决定了应用的生死。从早期的“调用一个接口”到如今复杂的智能体&#xff08;Agent&#xff09;工作流&#xff0c;开发团队在底座选型上面临着两条截然不同的演进路径&#xff1a;一条是追求便利与极致轻…

作者头像 李华