Linux内核调试与开发指南
1. 看门狗设备的用户空间管理
1.1 看门狗sysfs接口
看门狗框架允许通过sysfs接口从用户空间管理看门狗设备。前提是内核中启用了 CONFIG_WATCHDOG_SYSFS 配置选项,根目录为 /sys/class/watchdogX/ ,其中 X 是系统中看门狗设备的索引。每个看门狗目录包含以下属性:
| 属性 | 描述 |
| ---- | ---- |
| nowayout | 若设备支持 nowayout 特性则返回1,否则返回0 |
| status | 相当于 WDIOC_GETSTATUS ioctl,报告看门狗的内部状态位 |
| timeleft | 相当于 WDIOC_GETTIMELEFT ioctl,返回看门狗重置系统前剩余的时间(秒) |
| timeout | 显示当前编程的超时值 |
| identity | 包含看门狗设备的标识字符串 |
| bootstatus | 相当于 WDIOC_GETBOOTSTATUS ioctl,指示系统重置是否由看门狗设备引起 |
| state | 显示看门狗设备的活动/非活动状态 |
1.2 预超时事件处理
可以通过sysfs设置调节器(governor),调节器是一种策略管理器,根据外部参数采取特定操作。有热调节器、CPUFreq调节器和看门狗调节器,每个调节器在各自的驱动中实现。
查看可用的调节器:
# cat /sys/class/watchdog/watchdog0/pretimeout_available_governors
noop panic
检查是否可以选择预超时调节器:
# cat /sys/class/watchdog/watchdog0/pretimeout_governor
panic
# echo -n noop > /sys/class/watchdog/watchdog0/pretimeout_governor
# cat /sys/class/watchdog/watchdog0/pretimeout_governor
noop
检查预超时值:
# cat /sys/class/watchdog/watchdog0/pretimeout
10
2. Linux内核发布过程
2.1 内核发布类型
根据Linux内核发布模型,有三种活跃的内核发布类型:主线(mainline)、稳定版(stable release)和长期支持版(Long-Term Support,LTS)。
- 主线内核 :由子系统维护者收集和准备错误修复和新特性,提交给Linus Torvalds,包含在他的主线Linux树(即主Git仓库)中,所有稳定版都源于此。
- 稳定版内核 :基于主线内核发布,在新内核版本发布前,会通过发布候选标签提交给社区,开发者测试和完善新特性并反馈。Linus根据反馈决定最终版本是否发布,稳定版为 vX.Y 版本。
- 长期支持版内核 :为需要长期稳定性的系统提供支持。
2.2 内核发布流程
graph LR
A[子系统维护者收集特性和修复] --> B[提交给Linus Torvalds]
B --> C[Linus将其纳入主线Linux树]
C --> D[发布候选版本供社区测试]
D --> E{Linus决定是否发布最终版本}
E -- 是 --> F[发布稳定版内核]
E -- 否 --> D
F --> G[稳定版内核进入linux - stable树]
G --> H[可接收错误修复]
新主线内核通常每2 - 3个月发布一次,稳定版内核基于主线内核发布,错误修复需要先合并到主线树,再反向移植到稳定版。
2.3 相关链接
- https://www.kernel.org/ :可下载内核存档。
- https://www.kernel.org/category/releases.html :可获取最新LTS内核版本及其支持时间线。
- https://patchwork.kernel.org/ :可跟踪子系统的内核补丁提交情况。
3. Linux内核开发调试技巧
3.1 消息打印
在Linux内核开发中,消息打印和日志记录是常用的调试方法。 printk() 函数是内核消息打印的事实标准函数,类似于C库中的 printf() ,但有日志级别概念。
printk(<LOG_LEVEL> " printf like formatted message\n" );
其中 <LOG_LEVEL> 是 include/linux/kern_levels.h 中定义的八种日志级别之一,用于指定错误消息的严重程度。
3.2 内核日志级别
| 日志级别 | 定义 | 描述 |
|---|---|---|
| KERN_EMERG | “0” | 紧急消息,系统即将崩溃或不稳定 |
| KERN_ALERT | “1” | 发生严重情况,需立即采取行动 |
| KERN_CRIT | “2” | 关键情况,如严重的硬件/软件故障 |
| KERN_ERR | “3” | 错误条件,常用于驱动程序指示硬件问题或与子系统交互失败 |
| KERN_WARNING | “4” | 警告消息,本身不严重,但可能表示存在问题 |
| KERN_NOTICE | “5” | 无严重问题,但值得关注,常用于报告安全事件 |
| KERN_INFO | “6” | 信息性消息,如驱动初始化时的启动信息 |
| KERN_DEBUG | “7” | 调试目的,仅在启用 DEBUG 内核选项时有效 |
若未指定日志级别,默认使用 DEFAULT_MESSAGE_LOGLEVEL (通常为 KERN_WARNING ),可通过 CONFIG_DEFAULT_MESSAGE_LOGLEVEL 内核配置选项设置。
3.3 消息显示控制
内核通过比较消息的日志级别和 console_loglevel 内核变量来决定是否立即将消息显示给用户。
查看当前 console_loglevel :
$ cat /proc/sys/kernel/printk
4 4 1 7
第一个整数是当前控制台日志级别,第二个是默认值,第三个是可设置的最小控制台日志级别,第四个是启动时的默认控制台日志级别。
更改当前 console_loglevel :
# echo 8 > /proc/sys/kernel/printk
也可以使用 dmesg 命令:
# dmesg -n 5
还可以在启动时使用 loglevel 启动参数指定。
3.4 内核日志缓冲区
内核消息会记录在一个固定大小的循环缓冲区中。可以通过 LOG_BUF_SHIFT 选项在编译时设置缓冲区大小,也可以在启动时使用 log_buf_len 参数设置,例如 log_buf_len=1M (仅接受2的幂值)。
3.5 添加时间信息
通过启用 CONFIG_PRINTK_TIME 选项,可以为打印的消息添加时间信息。启用后,每个日志消息前会有时间戳:
$ dmesg
[…]
[ 1.260037] loop: module loaded
[ 1.260194] libphy: Fixed MDIO Bus: probed
[…]
可以在运行时通过以下命令控制时间戳的显示:
# echo 1 >/sys/module/printk/parameters/time
# cat /sys/module/printk/parameters/time
Y
4. Linux内核追踪与性能分析
4.1 Ftrace简介
Ftrace是Linux内核内部的追踪工具,可用于测量中断处理时间、跟踪耗时函数、计算高优先级任务激活时间、跟踪上下文切换等。
要支持Ftrace,需要启用以下内核选项:
- CONFIG_FUNCTION_TRACER
- CONFIG_FUNCTION_GRAPH_TRACER
- CONFIG_STACK_TRACER
- CONFIG_DYNAMIC_FTRACE
这些选项依赖于架构支持追踪特性,即启用 CONFIG_HAVE_FUNCTION_TRACER 、 CONFIG_HAVE_DYNAMIC_FTRACE 和 CONFIG_HAVE_FUNCTION_GRAPH_TRACER 选项。
挂载 tracefs 目录:
# mount -t tracefs nodev /sys/kernel/debug/tracing
4.2 可用追踪器
通过以下命令查看可用的追踪器:
# cat /sys/kernel/debug/tracing/available_tracers
blk function_graph wakeup_dl wakeup_rt wakeup irqsoff function nop
各追踪器特点如下:
| 追踪器 | 描述 |
| ---- | ---- |
| function | 无参数的函数调用追踪器 |
| function_graph | 带子调用的函数调用追踪器 |
| blk | 与块设备I/O操作相关的调用和事件追踪器 |
| mmiotrace | 内存映射I/O操作追踪器 |
| irqsoff | 追踪禁用中断的区域并保存最长延迟的追踪记录 |
| preemptoff | 追踪并记录禁用抢占的时间 |
| preemtirqsoff | 追踪并记录禁用中断和/或抢占的最长时间 |
| wakeup | 追踪并记录最高优先级任务唤醒后调度的最大延迟 |
| wakeup_rt | 追踪并记录实时任务唤醒后调度的最大延迟 |
| nop | 最简单的追踪器,仅显示 trace_printk() 调用的输出 |
4.3 函数追踪器
使用函数追踪器的测试脚本:
# cd /sys/kernel/debug/tracing
# echo function > current_tracer
# echo 1 > tracing_on
# sleep 1
# echo 0 > tracing_on
# less trace
执行该脚本后,输出包含进程名、进程ID、CPU编号、函数开始时间、被追踪函数名和调用它的父函数名等信息。
4.4 函数图追踪器
函数图追踪器比函数追踪器更详细,能显示每个函数的入口和出口点,可追踪带子调用的函数并测量执行时间。
测试脚本:
# cd /sys/kernel/debug/tracing
# echo function_graph > current_tracer
# echo 1 > tracing_on
# sleep 1
# echo 0 > tracing_on
# less trace
输出中, DURATION 显示函数运行时间, + 表示函数执行时间超过10微秒, ! 表示超过100微秒。
4.5 函数过滤
可以使用过滤器选择要追踪的函数,减少追踪开销。
只追踪 kfree 函数:
# echo kfree > set_ftrace_filter
禁用过滤器:
# echo > set_ftrace_filter
排除 kfree 函数:
# echo kfree > set_ftrace_notrace
还可以使用 set_ftrace_pid 工具追踪特定进程调用的函数。
4.6 追踪事件
4.6.1 追踪点
追踪点是触发系统事件的特殊代码插入点,分为动态和静态两种。静态追踪点不影响系统,仅在被检测函数末尾添加函数调用的几个字节和在单独部分添加数据结构;动态追踪点在执行相关代码片段时调用追踪函数,追踪数据写入环形缓冲区。
4.6.2 查看可用事件
# cat /sys/kernel/debug/tracing/available_events
mac80211:drv_return_void
mac80211:drv_return_int
[…]
更结构化的列表:
# ls /sys/kernel/debug/tracing/events
block gpio napi regmap syscalls
cfg80211 header_event net regulator task
[…]
4.6.3 追踪hrtimer相关函数
# cd /sys/kernel/debug/tracing/
# echo 0 > tracing_on
# echo > trace
# echo nop > current_tracer
# echo 1 > events/timer/enable
# echo 1 > tracing_on;
# sleep 1;
# echo 0 > tracing_on;
# echo 0 > events/timer/enable
# less trace
4.7 追踪特定进程
要追踪特定进程调用的内核函数,可以将 set_ftrace_pid 变量设置为该进程的PID。如果进程未运行,可以使用包装脚本:
#!/bin/sh
echo $$ > /debug/tracing/set_ftrace_pid
# [can set other filtering here]
echo function_graph > /debug/tracing/current_tracer
exec $*
假设脚本名为 trace_process.sh ,使用示例:
./trace_process.sh some_command
通过以上方法,可以更有效地进行Linux内核的开发和调试工作。
5. 总结与应用建议
5.1 核心要点总结
- 看门狗设备管理 :通过sysfs接口可在用户空间对看门狗设备进行管理,包括检查设备特性、状态、超时值等,还能处理预超时事件,设置相应的调节器。
- 内核发布过程 :Linux内核有主线、稳定版和长期支持版三种发布类型,发布过程涉及子系统维护者收集特性、提交给Linus Torvalds、社区测试反馈等环节,稳定版内核可接收反向移植的错误修复。
- 内核开发调试 :使用
printk()函数进行消息打印,有八种日志级别可用于区分消息严重程度。可通过console_loglevel控制消息显示,还能调整内核日志缓冲区大小和添加时间信息。 - 内核追踪与性能分析 :Ftrace是强大的内核内部追踪工具,有多种追踪器可供选择,能对函数调用、事件等进行追踪,还可使用过滤器和追踪特定进程。
5.2 应用建议
5.2.1 看门狗设备应用
- 当需要确保系统的可靠性时,可利用看门狗设备的特性。例如,在嵌入式系统中,设置合适的超时值,定期喂狗,防止系统因异常而崩溃。
- 对于预超时事件,可以根据实际需求选择合适的调节器,如在关键任务系统中,可选择
panic调节器,在系统即将超时前采取紧急措施。
5.2.2 内核开发调试应用
- 在开发新的内核模块或驱动时,使用
pr_*()系列宏进行消息打印,方便调试和日志记录。 - 当遇到难以定位的问题时,可通过调整
console_loglevel显示更多的日志信息,也可启用CONFIG_PRINTK_TIME添加时间信息,辅助分析问题。
5.2.3 内核追踪与性能分析应用
- 在优化系统性能时,使用Ftrace的不同追踪器来分析系统瓶颈。例如,使用
function_graph追踪器找出耗时较长的函数,进行针对性优化。 - 当需要追踪特定进程的内核函数调用时,使用
set_ftrace_pid工具,减少无关信息的干扰。
5.3 未来展望
随着Linux内核的不断发展,调试和追踪工具也会不断完善。未来可能会有更高效、更强大的工具出现,帮助开发者更轻松地进行内核开发和调试。同时,对于内核的安全性和稳定性要求也会越来越高,相关的技术和方法也会不断演进。
6. 常见问题解答
6.1 看门狗设备相关问题
6.1.1 如何判断看门狗设备是否支持 nowayout 特性?
可以通过查看 /sys/class/watchdog/watchdogX/nowayout 文件的值,若为1则支持,为0则不支持。
6.1.2 预超时调节器设置失败怎么办?
首先检查文件权限,确保有足够的权限进行写入操作。然后检查输入的调节器名称是否正确,是否在 pretimeout_available_governors 列表中。
6.2 内核发布与开发相关问题
6.2.1 如何获取最新的内核版本?
可以访问 https://www.kernel.org/ 下载内核存档,也可以关注 https://www.kernel.org/category/releases.html 获取最新LTS内核版本及其支持时间线。
6.2.2 为什么有些日志消息在控制台不显示?
这可能是因为消息的日志级别低于 console_loglevel 的值。可以通过 cat /proc/sys/kernel/printk 查看当前 console_loglevel ,并根据需要进行调整。
6.3 内核追踪与性能分析相关问题
6.3.1 Ftrace追踪数据丢失怎么办?
可以尝试增大内核日志缓冲区的大小,通过 log_buf_len 参数在启动时设置。同时,检查系统资源是否充足,避免因资源不足导致数据丢失。
6.3.2 如何选择合适的Ftrace追踪器?
根据具体的需求选择。如果只需要追踪函数调用,可选择 function 追踪器;如果需要查看函数的子调用和执行时间,可选择 function_graph 追踪器;如果关注系统的延迟问题,可选择 irqsoff 、 preemptoff 等延迟追踪器。
7. 总结
本文详细介绍了Linux内核调试与开发的相关知识,包括看门狗设备的用户空间管理、内核发布过程、开发调试技巧以及内核追踪与性能分析等方面。通过对这些知识的学习和应用,开发者可以更高效地进行Linux内核的开发和调试,提高系统的可靠性和性能。同时,我们也给出了常见问题的解答和应用建议,希望能对读者有所帮助。
以下是一个总结性的mermaid流程图,展示整个Linux内核开发调试的流程:
graph LR
A[看门狗设备管理] --> B[内核发布与获取]
B --> C[内核开发调试]
C --> D[内核追踪与性能分析]
D --> E[问题解决与优化]
E --> A
这个流程图表明,在Linux内核开发过程中,各个环节是相互关联、循环迭代的。从看门狗设备的管理确保系统可靠性,到获取合适的内核版本进行开发,再到使用调试技巧和追踪工具解决问题和优化性能,最后又回到看门狗设备管理等环节,不断提升系统的质量。
268



被折叠的 条评论
为什么被折叠?



