第18章 调试

内核调试的难度大于用户级

一、准备开始

开始之前需要的是:

  一个行为可靠且定义明确的bug

  一个隐匿bug的内核版本

  相关内核代码的知识和运气

想要成功的调试,取决于能不能将这些bug重现。

二、内核中的bug

产生:错误代码,同步错误,错误的管理硬件

症状:降低所有程序的运行性能,毁坏数据,系统死锁

三、通过打印来调试

1、健壮性

  printk()函数在任何时候任何地方都能调用

2、日志等级

  printfk()和printf()相比,可以指定一个日志级别,内核根据这个级别判断是否在终端上打印消息。

如果没有特别特别指定,函数会选用默认的DEFAULT_MESSAGE_LOGLEVEL,在当前来看是KERN_WARNING,即一个警告。

内核会把这些记录等级转化为"",n指等级,从0-7,对应表中从上到下,数字越小越重要。

对于调试信息, 有两种赋予记录等级的方法:

  保持终端的默认记录等级不变,给所有调试信息KERN_CRIT或更低的等级。

  给所有调试信息KERN_DEBUG等级,调整终端的默认记录等级。

3、记录缓冲区

内核消息保存在一个环形队列中,这个环形队列就是它的记录缓冲区,在单处理器的系统上默认值是16kb。

也就是说内核在同一时间只能保存16kb的内核消息,再多的话新消息就会覆盖老消息,读写都是按照环形队列方式操作的。

优点:

  健壮性:在中断上下文中也可以方便的使用。

  简单性:使记录维护起来更容易。

缺点:
  可能会丢失消息。

4、syslogd和klogd

klogd从记录缓冲区中获取内核消息,再通过syslogd守护进程将他们保存在系统日志文件中。

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

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

四、oops

oops是内核告知用户有不幸发生的最常用的方式。

内核很难自我修复,也不能将自己杀死,只能发布oops,过程包括:向终端上输出错误消息,输出寄存器中保存的信息,输出可供跟踪的回溯线索。

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

oops发生的时机:

  发生在中断上下文:内核无法继续,会陷入混乱,导致系统死机

  发生在idle进程或init进程(0号进程和1号进程):死机

  发生在其他进程运行时,内核会杀死该进程并尝试着继续执行

oops发生的可能原因:内存访问越界、非法的指令等

oops中包含的重要信息:寄存器上下文和回溯线索

回溯线索:显示了导致错误发生的函数调用链。

寄存器上下文信息也很有用,比如帮助冲进引发问题的现场

1、ksymoops

将回溯线索中的地址转化成有意义的符号名称的命令

2、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并打印信息

1、BUG()和BUG_ON()

被调用时会引发oops,导致栈的回溯和错误信息的打印。
可以把这些调用当做断言使用,想要断言某种情况不该发生。

2、BUILD_BUG_ON()

与BUG_ON()作用相同,仅在编译时调用,如果在编译阶段已提供的声明为真,编译会因为一个错误而终止。

3.panic()

可以引发更严重的错误,不但会打印错误信息,还会挂起整个系统,最糟糕的情况下使用。

4.dump_stack()

只在终端上打印寄存器上下文和函数的跟踪线索。

七、神奇的系统请求键

这个功能可以通过定义CONFIG_MAGIC_SYSRQ配置选项来启用。SysRq(系统请求)键在大多数键盘上都是标准键。
该功能被启用时,无论内核出于什么状态,都可以通过特殊的组合键和内核进行通信。
除了配置选项以外,还要通过一个sysctl用来标记该特性的开或关,启动命令如下:

  echo 1 > /proc/sys/kernel/sysrq

从终端上,可以输入Sysrq-h获取一份可用的选项列表:

SysRq-s:将“脏”缓冲区跟硬盘交换分区同步
SysRq-u:卸载所有的文件系统
SysRq-b:重启设备

八、内核调试器的传奇

1、gdb

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

gdb vmlinux /proc/kcore


vmlinx是未经压缩的内核映像,不是压缩过的zImage或bImage,它存放于源代码树的根目录上。

/proc/kcore作为一个参数选项,是作为core文件来用的,通过它能够访问到内核驻留的高端内存。只有超级用户才能读取此文件的数据。

可以使用gdb的所有命令来获取信息。例如:

打印一个变量的值:

p global_variable

反汇编一个函数:

disassemble function

-g参数还可以提供更多的信息。

局限性:没有办法修改内核数据、不能单步执行内核代码

2.kgdb

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

九、探测系统

1、使用uid作为选择条件

一般情况下,加入特性时,只要保留原有的算法而把新算法加入到其他位置上,基本就能保证安全。

可以把用户id(UID)作为选择条件来实现这种功能:
通过某种选择条件,安排到底执行哪种算法。

2、使用条件变量

如果代码与进程无关,或者希望有一个针对所有情况都能使用的机制来控制某个特性,可以使用条件变量。
这种方式比使用UID更简单,只需要创建一个全局变量作为一个条件选择开关:

如果该变量为0,就使用某一个分支上的代码;否则,选择另外一个分支。

可以通过某种接口提供对这个变量的操控,也可以直接通过调试器进行操控。

3、使用统计量

这种方法常用于使用者需要掌握某个特定事件的发生规律的时候。
通过创建统计量并提供某种机制访问其统计结果来掌握这个规律。

4、重复频率限制

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

(1)重复频率限制

限制调试信息,最多几秒打印一次,可以根据自己的需要调节频率。
(2)发生次数限制
这种方法是要调试信息至多输出几次,超过次数限制后就不能再输出。
这种方法可以用来确认在特定情况下某段代码的确被执行了。

两种方法用到的变量都是静态的、局部的。

十、用二分查找法找出引发罪恶的变更

当版本更新的时候引发bug时,可以用二分法查找出现bug这段时间内的版本。

linux内核分析 第五周读书笔记的更多相关文章

  1. linux内核分析第五周学习笔记

    linux内核分析第五周学习笔记 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.co ...

  2. Linux内核分析——第五周学习笔记

    第五周 扒开系统调用的“三层皮”(下) 一.知识点总结 (一)给MenuOS增加time和time-asm命令 在实验楼中,首先 强制删除menu (rm menu -rf) 重新克隆一个新版本的me ...

  3. linux内核分析 第六周读书笔记

    第三章 进程管理 3.1 进程 进程:处于执行期的程序 线程是在进程活动中的对象:内核调度的对象是线程而不是进程,在Linux系统中,并不区分线程和进程 在现代操作系统中, 进程提供两种虚拟机制:虚拟 ...

  4. Linux内核分析第五章读书笔记

    第五章 系统调用 在操作系统中,内核提供了用户进程与内核进行交互的一组接口,这些接口在应用程序和内核之间扮演了使者的角色,保证系统稳定可靠,避免应用程序肆意妄行. 5.1 与内核通信 系统调用在用户空 ...

  5. linux内核分析 第八周读书笔记

    第四章 进程调度 4.1 多任务 1.多任务操作系统就是能同时并发的交互执行多个进程的操作系统. 2.多任务操作系统使多个进程处于堵塞或者睡眠状态,实际不被投入执行,这些任务尽管位于内存,但是并不处于 ...

  6. linux内核分析 第七周读书笔记

    第七章 链接 1.链接是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载到存储器并执行. 2.链接可以执行于编译时,加载时,运行时. 7.1编译器驱动程序 1.大多数编译系统 ...

  7. LINUX内核分析第五周学习总结——扒开应用系统的三层皮(下)

    LINUX内核分析第五周学习总结——扒开应用系统的三层皮(下) 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/cou ...

  8. Linux内核分析第四章 读书笔记

    Linux内核分析第四章 读书笔记 第一部分--进程调度 进程调度:操作系统规定下的进程选取模式 面临问题:多任务选择问题 多任务操作系统就是能同时并发地交互执行多个进程的操作系统,在单处理器机器上这 ...

  9. LINUX内核分析第五周学习总结——扒开系统调用的“三层皮”(下)

    LINUX内核分析第五周学习总结--扒开系统调用的"三层皮"(下) 标签(空格分隔): 20135321余佳源 余佳源 原创作品转载请注明出处 <Linux内核分析>M ...

随机推荐

  1. javascript实现对html便签等字符的转义

    参考链接:https://www.jb51.net/article/152700.htm 请访问以上链接. 本人纯搬迁,防止原作者删除. <script> var HtmlUtil = { ...

  2. L2 Helios OPcodez

    天堂2 Helios太阳神版本 的客户端和服务端封包 *********************** Client ***********************00 SendLogOut01 Req ...

  3. 在虚拟机上搭建物理机可访问的web服务(IIS)

    0x0 前言 安装webug4.0的时候突发奇想,想学下如何在虚拟机里搭建网站,然后让主机像访问互联网的网站一样访问虚拟机的网站,为以后渗透测试搭建环境做准备 0x1 虚拟机安装win2003[以防万 ...

  4. Homebrew1.5之后安装PHP和扩展

    Homebrew 1.5 宣布放弃 homebrew/php, 转而使用homebrew/core维护, 详见https://brew.sh/2018/01/19/homebrew-1.5.0/ 于是 ...

  5. jobs命令详解

    基础命令学习目录首页 在用管理员执行一个命令后,用Ctrl+Z把命令转移到了后台.导致无法退出root的. 输入命令:exit终端显示:There are stopped jobs. 解决方法:方法一 ...

  6. 利用Cocoapods创建基于SVN的私有库podspec

    由于项目年后要进行组件化,考虑到公司内部实现的一些私有组件,不对外公开,而又想在不同项目中使用,该怎么办呢?由于cocoapods有了强大的功能,可以自己创建podspec,更可以设置私有的库.那么利 ...

  7. Scrum Meeting 5 -2014.11.11

    放假过掉一大半.大家都努力赶着进度,算法实现基本完成.可能还有些细小的改动,但也可以统一进入测试阶段了. 今天叫了部分在校人员开了个小会.任务决定以测试为主,同时开始进行服务器的部署. 在之前尝试服务 ...

  8. Bing词典vs有道词典比对测试报告——体验篇之软件适应性

    联网情况: 在联网情况下,针对每一次查询,有道词典的反应速度明显比必应词典快得多.据我推测有以下两个原因: 有道词典有本地词库而必应词典更多依赖联网. 有道词典的服务器在国内而必应的在国外. 断网情况 ...

  9. 奔跑吧DKY——团队Scrum冲刺阶段-Day 6

    今日完成任务 谭鑫:制作相应动画人物,并实现人物动画 黄宇塘:制作相应动画人物,并实现人物动画,制作背景图 赵晓海:制作相应动画人物,并实现人物动画 方艺雯:制作相应动画人物,并实现人物动画,编写博客 ...

  10. python实现树莓派开机自动发送IP到指定邮箱

    #!/usr/bin/python # -*- coding:UTF-8 -*- #测试发送邮件163邮箱发送到qq邮箱 import smtplib from email.mime.text imp ...