php-src debug マニュアル
by
onopon
Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
php-src debug マニュア PHPerKaigi 2024 おのぽん @onopon_engineer
Slide 2
Slide 2 text
X(旧Twitter)への投稿は、 #phperkaigi #a とつけていただけると嬉しいです! 2 はじめに
Slide 3
Slide 3 text
自己紹介 株式会社ウエディングパーク Photorait 本部 おのぽん(@onopon_engineer) ・2022年6月にウエディングパークに入社 ・前職では - 大規模ソーシャ ゲームのサーバエンジニア - 人工知能コミュニケーション ボットのサーバ全般 - Androidアプ 開発 を行い、業務でのPHP開発は未経験 ・エンジニア以外の時は大体卓球をしています🏓 ・パ 卓球選手のコーチもしており、 今年のパ パ ンピックでの活躍を目指し日々奮闘中 ・今月末もポー ンドに行ってきます😇 3
Slide 4
Slide 4 text
Photorait 全国のフォトウエディング・前撮りの撮影スタジオ・サ ン情報と共にクチコミを掲載している 日本最大級のフォトウエディング専門クチコミ情報サイト 4
Slide 5
Slide 5 text
5 本セッションを楽しんでいただくにあたり
Slide 6
Slide 6 text
6 右下にやる気ゲージが出てくることがあります。 本セッションを楽しんでいただくにあたり
Slide 7
Slide 7 text
7 ゲージがMaxに近づくほど、 僕のphp-srcを読みたい欲も上昇し 本セッションを楽しんでいただくにあたり
Slide 8
Slide 8 text
8 ゲージが0に近づくほど、僕の心は折れかけています。 本セッションを楽しんでいただくにあたり
Slide 9
Slide 9 text
9 どうぞ最後までお付き合い願います!!
Slide 10
Slide 10 text
10 php-srcのデバッグ環境を整え、適切にブ ークポイントを仕込めるようになろう! 本セッションのゴー
Slide 11
Slide 11 text
11 ここ半年間での僕の周りの出来事
Slide 12
Slide 12 text
12 phpで気になる挙動を発見しました。
Slide 13
Slide 13 text
13 突然ですが、問題です。 explode(',', '1,2'); を実行すると [1,2] が返ってきます。 では、 explode(',', ''); の返り値は次の3つのうちどれでしょうか? A: [] B: [''] C: [null]
Slide 14
Slide 14 text
14 突然ですが、問題です。 A: [] B: [''] C: [null] explode(',', '1,2'); を実行すると [1,2] が返ってきます。 では、 explode(',', ''); の返り値は次の3つのうちどれでしょうか?
Slide 15
Slide 15 text
15 ちゃまほりさんがwphpconの場で「php-src読もうよ!」と言っていたり
Slide 16
Slide 16 text
16 てきめんさんの作った関数がAcceptされたり
Slide 17
Slide 17 text
17 周りの尊敬するエンジニアさんはみんなphp-srcを読める! 僕も読めるようになりたい!
Slide 18
Slide 18 text
18 そもそもphp-srcって何だ?
Slide 19
Slide 19 text
19 phpファイ が動く簡単な流れ PHPのサイトにアクセス。
Slide 20
Slide 20 text
20 phpファイ が動く簡単な流れ PHPのサイトにアクセス。 アクセスされたPHPテキス トファイ 。 PHPerが好んで書くもの。
Slide 21
Slide 21 text
21 phpファイ が動く簡単な流れ Hello, world! PHPのサイトにアクセス。 アクセスされたPHPテキス トファイ 。 PHPerが好んで書くもの。 PHPテキストを解読し、適 切な振る舞いを行う。 アウトプット
Slide 22
Slide 22 text
22 このソースコードの ポジト 名こそがphp-src
Slide 23
Slide 23 text
23 php-srcはC言語から構成されている Hello, world! https://github.com/php/php-src テストするためにはbuildする必要がある
Slide 24
Slide 24 text
24 さっそくphp-srcを入れてbuildしてみよう! macでもできるかな😇
Slide 25
Slide 25 text
25 とりあえず調べながらやってみよう!
Slide 26
Slide 26 text
26 「php-src ビ ド mac」で検索 brew install hoge × n あれ、installうまくいかないぞ・・・ エ ー解消方法検索しないと😇 ./configure コマンドが通らない・・・ path指定やオプションが必要なのか。。 make -j4 成功してくれ・・・
Slide 27
Slide 27 text
27 build成功・・・!make test実行だ!!
Slide 28
Slide 28 text
28
Slide 29
Slide 29 text
29
Slide 30
Slide 30 text
30
Slide 31
Slide 31 text
31
Slide 32
Slide 32 text
32
Slide 33
Slide 33 text
33 ビ ドで詰んだ
Slide 34
Slide 34 text
34 あれ、ひょっとして僕以外にもphp-srcのビ ドに挑戦して諦めた方いるのでは?
Slide 35
Slide 35 text
35 初心者でもphp-buildでつまづかない未来を作ろう
Slide 36
Slide 36 text
36 Hello, php_build_environment
Slide 37
Slide 37 text
37 https://github.com/onopon/php_build_environment onopon php_build_environment
Slide 38
Slide 38 text
38 php_build_environment でphp-srcをデバッグする環境を整える手順 ● Docker をインストー する ● Visual Studio Codeをインストー する ● php_build_environment をcloneする ● php_build_environment 内にある initial_run.sh を実行する ○ sh ./initial_run.sh 以上。
Slide 39
Slide 39 text
39 initial_run.sh により行われること ● php-src のclone(ブ ンチはmaster) ● デバッグ用のdockerコンテナ「sandbox」の構築 ● sandbox上でphp-srcのbuild ● php-srcに ○ テスト用のファイ test.phpとast_parse_test.phpを設置 ■ 後ほど解説 ○ .vscode ディ クト を設置
Slide 40
Slide 40 text
40 sandbox コンテナについて ● コンテナのベースは ubuntu: 23.10 ● 必要なミド ウェアをインストー ○ デバッグに必要なgdbを利用可能な状態に ○ php-astもこのタイミングでインストー ● volume: php_build_environment 配下 ○ なので、php-srcのファイ をコンテナ外から書き換えても大丈夫
Slide 41
Slide 41 text
41 実際にデバッグ環境を整えてみよう
Slide 42
Slide 42 text
42 sh ./initial_run.sh を実行 ● 10分以上かかるので気長に待つ
Slide 43
Slide 43 text
43 Visual Studio Codeで開いてみよう モート エクスプ ー ーを選択
Slide 44
Slide 44 text
44 Visual Studio Codeで開いてみよう 開発コンテナーの中にいるphp_build_environment sandboxをアタッチ
Slide 45
Slide 45 text
45 test.php を実行してみよう デバッグ コンソー にHOGEと出力される
Slide 46
Slide 46 text
46 ast_parse_test.php を実行してみよう ast\Nodeがdumpされる
Slide 47
Slide 47 text
47 よし!いざデバッグするぞ!
Slide 48
Slide 48 text
48 ・・・と思ったけどphpの内部のある程度の流れを知らないとまた詰みそう
Slide 49
Slide 49 text
49 phpの大まかな流れ
Slide 50
Slide 50 text
50 phpファイ が動く簡単な流れ Hello, world! PHPのサイトにアクセス。 アクセスされたPHPテキス トファイ 。 PHPerが好んで書くもの。 PHPテキストを解読し、適 切な振る舞いを行う。 アウトプット
Slide 51
Slide 51 text
51 この時にPHPが行っていること SAPI = Zend Engineを呼び出すためのインターフェース (mod_php, php-fpm, cli etc…) Zend Engine:PHP スク プトを実行するエンジン ・スク プトを解析してAST化 ・ASTからOpcodeを生成 ・Opcodeより適切なHandlerを呼び出す アウトプット
Slide 52
Slide 52 text
52 この時にPHPが行っていること SAPI = Zend Engineを呼び出すためのインターフェース (mod_php, php-fpm, cli etc…) Zend Engine:PHP スク プトを実行するエンジン ・スク プトを解析してAST化 ・ASTからOpcodeを生成 ・Opcodeより適切なHandlerを呼び出す アウトプット この辺りをおさえれば デバッグできそう
Slide 53
Slide 53 text
SAPI = Zend Engineを呼び出すためのインターフェース (mod_php, php-fpm, cli etc…) Zend Engine:PHP スク プトを実行するエンジン ・スク プトを解析してAST化 ・ASTからOpcodeを生成 ・Opcodeより適切なHandlerを呼び出す アウトプット この辺りをおさえれば デバッグできそう AST この時にPHPが行っていること 53
Slide 54
Slide 54 text
54 ASTとは Abstract Syntax Tree(抽象構文木)の略。 Syntax Tree(構文木)から言語の意味に関係ある情報のみを取り出した木構造の木のこと。 https://ja.wikipedia.org/wiki/%E6%8A%BD%E8%B1%A1%E6%A7%8B%E6%96%87%E6%9C%A8
Slide 55
Slide 55 text
55 Syntax Tree → Abstract Syntax Tree echo("HOGE"); echo ( "HOGE" ) ; Source Code Syntax Tree Abstract Syntax Tree echo "HOGE"
Slide 56
Slide 56 text
56 ZendEngineでのAST typedef uint16_t zend_ast_kind; typedef uint16_t zend_ast_attr; struct _zend_ast { zend_ast_kind kind; /* Type of the node (ZEND_AST_* enum constant) */ zend_ast_attr attr; /* Additional attribute, use depending on node type */ uint32_t lineno; /* Line number */ zend_ast *child[1]; /* Array of children (using struct hack) */ }; Zend/zend_ast.h
Slide 57
Slide 57 text
57 ZendEngineでのAST typedef uint16_t zend_ast_kind; typedef uint16_t zend_ast_attr; struct _zend_ast { zend_ast_kind kind; /* Type of the node (ZEND_AST_* enum constant) */ zend_ast_attr attr; /* Additional attribute, use depending on node type */ uint32_t lineno; /* Line number */ zend_ast *child[1]; /* Array of children (using struct hack) */ }; Zend/zend_ast.h kind: astの種類 attr: 付属情報 lineno: 行番号 child: 子ノード kindとchildだけ抑えれば一旦大丈夫
Slide 58
Slide 58 text
58 echo("HOGE"); をast解析すると、 ast\Nodeがdumpされる
Slide 59
Slide 59 text
59 echo("HOGE"); をast解析すると、 kind:132(???) kind:283(???) "HOGE" children[0] children[0]
Slide 60
Slide 60 text
60 kind(=astの種類)はenumで宣言されている Zend/zend_ast.h の _zend_ast_kind にてenumで宣言されているが、ぱっと見わかりづらい Visual Studioの場合、カーソ を当ててみるとintで値が表示される
Slide 61
Slide 61 text
61 echo("HOGE"); をast解析すると、 kind:132(ZEND_AST_STMT_LIST) kind:283(ZEND_AST_ECHO) "HOGE" children[0] children[0]
Slide 62
Slide 62 text
62 Zend/zend_compile.c の zend_compile_stmt メソッド内にある switch (ast->kind) { ast→opcodeのbreak point Step in
Slide 63
Slide 63 text
SAPI = Zend Engineを呼び出すためのインターフェース (mod_php, php-fpm, cli etc…) Zend Engine:PHP スク プトを実行するエンジン ・スク プトを解析してAST化 ・ASTからOpcodeを生成 ・Opcodeより適切なHandlerを呼び出す アウトプット この辺りをおさえれば デバッグできそう Opcode この時にPHPが行っていること 63 Handler
Slide 64
Slide 64 text
64 Opcodeとは プ セッサが実行する操作に関する命令コードのこと https://ja.wikipedia.org/wiki/%E3%82%AA%E3%83%9A%E3%82%B3%E3%83%BC%E3%83%89
Slide 65
Slide 65 text
65 PHPのOpcodeはopcacheモジュー のデバッグの設定をすると確認できる $ sapi/cli/php\ -d opcache.opt_debug_level=0x10000\ -d opcache.enable_cli\ -d zend_extension=$(pwd)/modules/opcache.so\ test.php Visual Codeでデバッグすると下記が実行される
Slide 66
Slide 66 text
66 PHPのOpcodeはopcacheモジュー のデバッグ実行時 $_main: ; (lines=2, args=0, vars=0, tmps=0) ; (before optimizer) ; /src/php-src/test.php:1-2 ; return [] RANGE[0..0] 0000 ECHO string("HOGE") 0001 RETURN int(1)
Slide 67
Slide 67 text
67 PHPのOpcodeはopcacheモジュー のデバッグ実行時 $_main: ; (lines=2, args=0, vars=0, tmps=0) ; (before optimizer) ; /src/php-src/test.php:1-2 ; return [] RANGE[0..0] 0000 ECHO string("HOGE") 0001 RETURN int(1)
Slide 68
Slide 68 text
68 0000 ECHO string("HOGE") Opcode OPType
Slide 69
Slide 69 text
69 Opcodeの名前がHandlerとして利用される zend/zend_vm_execute.h で zend_execute メソッドが実行され、 opcodeに対応するhandlerメソッドが呼ばれる handlerは、 ZEND_{OPCODE_NAME}_SPEC_{OP_TYPE}_HANDLER ZEND_{OPCODE_NAME}_SPEC_{OP1_TYPE}_{OP2_TYPE}_HANDLER のようなメソッド名で用意されている
Slide 70
Slide 70 text
70 echoメソッドのhandlerは3つ用意されている(挙動はほとんど変わらない) echo("HOGE"); echo("HO"."GE"); ZEND_ECHO_SPEC_CONST_HANDLER デバッグ出力 0000 ECHO string("HOGE") 0001 RETURN int(1) $var = "HOGE"; echo($var); ZEND_ECHO_SPEC_CV_HANDLER デバッグ出力 0000 ASSIGN CV0($var) string("HOGE") 0001 ECHO CV0($var) 0002 RETURN int(1) $ho = "HO"; echo($ho."GE"); ZEND_ECHO_SPEC_TMPVAR_HANDLER デバッグ出力 0000 ASSIGN CV0($ho) string("HO") 0001 T2 = CONCAT CV0($ho) string("GE") 0002 ECHO T2 0003 RETURN int(1)
Slide 71
Slide 71 text
71 今回の例では ZEND_ECHO_SPEC_CONST_HANDLER にbreak point OP Typeがわからなくても、ZEND_ECHO_ で検索すればとりあえず見つかる
Slide 72
Slide 72 text
72 これでデバッグできるぞ!!
Slide 73
Slide 73 text
73 php-srcのデバッグ環境を整え、適切にブ ークポイントを仕込めるようになろう! 本セッションのゴー
Slide 74
Slide 74 text
74 まとめ ● php_src_environment を用意し、デバッグ環境を整備 ○ https://github.com/onopon/php_build_environment ● PHPはスク プトをAST化→OPCodeを生成→Handlerの呼び出しにより実行される ○ ast_parse_test.php によりast構造を確認できる ○ Zend/zend_compile.c の zend_compile_stmt メソッドにブ ークポイントを貼れ ばAST化後の流れを追える ○ Zend/zend_vm_execute.h 内で ZEND_{Opcode} と検索するとHandlerを見つ けることができる ■ そこにブ ークポイントを貼れば振る舞いの流れを追える onopon php_build_environment
Slide 75
Slide 75 text
75 ご清聴ありがとうございました!
Slide 76
Slide 76 text
76 Appendix
Slide 77
Slide 77 text
77 本資料作成にあたり参考にさせていただいた記事 php-srcを読んでみよう by 田実 誠 https://fortee.jp/phpcon-2022/proposal/1addf51d-6f72-4c96-9337-034ec6cc0643 PHPのOpcodeを 読んでみよう https://speakerdeck.com/yasuaki640/phpnoopcodewo-du-ndemiyou PHP AST 徹底解説 https://www.slideshare.net/do_aki/php-ast php-src の歩き方 https://www.slideshare.net/do_aki/phpsrc php and sapi and zendengine2 and... https://www.slideshare.net/do_aki/php-and-sapi-and-zendengine2-and PHP と SAPI と ZendEngine3 と https://www.slideshare.net/do_aki/php-sapi-zendengine3 [php-src読書録]その1: CLI実行からスク プト実行まで https://blog.freedom-man.com/php_src_1 深入理解Zend执行引擎(PHP5) https://gywbd.github.io/posts/2016/2/zend-execution-engine.html How PHP engine builds AST https://dev.to/mrsuh/how-php-engine-builds-ast-1nc4 How to dump and inspect PHP OPCodes https://php.watch/articles/php-dump-opcodes
Slide 78
Slide 78 text
78 ZEND_ECHO_SPEC_CONST_HANDLER
Slide 79
Slide 79 text
79 ZEND_ECHO_SPEC_CV_HANDLER
Slide 80
Slide 80 text
80 ZEND_ECHO_SPEC_TMPVAR_HANDLER