How can I run through a Perl program step by step? - perl

I have a Perl program written by someone else. When I run it, it silently exits without writing anything to the logfile. Is there a way I can run this Perl program step by step, line by line by the interpreter and thus get to see where it terminates?

Yes, there is the Perl debugger which you can invoke with perl -d.
Documentation can be found in perldoc perldebug and perldoc perldebtut.
Probably the most useful commands would be:
s - step into current line.
n - step over current line.
r - step out of current function.
p <expr> - print the expression.
b <line|subnm> - sets a breakpoint
T - produce a stack trace.
c [<line|subnm>] - continue running with optional one-time breakpoint.
h - help (for other commands).

Hachi has the answer. Use the Perl debugger by running perl with the -d flag. For information on how to use the debugger past starting it, see the Perl Debugging Tutorial.

There is a Perl module called "ptkdb" which is a standalone Perl interactive debugger. It works using the Tcl/Tk GUI, so you'll need that, too.
Depending on your OS you'll need to add some required modules.
Invoke it using
perl -d:ptkdb <your script>
If running some Unix/Linux system, you also need an X server.

There are two ways. The first is the one which Hachi and llioin already gave which is using the command-line switch "-d".
Or use an IDE. I am tried and used Komodo IDE which works like charm.

Related

How can you invoke interactive Perl debugging with hypnotoad or morbo?

I'm new to mojolicious but have been using Perl for some time. I have to jump through some hoops but I can get the interactive Perl debugger (and Komodo) working with remote connections for Apache but I can't find anything about interactive debugging with hypnotoad or morbo.
The command line examples in the basic tutorial on http://mojolicio.us/perldoc/Mojolicious/Guides/Tutorial#Hello-World work fine because you can launch them with perl -d, but I don't see anyway to tell the hypnotoadctl script to put the service in interactive debug mode ala apache.
Is this not possible? Hints? Tips? Pointers?
morbo and hypnotoad are perl programs, so you can launch them with the -d switch.
perl -d $(which morbo) myMojoApp.pl
It's probably easiest to sprinkle a bunch of $DB::single = 1 statements around you app where you want your initial breakpoints to go and run c as the first debugger command. When you run a request that hits a breakpoint, you'll get a debugger prompt in the terminal that launched morbo.
hypnotoad will be trickier to use with the debugger because it quickly closes all the standard filehandles, calls fork several times, and becomes a daemon.
As JHThorsen points out, standard Mojolicious tests are actually ordinary Perl scripts, so you can debug your tests with:
perl -d t/mytest.t
The -Ilib adds the lib/ directory to the #INC include list so your modules will be loaded.
One catch is that many modules are not loaded until execution time, so if the debugger hassles you about symbols that aren't loaded yet, you'll probably want to set breakpoints after forcing a debug prompt with a carefully inserted
$DB::single = 1;
Thanks to 'pink_mist'. You can do:
perl -d myMojoApp.pl daemon -l http://*:29849
But application config is not applyied. I do not know why.

Perl debugger on test modules

I'm running into problems testing a new addition to a module. (Specifically - the ~ operator seems to be not working in Math::Complex for this new feature only.) It's too bizarre to be what it appears but the ideal scheme would be to add the -d option on the top line of the .t program.
Well, I was quickly disabused of that idea! It does not invoke the debugger.
If I wanted to use the debugger, I'd need to create an edit of the .t program that:
Uses (the use command) the module directly. not in the form of
BEGIN { use_ok('My::Module') };
Does not "use Test::More;"
A few other edits that cause gluteal pains
The problem with doing that is that any changes I make in the edited test program I still need to transfer back to the true test program use in "make test". Error prone as best.
I am already using "make test TEST_VERBOSE=1" so that my stdio output shows up. But there's GOT to be a simpler way to invoke the debugger on the .t
Thanks for ideas here.
-- JS
use_ok tests are great, but you should have them in test files of their own, not test files that also test other things.
I'm not sure why you would need to avoid Test::More or use_ok to run the debugger, though. What does happen when you try your test directly:
perl -d -Mblib t/yourtestfile.t?
If all else fails, you can try using Enbugger in your test script.

How can I find out what script, program, or shell executed my Perl script?

How would I determine what script, program, or shell executed my Perl script?
Example: I might want to have human readable output if executed from shell (customized for each type of shell), a different type of output if called as a script from another perl script, and a machine readable format if executed from a program such as a continuous integration server.
Motivation: I have a tool that changes its output based on which shell executes it. I'd normally implement this behavior as an option to the script, but this tool's design doesn't allow for options. Other shells have environment variables that indicate what shell is running. I'm working on a patch to support Powershell, which has no such special variable.
Edit: Many of these answers happen to be linux specific. Unfortuantely, Powershell is for Windows. getppid, the $ENV{SHELL} variable, and shelling out to ps won't help in this case. This script needs to run cross-platform.
You use getppid(). Take this snippet in child.pl:
my $ppid = getppid();
system("ps --no-headers $ppid");
If you run it from the command line, system will show bash or similar (among other things). Execute it with system("perl child.pl"); in another script, e.g. parent.pl, and you will see that perl parent.pl executed it.
To capture just the name of the process with arguments (thanks to ikegami for the correct ps syntax):
my $ppid = getppid();
my $ps = `ps --no-headers -o cmd $ppid`;
chomp $ps;
EDIT: An alternative to this approach, might be to create soft links to your script, make the different contexts use different links to access your script and inspect $0 to build logic around that.
I would suggest a different approach to accomplish your goal. Instead of guessing at the context, make it more explicit. Each use case is wholly separate, so have three different interfaces.
A function which can be called inside a Perl program. This would likely return a Perl data structure. This is far easier, faster and more reliable than parsing script output. It would also serve as the basis for the scripts.
A script which outputs for the current shell. It can look at $ENV{SHELL} to discover what shell is running. For bonus points, provide a switch to explicitly override.
A script which can be called inside a non-Perl program, such as your continuous integration server, and issue machine readable output. XML and/or JSON or whatever.
2 and 3 would be just thin wrappers to format the data coming out of 1.
Each is tailored to fit its specific need. Each will work without heuristics. Each will be far simpler than trying to guess the context and what the user wants.
If you can't separate 2 and 3, have the continuous integration server set an environment variable and look for it.
Depending on your environment, you may be able to pick it up from the environment variables. Consider the following code:
/usr/bin/perl -MData::Dumper -e 'print Dumper(\%ENV);' | grep sh
On my Ubuntu system, it gets me:
'SHELL' => '/bin/bash',
So I guess that says I'm running perl from a bash shell. If you use something else, the SHELL variable may give you a hint.
But let's say you know you're in bash, but perl is run from a subshell. Then try:
/bin/sh -c "/usr/bin/perl -MData::Dumper -e 'print Dumper(\%ENV);'" | grep sh
You will find:
'_' => '/bin/sh',
'SHELL' => '/bin/bash',
So the shell is still bash, but bash has a variable $_ which also show the absolute filename of the shell or script being executed, which may also give a valuable hint. Similarily, for other environments there will most probably be clues left in the perl %ENV hash that should give you valuable hints.
If you're running PowerShell 2.0 or above (most likely), you can infer the shell as a parent process by examining the environment variable %psmodulepath%. By default, it points to the system modules under %windir%\system32\windowspowershell\v1.0\modules; this is what you would see if you examine the variable from cmd.exe.
However, when PowerShell starts up, it prepends the user's default module search path to this environment variable which looks like: %userprofile%\documents\windowspowershell\modules. This is inherited by child processes. So, your logic would be to test if %psmodulepath% starts with %userprofile% to detect powershell 2.0 or higher. This won't work in PowerShell 1.0 because it does not support modules.
This is on Windows XP with PowerShell v2.0, so take it with a grain of salt.
In a cmd.exe shell, I get:
PSModulePath=C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\
whereas in the PowerShell console window, I get:
PSModulePath=E:\Home\user\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsP
owerShell\v1.0\Modules\
where E:\Home\user is where my "My Documents" folder is. So, one heuristic may be to check if PSModulePath contains a user dependent path.
In addition, in a console window, I get:
!::=::\
in the environment. From the PowerShell ISE, I get:
!::=::\
!C:=C:\Documents and Settings\user

How do you carry out remote debug when running perl as CGI together with Apache?

Seems most are using the traditional way of print for debugging purpose, is there anyone that uses remote debug for perl in linux?
There are reasonably straightforward directions here: http://search.cpan.org/dist/Enbugger/lib/Enbugger.pod#From_gdb
Though that presupposes you have a long-running perl process (mod_perl, fastcgi, etc) that wasn't expecting to be run under the debugger. If you are just using vanilla CGI, you can configure your webserver to run perl -d and set the debugger to remote debugging via its TTY or RemotePort options. Or go ahead and use Enbugger in your actual perl code as in the directions above (again, setting TTY or RemotePort).
What sort of debugging? An actual perl debugger or using warn() with tail -f /var/log/apache/error.log?
In the end i would suggest swicting to Log::Log4perl. Unless you need an actual step by step debugger.
You you need an actual debugger, you likely won't want to use Apache in the mix. You can run your cgi from the command line and pass arguments CGI.pm.

perl debugger freezes

First time perl user and I am trying to debug some script to follow project logic and of course syntax.
Using cygwin after entering at command line $
$ perl -d sample.pl
Loading DB routines from perl5db.pl version 1.3
Editor support available.
Enter h or `h h' for help, or `perldoc perldebug' for more help.
main::(sample.pl:5): print 'Hello world.'; # Print a message
DB<1>
It hangs at the DB<1> line. I cannot enter anything at the prompt.
Is there a reason why this post is inappropriate? or how is this not clear?
This is the actual program code:
#!/usr/local/bin/perl
#
# Program to do the obvious
#
print 'Hello world.'; # Print a message
I upgraded my cygwin installation at home and ran into a similar problem (though maybe not the exact same problem -- the perl debugger still responds to my input but does not display my input, and fubars my input even after I quit the debugger). In the meantime while I figure what is going on, my workaround is to fire up xemacs, launch a shell (M-x shell), and run the perl debugger from the emacs buffer.
If this works for you, then there is something funky going on with your cygwin terminal settings. If your debugger hangs even in an emacs buffer, then something else funky is going on but I have no idea what it could be.
Sorry for reviving this three-year-old question, but I believe to have been hit with the same problem, and to have found the solution.
In my case, perl -de0 invokes infocmp from ncurses, which hangs in a weird way (can't kill it). And infocmp seemed to be a victim of my Avast anti-virus which is listed under BLODA as affecting Cygwin. Disabling it resolved the issue -- see if you have any of the listed applications and try disabling it (perhaps also try safe mode).
Also, simply renaming infocmp.exe allowed perl -d to run normally. In the end I used this approach and left my Avast running.
It could also be a different executable that perl -d is starting -- try to run whatever hangs with strace, see what is the last executable mentioned and try to see if that is the culprit.