内核调试linux
内核中的bug多种多样,表象也变化无穷,有一些独特的问题须要考虑。git
1、经过打印来调试(printk())编辑器
1.健壮性:函数
printk是一个弹性极佳的函数,尤为是随时都能被调用的特性(除了终端没有初始化以前--可用early_printk()解决)工具
2.日志等级oop
printk与printf最主要的区别是printk能够指定日志级别,内核根据级别判断是否在终端上打印消息(比某个特定值低的消息显示在终端上)ui
可供使用记录等级:spa
KERN_EMERG | 一个紧急状况 |
KERN_ALERT | 一个须要当即被注意到的错误 |
KERN_CRIT | 一个临界状况 |
KERN_ERR | 一个错误 |
KERN_WARNING | 一个警告 |
KERN_NOTICE | 一个普通的,不过可能须要注意的状况 |
KERN_INFO | 一条非正式的消息 |
KERN_DEBUG | 一条调试信息——通常是冗余信息 |
没指定记录等级时,会选用默认的DEFAULT_MESSAGE_LOGLEVEL,如今是KERN_WARNING调试
最重要的记录等级KERN_EMERG定为“<0>”日志
3.记录缓冲区
内核消息被保存在一个LOG_BUF_LEN大小的环形队列中,大小可经过设置CONFIG_LOG_BUF_SHIFT调整。(但处理器默认16kb)
环形队列好处:同时读写时,同步问题容易解决;
记录维护也更容易。
缺点:可能会丢失消息。
4.syslogd和klogd
用户空间的守护进程klogd从记录缓冲区获取内核消息,syslogd守护进程保存在系统日志文件中(默认是/var/log/messages,也可经过/etc/syslog.conf设置)。
读取方法:1)从/proc/kmsg文件中
2)经过syslog()系统调用;
但两种方法klogd都会阻塞。
启动klogd时可经过指定-c标志改变终端记录等级。
2、oops
内核很难自行修复,也不能将本身杀死,只能发布oops
1.ksymoops
回溯线索中的地址须要转化成有意义的符号名称,须要调用ksymoops,以及System.map
使用:
ksymoops saved_oops.txt
2.kallsyms
开发版的2.5引入了kallsyms特性。解码再也不须要System.map或ksymoops了。
3、内核调试配置选项
位于内核配置编辑器的内核开发菜单项中,都依赖与CONFIG_DEBUG_KERNEL
4、引起bug并打印信息
经常使用BUG()和BUG_ON()标记bug,提供断言并输出信息。
if (bad_thing) BUG();
或
BUG_ON(bad_thing);
还可用panic()引起更严重的错误,会挂起整个系统,只应该在最糟糕的状况使用。
dump_stack()只在终端上打印寄存器上下文和函数的跟踪线索。
5、系统请求键
1.可经过定义CONFIG_MAGIC_SYSRQ配置选项启用。被启用时,不管内核处于什么状态,都能经过特殊组合键与内核通讯。
启用命令:
echo 1 > /proc/sys/kernel/sysrq
2.SysRq-h:获取一份可用的选项列表
SysRq-s:将“脏”缓冲区与硬盘交换分区同步
SysRq-u:卸载全部文件系统
SysRq-b:重启设备(更多见P303)
3.系统请求键是调试和挽救垂危系统所必须的工具
6、调试器
1.gdb
gdb vmlinux /proc/kcore
vmlinux为未压缩的内核映像,经过/proc/kcore访问内核驻留的高端内存。
但不要把编译带调试信息的内核当作习惯(编译出的内核大不少)
局限性:不能修改内核数据;不能但不执行内核代码;不能加断点
2.kgdb
是一个补丁,可以让咱们在远端主机上经过串口利用gdb对内核调试
7、探测系统
1.UID做为选择条件
开发进程相关部分时,保证提供替代物的同时不破坏原有代码的可执行性;可用用户id做为选择条件实现:
如:
if (current->uid != 7777){ /*old method...*/ } else { /*new method...*/ }
2.使用条件变量(代码与进程无关或有针对全部状况都能使用的机制来控制某个特性)
3.使用统计量(用于掌握某个特定事件发生规律时)
4.重复频率限制
8、使用Git进行二分搜索
$git bisect start /*进行二分搜索*/ $git bisect bad <revision>/*提供出现问题的最先内核版本*/ $git bisect good v2.6.28/*提供可正常运行的版本*/
也可指定git仅在与错误相关的目录列表中去二分搜索提交的补丁。