How does the perl debugger find the source lines

P

Peter J. Holzer

I'm currently writing a plugin for qpsmtpd, which means that both the
plugin and the tests are read from a file, massaged a bit, compiled via
eval() and finally the test framework calls the test methods.

This seems to confuse the debugger a bit, because it looks like this:

| Qpsmtpd::plugin::run_tests(/home/hjp/wrk/qpsmtpd/t/Test/Qpsmtpd/Plugin.pm:36):
| 36: $plugin->$method();
| DB<2> s
| Qpsmtpd::plugin::no_bcc::pass1(t/plugin_tests/no_bcc:9):
| 9:
| DB<2> n
| Qpsmtpd::plugin::no_bcc::pass1(t/plugin_tests/no_bcc:11):
| 11:
| DB<2> n
| Qpsmtpd::plugin::no_bcc::pass1(t/plugin_tests/no_bcc:12):
| 12:
| DB<2>

The interesting thing is that it shows the correct source file
("t/plugin_tests/no_bcc") and the correct line numbers (9, 11, 12), but
not the contents of the lines, which look like this:

9 my ($self) = @_;
10
11 my $qp = $self->qp;
12 $qp->command("rset");

So, if the debugger knows the file and the line, why can't it display
the content?

hp
 
R

Rainer Weikusat

Ben Morrow said:
Quoth "Peter J. Holzer said:
I'm currently writing a plugin for qpsmtpd, which means that both the
plugin and the tests are read from a file, massaged a bit, compiled via
eval() and finally the test framework calls the test methods.

This seems to confuse the debugger a bit, because it looks like this: [...]

The interesting thing is that it shows the correct source file
("t/plugin_tests/no_bcc") and the correct line numbers (9, 11, 12), but
not the contents of the lines, which look like this:

9 my ($self) = @_;
10
11 my $qp = $self->qp;
12 $qp->command("rset");

So, if the debugger knows the file and the line, why can't it display
the content?

I'll see if I can come up with a more intelligent answer later, but to
start with you might want to read perldoc perl5db.pl (particularly 'DATA
STRUCTURES MAINTAINED BY CORE'), the entry for $^P in perlvar, and
perhaps perldoc perldebguts.

The simple answer seems to be 'because the array perl uses to locate
source lines' (assuming the path to the source file was a/b/c.pl, the
corresponding array would be

@_<a/b/c.pl

in package main) doesn't contain the code.

Example showing how to access that:

,----
| [rw@sable]/tmp#perl -d ab/a.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::(ab/a.pl:1): print 1;
| DB<1> $a = *{"_<ab/a.pl"}{ARRAY}
|
| DB<2> p @$a
| BEGIN { require 'perl5db.pl' };
| print 1;
| print 2;
`----

It is possible to load the source code lines into this array (offsetted
by 1) and the debugger then happily uses it.
Alternatively you might want to find a way to avoid using the debugger.
IME it causes more problems than it solves; for interactive debugging I
find Devel::REPL useful.

"Devel::REPL - a modern perl interactive shell"

As usual, modern means "It prints 'Hello, world!'" but it needs six
order of magnitude more infrastructure code than a simple

perl -e 'print "Hello, World!\n"'

would require" ...
 
P

Peter J. Holzer

Yes. The more interesting question is why they weren't there already; I
don't yet have an answer to that.

I played around with it a bit more, but I am just becoming more
confused. It's not like eval never fills in @{"_<$filename"}. In this
simple test script:

#!/usr/bin/perl
use v5.10;

eval ('
#line 1 "3a"
use v5.10;

sub foo {
say "bla";
}
');

foo();
say;

@{"_<3a"} is filled with the correct lines and I can singlestep into foo().

So, sometimes the lines are there and sometimes they aren't.

I'll try to come up with a minimal script which exhibits the faulty
behaviour.

hp
 
R

Rainer Weikusat

Ben Morrow said:
Quoth Rainer Weikusat <[email protected]>:
[...]
"Devel::REPL - a modern perl interactive shell"

As usual, modern means "It prints 'Hello, world!'" but it needs six
order of magnitude more infrastructure code than a simple

perl -e 'print "Hello, World!\n"'

would require" ...

Yup. It also gets all the hard things right, like running pieces of code
read separately in the same lexical context (or not, as you like).

I've actually casually read through the 'core' of the implementation
which is 123 lines of code and seems to be little more than a wrapper
around Term::Readline (the perl debugger will use that as well if
available) with a moose chained to its ankle because someone considered
that a fashionably pet in 2007. If the author is really convinced to
have solved any 'hard problems' (minus getting his head around the issue
in the first place) in there, I seriously hope that he doesn't ever
encounter a hard problem as this will probably blow a fuse in his head.

OTOH, even the most trivial problem can be made to look very commanding
by a suitably obfuscated solution, eg use

sub wrap_as_sub {
my ($self, $line, %args) = @_;
return qq!sub {\n!. ( $args{no_mangling} ? $line : $self->mangle_line($line) ).qq!\n}\n!;
}

instead of

sprintf('sub { %s }', $args{no_mangling} ? $line : $self->mangle_line($line));

minus any of the fancy features (including sensible handling of
exceptions thrown by the executed code), this is

----------
use Term::ReadLine;

sub run
{
eval($_[0]);
print STDERR ("XX: $@") if $@;
}

my ($term, $line);

$term = Term::ReadLine->new('Perl ERPL');
print(run($line), "\n") while defined($line = $term->readline('Perl ERPL>'));
print("\n");
 
R

Rainer Weikusat

[...]
sub run
{
eval($_[0]);
print STDERR ("XX: $@") if $@;
}

The 2nd line was a 'last second' addition to make this print compiler
errors encountered during eval which eats the return value of the
former. Slightly more complicated demo which deals with that:

----------
sub dorun
{
eval($_[0]);
}

sub run
{
my @r;

@r = &dorun;
return @r unless $@;

print STDERR ("XX: $@");
return;
}
-----------

A supposed-to-be-reusable class providing such a feature should probably
take some more pain in order to provide a clean execution environment
than just using an 'empty sub', eg, it should localize all or at least
some of the global variables affecting execution of Perl code in order
to avoid leaking parts of the 'executor' environment into the executed
code and the same in the opposite direction (especially @_ and $_).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top