crash内核调试准备事项之二三事-阿里云开发者社区

开发者社区> 开发与运维> 正文

crash内核调试准备事项之二三事

简介: ### 引言 解决Linux系统上疑难问题的常见方案之一是使用crash工具调试系统转储(coredump), 进入内核分析、排查。但是此方案时常不可行。这一点在内核较新的系统上尤甚。而捕捉 系统转储也有不少值得留意之处。我们一并讨论下使用crash工具调试系统转储的准备 事项及其背后的原因,以便更有效的使用此方案,减少无用功。 ### crash的黑魔法 crash工具对

引言

解决Linux系统上疑难问题的常见方案之一是使用crash工具调试系统转储(coredump),
进入内核分析、排查。但是此方案时常不可行。这一点在内核较新的系统上尤甚。而捕捉
系统转储也有不少值得留意之处。我们一并讨论下使用crash工具调试系统转储的准备
事项及其背后的原因,以便更有效的使用此方案,减少无用功。

crash的黑魔法

crash工具对内核和gdb使用了很多黑魔法,而非其公开的API或者文档化的
features。比如,crash并不是使用了libGDB框架,也不是如
ddd等gdb前端那样采用C/S架构。当然也
没有使用在Emacs内嵌gdb支持时采用的
"通信协议" -- gdb的的annotate特性。

那么,crash是怎么使用gdb的呢?crash使用自带而非系统安装的gdb。对自带的gdb,crash对
其打了补丁。通过这种方式,crash把gdb收编了。两者共存于同一进程,crash通过函数调用就
可以使用gdb。通过修改gdb命令执行完毕后返回哪个函数,crash就接管了入口。不管命令来自
交互式界面还是批处理文件,都是crash接到输入,进而路由命令,而后由自身、shell或者gdb
三者之一来执行命令。

crash解析系统转储,对黑魔法的使用也不遑多让。

凭借黑魔法,crash功能可观,但是却也时常因之无能为力。如何解决crash不能正常工作的
问题呢?答案是做好规划和准备,简化目标环境,降低复杂度,收集辅助数据,增加对目标环境的
认知。这也有助于我们理解crash的工作过程和验证crash结果。

源码和调试符号

调试需要调试符号和源码,但是不同的发行版,对于调试符号和源码的处理方式是不一样的。

对于CentOS、Fedora之类RHEL-Like的发行版,其有专门的软件源提供发布软件包各个
版本的调试符号和源码。可以从软件源手工下载,也可以调整yum/dnf的配置,把有关
软件源补充进来即可。比如,对于CentOS,其对应的软件源在
debuginfo.centos.org

而debian及其衍生的发行版,比如Ubuntu,几乎只能找到部分最新版本软件的调试符号,而且这些
调试符号对应的源码也往往无法拿到。

因此,如果使用的是debian或者其衍生的发行版,应备份内核源码等关键组建源码,并准备好相应的
构建环境,以备不时之需。

为makedumpfile提供额外信息

ECS之类的计算节点配备的内存越来越大,甚至内存大小都超出了其配备的磁盘空间。这种
情况下makedumpfile能够通过过滤和压缩产生较小系统转储,这个功能对存储和传递
系统转储无疑提供了便利。

但是便利并非没有成本。makedumpfile需要调试符号信息,以分析和判断哪些内存页需要压缩,
那些内存页可以丢弃。就是说在做系统转储时,需要有内核调试符号。变通之处是在有内核
调试符号的系统中,makedumpfile工具可以生成vmcoreinfo文件。这个文件在做系统
转储时可以替代内核调试符号使用。但是这个变通之处并非处处可行。比如qemu
虚机的monitor命令,其子命令dump-guest-memory就没有vmcoreinfo有关的选项。

但是,几乎所有的发行版,其提供的内核都开启了地址随机化(KASLR,
kernel address space layout randomization)。在没有关闭kaslr的情况下,
vmcoreinfo提供了系统的运行时信息,对于crash调试都是有益的。因此,在可能的情况下,
建议提供系统转储的同时,也提供vmcoreinfo文件。

使用内核命令行参数nokaslr即可关闭内核地址随机化。

使用kdump捕捉系统转储

在宿主机上我们可以把qemu进程视之为普通进程来做coredump;也可以使用qemu虚机的
monitor命令来保存虚拟机内存的方式来制作虚拟机的系统转储。这两种方案都有其应用
场景和便利之处。比如因为进程pid耗尽导致无法登陆或者业务进程无法启动的场景。但
这两种方案,即要在宿主机上有相应的权限,还缺少对虚拟机内部的知识,可用的
机制也不够灵活。

接下来我们讨论一个有竞争力的系统转储方案:基于kexec技术的Kdump。

kexec: 运行时启动新内核

kexec能够在运行时启动新内核。即在当前运行的Linux系统上,kexec能够让我们加载和
启用一个新的内核,代替老的内核来运行。这就带来了一种新的、生成系统转储的方案。

在Linux系统上,加载一个新的内核但不启动之。这时系统上就有了两个内核。一个是当前
在运行的内核,我们称之为生产内核;一个是刚刚加载但是没有运行的内核,我们称之为
捕获内核。然后把系统配置为生产内核panic时启动捕获内核。正如其名字所示的,捕获内核
负责为生产内核捕捉系统转储。

kdump怎么使用kexec?

预留内存

kdump要为捕获内核预留内存,这需要配置crashkernel内核命令行参数。RHEL-Like发行版
默认配置了这个参数,但是debian及其衍生版则未必。

持久化的配置内核命令行参数,需要调整GRUB的设定并刷新之,而后重启生效。因此,在
debian及其衍生版上部署kdump,如果新配置或者调整了内核命令行参数,需要重启系统。

提供守护进程

捕获内核依赖守护进程实现系统转储功能,这个守护进程需要kdump部署。这样捕获内核启动
后运行此守护进程即可。

那么,kdump是怎么通知捕获内核运行哪个守护进程的呢?答案是kdump提供了第二个守护进程。
这个守护进程运行在生产内核场景下,其职能就是实现某种机制用以告知捕获内核哪一个守护进程
是捕获进程(这里用进程不甚恰当,捕获进程不会在生产内核下运行)。这第二个守护进程
也负责处理内核有更新时的场景。

就是说,kdump提供了两个守护进程。一个运行在生产内核下,功能是告知捕获内核谁是捕获
进程;一个运行在捕获内核下,负责系统转储。

题外话,RHEL-Like发行版和debian及其衍生版实现上述功能采用了差异颇大的技术栈。

kdump的灵活性

可以充分借用makedumpfile的功能

捕获进程是单独的守护进程,使用的工具是makedumpfile。因之可以灵活的按需配置。比如说
把系统转储直接通过网络投递出去、过滤掉更多无用的内存页等等。更多细节请参考
makedumpfile的文档。

调配触发配置,扩大使用场景

生产内核panic时kdump才会生成系统转储。因此,可以按需调整系统,让其在特定条件下
panic,这样我们就能得到系统转储。

这里讨论两种情况。

调整内核参数

内核有参数控制某些情况出现时内核是否panic。比如vm.panic_on_oom参数。将之设定
为1则oom时会触发panic。其他类似的参数还有kernel.hung_task_panic
kernel.panic_on_rcu_stall等。

灵活使用魔术键

使用魔术键
可以手工触发或者在脚本中触发内核panic。了解这一点,则可以在生产内核场景下部署脚本,检测
到问题复现则触发内核panic。

如何部署kdump?

根据上面的讨论,部署需要:

  1. 部署软件包:

    • RHEL-Like的发行版部署kexec-tools。除非必要,否则不必让kexec负责重启功能。
    • debian及其衍生版需要部署kexec-tools和kdump-tools
  2. 检查grub配置,核实为捕获内核预留了内存
  3. 如果调整了内核命令行参数,则重启系统
  4. 验证守护进程运行了
  5. (可选)通过魔术键测试kdump工作。

小结

crash调试系统转储,源码、调试符号和转储内容,三者缺一不可。提前做好规划和准备,使用crash
解决疑难问题,会更加便利和有效。

参考

RHEL
debianUbuntu

RHEL-Like的发行版使用dracut

apt/
aptitude,CentOS、Fedora之类
RHEL-Like的发行版使用rpm/
yum/dnf

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

其他文章