😊

「Linuxカーネルの再現」を分かりやすくしました【linux.tokyoのアップデート1】

に公開

要約

  • コードの再現をよりしやすく、分かりやすくしました
  • writeシステムコールのみならず、fork(kernel_clone)・execも書きました(全制覇には1年はかかりそう)
  • その他、細かいUIなどの修正をしました

導入

前回の記事では、Linux カーネルの write システムコールを関数レベルで可視化し、「カーネルコードをどう読めばいいか」を直感的に理解できる仕組みを紹介しました。

https://zenn.dev/coffeecupjp/articles/07f01040a4c7a4

https://linux.tokyo

その後、機能を拡張し、fork() や exec() にも対応、さらに木構造ナビゲーション・JSON保存・Linux Readerとの連携などを追加しました。
今回は、そのアップデート内容と実際の進化ポイントを紹介します。

前回までに作った内容の不満点

前回の記事で紹介した「Linuxカーネル可視化サイト」ですが、木構造で関数追跡を理解できる反面、いくつかの不満点を自分で見つけました(ちょっと急行列車で急いで作りすぎていたかもしれません...)。

  1. 重要な関数候補は見れるが、そこに行くまでの経路が見づらい
  2. 重要な関数候補を押してから、目的の関数まで手動で飛ばないといけない
  3. 木構造が大きくなりすぎた時に、見づらくなってしまう
  4. せっかく自分で作った Linux-Reader との連携がない
  5. コンテンツが少ない(とはいえLinux6.17 arm64のシステムコール323個+aを全て制覇するのでも無職の自分の身でも余裕で1年以上かかりそうではあるのですが...)

そういうことなので、少し修正を入れたので、その内容に関する記事です。
読むのが面倒でしたら、細かい話は抜きに、まずは実際のサイトを触って見てもらえれば嬉しいです

https://linux.tokyo

修正点

ということで、1つ1つ修正を説明します(対応が順不同ですみません!)。

◾️選択された関数から、そこに行くまでの経路を再現できるように

前の記事では「再現」とは書いたものの、関数の経路をルートノードの関数から再現するには、1つ1つ押さなければならない状態でした。
つまり、例えば、「write(4)」の「send_call_function_single_ipi」のルート関数「nvme_irq」からの関係性を知りたい時(以下の画像を参照)は、

1つ1つ関数をクリックしていくしかありませんでした。「__smp_call_single_queue」→「generic_exec_single」→「smp_call_function_single_async」→「blk_mq_complete_send_ipi」と...

でも、これでは結構面倒です。
なので、選択された関数までの経路をルート関数から追跡できるような機能(リプレイ機能)を追加しました。

使い方は簡単。選択された関数の下に「ルートノードから再現する」の青いボタンが出てくるので、それを押すだけ。
これで、ルートノードの関数から1つ1つ順番に(「次のコードに進む」を押していくことで)目的の関数まで、関数の中身を見ることができます。

// 結構長いです...
「nvme_poll_cq」 -> 「nvme_handle_cqe」 -> 「nvme_try_complete_req」 -> 「blk_mq_complete_request_remote」 -> 「blk_mq_complete_send_ipi」 -> 「smp_call_function_single_async」 -> 「generic_exec_single」 -> 「__smp_call_single_queue」 -> 「send_call_function_single_ipi」

のように。
これで、本当の意味での「再現」に近づきました!やったね。

◾️write以外に、fork(kernel_clone)・execを追加

前回の記事では「Linuxカーネル全機能制覇」と書きましたが、ちゃんと調べたら数的には「Linux6.17 arm64のシステムコール323個+a」ともしかしたら400個近く機能を網羅しなければならず、どう考えたって、自分のような無職でさえも1年以上かかる見積もりになってしまいました。
ですが、諦めずに、とりあえずはfork, execという定番を書きました。

今はexitをやっているのですが、exit_fsの大きさが巨大でなかなか手こずっていたのですが、この様子だと2年かかるかも...
とは言え、システムコールにはマイナーなものもあるので、まずはメジャーなやつ(open, read, mmap, slab, sched, start_kernelなど)から気長にやっていきたいと思っています。

◾️木構造のJSONを保存できるようにし、Linux-Readerで再探索できるように

実はこの https://linux.tokyo というサイトは、Linux-Readerという自作VSCode拡張機能を使って生成したJSONファイルを表示することで作っているのですが、万が一「内容が足りない!」と思った人向けに Linux-Reader でも再探索できるようにしました。

再探索するには、以下の手順でできます。一応機能は作ったので、興味がある方がいたらやってみてください。

  1. 上記のVSCode拡張機能とLinuxカーネルとcompile_commands.json(bearコマンド+Linuxのビルドで生成)を用意します

https://marketplace.visualstudio.com/items?itemName=coffeecupjapan.linux-reader&ssr=false

  1. https://linux.tokyo の再探索をしたいページに飛び、「この関数探索の目的」の右の「JSON形式の木構造をダウンロード」をクリックします

  2. VSCode拡張機能をコマンドパレットから開き、「設定画面」から設定をします。設定は自動保存されないので、1つ1つ保存ボタンを押下する必要があります

  1. 設定が終わったら、チャット画面に戻り、「検索履歴入力に移動する」をクリックし、2で保存したJSONファイルのパスを入力すれば、木構造が表示されます。関数ごとに自動で割り振られた識別ハッシュ値を入力すれば、再探索ができます!

説明したものの、Linuxのビルドが必要なcompile_commands.jsonの生成など手間はかかるので、万が一「自分でやってみたい!」という方がいたらやってみたらどうか、くらいの温度感でした。

◾️重要な関数候補を押すと、目的の関数まで自動スクロールできるように

ここからの修正は軽いです。
今の https://linux.tokyo には、「主な関数経路」という重要な関数経路を木構造の中から選択状態にする機能があるんですが、こちらは自動で選択状態になった関数まで飛んでくれなかったので、飛ぶようにしました。

◾️木構造の全折りたたみをできるように

使ってみて思ったのですが、展開をしすぎると木構造が大きくなりすぎて分かりづらかったです。
なので、木構造を初期状態の「深さ2」までしか表示させない機能もつけました。

結び

今週の改善は、なかなかクリティカルなものが多かったのですが、今後も使いづらかったら改善していくつもりです。
次回は exit() の完読を目指しつつ、open/read/mmap などの代表的なシステムコールにも挑戦していきます。
コードの「構造美」を、より多くの人が直感的に感じられるようにしたいです。

Discussion