读书笔记(chapter18)
调试
18.1准备开始
18.2内核中的bug
1.从隐藏在源代码中的错误到展现在目击者面前的bug,往往是经历一系列连锁反应的事件才可能触发的
18.3通过打印来调试
1.健壮性
健壮性是printk()函数最容易让人们接受 一个特质;而且调用者连锁都不必使用
核心硬件部分的黑客依靠此时能够工作的硬件设备与外界通信;绝大部分人对此都不会感兴趣的。
2.日志等级
printk()与printf()最主要区别的就是前者可以指定一个日志级别。内核根据一个级别来判断是否在终端上打印消息
现在默认等级是kern_warning。由于这个默认值将来存在变化的可能性,所以还是应该给自己的消息指定一个记录等级。
3.记录缓冲区
而环形缓冲区的唯一缺点——可能会丢失消息,但是与简单性与健康性的好处相比,这点代价是值得的;
4.syslogd和klogd
在启动klogd的时候,可以通过指定 -c标志来改变终端的记录等级
5.从printf()到printk()的转换
18.4oops
如果oops在中断上下文时,内核根本无法继续,会陷并入混乱。如果oops在idle进程(pid为0)或者init进程(pid为1),结果同样的系统陷入混乱,因为内核缺了这两个重要的进程根本无法工作;内核会杀死该进程并尝试着继续执行
1.ksymoops oops可以说是一个经过解码的oops,内存地址都转换成了它们对应的函数,这需要调用ksymoops命令,并且还必须提供编译内核时产生的system.map
ksymoop saved_opps.txt
2.kallsyms
现场已经无须使用ksymoops工具了,开发版的2.5版内内核引入了kallsyms特性,它可以通过定义于config_kallsyms配置选项启用;
18.5
最有用的一个是sleep-inside-spinlock checking(自旋锁内睡眠选项),这些选项确实能完成不少调试工作.
内核提供一个原子操作计数器。它可以被配置成一旦在原子操作过程中进程进入睡眠或者一些可能引起睡眠的操作。这种调试方法捕获了大量bug
18.6
1.内核调用最常用的是bug()和bug_on();当被调用的时候,它们会引发oops,导致栈的回溯和错误信息的打印。这些声明会导致oops跟硬件的体系结构是相关的。可以用panic()引发更严重的错误;只需要在终端上打印一下栈的回溯信息来帮助调试;
18.7
1.当该功能被启用的时候,无论内核处于什么状态,都可以通过特殊的组合键跟内核进行通信。
2.输入sysrq-h获取一份可用的选项列表;sysrq-u卸载所有的文件系统,sysrq-b重启设备;
18.8
1.gdb(有很多局限性)
gdb_vmlinux /proc/kcore
2.kgdb
18.9
1用UID作为选择条件
2使用条件变量
3使用统计量
4重复频率限制
18.10
1.使用git二分搜索
2.从记录日志到git二分查找法.