Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

How can I print variable contents from the debugger non-interactively?

by davehorner (Scribe)
on Jul 15, 2017 at 00:16 UTC ( #1195149=perlquestion: print w/replies, xml ) Need Help??
davehorner has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to debug a perl script without modifying it.

I'm using perl -d -w -Mdiagnostics=-verbose file.pl --args-to-file.pl 2>&1.

This gives me great visibility into the lines of code that are being run, I can identify which lines are causing the issue and need to be investigated further but I'm not sure how to tell the debugger to print the contents of the variables. I don't care if I have to tell the debugger to print all variables (which would produce a lot of output). But what I would really prefer is to tell the debugger to print all the variable contents when executing line XXX or print variables named via regex.

I learned how to use the diagnostics pragma -d -w -M here: http://perldoc.perl.org/diagnostics.html

I have read the http://perldoc.perl.org/perldebug.html and see there is a $ENV{PERLDB_OPTS} that seems like it might be modified to provide such capabilities but I'm still not sure what debugger options I should be using.

Any help would be greatly appreciated!

Update: some feel this description is a bit vague so here's additional justification for not modifying the script and not running from an interactive debugger on the cmdline:
I'm interested in trying to use the debugger as a diagnostic tool when the script is run non-interactively from another script/system, you can change environment variables and cmdline args but you can't easily change the script or execute the script from an interactive debugger session. Lets imagine that there's something about this machine that it is running on that is causing the issue, modifying the script and getting it on the machine require a lot of effort. Maybe it's in an air gap network and getting changes requires new physical media to be shipped to a customer and physically mounted. Meaning it could take significant time to just get a debug script (i.e. additional print lines) on the specific machine, which then requires you to get the output delivered physically out of the air gap network for analysis externally and then you'd need to send another updated script with the actual fix and prune the debug statements. This back and forth takes a lot of time and could require multiple iterations as you are placing debug statements in places you suspect where the issue to reside, it might take 3 or 4 debug scripts to nail down the actual bug.

Changing the cmdline args and using perl -d -w -Mdiagnostics=-verbose file.pl --args-to-file.pl 2>&1 gets all the output required to understand what is actually being executed but it doesn't provide enough information about the variable contents to understand what it is about the environment/data that is causing the script to exhibit strange behavior.

--dave
  • Comment on How can I print variable contents from the debugger non-interactively?

Replies are listed 'Best First'.
Re: How can I print variable contents from the debugger non-interactively?
by Marshall (Abbot) on Jul 15, 2017 at 04:25 UTC
    I am trying to debug a perl script without modifying it.

    The single most powerful debug tool in Perl is "print" and Data::Dumper and its kinfolk like Data::Dump. Why is not modifying the program a requirement? Why not just add some print statements and be done with it?

    During debug, I add print statements all the time with a comment tag field to make them easy to delete later (my program editor makes that easy). The "change code, recompile, execute code" cycle is so fast (if you have a good development environment) in Perl that modifying the code to debug it is very sensible.

    Sometimes I will leave some debug statements in the code. These are things that I am likely to need later if there is some significant modification to the code.

    use constant DEBUG =>1; ... if (DEBUG){...code}
    In Perl if you set DEBUG =>0, there is no speed penalty for that if statement because Perl knows due to the constant value that the code will never be executed and it is not even compiled.

    Maybe you can find all kinds of tricky debug statements to get the debugger to do what you want right now. However, you will not know that stuff years from now when you are debugging some modification. For the most part, I recommend using "print" for transient debug issues. For some code where modifications are likely to require examining some data structure, I put in in if(DEBUG).

      Hi Marshall,

      Your comment is very useful (and I upvoted it for that reason), but it does not really answer davehorner's question, which pertained to the use of the Perl debugger.

      "... Perl knows due to the constant value that the code will never be executed and it is not even compiled"

      I didn't know this. Very nice. Thanks.

      Best regards, Karl

      «The Crux of the Biscuit is the Apostrophe»

      perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

      Marshall thank you for your reply, additional description for why one might want to debug the script without modifying it has been provided in the orginal question.

      Maybe you can find all kinds of tricky debug statements to get the debugger to do what you want right now. However, you will not know that stuff years from now when you are debugging some modification.

      I don't agree with this sentiment, I think learning to use the debugger and understanding how to use it to print and maybe even modify runtime behavior of the script without modification is a skill that could be useful years from now (i have a good memory and places to document the perl wisdom gleaned from this question/responses). Using print/debug statements is easy and effective, but I'm looking to further my understanding of basic perl tools and add to perl repertoire.
        Hi Dave!

        I was thinking of interactive debug commands.

        I believe that you will find in Perl, that the debugger is seldom used because its not required. I have to use a debugger (mandatory) when I write assembly code, I very seldom use a debugger for C code and almost never use a debugger for Perl code - for me, the Perl debugger is a once in a decade event. I have never required the Perl debugger to solve a code problem.

        I congratulate you on your curiosity and motivation to learn more about Perl!

        Perl is an amazingly introspective language. A Perl user function can find out things that are just not possible for a C program.

        Some useful stuff for debugging the caller stack is the Perl Caller() function.

        Some "standard" functions:

        $me = whoami(); $him = whowasi(); sub whoami { (caller(1))[3] } sub whowasi { (caller(2))[3] }
        I recommend study of the caller() function for your "debug repertoire".
Re: How can I print variable contents from the debugger non-interactively?
by LanX (Bishop) on Jul 15, 2017 at 01:02 UTC
    It's a bit vague, under which condition do you want the variables to be printed?

    Here some approaches

    • Set a watch expression which doesn't stop
    • Change &DB::DB
    • change &DB::sub

    See perldebguts#Writing-Your-Own-Debugger for inspiration.

    For instance PERL5DB="sub DB::DB { print $var }" perl -d your-script should continously print $var for each statement. (Untested)

    HTH

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

      Thank you very much LanX for the reply.

      Using PERL5DB="sub DB::DB { print $var }" perl -d your-script is a really great idea. I was not aware of the DB::DB sub.

      I tried defining this and running it with something like:
      PERL5DB="sub DB::DB { print \"VAR: \$var\n\" if(defined \$var); }" perl -d your-script

      However, it seems that this affects the way the std debugger works as I do not get the output from the debugger listing all the lines that are executed as before. It seems to not be called recursively all the way through the program without the std. debugger working. Looks like it only gets called top level and internal statements are not getting the DB::DB injected before execution.

      I saw your responses giving commands to the debugger ie. watch and action statements etc. Is there a way to provide this to the debugger via the $ENV{PERLDB_OPTS} variable?

      Thanks again.
      --dave
        > , it seems that this affects the way the std debugger works

        yes, it's still unclear for me if you want to step thru or run an automatic trace.

        > Is there a way to provide this to the debugger via the $ENV{PERLDB_OPTS} variable?

        Yes.

        edit

        At least in .perldb with afterinit

        sub afterinit { push @DB::typeahead, "b 4", "b 6"; }

        See perldebug#Debugger-Customization

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)
        Je suis Charlie!

Re: How can I print variable contents from the debugger non-interactively?
by zentara (Archbishop) on Jul 15, 2017 at 11:42 UTC
    Hi, if you would like a perl GUI for debugging, wherein you can set beakpoints, watched-variables, etc, try Devel-ptkdb which is a PerlTk frontend to debug. A TCL frontend is availble too. You can save your settings for multiple runs.

    There are numerous tutorials available if you google for "perl debugging ptkdb". It's actually very convenient to use.


    I'm not really a human, but I play one on earth. ..... an animated JAPH
      There's also Devel::hdb which runs a web server to which you can connect from your browser and set breakpoints and watch variables there.

      ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
        I like the Komodo IDE integration, not sure if it's included in the free Ko modo Edit version.
Re: How can I print variable contents from the debugger non-interactively? ( a = line action ; w = watch changes everywhere)
by LanX (Bishop) on Jul 15, 2017 at 10:42 UTC
    > to print all the variable contents when executing line XXX

    some hands on examples

    a action (per line) and w watchpoint (each time) take Perl code to be evaluated.

    you can do pretty nifty things with that already

    sample code

    use strict; use warnings; $|=1; # disable buffering my $a; our $y; for (0..10) { print; $a++; $y++; }

    a = action cmd on line
    DB<71> h a a [line] command Set an action to be done before the line is executed; line defaults to the current execution line. Sequence is: check for breakpoint/watchpoint, print line if necessary, do action, prompt user if necessary, execute line. a Does nothing

    a doesn't break unless you set $DB::single explicitly to 1

    w = watch-expression

    DB<79> h w w expr Add a global watch-expression. w Does nothing

    w stops if the returned value has changed

    w $a would stop each time $a is changing

    this only stops if $a is inside the intervall

    this only stops for the first print and the first non print (print returns 1)

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

      b for break also takes code

      like in a you can execute code Perl line, just return something false if you don't want to break into interactive mode

      DB<119> b 11 print "\n<$y>\n" if $y==3;0 DB<120> L d:/Users/RolfLangsdorf/AppData/Roaming/pm/tst_debuger.pl: 11: $a++; break if (print "\n<$y>\n" if $y==3;0) DB<120> c 0123 <3> 45678910 DB<120>

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)
      Je suis Charlie!

Re: How can I print variable contents from the debugger non-interactively? ( { = auto cmd ; X V y = dump by regex)
by LanX (Bishop) on Jul 15, 2017 at 13:06 UTC
    > or print variables named via regex.

    The following commands dump variables by regex

    DB<162> h X X [vars] Same as "V currentpackage [vars]". DB<163> h V V [pkg [vars]] List some (default all) variables in package (defaul +t current). Use ~pattern and !pattern for positive and negative regexps. DB<164> h y y [n [Vars]] List lexicals in higher scope <n>. Vars same as V.

    With "{" you can tell the debugger to automatically execute these (and other debugger) commands with each prompt, like when single stepping or when running into a breakpoint.

    DB<1> h { { db_command Define debugger command to run before each prompt. { ? List debugger commands to run before each prompt. {{ db_command Add to the list of debugger commands to run before ea +ch prompt. { * Delete the list of debugger commands to run before eac +h prompt.

    The following example

    • sets a conditional breakpoint at line 11
    • dumps all variables named y before each prompt
    c = continue runs into the breakpoint s = single step shows the dumping

    DB<239> b 11 $a==3 DB<240> L d:/Users/RolfLangsdorf/AppData/Roaming/pm/tst_debuger.pl: 11: $a++; break if ($a==3) DB<240> { X y DB<241> { pre-debugger commands: { -- X y DB<241> c 0123auto(-1) DB<241> X y $y = 3 DB<242> s auto(-1) DB<242> X y $y = 3 DB<243> s auto(-1) DB<243> X y $y = 4 DB<244> c 45678910auto(-1) DB<244> X y DB<245>

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

Re: How can I print variable contents from the debugger non-interactively?
by Laurent_R (Canon) on Jul 15, 2017 at 08:32 UTC
    Hi davehorner,

    It seems to me that the answers you've received so far may probably be more complicated than what you actually wanted to know.

    To print the content of a scalar variable $var, simply issue the following commands at the debugger prompt:

    p $var
    Sometimes it is better to put some special characters around the variable in order to see possible invisible characters:
    p "<$var>"
    To see the content of a non scalar variable such as an array or a hash, use the x command:
    x @array
    or use a reference to the variable for a clearer output:
    x \%hash;
    And remember you can always issue the h command at the debugger prompt to get some help:
    DB<1> h List/search source lines: Control script execution: l [ln|sub] List source code T Stack trace - or . List previous/current line s [expr] Single step [in +expr] v [line] View around line n [expr] Next, steps over + subs f filename View source in file <CR/Enter> Repeat last n or + s /pattern/ ?patt? Search forw/backw r Return from subr +outine M Show module versions c [ln|sub] Continue until p +osition Debugger controls: L List break/watch +/actions o [...] Set debugger options t [expr] Toggle trace [tr +ace expr] <[<]|{[{]|>[>] [cmd] Do pre/post-prompt b [ln|event|sub] [cnd] Set b +reakpoint ! [N|pat] Redo a previous command B ln|* Delete a/all bre +akpoints H [-num] Display last num commands a [ln] cmd Do cmd before li +ne = [a val] Define/list an alias A ln|* Delete a/all act +ions h [db_cmd] Get help on command w expr Add a watch expr +ession h h Complete help page W expr|* Delete a/all wat +ch exprs |[|]db_cmd Send output to pager ![!] syscmd Run cmd in a sub +process q or ^D Quit R Attempt a restar +t Data Examination: expr Execute perl code, also see: s,n,t expr x|m expr Evals expr in list context, dumps the result or lists + methods. p expr Print expression (uses script's current package). S [[!]pat] List subroutine names [not] matching pattern V [Pk [Vars]] List Variables in Package. Vars can be ~pattern or ! +pattern. X [Vars] Same as "V current_package [Vars]". i class inherita +nce tree. y [n [Vars]] List lexicals in higher scope <n>. Vars same as V. e Display thread id E Display all thread ids. For more help, type h cmd_letter, or run man perldebug for all docs.
      Well he said "non-interactively" , but yeah he might mean it differently.

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)
      Je suis Charlie!

        Oops, yes I missed that (I probably failed to read the title).

        Update: I wonder why someone would want to use the debugger non-interactively. I can't think of cases where this would be useful.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1195149]
Front-paged by stevieb
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (3)
As of 2017-11-19 17:06 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    In order to be able to say "I know Perl", you must have:













    Results (282 votes). Check out past polls.

    Notices?