linux内核设计与实现一书阅读整理 之第十八章
CHAPTER 18 调试
18.1 准备开始
需要的是准备是: - 一个bug - 一个藏匿bug的内核版本 - 相关内核代码的知识和运气
重点: 想要成功的进行调试,就取决于是否能让这些错误重现。如若不能,消灭bug就只能通过抽象出问题,再从代码中寻找蛛丝马迹来进行了。
18.2 内核中的bug
bug出现时可能的症状:
- 错误代码。(如没把正确的值存放在恰当的位置)
- 同步时发生的错误。(如共享变量锁定不当)
- 错误的管理硬件。(如给错误的控制寄存器发送错误的指令)
- ......
内核bug发作时可能的症状:
- 降低所有程序的运行性能
- 毁坏数据
- 使得系统处于死锁状态
- .......
概述:
内核中的bug表现得不像用户级程序中那么清晰——因为内核、用户以及硬件之间的交互会很微妙
- 从隐藏在源代码中的错误到展现在目击者面前的bug,往往是经历一系列连锁反应的事件才可能触发的
18.3 通过打印来调试
18.3.1 健壮性
健壮性是printk()函数最容易让人们接受的一个特质,在任何时候,任何地方都能调用它。
- 在中断上下文和进程上下文中被调用
- 在任何持有锁时被调用
- 在多处理器上同时被调用,并且不必使用锁。
printk()函数变体——early-printk()函数,区别仅在于可以更早(甚至在启动初期,终端还没有初始化之前)地工作
- 弹性极佳。
18.3.2 日志等级
- printk() 与printf()主要的的区别:前者可以指定一个日志级别,内核根据这个级别来判断是否打印消息。内核把级别比某个特定值低的所有消息显示在终端上。
- 终端默认的记录等级是KERN_WARNING
- 内核将最重要的记录等级KERNEMERG定为<0>;将无关紧要的记录等级KERNDEBUG定义为<7>
- 0 KERNEMERG 最重要 …… 7 KERNDEBUG 最不重要
- 对于调试信息, 有两种赋予记录等级的方法:
- 保持终端的默认记录等级不变,给所有调试信息KERN_CRIT或更低的等级。
- 给所有调试信息KERN_DEBUG等级,调整终端的默认记录等级。
18.3.3 记录缓冲区
- 内核消息都被记录在环形队列中,以队列方式进行读写;大小可以通过设置CONFIGLOGBUF_SHIFT进行调整
- 在单处理器上,该缓冲区大小默认为16KB,也就是说,超过的消息将覆盖旧消息
优势:
- 读写同步问题容易解决
- 记录的维护更加方便
缺点:可能会丢失信息。
18.3.4 syslogd和klogd ###
这是两个用户空间的守护进程,klogd从记录缓冲区中获取内核消息,再通过syslogd守护进程将他们保存在系统日志文件中。 - klogd
- 既可以从/proc/kmsg文件中,也可以通过syslog()系统调用读取这些消息。
- 默认是/proc方式。
- 两种情况klogd都会阻塞,知道有新的内核消息可供读出,唤醒之后默认处理是将消息传给syslogd。
- 可以通过-c标志来改变终端的记录等级
- syslogd
- 将它接收到的所有消息添加到一个文件中,默认是/var/log/messages。
18.4 oops
- • oops是内核告知用户有不幸发生的最常用方式(因为内核是整个系统的管理者,不能将自己杀死,也很难自行修复)
- • 通常,发送了oops之后,内核会处于不稳定的状态;如果oops在其他进程(除了0号idle和1号init进程)运行的时候发生,内核会杀死这些进程并尝试继续执行
过程包括:
- 向终端上输出错误消息
- 输出寄存器中保存的信息
- 输出可供跟踪的回溯线索
关于oops发生的时机:
1.发生在中断上下文:内核无法继续,会陷入混乱,导致系统死机
2.发生在idle进程或init进程(0号进程和1号进程),同上
3.发生在其他进程运行时,内核会杀死该进程并尝试着继续执行
oops发生的可能原因:
内存访问越界
非法的指令
……
oops中包含的重要信息:寄存器上下文和回溯线索回溯线索:显示了导致错误发生的函数调用链。
寄存器上下文信息也很有用,比如帮助冲进引发问题的现场
18.4.1 ksymoops
• 将回溯线索中的地址转换成有意义的符号名称:
• ksymoops saved_oops.txt
18.4.2 kallsyms
• 通过定义CONFIG_KALLSYMS配置选项启用,该选项中存放内核镜像中相应函数地址的符号名称,内核可以打印解码好的跟踪线索
18.5 内核调试配置选项
位于内核配置编辑器的内核开发菜单项中,都依赖于CONFIGDEBUGKERNEL。
slab layer debugging slab层调试选项 high-memory debugging 高端内存调试选项 I/O mapping debugging I/O映射调试选项 spin-lock debugging 自旋锁调试选项 stack-overflow debugging 栈溢出检查选项 sleep-inside-spinlock checking 自旋锁内睡眠选项 ……
- 原子操作:指那些能够不分隔执行的东西;在执行时不能中断否则就是完不成的代码。
例如;正在使用一个自旋锁或禁止抢占的代码。
使用锁时睡眠是引发死锁的元凶。
18.6 引发bug并打印信息
利用BUG()以及BUG_ON()(因为大多数体系结构都把这两个函数定义成某种非法操作,可以触发oops)
- 当做断言或者条件语句
调用panic()函数会在打印错误信息的同时挂起系统
- panic("terrible thing",terrible_thing)
调用dump_stack(),只在终端上打印寄存器上下文及函数的跟踪线索
18.7 神奇的系统请求键
- 这个功能可以通过定义CONFIGMAGICSYSRQ配置选项来启用。SysRq(系统请求)键在大多数键盘上都是标准键。
- 该功能被启用时,无论内核出于什么状态,都可以通过特殊的组合键和内核进行通信。
除了配置选项以外,还要通过一个sysctl用来标记该特性的开或关,启动命令如下:
echo 1 > /proc/sys/kernel/sysrq
Sysrq的几个命令:
SysRq-s:将“脏”缓冲区跟硬盘交换分区同步
SysRq-u:卸载所有的文件系统
SysRq-b:重启设备
18.8 内和调试的传奇
18.8.1 gdb
- 启动内核调试器
gdb vmlinux(未经压缩的内核映像)-
可以使用gdb的所有命令来获取信息。例如:
打印一个变量的值:
p global_variable 反汇编一个函数:
disassemble function -g参数还可以提供更多的信息。
局限性:
没有办法修改内核数据
不能单步执行内核代码
18.8.2 kgdb
- 是一个补丁 ,可以让我们在远程主机上通过串口利用gdb的所有功能对内核进行调试。
- 需要两台计算机:仪态运行带有kgdb补丁的内核,第二胎通过串行线使用gdb对第一台进行调试。
- 通过kgdb,gdb的所有功能都能使用:
- 读取和修改变量值
- 设置断点
- 设置关注变量
- 单步执行
18.9 探测系统
18.9.1 使用uid作为选择条件
- if(current->uid != 7777)
- {
- /老算法/
- else
- {
- /新算法/
- }
18.9.2 使用条件变量
- 如果代码与进程无关,或者希望有一个针对所有情况都能使用的机制来控制某个特性,可以使用条件变量。
这种方式比使用UID更简单,只需要创建一个全局变量作为一个条件选择开关:
如果该变量为0,就使用某一个分支上的代码;
否则,选择另外一个分支。
- 操控方式:某种接口,或者调试器。
18.9.3 使用统计量
- 这种方法常用于使用者需要掌握某个特定事件的发生规律的时候。
- 方法是创建统计量,并提供某种机制访问其统计结果。
定义全局变量
在/proc目录中创建一个文件
or新建一个系统调用
or通过调试器直接访问(最直接)
18.9.4.重复频率限制
(1)重复频率限制 (2)发生次数限制
18.10 用二分查找法找出引发罪恶的变更
18.11 使用Git进行二分搜索
总结
本章主要讲内核的调试,调试过程就是一种寻求实现与目标偏差的行为,通过学习各种调试技巧,,发现困难重重,但相信有一天努力会有成果的。
参考资料
《linux内核设计与实现》原书第三版
linux内核设计与实现一书阅读整理 之第十八章的更多相关文章
- linux内核设计与实现一书阅读整理 之第三章
chapter 3 进程管理 3.1 进程 进程就是处于执行期的程序. 进程就是正在执行的程序代码的实时结果. 内核调度的对象是线程而并非进程. 在现代操作系统中,进程提供两种虚拟机制: 虚拟处理器 ...
- linux内核设计与实现一书阅读整理 之第五章
CHAPTER 5 系统调用 5.1 与内核通信 系统调用在用户空间进程和硬件设备之间添加了一个中间层,该层主要作用有三个: 为用户空间提供了一种硬件的抽象接口 系统调用保证了系统的稳定和安全 每个进 ...
- linux内核设计与实现一书阅读整理 之第一二章整合
第一章:Linux内核简介 一.Unix和linux Unix是一个强大.健壮和稳定的操作系统. 1.Unix内核特点 十分简洁:仅提供几百个系统调用并且有明确的目的: 在Unix中,大部分东西都被( ...
- 《Linux内核设计与实现》CHAPTER17阅读梳理
<Linux内核设计与实现>CHAPTER17阅读梳理 [学习时间:3.5hours] [学习内容:设备类型,模块,内核对象,sysfs] 个人思考部分见[]标出的部分 一.课堂讲解整理& ...
- 《Linux内核设计与实现》CHAPTER4阅读梳理
<Linux内核设计与实现>CHAPTER4阅读梳理 [学习时间:3hours] [学习内容:多任务:进程调度策略:Linux中进程调度的关键问题:抢占] 个人思考部分见[]标出的部分 一 ...
- 《Linux内核设计与实现》CHAPTER18阅读梳理
<Linux内核设计与实现>CHAPTER18阅读梳理 [学习时间:2hours] [学习内容:bug的来源分析:bug调试途径] 一.bug来源 1.内核中的bug 内核中的bug表现得 ...
- 《Linux内核设计与实现》CHAPTER5阅读梳理
<Linux内核设计与实现>CHAPTER5阅读梳理 [学习时间:2.5hours] [学习内容:系统调用的概念.功能及实现:系统调用的创建和使用方法] CHAPTER5 系统调用 1.系 ...
- 《Linux内核设计与实现》CHAPTER13阅读梳理
<Linux内核设计与实现>第13章阅读总结 [edited by 5216lwr] 一.虚拟文件系统概述 1.虚拟文件系统 (也称作虚拟文件交换或VF)作为内核子系统,为用户空间程序提供 ...
- 读《Linux内核设计与实现》我想到了这些书
从题目中可以看到,这篇文章是以我读<Linux内核设计与实现>而想到的其他我读过的书,所以,这篇文章的主要支撑点是<Linux内核>. 开始读这本书已经 ...
随机推荐
- OpenSSH技术详解
一.什么是Openssh OpenSSH 是 SSH (Secure SHell) 协议的免费开源实现.SSH协议族可以用来进行远程控制, 或在计算机之间传送文件.而实现此功能的传统方式,如teln ...
- Ubuntu下载磁力链接,torrent,迅雷链接
用ubuntu下载电影:磁力链接,torrent,迅雷链接 需要软件:Ktorent, Amule 安装软件: sudo apt-get install ktorrent sudo apt-get i ...
- Spring学习(4)IOC容器配置bean:定义与实例化
一. IOC容器配置 1. 一些概念 (1)IOC容器: 定义:具有管理对象和管理对象之间的依赖关系的容器. 作用:应用程序无需自己创建对象,对象由IOC容器创建并组装.BeanFactory是IO ...
- 温习DL之一:梯度的概念
1.梯度的概念 梯度是一个矢量,表示某一函数在该点处的方向导数沿着该方向取得最大值,即函数在该点处沿着该方向变化最快. 在微积分里面,对多元函数的参数求∂偏导数,把求得的各个参数的偏导数以向量的形式写 ...
- 互评beta版本 - 探路者【贪吃蛇】
基于NABCD评论,及改进建议 1)N(Need 需求) 开发本软件一方面是为了让80,90后用户重温童年的美好记忆,另一方面也是为了增加对英语学习兴趣较弱.意志力薄弱的中小学生学习英语的兴趣和动力, ...
- 必应词典手机版(IOS版)与有道词典(IOS版)之软件分析【功能篇】【用户体验篇】
1.序言: 随着手机功能的不断更新和推广,手机应用市场的竞争变得愈发激烈.这次我们选择必应词典和有道词典的苹果客户端作对比,进一步分析这两款词典的客户端在功能和用户体验方面的利弊.这次测评的主要评测人 ...
- 20162328蔡文琛 大二week01
教材学习内容总结 算法+程序机构=程序 渐进复杂度称为算法的阶. 算法分析是计算机科学的基础课题. 增长函数显示了与问题大小相关的时间或空间的利用率. 算法的阶由算法增长函数的主项决定. 算法的阶给出 ...
- js 代码几种方式
var nameSpace={ //public } (function(){ //private })(); var module=(function(){ //private return { / ...
- 关闭Centos5.5的写磁盘I/O功能
一个Linux文件默认有3个时间. atime:对此文件的访问时间. ctime:此文件inode发生变化的时间. mtime:此文件的修改时间. 如果有多个小文件(比如Web服务器的页面上有多个小图 ...
- 【Leetcode】86. Partition List
Question: Given a linked list and a value x, partition it such that all nodes less than x come befor ...