Camelcade / Devel-Camelcadedb

Perl module for debugging with Perl5 plugin for IntelliJ
Other
23 stars 9 forks source link

Can't set breakpoints in code loaded via eval that contains #line directives #34

Open mbarbon opened 6 years ago

mbarbon commented 6 years ago

Devel::Camelcade version 2017.100.3

I can reproduce this issue when using ModPerl::Registry. I do not have a simple test case yet, but hopefully the description below is enough for you to understand the issue.

Some context: ModPerl::Registry compiles and caches CGI scripts under mod_perl for faster execution. For example this script:

#!/usr/bin/env perl

print "Content-Type: text/plain\n";
print "\n";
print "Hello, world!\n";

is converted to

package ModPerl::ROOT::ModPerl::RegistryBB::home_mattia_devel_dbgp_apache2_2dcamelcadedb_t_htdocs_registrybb_cgi_2epl;sub handler {local $0 = '/home/mattia/devel/dbgp/apache2-camelcadedb/t/htdocs/registrybb/cgi.pl';
#line 1 /home/mattia/devel/dbgp/apache2-camelcadedb/t/htdocs/registrybb/cgi.pl
#!/usr/bin/env perl

print "Content-Type: text/plain\n";
print "\n";
print "Hello, world!\n";

}

and loaded via eval STRING.

From my debugging, the issue is that Perl does not call DB::postponed for code loaded via eval STRING, so there is no mapping for the file in %_paths_to_perl_file_id_map, and the breakpoint is silently ignored.

hurricup commented 6 years ago

As far as I can say this may be fixed with http://search.cpan.org/~hurricup/Devel-Camelcadedb/lib/Devel/Camelcadedb.pod#TEMPLATE_ENGINES_INTEGRATION

akjohnston commented 6 years ago

Hi, Is there any chance that we can update the plugin so that this is fixed directly and debugging will work with code loaded using ModPerl::Registry or ModPerl::RegistryBB?

I have been asked to help support an existing system, and fundamentally changing the source code to make debugging work is not an option. Mattia (@mbarbon) has done great work writing a wrapper which just loads via the apache .conf files, but it doesn't work on our source because of the problem he has reported.

Please could someone look at the plugin and see if we can design a proper fix which doesn't require me to change our Perl source? I am very happy to help in any way I can, but although I'm an experienced developer in other languages I'm a newbie to Perl and I can't tackle this directly myself.

Thanks Andrew

hurricup commented 6 years ago

Doubt it can be fixed on the debugger side. Because we are talking about arbitrary changing of line numbers by the module and compilation of file form unknown source. I can imagine few hacks, but I believe this is not a good way.

hurricup commented 6 years ago

In default case ModPerl::RegistryCooker::convert_script_to_compiled_handler should be patched according to the manual above. It should notify debugger after compile()

akjohnston commented 6 years ago

I'm trying to develop a new version of ModPerl::Registry as instructed, but I'd appreciate a check on what I'm doing. I have created a new version which subclasses RegistryCooker and overrides convert_script_to_compiled_handler. That contains the following section:

` my $base = File::Basename::basename($self->{FILENAME}); my $nph = substr($base, 0, 4) eq 'nph-' ? '$_[0]->assbackwards(1);' : ""; my $script_name = $self->get_script_name || $0;

my $eval = join '',
    'package ',
    $self->{PACKAGE}, ";",
    "sub handler {",
    "local \$0 = '$script_name';",
    $nph,
    $shebang,
    $line,
    ${ $self->{CODE} },
    "\n}"; # last line comment without newline?

$rc = $self->compile(\$eval);
return $rc unless $rc == Apache2::Const::OK;
$self->debug(qq{compiled package \"$self->{PACKAGE}\"}) if DEBUG & D_NOISE;`

I think I have to modify this as follows, but I'm really not 100% sure:

` my $eval = join '', 'package ', $self->{PACKAGE}, ";", "sub handler {", "local \$0 = '$script_name';", $nph, $shebang, $line, ${ $self->{CODE} }, "\n}"; # last line comment without newline?

$rc = $self->compile(\$eval);

# IntelliJ debug support
{
    no strict 'refs';
    my $glob = *{'::DB::template_handler'};

    if ($glob && *{$glob}{CODE})
    {
        *{$glob}{CODE}->($self->{FILENAME}, $line);
    }
}
# end debg support

return $rc unless $rc == Apache2::Const::OK;
$self->debug(qq{compiled package \"$self->{PACKAGE}\"}) if DEBUG & D_NOISE;` 

Does that look right? Do I also need to add some code to open the connection to the debugger, or can I do this in the same way as before?

Please help, Thanks Andrew