《Linux内核设计与实现》课本第十八章自学笔记——20135203齐岳
《Linux内核设计与实现》课本第十八章自学笔记
By20135203齐岳
通过打印来调试
printk()是内核提供的格式化打印函数,除了和C库提供的printf()函数功能相同外还有一些资深的特殊功能
健壮性
在任何时候内核的任何地方都能调用printk()函数,只有在终端还未初始化的时候不能调用。
- 在中断上下文和进程上下文中被调用
- 在任何持有锁时被调用
- 在多处理器上同时被调用,并且不必使用锁。
解决办法是提供一个变体函数early _ printk(),但这种办法在某些硬件体系结构上无法实现,缺少可移植性。
日志等级
printk()可以指定一个日志级别,内核把级别比某个特定值低的所有消息显示在终端上。如果没有指定一个等级记录,函数会选用默认的DEFAULT _ MESSAGE _ LOGLEVEL,现在的默认等级为KERN _ WARNING。但默认值将来存在变化性,所以还是应该指定一个记录等级。
内核将最重要的记录等级KERN _ EMERG定为<0>,无关紧要的记录等级KERN _ DEBUG定为<7>
对于调试信息,有两种赋予记录等级的方法:
- 保持终端的默认记录等级不变,给所有调试信息KERN _ CRIT或更低的等级。
- 给所有调试信息KERN _ DEBUG等级,调整终端的默认记录等级。
记录缓冲区
内核消息都被保存在一个环形队列中,该缓冲区的大小可以在编译时通过设置CONFIG _ LOG _ BUF _ SHIFT进行调整,在单处理器的系统上默认值是16kb,也就是说内核在同一时间只能保存16kb的内核消息,再多的话新消息就会覆盖老消息。读写都是按照环形队列方式操作的。
- 优点:健壮性,在中断上下文中也可以方便的使用;简单性,使记录维护起来更容易。
- 缺点:可能会丢失消息。
syslogd和klogd
在Linux系统中,用户空间的守护进程klogd从记录缓冲区中获取内核消息,再通过syslogd守护进程将他们保存在系统日志文件中。
klogd:
既可以从/proc/kmsg文件中,也可以通过syslog()系统调用读取获得的内核信息,默认情况下以/proc方式实现。两种情况klogd都会阻塞,知道有新的内核消息可供读出,唤醒之后默认处理是将消息传给syslogd。可以通过-c标志来改变终端的记录等级。
syslogd:将它接收到的所有消息添加到一个文件中,默认是/var/log/messages。
oops
oops是内核告知用户有不幸发生的最常用的方式。
内核很难自我修复,也不能将自己杀死,只能发布oops,过程为:向终端上输出错误消息、输出寄存器中保存的信息、输出可供跟踪的回溯线索。通常发布oops之后,内核会处于一种不稳定状态。
oops发生的时机:
- 发生在中断上下文:内核无法继续,会陷入混乱,导致系统死机
- 发生在idle进程或init进程(0号进程和1号进程),同上
- 发生在其他进程运行时,内核会杀死该进程并尝试着继续执行
oops中包含的重要信息:
寄存器上下文和回溯线索
- 回溯线索:显示了导致错误发生的函数调用链,以便我们观察发生了什么。
- 寄存器上下文信息:帮助冲进引发问题的现场。
ksymoops
回溯线索中的地址需要转化成有意义的符号名称才可以方便使用,需要调用ksymoops命令,还必须提供编译内核时产生的System.map。如果用的是模块,还需要一些模块信息。调用方法:
kysmoop saved_oops.txt
kallsyms
现在的版本中不需要使用sysmoops这个工具,因为可能会发生很多问题,新版本中引入了kallsyms疼,可以通过定义CONFIG _ KALLSYMS配置选项启用。
内核调试配置选项
位于内核配置编辑器的内核开发菜单项中,都依赖于CONFIG _ DEBUG _ KERNEL。
- slab layer debugging slab层调试选项
- high-memory debugging 高端内存调试选项
- I/O mapping debugging I/O映射调试选项
- spin-lock debugging 自旋锁调试选项
- stack-overflow debugging 栈溢出检查选项
- sleep-inside-spinlock checking 自旋锁内睡眠选项
引发bug并打印信息
一些内调用可以用来方便标记bug,提供断言并输出信息。
BUG()和BUG_ON()
被调用时会引发oops,导致栈的回溯和错误信息的打印。
可以把这些调用当做断言使用,想要断言某种情况不该发生:if (bad_thing)BUG();或更好的形式:BUG_ON(bad_thing);
BUILD _ BUG_ ON()
与BUG_ON()作用相同,仅在编译时调用。
panic()
可以引发更严重的错误,不但会打印错误信息,还会挂起整个系统。
dump_stack()
只在终端上打印寄存器上下文和函数的跟踪线索。
神奇的系统请求键
这个功能可以通过定义CONFIG _ MAGIC _ SYSRQ配置选项来启用。SysRq(系统请求)键在大多数键盘上都是标准键。
该功能被启用时,无论内核出于什么状态,都可以通过特殊的组合键和内核进行通信。
除了配置选项以外,还要通过一个sysctl用来标记该特性的开或关,启动命令如下:
echo 1 > /proc/sys/kernel/sysrq
Sysrq的命令:
内核调试器的传奇
gdb(与本周实验内容结合)
可以使用标准的GNU调试器对正在运行的内核进行查看。针对内核启动调试器的方法与针对进程的方法大致相同:
gdb vmlinux /proc/kcore
- vmlinx:未经压缩的内核映像,区别于zImage或bImage,它存放于源代码树的根目录上。
- /proc/kcore作为一个参数选项,是作为core文件来用的,通过它能够访问到内核驻留的高端内存。只有超级用户才能读取此文件的数据。
可以使用gdb的所有命令来获取信息。
p global_variable//打印一个变量的值disassemble function//反汇编一个函数
-g参数还可以提供更多的信息。
局限性:
- 没有办法修改内核数据
不能单步执行内核代码
kgdb
是一个补丁 ,可以让我们在远程主机上通过串口利用gdb的所有功能对内核进行调试。
需要两台计算机:仪态运行带有kgdb补丁的内核,第二胎通过串行线使用gdb对第一台进行调试。
通过kgdb,gdb的所有功能都能使用:
- 读取和修改变量值
- 设置断点
- 设置关注变量
- 单步执行
探测系统
使用uid作为选择条件
一般情况下,加入特性时,只要保留原有的算法而把新算法加入到其他位置上,基本就能保证安全。
可以把用户id(UID)作为选择条件来实现这种功能,通过某种选择条件,安排到底执行哪种算法。
if (current-> uid !=7777) {/* 老算法…… */
} else {/* 新算法…… */
}
即,除了uid=7777的用户以外,其他所有的用户都是用的老算法,所以这个7777用户可以专门用来测试新算法。
使用条件变量
如果代码与进程无关,或者希望有一个针对所有情况都能使用的机制来控制某个特性,可以使用条件变量。
这种方式比使用UID更简单,只需要创建一个全局变量作为一个条件选择开关:
如果该变量为0,就使用某一个分支上的代码;
否则,选择另外一个分支。
操控方式:某种接口,或者调试器。
使用统计量
这种方法常用于使用者需要掌握某个特定事件的发生规律的时候。
方法是创建统计量,并提供某种机制访问其统计结果。
定义全局变量
在/proc目录中创建一个文件
or新建一个系统调用
or通过调试器直接访问(最直接)
注:不是SMP安全的,更好的方式是用原子操作。
重复频率限制
当系统的调试信息过多的时候,有两种方式可以防止这类问题发生:
重复频率限制:
就是限制调试信息,最多几秒打印一次,可以根据自己的需要调节频率。
例如printk()函数的调节频率,可以用printk_ratelimit()函数限制。
发生次数限制
这种方法是要调试信息至多输出几次,超过次数限制后就不能再输出。
这种方法可以用来确认在特定情况下某段代码的确被执行了。
注:用到的变量需要是静态的、局部的。不是SMP安全,不是抢占安全,更好的方式是用原子操作。
SMP(Symmetric Multi-Processing),对称多处理结构的简称,是指在一个计算机上汇集了一组处理器(多CPU),各CPU之间共享内存子系统以及总线结构。在这种技术的支持下,一个服务器系统可以同时运行多个处理器,并共享内存和其他的主机资源。
二分搜索
很多时候,内核的更新会带来bug,那么是哪一个内核版本带来的bug?可以使用二分法搜索。
我们可以利用GIT来实现这一步骤。
git bisect start # 告知git要进行二分搜索
git bisect bad <revision> # 已知出现问题的最早内核版本
git bisect bad # 当前版本就是引发bug的最初版本的情况下使用这条命令
git bisect good <revision> # 最新的可正常运行的内核版本
这之后,git就会利用二分搜索法在Linux源码树中,自动检测正常的版本内核和有bug的内核版本之间那个版本有隐患,然后再编译、运行以及测试正被检测的版本。
如果这个版本正常:
git bisect good
如果这个版本运行有异常:
git bisect bad
对于每一个命令,GIT将在吗诶一个版本的基础上反复二分搜索源码树,并且返回所查的下一个内核版本,一直到不能再进行二分搜索位置,最终git会打印出有问题的版本号。
转载于:https://www.cnblogs.com/July0207/p/5330924.html
《Linux内核设计与实现》课本第十八章自学笔记——20135203齐岳相关推荐
- 《深入理解计算机系统》课本第七章自学笔记——20135203齐岳
<深入理解计算机系统>课本自学笔记 第七章 链接 By20135203齐岳 链接:将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载(或拷贝)到存储器并执行. 现代 ...
- 《Linux内核设计与实现》 第五周 读书笔记(第十八章)
第18章 调试 20135307张嘉琪 18.1 准备开始 18.2 内核中的bug 内核中的bug多种多样,它们的产生可以有无数的原因,同时它们的表象也变化多端,从明白无误的错误代码(比如,没有把正 ...
- 《Linux内核设计与实现》 第八周读书笔记 第四章 进程调度
20135307 张嘉琪 第八周读书笔记 第四章 进程调度 调度程序负责决定将哪个进程投入运行,何时运行以及运行多长时间,进程调度程序可看做在可运行态进程之间分配有限的处理器时间资源的内核子系统.只有 ...
- 《Linux内核设计与实现》读书笔记(十九)- 可移植性
linux内核的移植性非常好, 目前的内核也支持非常多的体系结构(有20多个). 但是刚开始时, linux也只支持 intel i386 架构, 从 v1.2版开始支持 Digital Alpha, ...
- 《Linux内核设计与实现》读书笔记(十八)- 内核调试
内核调试的难点在于它不能像用户态程序调试那样打断点,随时暂停查看各个变量的状态. 也不能像用户态程序那样崩溃后迅速的重启,恢复初始状态. 用户态程序和内核交互,用户态程序的各种状态,错误等可以由内核来 ...
- 《Linux内核设计与实现》读书笔记(十二)- 内存管理
内核的内存使用不像用户空间那样随意,内核的内存出现错误时也只有靠自己来解决(用户空间的内存错误可以抛给内核来解决). 所有内核的内存管理必须要简洁而且高效. 主要内容: 内存的管理单元 获取内存的方法 ...
- 《Linux内核设计与实现》读书笔记 - 目录 (完结)
读完这本书回过头才发现, 第一篇笔记居然是 2012年8月发的, 将近一年半的时间才看完这本书(汗!!!). 为了方便以后查看, 做个<Linux内核设计与实现>读书笔记 的目录: < ...
- 读《Linux内核设计与实现》我想到了这些书
从题目中可以看到,这篇文章是以我读<Linux内核设计与实现>而想到的其他我读过的书,所以,这篇文章的主要支撑点是<Linux内核>. 开始读这本书已经 ...
- 读 Linux内核设计与实现 我想到了这些书
分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! ...
- Linux内核设计与实现学习笔记目录
**注:**这是别人的笔记,我只是把目录抄过来 <Linux内核设计与实现学习笔记> 1.<Linux内核设计与实现>读书笔记(一)-内核简介 2.<Linux内核设计与 ...
最新文章
- 一文读懂Python版的十大经典排序算法(附动图演示)
- 【Python-ML】SKlearn库层次聚类凝聚AgglomerativeClustering模型
- L13操作系统之树(过程)
- SPS :SPS 2003 安装过程中的语言版本问题。
- linux基础命令介绍十三:启动流程
- x64下进程保护HOOK
- ASP.net在线购物商城系统完全解析
- 泛型指针,原生指针和智能指针
- 手把手教你调用微信扫一扫,三分钟包会
- 从《牛津高阶英汉词典》中提取单词(1)
- linux鼠标选中的内容不能复制,解决vim不能使用鼠标右键复制的问题
- vector begin()用法
- 经验:常见木马和未授权控制软件的关闭 3
- MongoDB的授权和权限
- 我理解的国密知识与加密过程
- 正则匹配中英文全部特殊符号
- 【Python】如何判断丑数
- [译]5步分析pdf文件
- 在App Store和Google Play上推广应用程序
- 网络图像的文本识别(阿里天池竞赛)
热门文章
- 在现有计算机内安装另一个硬盘的原因,您有一台运行Windows7的计算机。您在计算机中安装第二个内部硬盘驱动器。您尝试创建一个系统映像,.. - 上学吧找答案...
- 历届电大计算机网考试题及答案,电大2012年计算机应用基础网考统考试题及答案...
- switch里面变量吗c语言,讨教一下关于switch语句中变量定义的相关问题
- java 神经网络算法_70行Java代码实现深度神经网络算法分享
- loadrunner 操作mysql_loadrunner动态从mysql取值
- 新建test.c为什么没有.h文件_新建STM32工程全局声明两个宏的原因
- linux监控文件是否传输,利用SecureCRT在linux与Windows之间传输文件
- html js 跳出框架,现在的web框架为什么把html和js又结合在一起了?
- python--综合小案例--文件读取以及梳理
- 修改Linux文件的读写权限