PHPの実行をPHPのソースコード(C言語)のレベルで見る方法

PHPソースコードを読めばわかるとおりC言語で書いてあります。
そのC言語の中でPHPがどんな処理をしているのかをデバッガであるgdbを用いて見ることができるのでそれを紹介します。まぁ普通のgdbの使い方なんですが:p

ソースをダウンロードしてコンパイル

PHP-5.2.6のソースをダウンロードします。
まず./configureするとのMakefileができます。
このMakefileの中で-gオプションがついていることを確認しましょう。*1

これがデバッガ(gdb)用のオプションで、コンパイルされたバイナリファイルにソースコードとの対応付けができます。

次にmakeします。時間がかかります。

サンプルファイル

makeしている間に次のようなPHPファイルを作成しましょう。

<?php
$i = "12";
$k = intval($i);
?>

これは文字列の"12"をintval関数によってintに換えるというものです。
今回はこの文字列を表す変数がPHPのソース内でどんなデータになっているかを見てみましょう。

ちなみに、このソースを用意した理由はデバッガで途中で止めるときのbreakpointにintval関数を使うことができるからです。
別にintval関数でなくてもかまいません。(PHPはとても大きなプログラムなので1行1行実行していったら時間がいくらあっても足りません。)

intval関数のソース

さて、得に理由もなくbreakpointとしてintval関数を選びました。
そのintval関数のソースを探しましょう。grepコマンドが便利です。

カレントディレクトリからintvalという文字列が入っているファイルの一覧を表示します。
あやしいのはgmp.c、basic_functions.c、type.cあたりです。
実際にファイルを開いていってtype.cにintval関数があることがわかりました。



実行する

gdbを使って実行します。たぶん実行するファイルはsapi/cli/phpっぽいです。makeしたときにこのファイルが目に入ったので:)

上の画像のとおり、type.cというソースファイルの中の、(intval関数の中)161行目でプログラムの実行を止められれば引数であるnumの正体がわかりそうです。

というわけで下の画像のようにgdbを動かします。自分が入力しているのは次の情報です。

  • b type.c:161 type.cの161行目(intval関数の中)にきたら実行を止める
  • hoge.phpを引数としてphpを実行する

(ここでtype.cの161行目で止まる)

  • 止まったときのnumというポインタが指す値を見てみる(zvalという構造体へのポインタのようだ)
  • さらにその先を見てみる(value, refcount, typeなどの値を持つ構造体のようだ)

中に"12"の文字が見えますね。単なる文字列でも、C言語のソースの中ではいりくんだ構造をしているのがわかりますね。

このnumがどんな構造体なのかはzend.hに書いてあります(via hogelog).


ちなみにgdbemacsから使うと便利です。はやみずさんが動画を上げてくれています。
gdbをEmacsから使う動画 - 日記を書く [・w・] はやみずさん
僕はMacのCarbonEmacsが大好きです。




うーん、いつもはgdbの左側にあるソースのバッファにbreakpointのマークと実行している行のマークが出るのだが、今回PHPを扱ったときは出なかった。なんでだろ。うーん。

と、いうわけでphpgdbで動かして内部の構造を知るというエントリでした。まる。*2

*1:デフォルトで-gがついているんですね。不思議ですね.

*2:もしLL futureとかでこういう話をしたら興味がある人はいるんだろうか