Invoking Perl debugger so that it runs until first breakpoint - perl

When I invoke my Perl debugger with perl -d myscript.pl, the debugger starts, but it does not execute any code until I press n (next) or c (continue).
Is there anyway to invoke the debugger and have it run through the code by default until it hits a breakpoint?
If so, is there any statement that I can use in my code as a breakpoint to have the debugger stop when it hits it?
Update:
Here is what I have in my .perldb file:
print "Reading ~/.perldb options.\n";
push #DB::typeahead, "c";
parse_options("NonStop=1");
Here is my hello_world.pl file:
use strict;
use warnings;
print "Hello world.\n";
$DB::single=1;
print "How are you?";
Here is the debugging session from running: perl -d hello_world.pl:
Reading ~/.perldb options.
Hello world
main::(hello_world.pl:6): print "How are you?";
auto(-1) DB<1> c
Debugged program terminated. Use q to quit or R to restart,
use o inhibit_exit to avoid stopping after program termination,
h q, h R or h o to get additional info.
DB<1> v
9563 9564
9565 sub at_exit {
9566==> "Debugged program terminated. Use `q' to quit or `R' to restart.";
9567 }
9568
9569 package DB; # Do not trace this 1; below!
DB<1>
In other words, my debugger skips print "How are you?", and instead stops once the program finishes, which is not what I want.
What I want is have the debugger run my code without stopping anywhere (nor at the beginning, nor at the end of my script), unless I explicitly have a $DB::single=1; statement, in which case I would like it to stop before running the next line. Any ways to do this?
For reference, I am using:
$perl --version
This is perl 5, version 14, subversion 1 (v5.14.1) built for x86_64-linux

Put
$DB::single = 1;
before any statement to set a permanent breakpoint in your code.
This works with compile-time code, too, and may be the only good way to set a breakpoint during the compile phase.
To have the debugger automatically start your code, you can manipulate the #DB::typeahead array in either a .perldb file or in a compile-time (BEGIN) block in your code. For example:
# .perldb file
push #DB::typeahead, "c";
or
BEGIN { push #DB::typeahead, "p 'Hello!'", "c" }
...
$DB::single = 1;
$x = want_to_stop_here();
There is also a "NonStop" option that you could set in .perldb or in the PERLDB_OPTS environment variable:
PERLDB_OPTS=NonStop perl -d myprogram.pl
All of this (and much more) is discussed deep in the bowels of perldebug and perl5db.pl
Update:
To address the issues raised in the most recent update. Use the following in ./perldb:
print "Reading ~/.perldb options.\n";
push #DB::typeahead, "c";
parse_options("inhibit_exit=0");

Also check out Enbugger. And while on the topic of debuggers, see Devel::Trepan which also works with Enbugger.

Related

continue command ignores breakpoints

I'm getting errors using CPAN and, as output is rather unhelpful, resorted to debugging this.
$ perl -d /usr/bin/cpan CPAN
Loading DB routines from perl5db.pl version 1.33
<...>
main::(/usr/bin/cpan:2): eval 'exec /usr/bin/perl -S $0 ${1+"$#"}'
main::(/usr/bin/cpan:3): if $running_under_some_shell;
DB<1> b /usr/lib/perl5/5.14/HTTP/Tiny.pm:125
DB<2> L
/usr/bin/cpan:
2: eval 'exec /usr/bin/perl -S $0 ${1+"$#"}'
break if (/usr/lib/perl5/5.14/HTTP/Tiny.pm:125)
DB<2> c
After c, the program runs to completion, ignoring the breakpoint.
/usr/lib/perl5/5.14/HTTP/Tiny.pm:125 is the following line, outside any conditional blocks.
my $request = {
method => $method,
scheme => $scheme,
host_port => ($port == $DefaultPort{$scheme} ? $host : "$host:$port"),
uri => $path_query,
headers => {},
};
Setting a break on line 142 (that's causing errors that I'm debugging) makes no difference.
From the L output, it looks like the breakpoint is set on the current line rather than the one I need. But, perldebug lists b file:line as valid syntax.
That syntax might be a newer addition, I wasn't able to get it working here either. I have 5.8.8 on Unix and 5.10.1 on Windows and both don't seem to work. I get the breakpoint on my current line as you do (it treats the whole string as a condition).
I'd suggest using another syntax as below.
Break on the method:
b HTTP::Tiny::some_method
Select the file, break on the line (it matches on paths, not module namespaces):
f HTTP/Tiny
b 125
If they are loaded at runtime with require or eval, the debugger won't know about the module yet so you can just type use HTTP::Tiny in the debugger first to force it to load.

Running Perl debugger twice

I have a case where I invoke the Perl debugger twice. For example, progA.pl:
use warnings;
use strict;
system("perl -d progB.pl");
and progB.pl:
use warnings;
use strict;
$DB::single=1;
print "Hello\n";
Then I run progA.pl like:
$ perl -d progA.pl
This does not work very well. On my system (Ubuntu 14.04, and Perl version 5.18), I get some errors from the debugger. For example:
### Forked, but do not know how to create a new TTY. ######### Since two debuggers fight for the same TTY, input is severely
entangled.
I know how to switch the output to a different window in xterms,
OS/2 consoles, and Mac OS X Terminal.app only. For a manual switch,
put the name of the created TTY in $DB::fork_TTY, or define a
function DB::get_fork_TTY() returning this.
On UNIX-like systems one can get the name of a TTY for the given
window by typing tty, and disconnect the shell from TTY by sleep
1000000.
It also tries to open a new terminal window, with title Dauther Perl debugger but the new terminal only show the error sh: 1: 3: Bad file descriptor.
How can these problems be avoided? I just want the debugger to work as normal.
Use 'do' instead of 'system'
perl -d progA.pl
# will stop after your $DB::single = 1
# line in progB.pl
perldoc -f do
do EXPR Uses the value of EXPR as a filename and executes the contents
of the file as a Perl script.
do 'stat.pl';
is just like
eval `cat stat.pl`;
I'm not sure if this is what you are looking for, because I don't understand the bigger picture of what you are trying to do.
But if you use a different debugger like Devel::Trepan at the outset, then things may work:
$ trepan.pl progA.pl
-- main::(progA.pl:4 #0x21282c8)
system("perl -d progB.pl");
(trepanpl): s
-- main::(progB.pl:3 #0x7042a8)
$DB::single=1;
(trepanpl): s
-- main::(progB.pl:4 #0x878be8)
print "Hello\n";
(trepanpl): s
Hello
Debugged program terminated. Use 'q' to quit or 'R' to restart.
(trepanpl): quit
trepan.pl: That's all, folks...
Debugged program terminated. Use 'q' to quit or 'R' to restart
(trepanpl) quit
trepan.pl: That's all, folks...
The (trepanpl) prompt after the "program terminated" message is a bit odd. But all it means here is that progB.pl is finished. After quitting that, as I did above, if you had another Perl statement after your system() command, then debugger show that rather give the second "finished" message.
Another feature of Devel::Trepan is that you can do nested debugging from inside that debugger with its debug command. Here is an example of that:
trepan.pl progA.pl
-- main::(progA.pl:4 #0x10612c8)
system("perl -d progB.pl");
set auto eval is on.
(trepanpl): debug system("perl -d progB.pl")
-- main::((eval 1437)[/usr/local/share/perl/5.18.2/Devel/Trepan/DB/../../../Devel/Trepan/DB/Eval.pm:129] remapped /tmp/HSXy.pl:6 #0x51f13e0)
system("perl -d progB.pl")
((trepanpl)): s
-- main::(progB.pl:3 #0x9382a8)
$DB::single=1;
(trepanpl): s
-- main::(progB.pl:4 #0xaacbe8)
print "Hello\n";
(trepanpl): s
Hello
Debugged program terminated. Use 'q' to quit or 'R' to restart.
(trepanpl): quit
trepan.pl: That's all, folks...
$DB::D[0] = 0
Leaving nested debug level 1
-- main::(progA.pl:4 #0x10612c8)
system("perl -d progB.pl");
(trepanpl):

How to set breakpoint on a particular file in Perl program?

My Perl program looks like:
foo/
foo/bar/
for/bar/test.pm
foo.pm
foo/bar.pm
test.pl
and use perl test.pl to start the program.
I want to debug a sub in foo/bar/test.pm. How to set a breakpoint on that sub?
To debug a perl script, use the -d switch to invoke the debugger.
perl -d test.pl
Within the debugger you can use b <line no> to set a breakpoint in the current file. Sometimes it is a hassle to set a breakpoint in a file that hasn't been loaded yet or that was loaded a long time ago, so you can also put the line
$DB::single = 1;
anywhere in any perl program, and the debugger will break immediately after it executes that line. This is also a good way (the only way?) to set a breakpoint in code that will be run at compile time.
Just use the fully qualified name of the sub as the argument to b:
b foo::bar::test::subname
Example:
$ perl -d -e'use CGI; CGI->new'
...
main::(-e:1): use CGI; CGI->new
DB<1> b CGI::new
DB<2> r
CGI::new(.../CGI.pm:337):
337: my($class,#initializer) = #_;
DB<2> q
You can enter f Module.pm to tell the debugger to look at that particular module. Once you've done that, b line_number will stop at that line in Module.pm.
Once the original script has passed use Module, then b subroutine will stop at that subroutine. The only catch here is that you can't make your first two debugger commands f Module.pm; b subroutine because when the script begins, it hasn't passed use Module, so Module.pm hasn't loaded yet, which means that perl can't see that Module.pm has subroutine.

How can I use Perl 5.10 features inside the debugger?

I am unable to evaluate 'modern Perl' code inside the Perl debugger. It works OK when debugging the code in a file, but not from the prompt.
Minimal example:
# Activating 5-10 features with -E (it works)
$ perl -E 'say "x"'
x
# Calling the debugger with -E
# It works for infile code, but for prompt line code...
$ perl -dEbug Loading DB routines from perl5db.pl version 1.33
DB say "x"
String found where operator expected at (eval 16)[/local-perl/lib/5.12.1/perl5db.pl:638] line 2, near "say "x""
at (eval 16)[/local-perl/lib/5.12.1/perl5db.pl:638] line 2
eval '($#, $!, $^E, $,, $/, $\\, $^W) = #saved;package main; $^D = $^D | $DB::db_stop;say "x";
(Note: the same happens with "use feature ':5.10'".)
Am I missing something?
I found a reference to the issue here, but it's about a year old. However, the relevant portion of the Perl source hasn't changed since and can be seen here. Essentially, if you take a look at toke.c in the Perl source, you see the following:
if (PL_perldb) {
/* Generate a string of Perl code to load the debugger.
* If PERL5DB is set, it will return the contents of that,
* otherwise a compile-time require of perl5db.pl. */
const char * const pdb = PerlEnv_getenv("PERL5DB");
...
}
...
if (PL_minus_E)
sv_catpvs(PL_linestr,
"use feature ':5." STRINGIFY(PERL_VERSION) "';");
Basically, the debugger is loaded before the -E flag is processed, so the features aren't yet enabled when the debugger gets loaded. The gist of this is that you can't currently use -E with the -d command. If you want to use say, switch, or any other feature from the debug prompt, you have to do it like this:
DB<1> use feature 'say'; say "x"
x
The closest I've seen to a solution is:
copy perl5db.pl from your PERL5LIB to either somewhere in PERL5LIB or the current directory, with a different name, say myperl5db.pl
2. Edit myperl5db.pl to have use feature ':5.10'; (or just 'state', or just 'say') on the first line.
3. Set the environment variable PERL5DB to "BEGIN { require 'myperl5db.pl' }"
Which I found at PerlMonks.

How can I test that a Perl program compiles from my test suite?

I'm building a regression system (not unit testing) for some Perl scripts.
A core component of the system is
`perl script.pl #params 1>stdoutfile 2>stderrfile`;
However, in the course of actually working on the scripts, they sometimes don't compile(Shock!). But perl itself will execute correctly. However, I don't know how to detect on stderr whether Perl failed to compile (and therefore wrote to stderr), or my script barfed on input (and therefore wrote to stderr).
How do I detect whether a program executed or not, without exhaustively finding Perl error messages and grepping the stderr file?
It might be easiest to do this in two steps:
system('$^X -c script.pl');
if ($? == 0) {
# it compiled, now let's see if it runs
system('$^X script.pl', #params, '1>stdoutfile', '2>stderrfile');
# check $?
}
else {
warn "script.pl didn't compile";
}
Note the use of $^X instead of perl. This is more flexible and robust. It ensures that you're running from the same installation instead of whatever interpreter shows up first in your path. The system call will inherit your environment (including PERL5LIB), so spawning a different version of perl could result in hard-to-diagnose compatibility errors.
When I want to check that a program compiles, I check that it compiles :)
Here's what I put into t/compile.t to run with the rest of my test suite. It stops all testing with the "bail out" if the script does not compile:
use Test::More tests => 1;
my $file = '...';
print "bail out! Script file is missing!" unless -e $file;
my $output = `$^X -c $file 2>&1`;
print "bail out! Script file does not compile!"
unless like( $output, qr/syntax OK$/, 'script compiles' );
Scripts are notoriously hard to test. You have to run them and then scrape their output. You can't unit test their guts... or can you?
#!/usr/bin/perl -w
# Only run if we're the file being executed by Perl
main() if $0 eq __FILE__;
sub main {
...your code here...
}
1;
Now you can load the script like any other library.
#!/usr/bin/perl -w
use Test::More;
require_ok("./script.pl");
You can even run and test main(). Test::Output is handy for capturing the output. You can say local #ARGV to control arguments or you can change main() to take #ARGV as an argument (recommended).
Then you can start splitting main() up into smaller routines which you can easily unit test.
Take a look at the $? variable.
From perldoc perlvar:
The status returned by the last pipe
close, backtick ("``") command,
successful call to wait() or
waitpid(), or from the system()
operator. This is just the 16-bit
status word returned by the
traditional Unix wait() system call
(or else is made up to look like it).
Thus, the exit value of the subprocess
is really ("$? >> 8"), and "$? & 127"
gives which signal, if any, the
process died from, and "$? & 128"
reports whether there was a core dump.
It sounds like you need IPC::Open3.