richterger / Perl-LanguageServer

Language Server for Perl
Other
220 stars 53 forks source link

Debugging of perl CGI scripts on Apache server #129

Open udgithub opened 2 years ago

udgithub commented 2 years ago

Sorry for sending this question - it's not directly an issue.

The LanguageServer works pretty well with VS Code and the "remote ssh" plugin when I want to debug perl scripts in the cmdline. But how can I tell a CGI script where to find the IDE (where the debugger is listening)? When debugging PHP with xdebug we can put such information into an .htaccess file like so: .htaccess php_value xdebug.remote_enable on php_value xdebug.remote_host localhost php_value xdebug.remote_port 9000 Is there a similar way for Perl CGI scripts?

Thanks a lot in advance.

ecos-ps commented 2 years ago

I think it has something to do with forking inside of a webserver. (please see https://github.com/richterger/Perl-LanguageServer/issues/126#issuecomment-1044505454) By now you have to invoke the script through the LanguageServer and can't configure some sort of listener onto another process. The Perl Language Server doesnt support forking by now, this would help - i guess. Your suggestion might be very useful.

richterger commented 2 years ago

To get this working, it would be necessary that the debugger of the LanguageServer would not start the debugee itself, but just waits for that the debugee (CGI script) gets started and contacts the debugger (mode attach instead of launch).

To get this working, it would be necessary to modify the sub launch inside of DebuggerProcess.pm. There you can see the options and environment vars that needs to be passed to the CGI script when it gets started. These settings are necessary to enable the perl internal debugger (this needs to be done at startup and can't be done at runtime). The sub launch in this case just needs to send the process event with the attach option.

I am happy to help you implementing this, but I am not currently using CGI scripts, so it's not on top of my TODO list.

peterdragon commented 1 year ago

To use perl debugger with mod_perl you need:

for early perl 5.10 Apache::DB from https://metacpan.org/pod/Apache::DB

for newer perl 5.14 or later Devel::DebugHooks

edit the http_modperl.conf as per the docs to add Apache::DB init call - this example for mod_perl 1

<IfModule mod_perl.c>

  Alias /cgi-perl /home/httpd/cgi-bin
  <Location /cgi-perl>
    setHandler perl-script
    PerlHandler Apache::PerlRun
    PerlFixupHandler +Apache::DB
    Options +ExecCGI
    allow from all
    PerlSendHeader On
#    PerlSetVar PerlRunOnce On

    #where db.pl is simply:
    # use Apache::DB ();
    # Apache::DB->init;
    PerlRequire conf/db.pl
  </Location>

</IfModule>

then run the apache mod_perl in foreground single-thread mode using -X flag you would need to set this as the "run perl" command in VSC in your Perl-LanguageServer configuration

/usr/local/apache/bin/httpd_modperl -X -F -f /usr/local/apache/conf/my_httpd.conf

in your web browser browse to the server address

the shell run should then break out into the perl debugger from apache and trigger VSC debugger (or you can run above command manually and use the perl command line debugger see "man perldebug")

jrenolds commented 1 year ago

@richterger very nice plugin!

It works great when I directly run a .cgi file. I'm able to add breakpoints in vscode.

When I run apache mod_perl, I'm able to use the interactive debugger by following https://perl.apache.org/docs/1.0/guide/debug.html#Interactive_mod_perl_Debugging, and modifying it to work with mod_perl 2.0 instead of 1.0.

The interactive debugger I get doing this with mod_perl is the same interactive debugger that displays when you run perl -d script.cgi

I modified https://github.com/richterger/Perl-LanguageServer/blob/master/lib/Perl/LanguageServer/DebuggerProcess.pm by changing launch to attach.

$self -> send_event ('process',
{
  name            => $self -> program,
  systemProcessId => $pid,
  isLocalProcess  => JSON::true(),
  startMethod     => 'attach',
}) ;

I commented out

    if (ref $self -> args)       # ref is array
        {
        $pid = $self -> run_async ([@sudoargs, $cmd, @inc, '-d', $fn, @{$self -> args}]) ;
        } 
    else                      # no ref is string
        {
        $pid = $self -> run_async (join (' ', @sudoargs, $cmd, @inc, '-d', $fn, $self -> args)) ;
        }
    }

and added this to start the apache server in debug mode

$pid = $self -> run_async ('httpd -X') ;

but since httpd -X runs in the foreground, the rest of the code after that line doesn't run so send_event doesn't get called.

I then manually ran httpd -X, got the process id for that, and set $pid to it directly, $pid=122 in this example.

When I run the vscode debugger it attaches successfully, but when I visit a cgi page in the browser nothing happens in vscode. In the window that I started httpd -X in, the interactive debugger shows up.

It breaks into ModPerl::Registry since I set PerlResponseHandler ModPerl::Registry in my apache config. I'm able to move through and skip into the cgi file I loaded in the browser with the interactive debugger, but nothing happens in vscode. VScode just shows the attached debugger.

Any idea on what I could try next? I understand that this isn't a high-priority issue, but would appreciate any advice.

peterdragon commented 1 year ago

Sounds tricky. I have some notes on debugging mod_perl 1 with the command line debugger. I can have a look next week and see if I can get that to work, then if it does apache 2 might.

peterdragon commented 1 year ago

@jrenolds what version of perl do you have linked with apache 2 ? ("perl -V")

Did you set it as "run perl" command in VSC in your Perl-LanguageServer configuration? Direct running with perl from the plugin will not work will perl < 5.16, it has to be a separate process.

jrenolds commented 1 year ago

I have perl 5.16. I modified the Perl source code for this plugin, and had it run http -X. It doesn't seem like there's a way to set that as the run perl command. I did try running http -X using containerArgs (I'm using docker), but it doesn't seem like containerArgs is meant for that.

When I run http -X it does create a separate process, and I'm able to get the process id.

I think aside from using attach, we would need to modify how files get mapped from vscode to the perl script that gets called by Apache::DB.

Apache::DB doesn't directly call the cgi files. Instead it runs a perl script that calls eval on the cgi file.

https://perl.apache.org/docs/1.0/guide/debug.html image

That's why in the example in the docs the perl interactive debugger shows that you're debugging a file called Apache::ROOT::perl::test_2epl::handler((eval 87):3): instead of /perl/test.pl.

peterdragon commented 1 year ago

@jrenolds for newer perl 5.14 or later, instead of Apache::DB the metacpan recommends Devel::DebugHooks Worth a try?

jrenolds commented 1 year ago

I looked at the docs for Devel::DebugHooks, and I don't see instructions for Apache.

peterdragon commented 1 year ago

https://metacpan.org/dist/Devel-DebugHooks/view/lib/Apache/DB.pm

jrenolds commented 1 year ago

I see, I can give that a try.

jrenolds commented 1 year ago

No luck with Devel-DebugHooks either