@SW: Debugger

PROGRAMMING Perl: Perl Debugger

Digging down into Perl hood with the debugger DIGGING DOWN INTO PERL www.sxc.hu

The Perl , 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 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. 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 : 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. ing shown on the previous page, and use nextstate opcodes al- the perl_compile script to compile it. Perl ways have a type num- stores the compiler options and the pa- ber of 174. So, let’s de- rameters used to configure it, and makes lete the old breakpoint them available via the Config module. by entering delete 1, and If you compile a Perl extension, you are set a new breakpoint, able to quickly set the correct compile again at the end of the options and include paths. while loop: This steps in Figure 3 give us a shared library titled optest.so, which contains (gdb) break if U nothing but a global pointer variable, PL_op->op_type my_special_op, of OP ** type. This vari- == 174 able will contain the address of the OP * (gdb) display U type opcode pointer, PL_op, later. As we Perl_op_dump compiled the shared library using -g, gdb (PL_op) will know the my_special_op data struc- ture, which gives us a workaround for The if condition that fol- querying the value of PL_op->op_type. lows the break tells gdb To allow this to happen, we need to not to stop unless Perl load the test library before the execut- is processing a type 174 able itself, using LD_PRELOAD, as opcode. The display shown in Figure 3. command defines an After defining the breakpoint with the action that gdb will per- known condition, and the output com- form after each break. mand, the display shows Perl processing This is particularly use- Line 10, and then Line 12, of the main ful for outputting vari- program after the break. Counting the Figure 3: Discovering which line of an active Perl script is cur- able values. lines reveals that these are the first and rently being processed, without debug information. The C Perl_op_ second lines of code in function() in the dump() function accepts spinner Listing. actions for the breakpoint set in Figure 2 the internal data structure of the Perl op- Note that the nextstate opcode does by a mouse click near the code line: code as input, and uses printf to output not directly reveal the file name of the the opcode’s properties. The function Perl script that is being processed. In- commands 1 comes from the Perl interpreter, and is stead, it provides the filename of the Perl silent used by Perl developers to debug unsta- package. If this happens to be "main", p PL_op->op_ppaddr ble developer versions. For analysis, gdb we know the interpreter is in the main cont will easily run functions located some- program. If the name is "LWP:: end where in the executable you are investi- UserAgent", for example, you can typi- gating (or in its libraries), so it makes cally find which file defines the package In this case, we want the stop at the first sense to debug with existing functions. using perldoc -m LWP::UserAgent. breakpoint (this explains the 1), but not After locating the problem with this to output line/ code information (silent); Intensifying the Search approach, troubleshooting is often triv- instead we need the address and name Even in a Perl program compiled without ial. Also, a carefully crafted logging of the function that implements the the -g flag, that is, a program that does strategy can help facilitate analysis of opcode (PL_op->op_ppaddr). The cont not contain debug information, you can the next problem. command that then follows tells gdb ascertain the line of Perl code that is run- For more in-depth information on the to carry on through the list of opcodes ning right now. However, in this case, analysis techniques introduced in this without waiting for user input. The gdb does not know that PL_op is an OP article (in addition to many other tech- lower command window in Figure 2 type variable, or that it has a op_type niques), check out [2], an incredible shows the outputs, after the process has attribute. You could calculate the offset piece of work that all developers should been continued (cont) following the from op_type to the start of the PL_op have on their desks. ■ breakpoint definition. structure, and then, using the Endian- ness of the Intel processor (least signifi- INFO Code Cracker cant byte first), you can calculate the [1] Listings for this article: To analyze rogue Perl programs at run- value of the op_type attribute, and com- http:// www. linux-magazine. com/ time, nextstate type opcodes are proba- pare it with 174. Magazine/ Downloads/ 75/ Perl bly our best bet. They tell us which Perl However, you might prefer to use a [2] “Self-Service Linux”, Mark Wilding package and line of the original Perl more simple trick: let’s put together a and Dan Behman, Prentice Hall, 2006

76 ISSUE 75 FEBRUARY 2007 WWW.LINUX - MAGAZINE.COM