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