1、early printk loglevel
printk的log输出是由console实现(会在其他文章中说明)。由于在kernel刚启动的过程中,还没有为串口等设备等注册console(在device probe阶段实现),此时无法通过正常的console来输出log。
为此,linux提供了early console机制,用于实现为设备注册console之前的早期log的输出。这个console在kernel启动的早期阶段就会被注册,主要通过输出设备(比如串口设备)的简单的write方法直接进行数据打印。
CONFIG_DEBUG_LL
ENTRY(printch)定义在arch/arm/debug.S中,需要用这个宏来打开。
CONFIG_EARLY_PRINTK
lichee\linux-3.10\arch\arm64\kernel\early_printk.c
2、initcall_debug
initcall_debug参数定位初始化过程中的错误信息发生的位置。
3、内核打印
Linux内核用函数printk打印调试信息,该函数的用法与C库打印函数printf格式类似,但在内核使用。用户可在内核代码中的某位置加入函数printk,直接把所关心的信息打打印到屏幕上或日志文件中。
函数printk根据日志级别(loglevel)对调试信息进行分类。日志级别用宏定义,展开为一个字符串,在编译时由预处理器将它和消息文本拼接成一个字符串。
(1)、不直接调用printk,而是调用pr_xxx,如下
(2)、不直接调用printk,而是调用dev_xxx
设备的名字将为打印前缀, dev_warn(); dev_info(); dev_emerg();
(3)、带函数与行数打印
printk("%s%d\n", __func__, __LINE__);
(4)、printk
printk打印级别动态调整
printk有8个loglevel,定义在lichee\linux-3.10\include\linux\ kern_levels.h中,其中数值范围从0到7,数值越小,优先级越低。未指定优先级的默认级别定义在/kernel/printk.c中,当优先级的值小console_loglevel这个整数变量的值,信息才能显示出来
printk在中断,软中断,spinlock里面都可以调用。printk的开销很大,尤其是串口打印,会让系统慢很多,所以产品里面减少不必要的打印,或者bootargs里面"quiet"。
(5)、内核带时间戳打印
(6)、dumpstack() warn_on(1)
回溯函数调用过程。
4、内核模块源码级调试
比较少用,参考kdb,gdb调试文档(待续,本人只用gdb调试过上层,没有调过内核,视频里面看也只是泛泛而讲)。
5、oops与panic
Oops英文单词的中文含义是“哎呀”,表示“惊叹”;Panic英文单词的中文含义是“惊慌”。所以panic的程度显然是高于oops的,因为惊叹不一定会惊慌,而惊慌最容易失措,内核panic后,就死机了,俗称内核崩溃。但是内核报oops,这个时候不见得会panic,它可能只是报个oops,杀死进程而已。
oops不一定panic,中断上下文的oops会panic,如果panic_on_oops设置为1,一律panic。
oops 显示发生错误时处理器的状态,包括 CPU 寄存器的内容、页描述符表的位置,以及其他一些信息。
--->cd0+a0=d70
6、其他内核debug选项和功能
(1)、 no_console_suspend
在suspend的时候console 不进行suspend,否则console suspend之后其他driver在suspend 过程中印的log都显示不出来,因此加这个参数一般用于调试suspend 和 resume。在bootargs中添加"no_console_suspend"参数。
(2)、SLUB_DEBUG kmemleak --->内存检测
Linux常见的内存访问错误有:越界访问(out of bounds)、访问已经释放的内存(use after free)、重复释放、内存泄露(memory leak)、栈溢出(stack overflow)等。
(a)、SLUB_DEBUG 内核中小块内存大量使用slab/slub分配器,slub_debug提供了:访问已经释放的内存、越界访问、重复释放内存等功能检测。
支持slub_debug内核配置
重新配置kernel选项,打开如下选项即可。
CONFIG_SLUB=y
CONFIG_SLUB_DEBUG=y
CONFIG_SLUB_DEBUG_ON=y
(1)、重复释放
2c4+10c -> 3D0
(2)、内存越界
(b)、kmemleak是内核提供的一种检测内存泄露工具,启动一个内核线程扫描内存,并打印发现新的未引用对象数量。
使用kmemlieak,需要打开如下内核选项。
CONFIG_HAVE_DEBUG_KMEMLEAK=y
CONFIG_DEBUG_KMEMLEAK=y
CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=400
# CONFIG_DEBUG_KMEMLEAK_TEST is not set
CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y---------或者关闭此选项,则不需要在命令行添加kmemleak=on。
(3)、DEBUG_ATOMIC_SLEEP -->检测在spinlock,中断,软中断中的sleep
(4)、RCU Stall
内核配置项:
(5)、Lockup detector
kernel/watchdog.c
NMI中断+定时器中断+高优先级RT线程
用定时器中断,检测高优先级线程有无机会执行->softlockup
用NMI,检测定时器中断有无机会执行->hard lockup
内核选项:
示例: