Digging Down Into Perl Hood with the Debugger DIGGING DOWN INTO PERL

Digging Down Into Perl Hood with the Debugger DIGGING DOWN INTO PERL

@SW:Perl Debugger PROGRAMMING Perl: Perl Debugger Digging down into Perl hood with the debugger DIGGING DOWN INTO PERL www.sxc.hu The Perl interpreter, perl, doesn’t often crash, but if it happens, not even the excellent Perl debugger will be able to help you. To allow the debugger to map the BY MICHAEL SCHILLI functions to lines in the C source code, you need to compile Perl with the -g compiler flag for troubleshooting sup- f you program in Perl rather than in beds it dynamically in the script. The C port. When the Configure script prompts C or C++, you will probably be code after the __END__ tag sets a pointer you to decide which optimizer/debugger Igrateful for a few things that Perl to an address of 0xcba00000, and then flag should be used, say -g in response, takes off your hands: memory allocation, it tells the strcpy C function to overwrite or use the following Configure command counting references, watching out for the protected kernel address on ma- line: ./Configure -D optimize=-g -d. rogue pointers, freeing up memory – chines that use the 32-bit x86 architec- these labors of Sisyphus are offloaded ture. The CPU notices what happened Listing 1: crash from the developer's desk by Perl’s vir- to the script and triggers an interrupt, at 01 #!/usr/bin/perl -w tual machine, helping developers to keep which point the Linux kernel pulls the focused on the implementation. rug out from underneath the offending 02 use strict; Down below in the engine room, program’s feet. 03 use Inline "C"; things can start to go awry. Although Figure 1 shows you how to call the 04 use Inline Config => you will rarely make the acquaintance of Perl script to reproduce the error in the 05 CLEAN_AFTER_BUILD => 0; a bug in a Perl release that actually takes GNU debugger, gdb. The calling binary down the C-based virtual machine, add- is the Perl interpreter, so the debugger 06 ins programmed by unwary C/ C++ will launch with gdb perl. To allow the 07 c_crash(43); developers can trip you up. interpreter to process the Perl crash 08 script, just call the run crash command 09 __END__ Linux Pulling the Rug in the debugger. After the crash, gdb will 10 __C__ Out from Under Your Feet give you the C code for the line that The script in Listing 1 uses a C extension caused the crash. The debugger bt (for 11 int c_crash( int num ) { to deliberately take down the interpreter backtrace) command (you could use 12 char *cp = 0xcba00000; with a segmentation fault. To do so, it where as an alternative) also shows the 13 strcpy(cp, "Ouch!"); uses the Inline CPAN module, which hierarchy of the calling C function as a 14 } compiles the attached C code and em- stack trace. 72 ISSUE 75 FEBRUARY 2007 WWW.LINUX - MAGAZINE.COM Perl: Perl Debugger PROGRAMMING You can extract in- $ ls -l core.* formation from Perl -rw------- 1 mschilli mschilli U compiled in the nor- 1658880 Nov 3 21:30 core.1234 mal way. Although the post-mortem is The core dump is normally stored in the slightly more difficult, directory where the program was called, a trick, which I will unless /proc/sys/kernel/core_pattern says explain later, can help to do otherwise. If you want to find out you avoid excessive what caused the crash, run the debugger hex juggling. against the executable and the core file (as in gdb perl core.1234). Your debugger Post-Mortem session should look something like Fig- of a Script ure 1, and you will be able to do a stack If a crash occurs in a trace at a point just before the crash oc- running program, the curred. What you can’t do, however, is Linux kernel will nor- actually execute this memory snapshot. mally create a core The stacktrace in Figure 1 tells us that file. If not, you may perl crashed in a file called crash_3e35.xs Figure 1: A gdb session showing the stack trace. find that bash is pre- (Line 7) inside a C function called venting core dumps c_crash() while trying to executed the C If you fail to do this, analysis becomes due to the default setting of ulimit -c 0. strcpy() function. If you now use the de- tricky due to the lack of references to If you change this to ulimit -c unlimited bugger’s print cp command to check the the C source code, and if the executable instead, you will find a core file (core or target address, a value of 0xcba00000 is has been stripped, you have little to even core.xxxx with the pid attached): returned. This explains the crash to the work with; let’s leave this interpretation investigating detective. of disassembled assembler code in the $ ./crash However, gdb only tells you about the hands of long-bearded gurus! Segmentation fault (core dumped) goings on at C level. How can you find advertisement WWW.LINUX - MAGAZINE.COM ISSUE 75 FEBRUARY 2007 73 PROGRAMMING Perl: Perl Debugger argument stack, and These opcode structures are the building this is also where the blocks that Perl programs are built with, value of 43 is repre- after the compiler has read the source sented as one of Perl’s code from the script. SV (Scalar Value) Let’s try to find out what type the structures. To extract global PL_op variable, which you can the integer value, you see here, is. Considering the excessive must cast PL_stack_ use of macros in the Perl kernel, this can sp->sv_any to be quite difficult to do. gdb can help: (XPVIV*); it will return the numeric (gdb) whatis PL_op value of the argument type = OP * passed in to c_crash() in its xiv_iv member: A print *PL_op command in the lower gdb window shows the content of the (gdb) p ((XPVIV*)U data structure. PL_op is a pointer to a PL_stack_sp-> structure, and the asterisk * tells gdb not sv_any)->xiv_iv to display the address, but rather the $1 = 43 content of the data structure. For a per- manent graphic display of the opcode Cheers! data in Figure 2 in the top window of Figure 2: The GUI debugger, ddd, has latched onto a Perl process, The gdb debugger can ddd, you need to enter graph display and is now outputing the opcodes that Perl’s virtual machine is also notch into an ac- `p PL_op` in the gdb window, and then currently performing. tive process. In this double-click the hex address (it’s under- case, it automatically lined in blue) in the top display of the out which Perl script and which line the stops the process for a short time, and opcode box that appears. This tells ddd crash occurred in? To do so, you will then steps through it when requested to. to expand the data structure hiding be- need to analyze Perl’s C data structures, This is particularly useful when a Perl hind this address, and display its attri- which will give you some insight into process hangs, and you have not imple- butes in the new, larger box on the right. the status of the virtual machine at the mented logging. The output for the OP node reveals time of the crash. The Perl program in Listing spinner more than just pointers to following How can you ascertain that c_crash only calls an infinite sleep() loop and OPs and an address for the code to be was called with an argument of 43? To outputs its process ID and the time in executed; there is also a op_type field, do so, you need some knowledge of the seconds since the epoch. If the process which tells us the opcode type. internal workings of Perl, which you can ID is 1234, calling gdb perl -p 1234 will glean from the perlguts and perlhack latch onto the active process. Instead of Opcode Parade manpages. Perl’s virtual machine pushes the command-line debugger, we will use To display the opcodes for an active Perl function arguments onto the stack, in a the GUI-based version, ddd. You can see program, you must define the following similar style to a C compiler, before they the debugger in Figure 2, and your distri- are called by a Perl function. The PL_ bution should include it. ddd under- Listing 4: perl_compile stack_sp variable points to the tip of the stands gdb command-line options, so 01 #!/usr/bin/perl -w you can replace gdb with ddd in the pre- 02 use strict; Listing 2: spinner vious command line. You are likely to 03 use Config; catch the Perl process sleep()ing. #!/usr/bin/perl -w The up tells the debugger to jump up 04 02 use strict; to the next highest layer of stackframes, 05 my($file) = @ARGV; 03 that is, to move up in the function call 06 die "usage $0 file.c" unless 04 while(1) { hierarchy. Four levels further up, the defined $file; 05 function(time); source code window shows the short 07 (my $solib = $file) =~ /\ 06 sleep(1); while loop running the opcodes for a s.c/.so/; script in the Perl interpreter (Figure 2). 08 07 } 09 my $cmd = /\ 08 Listing 3: optest.c "gcc -shared -o $solib " . 09 sub function { 01 #include "EXTERN.h" 10 "$Config{ccflags} -g -fpic " . 10 my($time) = @_; 02 #include "perl.h" 11 "-I$Config{archlibexp}/CORE 11 03 #include "XSUB.h" $file"; 12 print "$$: $time\n"; 04 struct op **my_special_op = 12 13 } NULL; 13 system $cmd; 74 ISSUE 75 FEBRUARY 2007 WWW.LINUX - MAGAZINE.COM advertisement PROGRAMMING Perl: Perl Debugger code the virtual ma- shared library based on the optest.c list- chine is running.

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    5 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us