考えられる方法の1つは、を使用することgdb
です。
まず、perlインタープリターのデバッグシンボルが必要です。たとえば、私のDebianシステムでは、このためのperl-debug
パッケージをインストールする必要がありました。インストール後、/usr/lib/debug/usr/bin/perl
これを後でgdbに渡します。元のスタックしたPerlスクリプトは/usr/bin/perl
、新しくインストールされたデバッグバージョンではなく、を使用して開始されたことに注意してください。
この例のために、このPerlスクリプトを実行してみましょう。
$ cat test.pl
#! /usr/bin/perl
use strict;
use warnings;
print "pid: ", $$, "\n";
while (1) {
print "line ", __LINE__, "\n"; sleep 1;
print "line ", __LINE__, "\n"; sleep 1;
}
実行すると、次のような出力が得られます。
$ ./test.pl
pid: 15764
line 9
line 10
line 9
line 10
^C
それでは、gdbを起動しましょう。現在実行中のtest.plによって印刷されたpidを使用します。いくつかの初期情報(「...から記号を読み取る」)の後にプロンプトが表示されます。
$ gdb /usr/lib/debug/usr/bin/perl 15809
[snip]
(gdb)
その間、gdbをperlインタープリターに接続しているため、perlは停止します。
$ ./test.pl
pid: 15809
line 9
line 10
[snip]
line 9
line 10
line 9
[no further output]
それでは、バックトレースのためにgdbに戻りましょう。
(gdb) backtrace
#0 0x00007fd5b4479830 in __nanosleep_nocancel () at ../sysdeps/unix/syscall-template.S:82
#1 0x00007fd5b44796c0 in __sleep (seconds=<optimized out>) at ../sysdeps/unix/sysv/linux/sleep.c:138
#2 0x00007fd5b4efc1e2 in Perl_pp_sleep (my_perl=0x1a91010) at pp_sys.c:4586
#3 0x00007fd5b4ea89b6 in Perl_runops_standard (my_perl=0x1a91010) at run.c:41
#4 0x00007fd5b4e4a585 in S_run_body (oldscope=1, my_perl=0x1a91010) at perl.c:2350
#5 perl_run (my_perl=0x1a91010) at perl.c:2268
#6 0x0000000000400f89 in main (argc=2, argv=0x7fff4de87628, env=0x7fff4de87640) at perlmain.c:120
おそらく、perlはsleep()の途中でたまたま停止しました。しかし、どれですか?
次に、現在実行中の(Perl)ソースファイルと行でperlの内部情報を探す場所を特定する必要があります。もともと私はmod_perlのdoumentationにいくつかの関連情報を見つけました。curinfo
そこにあるマクロを探してください。
(gdb) p my_perl->Icurcop->cop_file
$1 = 0x1abd810 "./test.pl"
(gdb) p my_perl->Icurcop->cop_line
$2 = 9
ご覧のとおり、test.plの9行目です。スクリプトの出力に基づいて予想どおりです。
リンクされたドキュメントには、スレッド化された/スレッド化されていないperlバイナリに関するいくつかの違いが記載されています(上記の例は、スレッド化されたperl、v5.14.2用です)。について話しているので、少し時代遅れに見えますが、my_perl->Tcurcop
私が探していたものを。という名前で見つけましたmy_perl->Icurcop
。現時点では、perlの内部に精通していないため、名前が変更された理由がわかりません。
これがお役に立てば幸いです。