基于printk问题调试
1 printk相关介绍
printk()是Linux内核中最广为人知的函数之一。它是我们打印消息的标准工具,通常也是追踪和调试 的最基本方法。
所有的printk()消息都会被打印到内核日志缓冲区,这是一个通过/dev/kmsg输出到用户空间的环 形缓冲区。读取它的通常方法是使用 dmesg 。
https://www.kernel.org/doc/html/v5.15/translations/zh_CN/core-api/printk-basics.html
2 initcall_debug
2.1 使用说明:
Documentation/kernel-parameters.txt中的说明如下:
initcall_debug [KNL] Trace initcalls as they are executed. Useful
for working out where the kernel is dying during startup.
说明initcall_debug是一个内核参数,可以跟踪initcall,用来定位内核初始化的问题。在cmdline中增加initcall_debug后,内核启动过程中会增加如下形式的日志,在调用每一个init函数前有一句打印,结束后再有一句打印并且输出了该Init函数运行的时间,通过这个信息可以用来定位启动过程中哪个init函数运行失败以及哪些init函数运行时间较长。
calling init_workqueues+0x0/0x414 @ 1
initcall init_workqueues+0x0/0x414 returned 0 after 0 usecs
除了在启动过程中会增加日志外,在系统休眠唤醒过程中也会增加如下形式的日志,可以用来定位休眠唤醒失败及休眠唤醒时间太长的问题。
calling xxxxxx.dma+ @ 6, parent: xxx.0
call xxxxxx.dma+ returned 0 after 2 usecs
2.2 使能loglevel
当我们使能initcall_debug功能之后发现,这个log并没有默认输出到串口中,对于那些系统启动过程就卡死的问题,我们很难看到对应的log来定位问题,所以我们可以考虑把loglevel默认打印级别调高,比如在cmdline中设置loglevel=8,这样就会默认把所有log输出到串口了.
2.3 解析initcall debug log
cat log.txt | grep "initcall" | sed "s/\(.*\)after\(.*\)/\2 \1/g" | sort -n
这个命令可以解析log中的initcall数据,并根据时间长短进行排序.