Skip to content

Commit 64c8012

Browse files
committed
perl5db.pl: b subname and c subname break on first executable line
This currently doesn't try to handle "b postpone subname" since that internally has an offset function that doesn't really work with this implementation. This is a partial fix for #799
1 parent 097911a commit 64c8012

File tree

2 files changed

+143
-28
lines changed

2 files changed

+143
-28
lines changed

lib/perl5db.pl

Lines changed: 69 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ BEGIN
532532
use vars qw($VERSION $header);
533533

534534
# bump to X.XX in blead, only use X.XX_XX in maint
535-
$VERSION = '1.80';
535+
$VERSION = '1.81';
536536

537537
$header = "perl5db.pl version $VERSION";
538538

@@ -2033,19 +2033,12 @@ sub _DB__handle_c_command {
20332033
# Qualify it to the current package unless it's
20342034
# already qualified.
20352035
$subname = $package . "::" . $subname
2036-
unless $subname =~ /::/;
2036+
unless $subname =~ /::/;
20372037

2038-
# find_sub will return "file:line_number" corresponding
2039-
# to where the subroutine is defined; we call find_sub,
2040-
# break up the return value, and assign it in one
2041-
# operation.
2042-
( $file, $i ) = ( find_sub($subname) =~ /^(.*):(.*)$/ );
2043-
2044-
# Force the line number to be numeric.
2045-
$i = $i + 0;
2038+
my ($file, $line) = eval { subroutine_first_breakable_line($subname) };
20462039

20472040
# If we got a line number, we found the sub.
2048-
if ($i) {
2041+
if ($line) {
20492042

20502043
# Switch all the debugger's internals around so
20512044
# we're actually working with that file.
@@ -2055,22 +2048,13 @@ sub _DB__handle_c_command {
20552048
# Mark that there's a breakpoint in this file.
20562049
$had_breakpoints{$filename} |= 1;
20572050

2058-
# Scan forward to the first executable line
2059-
# after the 'sub whatever' line.
2060-
$max = $#dbline;
2061-
my $_line_num = $i;
2062-
while ($dbline[$_line_num] == 0 && $_line_num< $max)
2063-
{
2064-
$_line_num++;
2065-
}
2066-
$i = $_line_num;
2067-
} ## end if ($i)
2068-
2069-
# We didn't find a sub by that name.
2051+
$i = $line;
2052+
} ## end if ($line)
20702053
else {
2071-
print $OUT "Subroutine $subname not found.\n";
2054+
print $OUT $@;
20722055
next CMD;
20732056
}
2057+
20742058
} ## end if ($subname =~ /\D/)
20752059

20762060
# At this point, either the subname was all digits (an
@@ -5389,6 +5373,65 @@ sub subroutine_filename_lines {
53895373
return (find_sub($subname) =~ /^(.*):(\d+)-(\d+)$/);
53905374
} ## end sub subroutine_filename_lines
53915375

5376+
=head2 subroutine_first_breakable_line(subname)
5377+
5378+
Attempts to find the filename and first breakable line by execution
5379+
order for the subroutine specified by C<subname>.
5380+
5381+
If this isn't possible, such as when debugging with C<miniperl>, finds
5382+
the first breakable line by line order for the subroutine specified by
5383+
C<subname>.
5384+
5385+
Return the filename and breakable line number:
5386+
5387+
my ($file, $line) = subroutine_first_breakable_line(subname);
5388+
5389+
Throws an error message if C<subname> cannot be found or is not
5390+
breakable.
5391+
5392+
=cut
5393+
5394+
sub _first_breakable_via_B {
5395+
my ( $subname ) = @_;
5396+
5397+
my $cv = do {
5398+
no strict "refs";
5399+
*$subname{CODE};
5400+
};
5401+
ref $cv eq "CODE"
5402+
or return;
5403+
5404+
eval { require B; 1 }
5405+
or return;
5406+
5407+
my $bcv = B::svref_2object($cv);
5408+
5409+
$bcv->XSUB
5410+
and die "Cannot break on XSUB $subname\n";
5411+
5412+
for (my $op = $bcv->START; !$op->isa("B::NULL"); $op = $op->next) {
5413+
$op->name eq "dbstate"
5414+
and return ( $op->file, $op->line, $op->line );
5415+
}
5416+
5417+
return;
5418+
}
5419+
5420+
sub subroutine_first_breakable_line {
5421+
my ( $subname ) = @_;
5422+
5423+
my ($file, $line) = _first_breakable_via_B($subname);
5424+
unless ($file) {
5425+
# at the very least this allows miniperl to debug
5426+
( $file, my ($s, $e) ) = subroutine_filename_lines($subname)
5427+
or die "Subroutine $subname not found.\n";
5428+
5429+
$line = breakable_line_in_filename($file, $s, $e);
5430+
}
5431+
5432+
return ($file, $line );
5433+
}
5434+
53925435
=head3 break_subroutine(subname) (API)
53935436
53945437
Places a break on the first line possible in the specified subroutine. Uses
@@ -5401,16 +5444,14 @@ sub break_subroutine {
54015444
my $subname = shift;
54025445

54035446
# Get filename, start, and end.
5404-
my ( $file, $s, $e ) = subroutine_filename_lines($subname)
5405-
or die "Subroutine $subname not found.\n";
5406-
5447+
my ( $file, $line ) = subroutine_first_breakable_line($subname);
54075448

54085449
# Null condition changes to '1' (always true).
54095450
my $cond = @_ ? shift(@_) : 1;
54105451

54115452
# Put a break the first place possible in the range of lines
54125453
# that make up this subroutine.
5413-
break_on_filename_line_range( $file, $s, $e, $cond );
5454+
break_on_filename_line_range( $file, $line, $line, $cond );
54145455

54155456
return;
54165457
} ## end sub break_subroutine

lib/perl5db.t

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3491,6 +3491,80 @@ EOS
34913491
$wrapper->output_like(qr/\bOK\b/, "check the line is IOK");
34923492
}
34933493

3494+
{
3495+
# https://github.com/Perl/perl5/issues/799
3496+
my $prog = <<'EOS';
3497+
sub problem {
3498+
$SIG{__DIE__} = sub {
3499+
die "<b problem> will set a break point here.\n";
3500+
}; # The break point _should_ be set here.
3501+
warn "This line will run even if you enter <c problem>.\n";
3502+
}
3503+
&problem;
3504+
EOS
3505+
3506+
my $wrapper = DebugWrap->new(
3507+
{
3508+
cmds =>
3509+
[
3510+
"b problem",
3511+
"c",
3512+
"q"
3513+
],
3514+
prog => \$prog
3515+
}
3516+
);
3517+
$wrapper->contents_like(qr/The break point _should_/, "break at right place (b)");
3518+
$wrapper->output_unlike(qr/This line will run even if you enter <c problem>\./,
3519+
"didn't run the wrong code (b)");
3520+
3521+
$wrapper = DebugWrap->new(
3522+
{
3523+
cmds =>
3524+
[
3525+
"c problem",
3526+
"q"
3527+
],
3528+
prog => \$prog
3529+
}
3530+
);
3531+
$wrapper->contents_like(qr/The break point _should_/, "break at right place (c)");
3532+
$wrapper->output_unlike(qr/This line will run even if you enter <c problem>\./,
3533+
"didn't run the wrong code (c)");
3534+
3535+
$wrapper = DebugWrap->new(
3536+
{
3537+
cmds =>
3538+
[
3539+
"c unknown",
3540+
"q"
3541+
],
3542+
prog => \$prog
3543+
}
3544+
);
3545+
$wrapper->contents_like(qr/Subroutine main::unknown not found/, "fail to continue to unknown");
3546+
$wrapper->contents_unlike(qr/DB::subroutine_first_breakable_line/,
3547+
"no backtrace for the error message");
3548+
3549+
}
3550+
3551+
{
3552+
my $wrapper = DebugWrap->new(
3553+
{
3554+
cmds =>
3555+
[
3556+
"b B::svref_2object",
3557+
"q"
3558+
],
3559+
prog => \<<'EOS'
3560+
use B;
3561+
print "Hello\n";
3562+
EOS
3563+
}
3564+
);
3565+
$wrapper->contents_like(qr/Cannot break on XSUB B::svref_2object/, "can't break on XSUB");
3566+
}
3567+
34943568
done_testing();
34953569

34963570
END {

0 commit comments

Comments
 (0)