《Linux内核设计与实现》学习总结 Chap18
一、准备开始
1、一个确定的bug,但大部分bug通常都不是行为可靠且定义明确的。
2、一个藏匿bug的内核版本。
3、相关内核代码的知识和运气。
二、内核中的bug
1、bug的表象:
明白无误的错误代码,同步时发生的错误,错误地管理硬件,降低所有程序的运行性能,毁坏数据,使系统处于死锁状态。
2、引用空指针会导致产生一个oops,垃圾数据可能会导致系统崩溃。
三、通过打印来调试
1、printk()是内核的格式化打印函数,与C库提供的printf()函数功能基本相同。
2、printk()在任何时候、任何地方都能调用它。除了系统启动过程中,终端还没有初始化之前,在某些地方不能使用它。
early_printk()在启动过程的初期就具备在终端上打印的能力,但缺少可移植性。
3、printk()和printf()的最主要区别:
printk()可以指定一个日志级别,内核根据这个级别来判断是否在终端上打印消息。
内核同这个指定的记录等级和当前终端的记录等级console_loglevel来决定是不是向终端上打印。
如果你没有特别指定一个记录等级,函数会选用默认的DEFAULT_MESSAGE_LOGLEVEL。
内核将最重要的记录等级KERN_EMERG定为“<0>”,将无关紧要的记录等级KERN_DEBUG定为“<7>”。
例:
当编译预处理完成后,代码被编译成如下格式:
4、给调用的printk()赋记录等级的方法
(1)保持终端的默认记录等级不变,给所有调试信息KERN_CRIT或更低的等级。
(2)给所有调试信息KERN_DEBUG等级,而调整终端的默认记录等级。
5、内核消息都被保存在一个LOG_BUF_LEN大小的环形队列中。
该缓冲区大小可以在编译时通过设置CONFIG_LOG_BUF_SHIFT进行调整,在单处理器的系统上其默认值是16KB。
**使用环形队列的优劣**
6、用户空间的守护进程klogd从记录缓冲区中获取内核消息,再通过syslogd守护进程将它们保存在系统日志文件中。
四、OOPS
1、oops是内核告知用户有不幸发生的最常用的方式。
这个过程包括向终端上输出错误消息,输出寄存器中保存的信息并输出可供跟踪的回溯线索。
2、如果oops在中断上下文时发生,内核根本无法继续,它会陷入混乱,导致系统死机。
如果oops在idle进程(pid为0)或者init进程(pid为1)时发生,结果同样是系统陷入混乱。
3、oops中包含的重要信息:寄存器上下文和回溯线索。
回溯线索中的地址需要转化成有意义的符号名称:调用ksymoops命令,并且提供编译内核时产生的System.map;如果使用的是模块,还需要一些模块信息。
ksymoops saved_oops.txt
4、kallsyms特性,它可以通过定义CONFIG_KALLSYMS配置选项启用。
五、内核调试配置选项
原子操作:指那些能够不分隔执行的东西,在执行时不能中断否则就是完不成的代码。
六、引发bug并打印信息
1、一些内核调用可以用来方便标记bug,提供断言并输出信息。最常用的两个是BUG()和BUG_ON()。
当被调用的时候,会引发oops。可以把这些调用当做断言使用,想要断言某种情况不该发生:
BUG_ON()比BUG()更清晰、更可读,而且BUG_ON()会将其声明作为一个语句放入unlikely()中。
BUILD_BUG_ON()与BUG_ON()作用相同,仅在编译时调用。
可以用panic()引发更严重的错误:打印错误信息,挂起整个系统,但应该在最糟糕的情况下使用它。
七、神奇的系统请求键
1、神奇的系统请求键(Magic SysRq key),该功能可以通过定义CONFIG_MAGIC_SYSRQ配置选项来启用。当该功能被启用的时候,无论内核处于什么状态,都可以通过特殊的组合键跟内核进行通信。
2、除了配置选项外,还要通过一个sysctl用来标记该特性的开或关:
echo 1 > /proc/sys/kernel/sysrq
八、内核调试器的传奇
1、gdb
可以使用标准的GNU调试器对正在运行的内核进行查看:gdb vmlinux /proc/kcore
其中vmlinux文件时未经压缩的内核映像,它存放在源代码树的根目录上。
/proc/kcore作为一个参数选项,是作为core文件来用的,通过它能够访问到内核驻留的高端内存。
如果编译内核的时候使用-g参数,gdb还可以提供更多的信息。
2、kgdb
是一个补丁,它可以让我们在远端主机上通过串口利用gdb的所有功能对内核进行调试。
九、探测系统
1、用UID作为选择条件
2、使用条件变量
如果代码与进程无关,或者希望有一个针对所有情况都能使用的机制来控制某个特性,可以使用条件变量。
3、使用统计量
需要掌握某个特定事件的发生规律或需要比较多个事件并从中得出规律。
4、重复频率限制:某种事件发生的非常频繁,而又需要观察它的整体进展情况。
发生次数限制:确认在特定情况下某段代码确实被执行了。
不管哪种情况,用到的变量都应该是静态的static,并且应该限制在函数的局部范围以内,这样才能保证变量的值在经历多次函数调用后仍然能够保留下来。
十、用二分查找法找出引发罪恶的变更
一开始,需要一个可靠的可复制的错误,最好是系统一启动就能查证的bug。
接下来,需要一个能确保没问题的内核。
接下来,还需要一个肯定有问题的内核。
十一、使用Git进行二分搜索
一开始,告诉Git进行二分搜索:git bisect start。
如果这个版本一切正常,可以运行下面的命令:git bisect good。
如果证明这个给定的内核版本有bug,可以运行:git bisect bad。
如果你已经知道引发bug的源(比如,x86机型的启动代码),你可以指定git仅仅在与错误相关的目录列表中去二分搜索提交的补丁:git bisect start - arch/x86
总结:
这一章主要介绍了系统调用的知识,与MOOC中的视频教学相辅相成,在许多细节上作了补充,尤其在如何增加一个新的系统调用上介绍的很详细。另外,编写规范的、最优化的、安全的系统调用所遵循的概念和内核接口规范也值得我们注意。
系统调用是利用了软中断的机制,由API、POSIX和C库协调工作。虽然系统调用使用起来非常方便,但仍要尽量避免每出现一种新的抽象就简单的加入一个新的系统调用,而新系统调用增添频率很低也反映出Linux是一个相对较为稳定并且功能已经较为完善的操作系统。
《Linux内核设计与实现》学习总结 Chap18的更多相关文章
- Linux内核设计第一周学习总结 计算机如何工作
北京电子科技学院 20135310陈巧然 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-100002 ...
- Linux内核设计第二周学习总结 完成一个简单的时间片轮转多道程序内核代码
陈巧然 原创作品 转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.使用实验楼的虚拟机 ...
- Linux内核设计第四周学习总结 使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用
陈巧然原创作品 转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 实验目的: 使用库函数A ...
- linux内核设计与实现学习笔记-模块
模块 1.概念: 如果让LINUX Kernel单独运行在一个保护区域,那么LINUX Kernel就成为了“单内核”. LINUX Kernel是组件模式的,所谓组件模式是指:LINUX K ...
- 《Linux内核设计与实现》课本第五章学习笔记——20135203齐岳
<Linux内核设计与实现>课本第五章学习笔记 By20135203齐岳 与内核通信 用户空间进程和硬件设备之间通过系统调用来交互,其主要作用有三个. 为用户空间提供了硬件的抽象接口. 保 ...
- 《Linux内核设计与实现》课本第一章&第二章学习笔记
<Linux内核设计与实现>课本学习笔记 By20135203齐岳 一.Linux内核简介 Unix内核的特点 Unix很简洁,所提供的系统调用都有很明确的设计目的. Unix中一切皆文件 ...
- 《Linux内核设计与实现》 第一二章学习笔记
<Linux内核设计与实现> 第一二章学习笔记 第一章 Linux内核简介 1.1 Unix的历史 Unix的特点 Unix很简洁,所提供的系统调用都有很明确的设计目的. Unix中一切皆 ...
- 《Linux内核设计与实现》第四章学习笔记
<Linux内核设计与实现>第四章学习笔记 ——进程调度 姓名:王玮怡 学号:20135116 一.多任务 1.多任务操作系统的含义 多任务操作系统就是能同时并发地交 ...
- 《Linux内核设计与实现》第五章学习笔记
<Linux内核设计与实现>第五章学习笔记 姓名:王玮怡 学号:20135116 一.与内核通信 在Linux中,系统调用是用户空间访问内核的唯一手段:除异常和陷入外,它们是内核 ...
- 《Linux内核设计与实现》第四章学习笔记——进程调度
<Linux内核设计与实现>第四章学习笔记——进程调 ...
随机推荐
- Datawhale MySQL 训练营 Task3 表操作
目录 学习内容 1.MySQL 表数据类型 2. 用SQL语句创建表 3. 用SQL语句向表中添加数据 4. 用SQL语句删除表 5. 用SQL语句修改表 作业 参考链接 学习内容 1.MySQL 表 ...
- Django缓存配置和使用
- 缓存 - 配置 CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'LOCAT ...
- linux 其他知识目录
博客目录总纲首页 为博客园添加目录的方法总结 linux 命令自动补全包 手动配置网卡 nginx日志统计 Linux 深入理解inode/block/superblock /proc/sys目录下各 ...
- spring boot的maven项目报404错误
$.ajax({ async: false, type: "POST", url:'searchFileSource', contentType : "applicati ...
- 20172329 2018-2019《Java程序设计与数据结构》课程总结
作者:lalalouye(20172329王文彬) 2018-2019年大二Java程序设计与数据结构课程总目录:第一周 第二周 第三周 第四周 第五周 第六周 第七周 第八周 第九周 实验一 实验二 ...
- Percona XtraDB Cluster 5.7
附加:相关在线文档https://www.percona.com/software/documentation 安装要求: 1.root权限2.保证开放3306.4444.4567.4568端口3.关 ...
- 文件名命工具类(将指定目录下的文件的type类型的文件,进行重命名,命名后的文件将去掉type)
import java.io.File; /** * <b>function:</b> 文件命名工具类 * @author hoojo * @createDate 2012-5 ...
- eg_5
问题描述:输入两个字符串,从第一字符串中删除第二个字符串中所有的字符. 例如,输入”They are students.”和”aeiou”,则删除之后的第一个字符串变成”Thy r stdnts.” ...
- 对于Redis的了解
Redis :高性能的key-value数据库,支持存储的value类型包括字符串.链表.集合.有序集合.哈希类型. redis使用两种文件格式:全量数据和增量请求. 全量数据格式是将内存中的数据写入 ...
- es6 ...展开运算符
展开运算符,目前应用在数组上,对象展开运算符,将在es7 提案 1.两个对象连接返回新的对象 let a = {aa:'aa'} let b = {bb:'bb'} let c = {...a,. ...