LWN: 想用python命令来调试kernel吗?drgn就是了!

栏目: C · 发布时间: 4年前

内容简介:ByMay 29, 2019LSFMM

A kernel debugger in Python: drgn

By Jake Edge

May 29, 2019

LSFMM

2019 Linux Storage, Filesystem, and Memory-Management Summit (LSFMM)会议上,Omar Sandoval介绍了一款kernel调试器,可以利用 Python 脚本来访问正在运行的kernel里的数据结构。Sandoval是Facebook的一员,他经常需要调试一些kernel问题,总苦恼于当前的 工具 不太趁手。因此他创建了drgn,一个python library形式的kernel debugger(调试器)。

Sandoval首先对drgn(发音同dragon)进行了一个快速演示,登入一台虚拟机,然后用drgn -k命令就连上了当前在运行的Linux kernel,然后用python的交互式 shell 里的几行命令,查看了根文件系统的具体superblock信息,进而循环查看了这个superblock里缓存的inode的信息,包括它们对应的文件路径。然后他演示了一些更有趣的功能,例如列出所有大于1MB的文件的inode。还查看了size比较大的kernel module,库文件,systemd等等。

Sandoval平时经常开发Btrfs和块设备层的代码,不过他也需要调查各种kernel相关的奇怪问题。Facebok有非常多的服务器,有时会有一些“极其罕见的、百万分之一概率的问题”在他们的环境里隔一段时间出现一次。他都会主动帮助调查一下。这个过程中他熟悉了GDB, crash,还有eBPF,不过他很快发现他经常需要对kernel数据结构做各种复杂的分析,所以最终他自己开发了drgn来满足这一需求。

LWN: 想用python命令来调试kernel吗?drgn就是了!

他认为GDB确实有很多优秀功能,包括能把各种类型、变量、公式都很漂亮的打印输出出来。不过它更擅长利用breakpoint(断点)方式的debug,而不适合他在生产环境里debug的需求。GDB支持脚本,但是只是对现有的GDB命令的包装,不够丰富。

Crash也是为内核调试专门开发的工具。它能很好的支持kernel里的链表(linked list,不知道有多少人知道晾衣夹这个梗——译者),各种结构,进程,等等。不过如果要调查其他的内容,就会感到很难下手了,因为它的扩展性不是很强。当Sandoval使用crash的时候,他经常得dump很多数据出来,用其他工具来做进一步的分析处理。

BPF和BCC也都是非常棒的工具,他用这些工具也很频繁。不过通常需要在bug出现的时候采集到具体信息,并且系统得保持正常运行状态,否则无法使用这些工具。很多他调查的bug都是好几个小时之前发生的,server也都因此挂死没法再执行shell命令了,或者他可能只是拿到一份memory dump内存映像文件来debug。这些情况下BPF都没有什么用处了,毕竟BPF主要是用来做tracing方式调试的,不适用于交互式的调试器场景。

Drgn主要目标是能用正式的编程语言来做调试,甚至可以写成真正的程序。Drgn能够很轻松的把需要的信息打印出来,写入文本文件,然后用脚本来处理;也可以直接用Python接口的GDB来调试。他有时候称呼drgn为“debugger as a library”,因为drgn不是像crash或gdb那样,仅仅提供了支持少数几个命令的交互界面。相反的,drgn把所有数据类型、变量等等都包装好了,你可以对他们做任何操作。可以查看这份User Guide来初步了解如何使用(https://drgn.readthedocs.io/en/latest/user_guide.html  )。

然后他进行了更进一步的drgn高级功能演示,包括交互式场景,也有脚本方式。首先是演示交互式调试场景,他先让drgn把一个变量作为一个目标object返回回来,这个object还包含更多信息,例如变量类型(也是另一个object),地址,当时的值等。开发者还可以通过链表循环来查看更多信息,他就演示了对struct task_struct这个链表进行遍历,列出了所有从init task到全部子进程的信息。

在现场演示如何使用这个链表遍历功能的时候,他告诉大家,如果经常要重复写这些命令,正常人都会感到乏味无聊。所以drgn还提供了一组helper function帮助函数,能把这部分工作简单化。目前,大多数都是文件系统和块设备层的常用功能,不过很快会加更多网络等kernel其他子系统相关helper function。

接下来,他演示了一次真实事件的debug过程,当时是跟同事一起调查一个虚拟机里的业务服务(production server,特指正在对外提供服务的服务器——译者)。这台服务器是一台存储服务器,主要存放cold data (指不常用的数据),因此磁盘会经常在一段时间没有访问之后被关闭来省电。这样磁盘经常on/off开关的场景下,就触发了一个kernel bug。这里的存储服务是运行在一个container(容器)里的,有时候停止container的操作会卡住无法结束。在他开始查看这个问题的时候,很快他发现container其实在很长时间之后还是停下来了,这里可能是有什么资源泄露了。现场他演示了如何查看block cgroup数据结构,以及Python Set object类型来调查每个block cgroup里的请求队列的数量。他也分析了ID allocator (IDA)关联的radix tree(IDA是用于区分请求队列的),来印证他的分析。最终他看到在一个引用循环(reference cycle)里面,request queue实际上发生了泄露,没有得到回收。

现场他还举了其他的一个例子,是利用drgn来调查Btrfs异常返回ENOSPC的问题。最终查下来是对孤儿文件(orphaned files)保留了额外的metadata空间导致的。一旦确认是这个问题,进而就确认了哪些进程一直在产生孤儿文件,这样在Btrfs的正式fix patch合入之前,可以周期性的重启这个进程来解决。此外,每次他需要调查一个不太熟悉的kernel subsystem的时候,他经常就会用drgn来查看里面的关键数据结构,从而帮助他理解这个子系统。

drgn的核心部分是一个libdrgn C语言库。假如有人不喜欢用python,也希望自己来处理各种异常情况的话,可以直接用 C语言 来调用libdrgn实现调试功能。drgn还有一组可以选择打开与否的后端程序帮助读取各种内存文件,例如正在运行的系统里的/proc/kcore文件,crash dump文件,或者/proc//mem这样的特定进程的内存内容。drgn是用DWARF标准来获取数据类型和符号,这里倒是不如想象的容易,他花了比预想的多得多的时间来优化对DWARF数据的访问。这个接口也是可以扩展的,不过他目前只实现了DWARF。

优化之后,drgn只要半秒钟就能启动好,而crash需要大概15s的时间启动。drgn启动非常快,所以他越来越喜欢用它,每次要用crash的时候总是有点挠头。

drgn里面还嵌入了一个C语言实现的解析器。这样drgn就能处理不少特殊情况,例如需要做隐性的数据类型转换或者整形数的扩展等等。这部分实现也很麻烦,花了不少时间,不过这样他就能确保相应的转换过的代码运行过程跟在kernel里时一样了。

他也介绍了drgn目前缺失的最大功能是backtrace。现在只能访问全局变量,虽然说大多数情况下也够用了,不过他还是有时候不得不拿出crash工具来获取更多信息,然后帮助drgn来分析当时的情况。backtrace当然也是可以在drgn里支持的,只是他现在还没有完成这部分。后续他很想能用BPF Type Format(BTF)来取代DWARF,因为BTF更加小,更加简单。不过这里有个最大问题是BTF不支持变量,等BTF支持变量之后,他肯定会用BTF。此外他还在准备一组常用的drgn脚本和工具,会提交到git仓库里。

还有一个让他很烦恼的问题,就是是否集成BPF和BCC。有个想法是利用BPF来做存活系统上的debug(live debugging),而drgn用于出错之后的debug(after-the-fact debugging)。这两种工具有些地方是重复的,他还没有想好怎么能统一起来。BPF因为没有循环支持,所以有时候不太好用。而drgn又没法在bug发生的时候及时抓住现场,也不太爽。他有一个“疯狂的想法”,就是在BPF触发breakpoint的位置,调用到user-space的drgn进程,不过这里他还没有想清楚是否完全可行。

译者补充:在LWN的这则新闻下面,有很多评论者提到epython/pykdump,以及crash-python项目,之前经常用crash、并且喜欢python的话,可以试用一下这两个项目。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Node.js实战

Node.js实战

[美] Mike Cantelon、[美] TJ Holowaychuk、[美] Nathan Rajlich / 吴海星 / 人民邮电出版社 / 2014-5 / 69.00元

服务器端JavaScript?没错。Node.js是一个JavaScript服务器,支持可伸缩的高性能Web应用。借助异步I/O,这个服务器可以同时做很多事情,能满足聊天、游戏和实时统计等应用的需求。并且既然是JavaScript,那你就可以全栈使用一种语言。 本书向读者展示了如何构建产品级应用,对关键概念的介绍清晰明了,贴近实际的例子,涵盖从安装到部署的各个环节,是一部讲解与实践并重的优秀......一起来看看 《Node.js实战》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

MD5 加密
MD5 加密

MD5 加密工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具