news 2026/9/3 7:16:09

Dynamic Debug的原理分析:debugfs的具体应用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Dynamic Debug的原理分析:debugfs的具体应用

1. 前文回顾

Linux的Dynamic debug功能简单讲了下如何使用。再来回顾下其概念和用法。
Dynamic Debug 是 Linux 内核的动态调试功能,允许在运行时动态开启/关闭特定的pr_debug()dev_dbg()输出,而无需重新编译内核。

核心特点:

  • ✅ 运行时控制:无需重启
  • ✅ 精细化控制:可按模块、文件、函数、行号过滤
  • ✅ 零性能开销:关闭时完全无开销
  • ✅ 使用 DebugFS 作为控制接口

1.1 DebugFS 控制接口

主控制文件:/sys/kernel/debug/dynamic_debug/control

# 查看所有可用的 debug 点$cat/sys/kernel/debug/dynamic_debug/control drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c:123[amdgpu]amdgpu_init=_"AMDGPU driver loaded\012"drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:456[amdgpu]amdgpu_device_init=_"Device init started\012"...# 启用特定模块的所有 debug 输出$echo'module amdgpu +p'>/sys/kernel/debug/dynamic_debug/control# 启用特定文件的 debug 输出$echo'file amdgpu_ring.c +p'>/sys/kernel/debug/dynamic_debug/control# 启用特定函数的 debug 输出$echo'func amdgpu_ring_init +p'>/sys/kernel/debug/dynamic_debug/control# 禁用 debug 输出$echo'module amdgpu -p'>/sys/kernel/debug/dynamic_debug/control

2. 内核实现分析

位置:lib/dynamic_debug.c

2.1. 数据结构
/* 每个 pr_debug() 对应一个 _ddebug 结构 */struct_ddebug{constchar*modname;/* 模块名 */constchar*function;/* 函数名 */constchar*filename;/* 文件名 */constchar*format;/* 格式字符串 */unsignedintlineno:18;/* 行号 */unsignedintflags:8;/* 标志 (是否启用) */}__attribute__((aligned(8)));/* 标志定义 */#define_DPRINTK_FLAGS_PRINT(1<<0)/* 启用打印 */#define_DPRINTK_FLAGS_INCL_MODNAME(1<<1)#define_DPRINTK_FLAGS_INCL_FUNCNAME(1<<2)#define_DPRINTK_FLAGS_INCL_LINENO(1<<3)
2.2. DebugFS 文件操作
/* 读操作:显示所有 debug 点 */staticintddebug_proc_show(structseq_file*m,void*p){structddebug_iter*iter=m->private;struct_ddebug*dp=p;charflagsbuf[10];/* 格式化输出每个 debug 点的信息 */seq_printf(m,"%s:%u [%s]%s =%s \"%s\"\n",trim_prefix(dp->filename),dp->lineno,iter->table->mod_name,dp->function,ddebug_describe_flags(dp->flags,flagsbuf,sizeof(flagsbuf)),dp->format);return0;}/* 写操作:处理控制命令 */staticssize_tddebug_proc_write(structfile*file,constchar__user*ubuf,size_tlen,loff_t*offp){char*tmpbuf;intret;/* 限制输入大小 */if(len==0||len>PAGE_SIZE)return-EINVAL;/* 从用户空间复制命令 */tmpbuf=memdup_user_nul(ubuf,len);if(IS_ERR(tmpbuf))returnPTR_ERR(tmpbuf);/* 解析并应用控制命令 */ret=ddebug_exec_queries(tmpbuf,NULL);kfree(tmpbuf);if(ret<0)returnret;returnlen;}/* file_operations 定义 */staticconststructfile_operationsddebug_proc_fops={.owner=THIS_MODULE,.open=ddebug_proc_open,.read=seq_read,.llseek=seq_lseek,.release=seq_release_private,.write=ddebug_proc_write,};
2.3. 初始化
staticint__initdynamic_debug_init_debugfs(void){structdentry*dir;/* 创建 dynamic_debug 目录 */dir=debugfs_create_dir("dynamic_debug",NULL);if(!dir)return-ENOMEM;/* 创建 control 文件 */debugfs_create_file("control",0644,dir,NULL,&ddebug_proc_fops);return0;}fs_initcall(dynamic_debug_init_debugfs);

2.4 pr_debug() 宏实现

/* include/linux/dynamic_debug.h */#ifdefCONFIG_DYNAMIC_DEBUG#definepr_debug(fmt,...)\do{\staticstruct_ddebug__aligned(8)\__section("__dyndbg")descriptor={\.modname=KBUILD_MODNAME,\.function=__func__,\.filename=__FILE__,\.format=(fmt),\.lineno=__LINE__,\.flags=_DPRINTK_FLAGS_DEFAULT,\};\if(unlikely(descriptor.flags&_DPRINTK_FLAGS_PRINT))\__dynamic_pr_debug(&descriptor,pr_fmt(fmt),\##__VA_ARGS__);\}while(0)#else#definepr_debug(fmt,...)no_printk(fmt,##__VA_ARGS__)#endif

工作原理:

  1. 每个pr_debug()编译时生成一个_ddebug结构
  2. 所有_ddebug放在特殊段__dyndbg
  3. 内核启动时收集所有_ddebug结构
  4. 通过 debugfs 控制flags字段
  5. 运行时检查flags决定是否打印

使用示例

驱动代码
/* drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c */intamdgpu_ring_init(structamdgpu_device*adev,structamdgpu_ring*ring,unsignedintmax_dw,structamdgpu_irq_src*irq_src){/* 这些 pr_debug 默认不输出 */pr_debug("Initializing ring %s\n",ring->name);pr_debug("Ring size: %u DWs\n",max_dw);/* ... 初始化逻辑 ... */pr_debug("Ring %s initialized successfully\n",ring->name);return0;}
运行时控制
# 启用该文件的所有 debug 输出$echo'file amdgpu_ring.c +p'>/sys/kernel/debug/dynamic_debug/control# 现在执行操作会看到 debug 信息$dmesg|tail[123.456]amdgpu: Initializing ring gfx[123.457]amdgpu: Ring size:1024DWs[123.458]amdgpu: Ring gfx initialized successfully# 禁用$echo'file amdgpu_ring.c -p'>/sys/kernel/debug/dynamic_debug/control

高级用法

# 按行号启用$echo'file amdgpu_ring.c line 123 +p'>control# 组合条件(文件 + 函数)$echo'file amdgpu_ring.c func amdgpu_ring_init +p'>control# 格式化标志$echo'module amdgpu +pflmt'>control# +p: 启用打印# +f: 包含函数名# +l: 包含行号# +m: 包含模块名# +t: 包含线程 ID# 使用通配符$echo'file amdgpu_* +p'>control $echo'func *_init +p'>control

性能影响分析

/* 关闭时的性能开销 */if(unlikely(descriptor.flags&_DPRINTK_FLAGS_PRINT))// 仅一次位测试__dynamic_pr_debug(&descriptor,...);// 不执行/* * unlikely() 提示:分支预测优化 * 位测试:极快的 CPU 操作 * 关闭时:几乎零开销(<1 纳秒) */

与其他调试方式对比

方式运行时控制性能开销灵活性需要重启
printk
Dynamic Debug极低
Ftrace极高
条件编译 (#ifdef)

学习要点

Dynamic Debug 展示了 DebugFS 的典型应用模式:

  1. 复杂的写操作

    • 解析用户命令
    • 应用配置到内核数据结构
    • 错误处理和验证
  2. 大量数据的读操作

    • 使用 seq_file 遍历内核数据
    • 格式化输出便于阅读
  3. 运行时控制内核行为

    • 无需重启或重新加载模块
    • 即时生效
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/3 0:23:26

【必收藏】从零搭建AI智能体:三大低代码平台(Dify/n8n/Coze)实战指南

本文系统解析AI智能体低代码平台的核心价值与三大主流工具(Dify/n8n/Coze)的特性和优劣。Dify适合企业级应用&#xff0c;n8n擅长业务流程自动化&#xff0c;Coze则对零代码用户友好。文章详细对比了各平台的技术门槛、开发效率、扩展能力和部署要求&#xff0c;并提供基于不同…

作者头像 李华
网站建设 2026/9/3 2:03:52

基于数据挖掘的疾病数据可视化与预测系统开题报告

山东中医药大学本科生毕业论文&#xff08;设计&#xff09;开题报告毕业论文&#xff08;设计&#xff09;题目&#xff1a; 学 院&#xff1a;智能信息与工程学院专 业&#xff1a; 班 级&#xff1a; 学 号&#xff1a;学生姓名&#xff1a; 指导教师&#xff1…

作者头像 李华
网站建设 2026/9/3 0:19:01

Linux进程排查实战:strace和lsof救命指南

服务起不来&#xff0c;日志没报错。进程在跑&#xff0c;但就是不干活。 这种问题最恶心&#xff0c;看日志看不出问题&#xff0c;看监控也没异常。 这时候就需要strace和lsof这两个神器了。 strace&#xff1a;跟踪系统调用 strace能看到进程在做什么系统调用&#xff0c;相…

作者头像 李华
网站建设 2026/9/2 23:54:34

二手车线上交易小程序源码系统,全流程闭环管理的小程序源码系统

温馨提示&#xff1a;文末有资源获取方式面向团队作战的流程化管理引擎&#xff1a;本系统设计超越了单一的车辆展示&#xff0c;深度融合了内部协同办公理念&#xff0c;为拥有市场、销售、库存管理等不同岗位的二手车团队&#xff0c;打造了一个从线索获取到成交分析的全流程…

作者头像 李华
网站建设 2026/9/3 1:49:03

手把手教你获取Open-AutoGLM源码,立即构建专属AI代码引擎

第一章&#xff1a;Open-AutoGLM源码下载 获取 Open-AutoGLM 的源码是参与其开发与本地部署的第一步。该项目托管于 GitHub 平台&#xff0c;采用开源协议发布&#xff0c;开发者可通过 Git 工具进行克隆或直接下载压缩包。 准备工作 在开始之前&#xff0c;请确保系统已安装以…

作者头像 李华