Linux 调试之动态打印

Linux调试之(一)内核动态打印 文章目录Linux动态打印的两种方式一、驱动使用module_param_named方法**1.驱动添加代码:2.打开动态打印二、系统动态打印【1】配置Kconfig【2】配置Makefile【3】配置内核,使支持动态调试【4】编译加载【5】控制端动态修改打印级别(1)修改系统的打印级别(2)修改局部动态打印 Linux动态打印的两种方式 https://blog.youkuaiyun.com/u010481... 阅读详情


一、概述

在 kernel 驱动代码中,使用动态输出是系统内核调试的重要手段之一,printk 打印是全局的,只能设置输出等级,而且使用 printk 每次都要重新编译内核,很不方便。。而动态输出可以在不需要重新编译内核的情况下,方便的打印出内核的 debug 信息。动态输出可以动态选择打开某个内核子系统的输出,可以有选择性地打开某些模块的输出,printk 被 dev_info,dev_dbg,dev_err 之类的函数代替,dev_xxx 函数的本质还是使用 printk 打印的,只是对 printk 进行了一层包装。

在系统运行时候,动态打印可以由系统维护者动态打开内核子系统的打印,可以有选择性地打开某些模块的打印。要使用动态打印,必须在内核配置时打开 CONFIG_DYNAMIC_DEBUG 宏。

CONFIG_DEBUG_FS=y
CONFIG_DYNAMIC_DEBUG=y

CONFIG_DYNAMIC_DEBUG 是配置动态输出,它依赖于 CONFIG_DEBUG_FS,而 CONFIG_DEBUG_FS 是 debugfs 文件系统。debugfs默认会挂载到 /sys/kernel/debug,如果没有挂载,可以执行以下命令挂载:

$ mount -t debugfs none /sys/kernel/debug

二、printk

1、printk 消息级别

Linux 内核共提供了八种不同的消息级别,分为级别 0~7。数值越大,表示级别越低,对应的消息越不重要。相应的宏定义在 include/linux/kern_levels.h 文件中。

#define KERN_SOH    "\001"      /* ASCII Start Of Header */
#define KERN_SOH_ASCII  '\001'

#define KERN_EMERG  KERN_SOH "0"    /* system is unusable */
#define KERN_ALERT  KERN_SOH "1"    /* action must be taken immediately */
#define KERN_CRIT   KERN_SOH "2"    /* critical conditions */
#define KERN_ERR    KERN_SOH "3"    /* error conditions */
#define KERN_WARNING    KERN_SOH "4"    /* warning conditions */
#define KERN_NOTICE KERN_SOH "5"    /* normal but significant condition */
#define KERN_INFO   KERN_SOH "6"    /* informational */
#define KERN_DEBUG  KERN_SOH "7"    /* debug-level messages */
  • KERN_EMERG 表示紧急事件,一般是系统崩溃之前提示的消息;
  • KERN_ALERT 表示必须立即采取行动的消息;
  • KERN_CRIT 表示临界状态,通常涉及严重的硬件或软件操作失败;
  • KERN_ERR 用于报告错误状态,设备驱动程序会经常使用该级别来报告来自硬件的问题;
  • KERN_WARNING 对可能出现问题的情况进行警告,这类情况通常不会对系统造成严重的问题;
  • KERN_NOTICE 表示有必要进行提示的正常情形,许多与安全相关的状况用这个级别进行汇报;
  • KERN_INFO 表示内核提示信息,很多驱动程序在启动的时候,用这个级别打印出它们找到的硬件信息;
  • KERN_DEBUG 用于调试信息。

2、调整内核 printk 打印级别

通过 /proc/sys/kernel/printk 文件可以调节 printk 的输出等级,该文件有 4 个数字值:

$ cat /proc/sys/kernel/printk
4	4	1	7

四个数值含义分别如下:

  • 控制台日志级别:优先级高于该值的消息将被打印至控制台;
  • 默认的消息日志级别:将用该优先级来打印没有优先级的消息(即 printk 没有指定消息级别);
  • 最低的控制台日志级别:控制台日志级别可被设置的最小值(最高优先级);
  • 默认的控制台日志级别:控制台日志级别的缺省值。

通过修改 /proc/sys/kernel/printk 中的值来改变内核打印效果。例如,屏蔽掉所有的内核 printk 打印,只需要把第一个数值调到最小值 1 或者 0,指令如下:

$ echo 1 4 1 7 > /proc/sys/kernel/printk

三、dynamic debug 的使用

1、dev_xxx 函数

下面简述下几个 dev_xxx 函数的基本使用规则,以及动态调试使用方式。

  • dev_info(): 启动过程、或者模块加载过程等 “通知类的” 信息等,一般只会通知一次,例如 probe 函数;
  • dev_dbg(): 一般使用在普通错误,如 -EINVAL、-ENOMEM 等 errno 发生处,用于调试;
  • dev_err(): 一般使用在严重错误,尤其是用户无法得到 errno 的地方,或者程序员不容易猜测系统哪里出了问题的地方。

dev_debug 的定义在文件 include/linux/device.h:

#if defined(CONFIG_DYNAMIC_DEBUG)
#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

pr_debug 的定义在文件 include/linux/printk.h,从 pr_debug 的源码注释建议:如果写驱动,请用 dev_dbg。

/* If you are writing a driver, please use dev_dbg instead */
#if defined(CONFIG_DYNAMIC_DEBUG)
#include <linux/dynamic_debug.h>

/* 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
配置pr_debug/dev_dbg输出情况
CONFIG_DYNAMIC_DEBUG=y
DEBUG=n
调用 dynamic_pr_debug/dynamic_dev_dbg, echo -n “file xxx.c +p” > /sys/kernel/debug/dynamic_debug/control
CONFIG_DYNAMIC_DEBUG=y
DEBUG=y
调用 dynamic_pr_debug/dynamic_dev_dbg,增加启动参数 loglevel=8 之后,kernel 启动阶段就能看到 log
CONFIG_DYNAMIC_DEBUG=n
DEBUG=y
调用 printk,打印等级是 KERN_DEBUG=7,所以要将打印等级设置为 8(echo 8 > /proc/sys/kernel/printk)才能看到输出
CONFIG_DYNAMIC_DEBUG=n
DEBUG=n
不打印

2、动态输出支持的特性

动态输出在 debugfs 文件系统中对应的是 control 文件节点。control 文件节点记录了系统中所有使用动态输出技术的文件名路径,输出语句所在的行号、模块名和将要输出的语句等。

你可以通过以下命令查看目前所有调试状态的行为配置:

$ cat /sys/kernel/debug/dynamic_debug/control

你也可以应用标准的 Unix 文本过滤命令来过滤这些数据, 例如:

$ grep -i rdma /sys/kernel/debug/dynamic_debug/control  | wc -l

3、命令行格式

在语法层面上,一个命令由一系列的规格匹配组成,最后由一个标记来改变这规格。

command ::= match-spec* flags-spec

match-spec 常用来选择一个已知的 dprintk() 调用点的子集来套用 flags-spec。把他们当做彼此之间的每对做隐式查询。注意,一个空的 match_specs 列表是有可能的,但不是非常有用,因为它不会匹配任何调用点的调试子句。

一个匹配规范由一个关键字组成,关键字控制被比较的调用点的属性和要比较的值。可能关键字是:

match-spec ::= 'func' string    |
	           'file' string    |
	           'module' string  |
	           'format' string  |
	           'line' line-range
	           

line-range ::= lineno |
       		'-'lineno |
       	    lineno'-' |
  	        lineno'-'lineno

注意:line-range 不能包含空格,例如,“1-30”是有效的范围,但“1 - 30”就是无效的

每个关键字的含义如下:

  • func:给定的字符串会和每个调用点的函数名比较。例如: func svc_tcp_accept
  • file:给定的字符串会和每个调用点的源文件的全路径名或者相对名比较。例如: file svcsock.c, file /usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c
  • module:给定的字符串会和每个调用点的模块名进行比较。模块名是和在 ls mod 里看到的字符串一样。例如,module sunrpc
  • format:给定的字符串会在动态调试格式字符串里查找。注意这字符串不需要匹配这个格式。空格和其他特殊字符能够用八进制字符语法来转义,例如空字符是 \040。作为选择,这个字符串可以附上双引号 " 或者是单引号 ‘。例如:
format svcrdma:         // NFS/RDMA 服务器的dprintks
format readahead        // 一些在预加载缓存里的dprintks
format nfsd:\040SETATTR // 一个使用空格来匹配格式的方式
format "nfsd: SETATTR"  // 一个整齐的方法来用空格匹配格式
format 'nfsd: SETATTR'  // 同样是一个用空格来匹配格式的方法和
  • line:给定的行号或者是行号范围会和每个 dprintk() 调用点的行号进行比较。例如:
line 1603      // 准确定位到1603行 
line 1600-1605 // 1600行到1605行之间的6行
line -1605     // 从第一行到1605行之间的1605行
line 1600-     // 从1600行到结尾的全部行

标记规范包含了一个由一个或多个标记字符跟随的变化操作。这变化操作如下所示:

- // 移除给定的标记
+ // 加入给定的标记
= // 设置标记到给定的标记上 
f // 包含已打印消息的函数名
l // 包含已在打印消息的行号
m // 包含已打印消息的模块名
p // 产生一个 printk() 消息到显示系统启动日志
t // 包含了不在中断上下文中产生的消息里的线程ID

4、动态打印

例:

# 打开一个文件中所有动态打印语句
$ echo -n "file gadget.c +p" > /sys/kernel/debug/dynamic_debug/control

# 打开一个模块所有动态打印语句
$ echo "moudle dwc3 +p" > /sys/kernel/debug/dynamic_debug/control

# 打开一个函数中所有的动态打印语句
$ echo "func svc_process +p" > /sys/kernel/debug/dynamic_debug/control

# 打开文件路径中包含 usb 的文件里所有的动态打印语句
echo -n "*usb* +p" > /sys/kernel/debug/dynamic_debug/control

上面是打开动态打印语句的例子,除了能打印 pr_debug() / dev_dbg() 函数中定义的输出外,还能打印一些额外信息,例如函数名、行号、模块名字和线程 ID 等。

参数:

  • p:打开动态打印语句。
  • f:打印函数名
  • l:打印行号
  • m:打印模块名字
  • t:打印线程 ID

另外,还可以在各个子系统的 Makefile 中添加 ccflags 来打开动态输出语句:

Makefile:
ccflags-y += -DDEBUG
ccflags-y += -DVERBOSE_DEBUG
C#调用bartender进行动态打印以及批量打印的完整教程 信息化过程中难免接触到标签打印机,bartender是一款功能齐全的设计打印软件,可以设计标签模板内容,手动打印或者对接程序进行动态打印。应网友要求,出一个较为详细的教程。 阅读详情

相关推荐

print_hex_dump调试内核,嘎嘎香

prefix_type: 地址的输出格式是按照偏移、绝对地址或者不输出地址 (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE)print_hex_dump是 Linux 内核中的一个函数,用于以十六进制和 ASCII 码格式打印内存数据块。最近在验证芯片功能的过程中发现了一个好用的内核调试接口,print_hex_dump,除了直接打印16进制和ascii外,还支持动态调试打印。@prefix_str: 打印的前缀字符串。

珂珂可爱多 1758

Linux 内核动态打印调试(dev_info、 dev_dbg )

在 kernel 驱动代码中,使用动态输出是系统内核调试的重要手段之一,printk打印是全局的,只能设置输出等级。而动态输出可以动态选择打开某个内核子系统的输出,可以有选择性地打开某些模块的输出,printk被dev_info,dev_dbg,dev_err之类的函数代替,dev_xxx函数的本质还是使用printk打印的,只是对printk进行了一层包装。下面简述下这几个dev_xxx函数的基本使用规则,以及动态调试使用方式。

嵌入式大师之路 9240

Linux系统调试课:如何使用dynamic debug动态打印调试

沉淀、分享、成长,让自己和他人都能有所收获!😄

内核笔记 3760

Linux内核打印等级

打印等级有四个数字,这四个数字分别代表console_ loglevel (控制台日志等级)、default_message_loglevel (默认消息等级)、minimum_console_ loglevel (最低控制台日志等级)、default_console_loglevel (默认控制台日志的等级)。这四个等级定义在kernel/printk/ printk. c文件。作用: dmesg命令可以用来显示打印信息。

lufei12345678的博客 2179

【驱动】TI AM437x(内核调试-02):dynamic 动态打印调试

dynamic 动态控制打印信息:打开、关闭打印;指定驱动模块、文件、函数打印

郭老二 657

9、利用内核强大的动态调试功能进行调试

本文详细介绍了如何利用Linux内核的动态调试功能进行高效调试。内容涵盖动态调试API的使用、控制文件的配置与操作、标志说明符的设置、以及在生产环境中对内核模块的调试方法。通过具体的代码示例和操作命令,帮助开发者在不重新编译内核的情况下,灵活地启用或禁用调试信息,快速定位和解决内核相关问题。

e1f2g的博客 57

Linux调试方式之动态打印(module_param_named)

Linux调试方式之动态打印(module_param_named) 文章目录Linux调试方式之动态打印(module_param_named)module_param_named分析module_param_named使用案例 内核版本 Linux4.4 作者 nineyole module_param_named分析 在很多时候,我们需要记录一些调试信息,如果每次都用printk打印,会有很多无用代码,因此可以调用如下代码来申明一个变量。 module_param_named(db

学无止境 4812

数据驱动的老年人健康管理与生活品质提升实践研究

摘要 全球人口老龄化趋势显著,2025年65岁以上人口预计达8.57亿,中国老年人口已突破3亿。老年人健康挑战突出,75%以上患慢性病,且独居老人心理健康与应急需求迫切。数据驱动的健康管理通过智能设备(如跌倒检测、远程监测)和AI技术(如疾病预测算法)提升效率,改善生活品质。研究提出差异化需求解决方案,如慢性病患者的持续监测与用药管理,高龄老人的综合护理服务,并探讨政策与商业模式以推动智慧养老产业发展,2024年市场规模已达6.8万亿元。

聚焦程序设计语言理论与前沿技术落地,拆解代码世界的底层逻辑,探索语言设计的 “创造与沟通” 之道。从编译原理、类型系统到 AI 技术在金融、医疗、制造、养老、大健康等领域的实战案例,分享硬核技术干货与工程化思考。 1628

内核打印调试printk学习笔记

内核打印调试printk学习笔记Printk打印格式与打印等级打印数据打印等级日志级别(loglevel)修改控制台打印等级控制台、终端和串口之间的关系终端(terminal)与控制台(console)控制台与串口嵌入式平台下的console查看和重映射伪终端 Printk打印格式与打印等级 打印数据 打印数据格式(跟printf类似、不支持浮点型) 打印指针 %p:打印指针地址 %pF:打印函数指针的函数名和偏移地址 %pf:只打印函数指针的函数名,不打印偏移地址 …

雪夜的博客 3086

基于ADS1299的8通道脑电采集系统硬件设计实战

生物电信号采集是医疗电子与可穿戴设备中的关键环节,微弱信号的高保真放大与数字化处理直接影响系统性能。高精度模数转换器与低噪声模拟前端设计成为工程实践的核心。ADS1299作为专用生物电测量芯片,集成多通道低噪声放大器与24位Δ-Σ ADC,广泛应用于脑电、心电等生理信号检测。本文基于ADS1299构建8通道脑电采集系统,详细阐述硬件架构、电源与参考设计、输入保护、PCB布局布线、固件SPI配置及数据读取,并结合实测数据分享噪声抑制与调试经验,为EEG采集设备开发提供完整参考。

weixin_29169505的博客 222

达梦DM8整合Seata AT模式实战:手把手教你搞定分布式事务(含源码修改避坑)

本文详细介绍了达梦DM8数据库与Seata AT模式的深度整合实战,包括环境准备、架构设计、源码适配及分布式事务落地。通过独创性源码改造,解决了Seata官方对达梦数据库AT模式支持的限制,为国产数据库在微服务架构中的应用提供了可靠的事务保障。

weixin_30764771的博客 332

Linux内核驱动调试信息打印分析

在Linux内核驱动中,不能使用标准C库的printf函数,因为内核运行在内核空间,无法直接使用用户空间的库函数。

shanstellar的博客 677

嵌入式开发必备:UART、RS232、RS485通信协议实战对比(附代码示例)

本文从嵌入式开发实战角度,深度对比了UART、RS232和RS485三种核心串行通信协议。详细解析了它们的工作原理、硬件连接、代码配置及典型应用场景,并提供了基于通信距离、节点数量和电磁环境的三维度选型指南,帮助开发者根据项目需求做出最优技术决策。

i0j1k2l3m的博客 474

linux中打开内核的动态调试

1. 简介 在调试linux的驱动的时候,会遇到dev_dbg (“xxx”); ,如何让他显示出来,是本片文章的重点目的。 2. 分析 dev_dbg 的源码 #if defined(CONFIG_DYNAMIC_DEBUG) #define dev_dbg(dev, format, ...) \ do { \ dynamic_dev_dbg(...

老鹏 3027

CentOS7环境下搭建 rsyslog 日志服务器,rsyslog+loganalyzer

1.系统环境部署 ip hostname 192.168.200.182 web 192.168.200.184 rsyslog-mysql 关闭防火墙、selinux、下载epel源 [root@web ~]# systemctl status firewalld.service ● firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/f

sehn_的博客 3751

Reeds-Shepp曲线公式推导及代码实现-第二部分(共三部分)

文章目录2. Reeds-Shepp求解2.1 L+S+L+L^+S^+L^+L+S+L+2.2 L+S+R+L^+S^+R^+L+S+R+2.3 L+R−L+L^+R^-L^+L+R−L+2.4 L+R−L−L^+R^-L^-L+R−L−2.5 L+R+L−L^+R^+L^-L+R+L−2.6 L+Rβ+Lβ−R−L^+R_{\beta}^+L_{\beta}^-R^-L+Rβ+​Lβ−​R−2.7 L+Rβ−Lβ−R+L^+R_{\beta}^-L_{\beta}^-R^+L+Rβ−​Lβ−​R+2.8

jianmo的博客 1209

Linux内核调试 - dynamic debug

文件目录:kernel-4.14\Documentation\admin-guide\dynamic-debug-howto.rst参数作用。

u010971180的博客 923

用逻辑分析仪实测EM4095:125kHz RFID耳标解码的电压与脉宽玄学

本文通过逻辑分析仪实测EM4095芯片,深入解析125kHz RFID耳标解码中的电压与脉宽关联现象。揭示了供电电压对曼彻斯特编码脉宽的影响规律,并提供了一套可落地的调试方法论,包括信号链路解析、逻辑分析仪配置技巧及系统级稳定性提升方案,帮助开发者解决解码不稳定问题。

weixin_30629653的博客 327

第3章 Linux内核调试手段之内核打印

开始前面说的话在我写代码的生涯里,我看到过很多大神炫耀自己的调试手段,也看到很多大神写过非常厉害的代码,我认为,相比于写代码,调试更加重要,而那些能在写代码的时候就加入了...

嵌入式Linux 3721

【WorkBuddy专栏32】从「分文件夹」到「组队打仗」——WorkBuddy v5.0项目模式深度拆解

【WorkBuddy专栏32】从「分文件夹」到「组队打仗」——WorkBuddy v5.0项目模式深度拆解

AI人人懂 294

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

linux定义调试日志,linux debug技巧(动态调试)

proc文件系统中可以查看一些正在运行的变量如device-treesh-3.2# cat /proc/device-tree/#address-cells fixedregulator@9/#size-cells gpio-keys/atf_logger/ interrupt-parent chose...

weixin_39731271的博客 888

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

【Linux】驱动内核调试,是需要几板斧的

在驱动开发中,亦有调试的手段和方法,这些是我们解决和排查问题的利器。

希希雾里 3418

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

上一篇: Linux 下查看 CPU 使用率
下一篇: Linux 进程调度(二)之进程的上下文切换
Projectsauron
博客等级 码龄4年 2587粉丝 100原创
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值