1

デバッグしようとしている Perl (Linux 環境) のかなり複雑なプログラムに問題があります。ここの簡単なスニペットで問題をシミュレートできます ( test.pl):

use warnings;
use strict;
use feature qw/say/;

my @testa = ();
my $numelems = 10000;

# populate array/list of arrays
for (my $ix = 0; $ix < $numelems; $ix++) {
  my @miniarr = ($ix, 1);
  push(@testa, \@miniarr);
}

say "Array is now " . scalar(@testa) . " elements long";

my $BADnumelems = $numelems + 2;
my $sum = 0;

# loop through array/list of arrays
for (my $ix = 0; $ix < $BADnumelems; $ix++) {
  my @minientry = @{$testa[$ix]};
  $sum += $minientry[0];
}

say "Sum of elements is $sum";

このプログラムを実行すると、次のように終了します。

$ perl test.pl 
Array is now 10000 elements long
Can't use an undefined value as an ARRAY reference at test.pl line 22.

だから、今私はそれをデバッグしたいと思います-しかし、エラーによりプログラムが終了し、デバッガーが終了します:

$ perl -d test.pl 

Loading DB routines from perl5db.pl version 1.32
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

main::(test.pl:6):  my @testa = ();
  DB<1> c
Array is now 10000 elements long
Can't use an undefined value as an ARRAY reference at test.pl line 22.
 at test.pl line 22
Debugged program terminated.  Use q to quit or R to restart,
  use o inhibit_exit to avoid stopping after program termination,
  h q, h R or h o to get additional info.  
  DB<1> p $sum

  DB<2> exit
$ 

 

次に、デバッガー (PerlMonks) でブレーク オン ワーニングを見つけました。だから私はこれを追加しようとしました:

...
use feature qw/say/;

$SIG{__DIE__} = sub { my($signal) = @_; say "DIEhandler: $signal"; $DB::single = 1; };
$SIG{__WARN__} = sub { my($signal) = @_; say "WARNhandler: $signal"; $DB::single = 1; };

my @testa = ();
...

...しかし、これもデバッガーを殺します:

$ perl -d test.pl 

Loading DB routines from perl5db.pl version 1.32
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

main::(test.pl:6):  $SIG{__DIE__} = sub { my($signal) = @_; say "DIEhandler: $signal"; $DB::single = 1; };
  DB<1> c
Array is now 10000 elements long
DIEhandler: Can't use an undefined value as an ARRAY reference at test.pl line 25.

Can't use an undefined value as an ARRAY reference at test.pl line 25.
Debugged program terminated.  Use q to quit or R to restart,
  use o inhibit_exit to avoid stopping after program termination,
  h q, h R or h o to get additional info.  

 

さて、問題は、Ctrl-C でプログラムを中断すると、通常、デバッガーがステップ モードに入るということです。たとえば、 を設定my $numelems = 100000000;し、ループ中に Ctrl-C を押すと、次のようにデバッグできます。

$ perl -d test.pl 

Loading DB routines from perl5db.pl version 1.32
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

main::(test.pl:6):  $SIG{__DIE__} = sub { my($signal) = @_; say "DIEhandler: $signal"; $DB::single = 1; };
  DB<1> c
^Cmain::(test.pl:14):     my @miniarr = ($ix, 1);
  DB<1> p $ix
148607
  DB<2> q

これで、ソース perl プログラムにブレーク ポイントを挿入できます。

...
for (my $ix = 0; $ix < $BADnumelems; $ix++) {
  $DB::single = 1;               ### <=== BREAK HERE
  my @minientry = @{$testa[$ix]};
...

しかし、次の場合にループに入ります$ix = 0

$ perl -d test.pl 

Loading DB routines from perl5db.pl version 1.32
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

main::(test.pl:6):  $SIG{__DIE__} = sub { my($signal) = @_; say "DIEhandler: $signal"; $DB::single = 1; };
  DB<1> c
Array is now 10000 elements long
main::(test.pl:26):   my @minientry = @{$testa[$ix]};
  DB<1> p $ix
0
  DB<2> q

...そして、問題のある部分に到達するために 10000 個の要素をステップスルーしたくありません:)

 

それで、私は次のように考えました-Perlスクリプト自体からSIGINT(Ctrl-C)を発生/生成/作成する方法があれば、ダイハンドラーからそれを発生させ、できればステップインを引き起こすことができますプロセスが終了する前にデバッガー。だから、私の質問は次のとおりです。

  • Perl スクリプトから SIGINT を上げることは可能ですか?
  • 前のことが可能である場合、プロセスが終了する前に、ダイ ハンドラから Ctrl-C を使用してデバッガ ステップ モードに入ることができますか?
  • 前のことが不可能dieな場合 - プログラムs の行で、デバッガーのステップ モードに入る必要がある可能性はありますか?
4

2 に答える 2

0

:)これらのおかげで、うまくいきました(ただし、すべてを正しく理解しているかどうかはわかりません):

コードをevalラップで変更するだけで、次のようになりますwarn

...
# loop through array/list of arrays
for (my $ix = 0; $ix < $BADnumelems; $ix++) {
  eval {
    my @minientry;
    @minientry = @{$testa[$ix]};
    $sum += $minientry[0];
  }; # just this causes step into debugger at $ix = 10001
  warn $@ if $@; # this causes step into debugger at $ix=10000 (OK)
}
...

...その後、デバッガは次のように動作します:

$ perl -d test.pl 

Loading DB routines from perl5db.pl version 1.32
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

main::(test.pl:6):  $SIG{__DIE__} = sub { my($signal) = @_; say "DIEhandler: $signal"; @_ = (); $DB::single = 1; };
  DB<1> c
Array is now 10000 elements long
DIEhandler: Can't use an undefined value as an ARRAY reference at test.pl line 27.

main::(test.pl:30):   warn $@ if $@; # this causes step into debugger at $ix=10000 (OK)
  DB<1> p $ix
10000
  DB<2> p @{$testa[$ix]}

  DB<3> p @{$testa[$ix-1]}
99991
  DB<4> p join("--", @{$testa[$ix]})

  DB<5> p join("--", @{$testa[$ix-1]})
9999--1
  DB<6> q

...つまり、私が望んでいた問題のある行に直接入ります。

さて、これが誰かに役立つことを願っています、
乾杯!

編集:関連する可能性もあります: eval を使用する前に $@ をローカライズする必要があるのはなぜですか?

于 2013-02-07T16:43:02.960 に答える
0

$DB::single指定した条件でのみ壊れるように式に設定できます。

...
for (my $ix = 0; $ix < $BADnumelems; $ix++) {

  $DB::single ||= ref($testa[$ix]) ne 'ARRAY';

  my @minientry = @{$testa[$ix]};
  $sum += $minientry[0];
}
...

...
for (my $ix = 0; $ix < $BADnumelems; $ix++) {
  eval {
      my @minientry = @{$testa[$ix]};
      $sum += $minientry[0];
  };
  $DB::single ||= $@; # break if eval block fails
  # give debugger somewhere to break before proceeding to next iteration
  1;
}
...

(実際にそのブロック (またはそのブロックの後のコード) の各反復をステップ実行している場合、Perl は true に設定し$DB::single ||= ...たいので、コードでその値を不注意に設定解除して防止したくないためです)コードの他の行をステップ実行する必要はありません。)$DB::single = ...$DB::single

于 2013-02-07T17:04:41.537 に答える