第十八章读书笔记——调试

第十八章 调试

准备开始

准备工作需要的是:

  • 一个bug
  • 一个藏匿bug的内核版本
  • 相关内核代码的知识和运气

内核中的bug

内核bug的原因可能有:

  • 错误代码
  • 同步时发生的错误,例如共享变量锁定不当
  • 错误的管理硬件

内核bug发作的症状可能有:

  • 降低所有程序的运行性能
  • 毁坏数据
  • 使得系统处于死锁状态

通过打印来调试

这里说的打印是指的内核的格式化打印函数printk(),因为它有自己的一些特殊的功能:

健壮性:健壮性的意思是,在任何时候,任何地方都能调用它

  • 在中断上下文和进程上下文中被调用
  • 在任何持有锁时被调用
  • 在多处理器上同时被调用,并且不必使用锁。

弹性极佳

记录缓冲区

内核消息是保存在一个环形队列中,这个环形队列就是它的记录缓冲区
内核在同一时间只能保存16kb的内核消息,再多的话新消息就会覆盖老消息,读写都是按照环形队列方式操作的
优点:

  • 健壮性:在中断上下文中也可以方便的使用
  • 简单性:使记录维护起来更容易
    缺点:可能会丢失消息

syslogd和klogd:这是两个用户空间的守护进程,klogd从记录缓冲区中获取内核消息,再通过syslogd守护进程将他们保存在系统日志文件中。

klogd

可以从/proc/kmsg文件中,也可以通过syslog()系统调用读取这些消息,默认是/proc方式
两种情况klogd都会阻塞,知道有新的内核消息可供读出,唤醒之后默认处理是将消息传给syslogd
可以通过-c标志来改变终端的记录等级

syslogd

将它接收到的所有消息添加到一个文件中,默认是/var/log/messages

oops

oops是内核告知用户有不幸发生的最常用的方式
内核很难自我修复,也不能将自己杀死,只能发布oops

  • 向终端上输出错误消息
  • 输出寄存器中保存的信息
  • 输出可供跟踪的回溯线索

通常发送完oops之后,内核会处于一种不稳定状态

oops发生的时机:

  • 发生在中断上下文:内核无法继续,会陷入混乱,导致系统死机
  • 发生在idle进程或init进程(0号进程和1号进程),同上
  • 发生在其他进程运行时,内核会杀死该进程并尝试着继续执行
    oops发生的可能原因:
  • 内存访问越界
  • 非法的指令
    oops中包含的重要信息:寄存器上下文和回溯线索

神奇的系统请求键

这个功能可以通过定义CONFIG_MAGIC_SYSRQ配置选项来启用
SysRq(系统请求)键在大多数键盘上都是标准键
该功能被启用时,无论内核出于什么状态,都可以通过特殊的组合键和内核进行通信

内核调试器的传奇

gdb:
可以使用标准的GNU调试器对正在运行的内核进行查看。
针对内核启动调试器的方法与针对进程的方法大致相同:

局限性:

  • 没有办法修改内核数据
  • 不能单步执行内核代码
    kgdb:
    是一个补丁 ,可以让我们在远程主机上通过串口利用gdb的所有功能对内核进行调试
    需要两台计算机:仪态运行带有kgdb补丁的内核,第二胎通过串行线使用gdb对第一台进行调试
    通过kgdb,gdb的所有功能都能使用:
  • 读取和修改变量值
  • 设置断点
  • 设置关注变量
  • 单步执行
    探测系统

使用uid作为选择条件:一般情况下,加入特性时,只要保留原有的算法而把新算法加入到其他位置上,基本就能保证安全

使用条件变量:
如果代码与进程无关,或者希望有一个针对所有情况都能使用的机制来控制某个特性,可以使用条件变量
使用统计量:
这种方法常用于使用者需要掌握某个特定事件的发生规律的时候
方法是创建统计量,并提供某种机制访问其统计结果

重复频率限制
当系统的调试信息过多的时候,有两种方式可以防止这类问题发生:

重复频率限制
发生次数限制

  • 重复频率限制
  • 发生次数限制

总结:

这一章中 ,学到了有关内核bug和调试的很多知识。

posted @ 2016-03-30 23:46  20135330张若嘉  阅读(257)  评论(0编辑  收藏  举报