vmlinuz から vmlinux を抽出する方法

普段生活していると vmlinuz を vmlinux に変換したくなることはしばしばあると思いますが、その手順はどうも忘れがち。
今回はその変換レシピをメモ。

前提知識

まず、vmlinuz の中には gzip 圧縮されたカーネルイメージが同梱されています。
同梱というより、vmlinuz は vmlinux + ちょっとしたヘッダやメタ情報といった感じで、メインはカーネルイメージです。
このカーネルイメージを取り出し、展開したものが vmlinux です。

vmlinuz イメージを用意

まず vmlinuz とはなにか。これは /boot 下にある vmlinux-* から始まるファイル。
/boot/vmlinuz-3.2.0-52-generic みたいなファイル、ありますよね?
こいつを専用のワーキングディレクトリに移動。場所は /tmp/kernel で。

$ mkdir /tmp/kernel
$ sudo cp /boot/vmlinuz-3.2.0-52-generic /tmp/kernel/vmlinuz
$ sudo chmod +r /tmp/kernel/vmlinuz

ついでに名前も vmlinuz に変更。さらに読めるよう chmod.

展開

さて早速展開します。
とはいえ、どこから展開すればよいのでしょう?
カーネルイメージは gzip 圧縮されているので、gzip ヘッダ('1f 8b 08 00')を探してやりましょう。

aoking:/tmp/kernel $ od -A d -t x1 vmlinuz | grep '1f 8b 08 00'
0018016 48 8d 83 f0 6f 4b 00 ff e0 1f 8b 08 00 00 00 00


発見。18016 バイトの列の 10 バイト目からです。つまり、18026 バイトからがカーネルイメージであって、それ以前のものは破棄すべきデータです。
18026 バイト以降を展開してファイルに保存するコマンドは下記の通り。

aoking:/tmp/kernel $ dd if=vmlinuz bs=1 skip=18025 | zcat > vmlinux

gzip: stdin: decompression OK, trailing garbage ignored

見ての通り、dd コマンドで先頭をスキップし、それ以降を zcat に渡して展開したものを vmlinux に吐き出してます。これで vmlinux イメージの抽出は完了。

aoking:/tmp/kernel $ file vmlinux
vmlinux: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=0x62a37e23540d4dd4230ebbb70970051b38d7391f, stripped

ちなみに

今回は 18025 バイト分をスキップしましたが、それを間違えると zcat に怒られるので間違った vmlinux イメージが作られる心配は無しです。

aoking:/tmp/kernel $ dd if=vmlinuz bs=1 skip=18026 | zcat > vmlinux

gzip: stdin: not in gzip format