crash
是一个用于分析Linux内核转储文件(vmcore
)的工具。正在运行的内核安装上debuginfo
包之后,直接运行crash
也可以直接分析运行中的内核,这对于分析一些内核问题极为有用。
在我们的某个场景中,需要分析NFQUEUE
队列中的数据包内容。队列在内核中的表示是结构体nfqnl_instance
,数据包sk_buff
通过nf_queue_entry
结构链在队列nfqnl_instance
中。
要找到对应的nfqnl_instance
,需要执行多条crash
命令:
加载内核模块
nfnetlink_queue
:1
mod -s nfnetlink_queue
查看索引数字:
1
p nfnl_queue_net_id
获取
net.gen
地址:1
net.gen init_net
通过上述步骤获取的地址进一步获取
net_generic.ptr
:
1 | struct net_generic.ptr 0xffff9312763e5680 |
从上述步骤获取地址读取若干地址:
1
rd -x 0xffffa08279cda518 12
根据第二步中获取的索引数字找到
nfnl_queue_net
的地址,并进一步查看其结构:1
struct nfnl_queue_net ffffa0852b249900
从中找到
nfqnl_instance
结构地址并查看:1
struct nfqnl_instance 0xffff931109f736c0
从中通过链表找到所有的
nf_queue_entry
进行查看:1
struct nf_queue_entry 0xffff931529496d80
整个过程是有顺序依赖的,后序步骤的命令需要前边步骤所返回的地址。每次分析都需要从头手动执行一遍效率太低,因而期望可以有批量执行命令脚本的能力。
crash
支持通过-i
参数或者<
符号读入批量命令进行执行,但这种方式需要把所有的命令提前写入文件。对于我们这种后序命令依赖前序命令的结果,这种方式就不奏效了。
经过查阅,发现crash
工具支持so
扩展,可以通过C
语言开发crash
扩展,可以参考:
我们可以在自定义扩展中依次调用crash
命令,并解析命令输出,进而拼接出后序命令。当然,用C
语言解析命令字符串输出的这种逻辑开发效率较低,我们可以将执行命令的能力导出到Lua
语言中,由Lua
脚本来解析命令输出,从而给crash
添加上执行脚本的能力。
上述查找nfqnl_instance
的逻辑可以通过Lua
脚本来完成:
1 | require "crash" |
扩展的实现位于:
参考: