AJAJA: Systemモジュールがロードされるまでの制御フローの解析
AJAJAを実際に走らせてみて、AJAJAの動作をもう少し詳しく知りたくなりました。特に、AJAJAでCGIを実現するのに利用されているSystemモジュールが、どのようにしてユーザーランドから利用できるようにしているのか、興味を持ちました。そこで今回は、Systemモジュールが、実行コンテキストにロードされるまでの制御フローを解析してみたいと思います。今回、解析するソースコードはrev #30を用いることにします。
解析方法
ソースコードの流れを理解する方法として、
の2つがあるかと思います。
今回は、両方のアプローチを用いて、ソースコードの解析をしていきました。
まず、動的な方法で解析するために、ssjs単体をビルドする方法を調べました。
ソースコードを読んで試行錯誤した結果、以下のコマンドでssjs単体をビルドできることがわかりました。makeの引数に「BUILD_OPT=1」を指定すると、ビルドされるssjsの実行バイナリが最適化されます。
% cd ajaja-build/bin/mozilla/js/src % make -f Makefile.ref BUILD_OPT=1
ちなみに、asp_jsとssjsの実行バイナリの内容は全く同じで、単にハードリンクをしてasp_jsが作られています。(実行バイナリがASPモードとして動作するかどうかの判定は、実行バイナリのファイル名で行っているようです。)
以下のようにすれば、ビルドした実行バイナリの動作確認ができます。(最適化を無効にしてビルドした場合は、Linux_ALL_DBG.OBJディレクトリ以下に実行バイナリが作られます。) 以下の例では、「print("hello")」を評価しています。(print関数は、ssjsのみで利用可能な組み込み関数です。)「quit()」を評価することで、ssjsを終了できます。
% ./Linux_All_OPT.OBJ/js js> print("hello") hello js> quit() %
このようにssjs単体をビルドできるようにした状態で、ソースコードの解析を行っていきました。
動的解析のテクニック
SpiderMonkeyへのパッチ(ajaja-build/bin/ajaja/js.patch)は、パッチを読むと、ajaja-build/bin/mozilla/js/src/js.cに適用されることがわかります。ですので、このjs.cがAJAJAにおいて核になっているソースコードであると予想できます。
ソースコードを読んでいて、プログラムの制御フローを調べたい時は、C言語の標準ライブラリで提供されているprintf関数を使います。プログラムを走らせて動的にソースコードを解析する際に、printf関数は非常に強力な武器になります。
では、js.cの制御フローの中で気になる所にprintf関数でマーキングしていきます。以下は、Process関数とProcessArgs関数の挙動が不明で、いつ制御が帰ってくるのか調べたいという場合のマーキングの例です。
% vim ajaja-build/bin/mozilla/js/src/js.c [...] int main(int argc, char **argv, char **envp) { [...] printf("#1\n"); #ifdef ASP_JS /* init.js */ sprintf(buff, "%s/init.js", JSPATH); Process(cx, glob, buff, JS_FALSE); #endif printf("#2\n"); result = ProcessArgs(cx, glob, argv, argc); printf("#3\n"); [...]
ビルドをして、実行してみます。
% cd ajaja-build/bin/mozilla/js/src % make -f Makefile.ref BUILD_OPT=1 % ./Linux_All_OPT.OBJ/js #1 #2 js> print("hello") hello js> quit() #3 %
この実行結果から、Process関数はすぐに制御を戻してくる一方で、ProcessArgs関数は、シェル内でquit()が評価されるまで制御が戻ってこないことがわかります。この結果からわかるように、ソースコードを単に眺めただけではわかりにくい制御フローが、少しの努力で解析できました。
解析結果
このような動的解析のテックニックと、静的なコードリーディングを通して、Systemモジュールが、実行コンテキストにロードされるまでの制御フローを解析した結果が、以下の図です。青とオレンジの線が制御フローを示しています。
青の線(1)は、ユーザーランドにあるJavaScriptのコードが実行されるまでの制御フローを示しています。init.jsのuse関数に矢印が入っていますが、これは、Process関数によってuse関数がSpiderMonkeyの仮想マシンが解釈可能なAST(抽象木)に変換されると考えられるからです。
オレンジの線(2)は、ユーザーランドにあるJavaScriptのコードで「use('System');」というコードが存在する場合の制御フローです。(1)でSpiderMonkeyの仮想マシンの実行コンテキストに、先ほどのuse関数がロードされているので、use関数の本体が実行可能です。
まだまだ説明不足の所が多くありますが、今回の試みが、Systemモジュールのような共有ライブラリ型(*.so)のモジュールを、自分で書いてみたいという方の何かの役に立てれば幸いです。
Code Reading―オープンソースから学ぶソフトウェア開発技法
- 作者: トップスタジオ,まつもとゆきひろ,平林俊一,鵜飼文敏
- 出版社/メーカー: 毎日コミュニケーションズ
- 発売日: 2004/06/01
- メディア: 単行本
- 購入: 18人 クリック: 550回
- この商品を含むブログ (214件) を見る