须要的是准备是: - 一个bug - 一个藏匿bug的内核版本 - 相关内核代码的知识和运气linux
重点: 想要成功的进行调试,就取决因而否能让这些错误重现。如若不能,消灭bug就只能经过抽象出问题,再从代码中寻找蛛丝马迹来进行了。算法
bug出现时可能的症状:sass
内核bug发做时可能的症状:app
概述:编辑器
内核中的bug表现得不像用户级程序中那么清晰——由于内核、用户以及硬件之间的交互会很微妙ide
健壮性是printk()函数最容易让人们接受的一个特质,在任什么时候候,任何地方都能调用它。函数
printk()函数变体——early-printk()函数,区别仅在于能够更早(甚至在启动初期,终端尚未初始化以前)地工做oop
优点:性能
缺点:可能会丢失信息。学习
这是两个用户空间的守护进程,klogd从记录缓冲区中获取内核消息,再经过syslogd守护进程将他们保存在系统日志文件中。 - klogd
- 既能够从/proc/kmsg文件中,也能够经过syslog()系统调用读取这些消息。 - 默认是/proc方式。 - 两种状况klogd都会阻塞,知道有新的内核消息可供读出,唤醒以后默认处理是将消息传给syslogd。 - 能够经过-c标志来改变终端的记录等级
过程包括:
关于oops发生的时机:
1.发生在中断上下文:内核没法继续,会陷入混乱,致使系统死机
2.发生在idle进程或init进程(0号进程和1号进程),同上
3.发生在其余进程运行时,内核会杀死该进程并尝试着继续执行
oops发生的可能缘由:
内存访问越界
非法的指令
……
oops中包含的重要信息:寄存器上下文和回溯线索回溯线索:显示了致使错误发生的函数调用链。
寄存器上下文信息也颇有用,好比帮助冲进引起问题的现场
• 将回溯线索中的地址转换成有意义的符号名称:
• ksymoops saved_oops.txt
• 经过定义CONFIG_KALLSYMS配置选项启用,该选项中存放内核镜像中相应函数地址的符号名称,内核能够打印解码好的跟踪线索
位于内核配置编辑器的内核开发菜单项中,都依赖于CONFIGDEBUGKERNEL。
slab layer debugging slab层调试选项 high-memory debugging 高端内存调试选项 I/O mapping debugging I/O映射调试选项 spin-lock debugging 自旋锁调试选项 stack-overflow debugging 栈溢出检查选项 sleep-inside-spinlock checking 自旋锁内睡眠选项 ……
例如;正在使用一个自旋锁或禁止抢占的代码。 使用锁时睡眠是引起死锁的元凶。
利用BUG()以及BUG_ON()(由于大多数体系结构都把这两个函数定义成某种非法操做,能够触发oops)
调用panic()函数会在打印错误信息的同时挂起系统
调用dump_stack(),只在终端上打印寄存器上下文及函数的跟踪线索
除了配置选项之外,还要经过一个sysctl用来标记该特性的开或关,启动命令以下:
echo 1 > /proc/sys/kernel/sysrq
Sysrq的几个命令:
SysRq-s:将“脏”缓冲区跟硬盘交换分区同步 SysRq-u:卸载全部的文件系统 SysRq-b:重启设备
gdb vmlinux(未经压缩的内核映像)-
可使用gdb的全部命令来获取信息。例如:
打印一个变量的值: p global_variable 反汇编一个函数: disassemble function -g参数还能够提供更多的信息。
局限性:
没有办法修改内核数据
不能单步执行内核代码
- 读取和修改变量值 - 设置断点 - 设置关注变量 - 单步执行
这种方式比使用UID更简单,只须要建立一个全局变量做为一个条件选择开关:
若是该变量为0,就使用某一个分支上的代码; 不然,选择另一个分支。
定义全局变量
在/proc目录中建立一个文件 or新建一个系统调用 or经过调试器直接访问(最直接)
(1)重复频率限制 (2)发生次数限制
本章主要讲内核的调试,调试过程就是一种寻求实现与目标误差的行为,经过学习各类调试技巧,,发现困难重重,但相信有一天努力会有成果的。
《linux内核设计与实现》原书第三版