《Linux内核设计与实现》 第十八章学习笔记

调  试

1、准备开始

  • 一个bug
  • 一个藏匿bug的内核版本
  • 相关内核代码的知识和运气
  • 知道这个bug最先出如今哪一个内核版本中。

一、想要成功进行调试:linux

  • 让这些错误重现
  • 抽象出问题
  • 从代码中搜索

 

2、内核中的buggit

  从隐藏在源代码中的错误到展示在目睹者面前的bug,每每是经历一系列连锁反应的事件才可能触发的。内核确实有一些独特的问题须要考虑,像定时限制和竞争条件等,它们都是容许多个线程在内核中同时运行产生的结果。ide

 

3、经过打印来调试
  内核提供的打印函数printk()和C 库提供的printf()函数功能几乎相同。函数

一、健壮性oop

  • 健壮性是printk() 函数最容易让人们接受的一个特质..能够在中断上下文和进程上下中被调用,能够在任何持有锁时被调用,能够在多处理器上同时被调用,并且调用者连锁都没必要使用。
  • 解决的办单是提供一个printk() 的变体函数一一early_printk(),这个函数在启动过程的初期就具备在终端上打印的能力,它的功能与prink()彻底相同,区别仅仅在于名字和可以更早地工做,不过,因为该函数在一些内核支持的硬件体系结构上没法实现,因此这种办法峡少可移植性。

二、日志等级spa

  • printk()和printf()在使用上最主要的区别就是前者能够指定一个日志级别, 内核根据这个级别来判断是否在终端上打印消息。内核把级别比某个特定值低的全部消息显示在终端上。

三、记录缓冲区线程

  • 内核消息都被保存在一个LOG_BUF_LEN 大小的环形队列中。该缓冲区大小能够在编译时经过设置CONFIG_LOG_BUF_SHIFf 进行调整。在单处理器的系统上其默认值是16。若是消息队列已经达到最大值,那么若是再有printk()调用,新消息将覆盖队列中的老消息。这个记录缓冲区之因此称为环形,是由于它的读写都是按照环形队列方式进行操做的。
  • 环形缓冲区的惟一缺点一一可能会丢失消息

四、syslogd 和klogd调试

  • syslogd 守护进程把它接收到的全部消息添加进一个文件中,该文件默认是/var/log/messages.也能够经过/etc/syslog.conf 配置文件从新指定。在启动klogd 的时候,能够经过指定-c 标志来改变终端的记录级。

 

4、oops日志

  • oops 是内核告知用户有不幸发生的最经常使用的方式。oops 的产生有不少可能缘由,其中包括内存访问越界或者非法的指令等。

一、ksymoops
  若是使用的是模块, 还须要一些模块信息。ksymoops 一般会自行解析这些信息,调用后获得解码板的oops队列

ksymoops saved_ oops. txt

二、kallsyms

  • 经过定义CONFIG_KALLS YMS 配置选项启用。该选项存放着内核镜像中相应函数地址的符号名称,因此内核能够打印解码好的跟踪线索

 

5、内核调试配置选项
  内核开发( Kernel hacking)菜单项中,它们都依赖于CONFIG_DEBUG_KERNEL。。其中最有用的一个是sleep-inside-spinlock-checking (自旋锁内睡眠选项)。使用锁时睡眠是引起死锁的元凶。因此,包括正使用锁的时候调用,正使用锁的时候以阻塞方式请求分配内存和在引用单CPU 数据时睡眼在内,各类潜在的bug 都可以被探测到。

 

6、引起bug 并打印信息
  最经常使用的两个是BUG() 和BUG_ON()。当披调用的时候,它们会引起oops ,致使栓的回溯和错误信息的打印能够把这些调用当作断言使用,想要断言某种状况不应发生:

if (bad_thing)
BUG();

  或者使用更好的形式:

BUG_ON (bad_thing);

  多数内核开发者相信BUG_ON()比BUG()更清晰、更可读, 并且BUG_ON()会将其声明做为一个语句放入unlikely()中。

  能够用panic()引起更严重的错误。调用panic()不但会打印错误消息,并且还会挂起整个系统。显然,只应该在最糟糕的状况下使用它

if (terrible_thing)
panic ( ” terrible thing is %ld\n ”, terrible_thing);

 

7、内核调试器的传奇
一、gdb

  • 可使用标准的GNU 调试器对正在运行的内核进行查看。针对内核启动调试器的方站与针对进程的方栋大体相同:

gdb vml inux /proc/kcore

  【其中vmlinux 文件是未经压缩的内核映像,不是压缩过的zlmage 或bzlmage,它存放在源代码树的根目录上。】

  • /proc/kcore 做为一个参数选项,是做为core 文件来用的,经过它可以访问到内核驻留的高端内存。只有超级用户才能读取此文件的数据。可使用gdb 的全部命令来获取信息。若是编译内核的时候使用了-g 参数(在内核的Makefile 文件的CFLAGS 变量中加入-g),gdb 还能够提供更多的信息。

二、kgdb

  • kgdb 是一个补丁,它可让咱们在远端主机上经过串口利用gdb 的全部功能对内核进行调试。这须要两台计算机:第一台运行带有kgdb补丁的内核,第二台经过行线(不经过modem,直接链接两台机器的电缆)使用gdb对第一台进行调试。

8、使用Git 进行二分搜索

一开始,你得告诉Git 你要进行二分搜索:

$ git bisect start

而后再为Git 提供一个出现问题的最先内核版本:

$ git bisect bad <revision>

若是当前的内核版本就是引起bug的罪魁祸首,那么就没必要提供内核版本:

$ git bisect bad

而后,还得为Git 提供一个最新的可正常运行的内核版本:

$ git bisect good v2.6.28

若是这个版本一切正常,能够运行下面的命令:

$ git bisect good

若是这个版本运行有异常一一也就是说,若是证实这个给定的内核版本有bug,能够运行:

$ git bisect bad

若是你已经知道引起bug 的源(好比, x86 机型的启动代码),你能够指定git仅仅在与错模相关的目录列表中去二分搜索提交的补丁。

$ git bisect start - arch/x86
相关文章
相关标签/搜索