- 八雲アナグラ(@AnaTofuZ)
- (3月まで)沖縄の(3月まで)学生
- Perlで修論を通した
- 4月からは社会に放出されます
- 本州にも放出されます
- Perl処理系をよむRTA
- RTAなのでターミナルで進行します
- 詳細が気になる方は昨年のアドベントカレンダーに投稿したブログをどうぞ!
- C言語で実装されている
- Cが読めれば読める(それはそう)
- GitHubでCのソースコードを読むのはつらい
- 処理をトレースしながら読むと読みやすい
- どこのご家庭にもあるPerl5のソースコード
- デバッグビルドをする必要がある
- C言語のデバッガ
- macOS
- lldb
- linux
- gdb
- macOS
- いい感じのgrep & findツール
- 個人的にはRust制ツール
- ripgrep
- fd
- 個人的にはRust制ツール
- 最近入った連鎖比較(Chained comparisons)!!
- こういうやつ
if ( 10 < $n <= 20 ) {...}
- まずConfigureを実行する
./Configure -DDEBUGGING=-g -Doptimize=-O0 -de -Dusedevel -Dversiononly
-
-DDEBUGGING=-g
-g
でCデバッガでデバッグ可能なバイナリを生成
-
-Doptimize=-O0
- 最適化を無効
-
-de
- Configureの対話処理をスキップ
-
Dusevel
- 安定番じゃなくてもビルドできるようにするおまじない
- 新鮮なPerl5をビルドするときに必須
-
あとは気合
$make -j
$make install
-rw-r--r-- 1 anatofuz anatofuz 2600992 Feb 19 17:11 regcomp.o
-rwxr-xr-x 1 anatofuz anatofuz 6464640 Feb 19 17:11 miniperl*
-rw-r--r-- 1 anatofuz anatofuz 280024 Feb 19 17:11 perl.o
-rw-r--r-- 1 anatofuz anatofuz 46320 Feb 19 17:11 DynaLoader.o
-rw-r--r-- 1 anatofuz anatofuz 10025810 Feb 19 17:11 libperl.a
drwxr-xr-x 64 anatofuz anatofuz 4096 Feb 19 17:11 lib/
-rw-r--r-- 1 anatofuz anatofuz 550 Feb 19 17:12 extra.pods
drwxr-xr-x 2 anatofuz anatofuz 12288 Feb 19 17:12 pod/
drwxr-xr-x 2 anatofuz anatofuz 4096 Feb 19 17:12 utils/
-rw-r--r-- 1 anatofuz anatofuz 4722 Feb 19 17:12 perlmain.c
-rw-r--r-- 1 anatofuz anatofuz 15256 Feb 19 17:12 perlmain.o
-rwxr-xr-x 1 anatofuz anatofuz 6592080 Feb 19 17:12 perl*
#!/usr/bin/env perl
if (0 < $ARGV[0] < 10 ) {
print "true!\n";
}
- 一種のアセンブラみたいなものに変換して実行している
- バイトコードインタプリタ
- プロセスVMとも
Perlの内部命令 == Cの関数
に対応している
- B::Terseを使うと見やすい
- この命令はCだと
Perl_pp_
+ 命令名の関数になるPerl_pp_const
Perl_pp_cmpchain_dup
- この命令はCだと
$./perl -MO=Terse,-exec,-src japanpm.pl
OP (0x5625eefc80a0) enter
# 2: if (0 < $ARGV[0] < 10 ) {
COP (0x5625eefc8110) nextstate
SVOP (0x5625eefc6388) const IV (0x5625eefbe4e8) 0
SVOP (0x5625eefc6350) aelemfast GV (0x5625eefbdea0) *ARGV
UNOP (0x5625eefc83a0) cmpchain_dup
BINOP (0x5625eefc6260) lt
LOGOP (0x5625eefc8330) cmpchain_and
SVOP (0x5625eefc6228) const IV (0x5625eefbe650) 10
BINOP (0x5625eefc61e8) lt
LOGOP (0x5625eefc81a8) and
OP (0x5625eefc82c8) pushmark
SVOP (0x5625eefc82f8) const PV (0x5625eefbe5a8) "true!\n"
LISTOP (0x5625eefc8288) print
LISTOP (0x5625eefc80d0) leave [1]
- 引数与えて実行
$gdb --args ./perl japanpm.pl
- grepしながらそれっぽいのを探す
PP()
はマクロ
Perl_pp_
+ 命令名の関数で止める- いったんmainくらいまで動かすとロード可能になる
- svtypeでキャストして0xffとANDをとるとなんか数値が出る
- ここで
sv.h
を見る - 実態はenumで定義しているPerlの内部型の番号
- ここで
(gdb) p ((svtype)(right)->sv_flags & 0xff)
$23 = 0
(gdb) p ((svtype)(left)->sv_flags & 0xff)
$21 = 1
- 0はNULLの値
- Perlの内部だと0系は特別扱いしているっぽい
(gdb) p (svtype)*left
$19 = 1436120072
(gdb) p (svtype)*right
$20 = SVt_NULL
p *(XPVIV*)right->sv_any
とかすると見える- 興奮しますね
- Perlは内部命令をするときに必要なデータをスタックにいれる
- popとかpushとかの操作で各命令で出し入れする
- スタックポインタspで操作できる
@sp
みたいな感じ
(lldb) p *(XPVIV*)(*(sp))->sv_any
- spから1を引くと、スタックの中身をたどっていける
(lldb) p *(XPVIV*)(*(right)).sv_any
(XPVIV) $35 = {
xmg_stash = 0x0000800900000004
xmg_u = {
xmg_magic = 0x0000000101204340
xmg_hash_index = 4313858880
}
xpv_cur = 4320283672
xpv_len_u = {
xpvlenu_len = 18695992639489
xpvlenu_rx = 0x0000110100000001
}
xiv_u = {
xivu_iv = 5
xivu_uv = 5
xivu_namehek = 0x0000000000000005
xivu_eval_seen = true
}
}
(lldb) p *(XPVIV*)(*(left)).sv_any
(XPVIV) $36 = {
xmg_stash = 0x0000110100000001
xmg_u = {
xmg_magic = 0x0000000000000005
xmg_hash_index = 5
}
xpv_cur = 4320283696
xpv_len_u = {
xpvlenu_len = 576760923272773633
xpvlenu_rx = 0x0801110100000001
}
xiv_u = {
xivu_iv = 1
xivu_uv = 1
xivu_namehek = 0x0000000000000001
xivu_eval_seen = true
}
}
-
leftには1, rightには5が入っています。
-
そしてスタックポインタspの値を確認します。
(lldb) p *(XPVIV*)(*(sp))->sv_any
(XPVIV) $38 = {
xmg_stash = 0x0000110100000001
xmg_u = {
xmg_magic = 0x0000000000000005
xmg_hash_index = 5
}
xpv_cur = 4320283696
xpv_len_u = {
xpvlenu_len = 576760923272773633
xpvlenu_rx = 0x0801110100000001
}
xiv_u = {
xivu_iv = 1
xivu_uv = 1
xivu_namehek = 0x0000000000000001
xivu_eval_seen = true
}
}
(lldb) p *(XPVIV*)(*(sp-1))->sv_any
(XPVIV) $40 = {
xmg_stash = 0x0000800900000004
xmg_u = {
xmg_magic = 0x0000000101204340
xmg_hash_index = 4313858880
}
xpv_cur = 4320283672
xpv_len_u = {
xpvlenu_len = 18695992639489
xpvlenu_rx = 0x0000110100000001
}
xiv_u = {
xivu_iv = 5
xivu_uv = 5
xivu_namehek = 0x0000000000000005
xivu_eval_seen = true
}
}
(lldb) p *(XPVIV*)(*(sp-2))->sv_any
error: Couldn't apply expression side effects : Couldn't dematerialize a result variable: couldn't read its memory
つまり現在spとleftは同じ場所を刺しており、sp-1の箇所に5があります。 perlで書くと 現在のスタックは(5, 1)という感じでしょうか。
ちなみにfreeしていないので、spに1を足すと、rightが見れます。
(lldb) p *(XPVIV*)(*(sp+1))->sv_any
(XPVIV) $42 = {
xmg_stash = 0x0000800900000004
xmg_u = {
xmg_magic = 0x0000000101204340
xmg_hash_index = 4313858880
}
xpv_cur = 4320283672
xpv_len_u = {
xpvlenu_len = 18695992639489
xpvlenu_rx = 0x0000110100000001
}
xiv_u = {
xivu_iv = 5
xivu_uv = 5
xivu_namehek = 0x0000000000000005
xivu_eval_seen = true
}
}
ここで処理を進めてみます。
(lldb) n
Process 7847 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = step over
frame #0: 0x00000001001bb193 perl`Perl_pp_lt at pp.c:2073:5
2070 flags_and = SvFLAGS(left) & SvFLAGS(right);
2071 flags_or = SvFLAGS(left) | SvFLAGS(right);
2072
-> 2073 SETs(boolSV(
2074 ( (flags_and & SVf_IOK) && ((flags_or & SVf_IVisUV) ==0 ) )
2075 ? (SvIVX(left) < SvIVX(right))
2076 : (flags_and & SVf_NOK)
Target 0: (perl) stopped.
(lldb) n
Process 7847 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = step over
frame #0: 0x00000001001bb26d perl`Perl_pp_lt at pp.c:2080:5
2077 ? (SvNVX(left) < SvNVX(right))
2078 : (do_ncmp(left, right) == -1)
2079 ));
-> 2080 RETURN;
2081 }
2082
2083 PP(pp_gt)
Target 0: (perl) stopped.
なにか計算が行われ、結果をRETURNするとこになりました。 この次点でのスタックの中身を確認します。
(lldb) p *(XPVIV*)(*(sp))->sv_any
(XPVIV) $22 = {
xmg_stash = 0x0000000000000000
xmg_u = {
xmg_magic = 0x0000000000000000
xmg_hash_index = 0
}
xpv_cur = 1
xpv_len_u = {
xpvlenu_len = 0
xpvlenu_rx = 0x0000000000000000
}
xiv_u = {
xivu_iv = 1
xivu_uv = 1
xivu_namehek = 0x0000000000000001
xivu_eval_seen = true
}
}
(lldb) p *(XPVIV*)(*(sp-1))->sv_any
(XPVIV) $23 = {
xmg_stash = 0x0000800900000004
xmg_u = {
xmg_magic = 0x0000000101804cb0
xmg_hash_index = 4320152752
}
xpv_cur = 4328597528
xpv_len_u = {
xpvlenu_len = 18695992639489
xpvlenu_rx = 0x0000110100000001
}
xiv_u = {
xivu_iv = 5
xivu_uv = 5
xivu_namehek = 0x0000000000000005
xivu_eval_seen = true
}
}