最近更新2025-04-05,基于ChatDBG和kdump-gdbserver实现了python便利地获取调试信息。最近更新2025-04-17,对脚本做了进一步封装且尝试新的思路
环境搭建
参考这里
Kdump的分析流程
我对于AI相关的技术包括Agent之类一窍不通,所以先来看我熟悉的领域,内核的调试与分析。
“LLM分析崩溃转储现场”这件事有开源项目在做,ChatDBG就是一个例子。我先读了下这个项目的源码。更多的内容就不赘述,它是以gdb/pdb/lldb相关插件的形式工作的,以熟悉的gdb为例。它实现了一个"why"命令让LLM分析崩溃或者相关现场原因。
ChatDBG的实现
总体的思路是将相关的信息打包成结构化的数据发给LLM:
1 | def build_initial_prompt( |
这些传入的参数取决于各个调试器类自己的实现。对于gdb,其他的都好说,主要核心内容是它通过gdb-python接口对堆栈做了回溯,并且提取了对应的调试信息,将最顶部的三个堆栈处对应的上下十行的源代码加了行号之后都打包发给LLM。
核心的思路就是想办法将人做的东西用代码自动化获取,结构化打包发给LLM,让它吐东西出来
问题
首先,gdb只支持ELF格式的镜像,需要对makedumpfile做一些配置。其对于地址的映射关系写在ELF头的LOAD字段里面。但是vmcore是按照物理地址映射的,在关闭kaslr的情况下,ELF头中只有直接映射地址区域的内容,而没有vmalloc相关的地址。内核如果使用vmalloc,尤其是用vmalloc分配栈,这会导致我们的栈地址无法访问。
1 | #0 0xffffffff811d440b in crash_setup_regs (newregs=0xffffc900003cfd18, oldregs=0x0 <fixed_percpu_data>) at ./arch/x86/include/asm/kexec.h:111 |
crash虽然没有这个问题,但是其操作很复杂且没有封装的api,模拟终端操作会很呆而且其不支持读取vmlinux的调试信息,要想把堆栈地址和源码对应,需要做单独的处理和转换,到时候还需要建立联系,非常麻烦。
以我个人的经验来说,想办法让gdb能够调试vmcore,然后用gdb-python api会比后者方便很多。我甚至考虑过修改vmcore的文件头,但是这更麻烦,并且每个dump文件都要重复。在目前我考虑头痛医头脚痛医脚的方法,在内核编译选项里关闭了CONFIG_VMAP_STACK
,让内核栈不用vmalloc去分配,这样暂时性地解决了gdb无法读取内核栈地址的问题。然后采用gdb-python的api去回溯堆栈就可以了。
后续我发现了一个相关的库,有人以lib的形式实现了一个libkdumpfile并提供了pykdumpfile的api,安装之后就可以用这套api在python解析vmcore文件而不用单独操作crash了。同时,这里还有一个用CS结构思想实现的kdump-gdbserver,它能通过建立一个远程调试服务器的方法让gdb去attach vmcore,而且代码很轻量(建立在pykdumpfile的基础上)。
这无疑成为了我们的首选,经过不懈地测试,我暂时跑通了这玩意,并且测试成功,能够靠gdb命令来获取内核崩溃现场的堆栈信息了。说暂时是因为这个项目提供的gdb命令还是存在问题,没办法很好地分析现场的其他线程/任务,但是目前不太需要这些信息。有了gdb-python这个工具之后后续的很多事都是很简单的了,直接api调用即可。
甚至神智不清到将vmlinux和vmcore匹配错了还认真提了个issue给人家发邮件orz,Peter老哥人很好,专门回复了我
效果如下,这是测试函数效果时用注册的测试命令在gdb内部的输出:
更好,更智能,更符合人类思维的检索方式——AST
文件路径获取还是比较僵硬的,下一步我们要为linux内核构建一个能够利用代码本身的依赖关系做查找的东西,利用AST。
AST是