Debugging a Module

Because of the way they are constructed, modules are difficult to debug. The problem is that you have to debug Perl, but the module is not part of the Perl program proper. Instead, it’s loaded during the program run.

The first step to debugging a module is to create a debuggable version of Perl. By default, when you build and install Perl, the system builds an optimized version with no debugging information.

To build a debug version of the program, you’ll have to rebuild it.

This is done at configuration time. The first step in building the Perl program from source is to run the Configure command. It asks you for the compiler optimizing/debugger flag to be used to create the program. The default (–02) is good for a production version of the program. For a debug version, you’ll need to answer this question flag –g (enable debug).

By default, perl5 compiles with the –0 flag to use the optimizer. Alternatively, you might want to use the symbolic debugger, which uses the –g flag (on traditional UNIX systems). To use neither flag, specify the word “none”. Either flag can be specified here:

What optimizer/debugger flag should be used? [–02] –g

The next question the configuration tool asks is for any additional compilation flags. Because you answered –g in the previous step, the flag –DDEBUGGING will be added to the compiler flags. (Leave this option alone.) The configuration tool continues to run:

Checking if your compiler accepts –fno–strict–aliasing 
Yes, it does. 

Your C compiler may want other flags.  For this question you should include 
–I/whatever and –DWHATEVER flags and any other flags used by the C compiler, 
but you should NOT include libraries or ld flags like –lwhatever.  If you 
want perl5 to honor its debug switch, you should include –DDEBUGGING here. 
Your C compiler might also need additional flags, such as –D_POSIX_SOURCE. 

To use no flags, specify the word "none". 

Any additional cc flags? 
[–DDEBUGGING –fno–strict–aliasing –I/usr/local/include]

After you’ve compiled and built the Perl program, you can use it for debugging your modules.

Running the Debugger

To debug the module, you must first run the debugger on Perl. The example in this chapter uses the gdb debugger on Linux. This section shows you how to use this debugger to debug the function.

The first step is to figure out the name of the function. Although it is called mt_op, the Perl-to-C translation program (xsubpp) mangles the name.

Inspect the C code to see what xsubpp generates. In this case, the function declaration is

#line 18 "mt_op.c" 
XS(XS_mt_op_mt_op) 
{
    dXSARGS;

From this, you can see that the name of the function generated is XS_mt_op_mt_op. Now that you know what you are debugging, you can start the debugging.

The first thing to do is to start the debugger on the Perl program:

$ gdb /home/oualline/local/bin/perl 

GNU gdb 5.0 
Copyright 2000 Free Software Foundation, Inc. 
GDB is free software, covered by the GNU General Public License, and you are 
welcome to change it and/or distribute copies of it under certain conditions. 
Type "show copying" to see the conditions. 
There is absolutely no warranty for GDB.  Type "show warranty" for details. 
This GDB was configured as "i586–pc–linux–gnu"...

At this point, the module is not loaded, so putting in the breakpoint takes several steps. First, set a breakpoint in the library function that loads the dynamic library (dlopen):

(gdb) break dlopen 
Breakpoint 1 at 0x805a098

Next, run the program. The argument is the name of the script you are running (in this case mk–test.pl):

(gdb) run mt–test.pl 
Starting program: /home/oualline/local/bin/perl mt–test.pl 

Breakpoint 1, 0x805a098 in dlopen ()

You’ve hit the breakpoint. Go up one level (to the function in the Perl program that called the dlopen function) and see what module is being loaded:

(gdb) up 
#1  0x805a746 in XS_DynaLoader_dl_load_file (cv=0x8168d5c) at 
DynaLoader.xs:187 
warning: Source file is more recent than executable. 
187        RETVAL = dlopen(filename, mode) ; 
(gdb) print filename 
$1 = 0x8155288 "/home/oualline/local/lib/perl5/5.6.1/ 
i586–linux/auto/IO/IO.so"

This is not the module you want, so continue as follows:

(gdb) cont 
Continuing. 

Breakpoint 1, 0x805a098 in dlopen ()

You’ve hit the dlopen again, so go up a level and check the filename:

(gdb) up 
#1  0x805a746 in XS_DynaLoader_dl_load_file (cv=0x8168d5c) at 
DynaLoader.xs:187 
187        RETVAL = dlopen(filename, mode) ; 
(gdb) print filename 
$2 = 0x8155248 "/home/oualline/local/lib/perl5/5.6.1/ 
i586–linux/auto/Fcntl/Fcntl.so"

This is still not the module you want, so go on:

(gdb) cont 
Continuing. 

Breakpoint 1, 0x805a098 in dlopen () 
(gdb) up 
#1  0x805a746 in XS_DynaLoader_dl_load_file (cv=0x8168d5c) at 
DynaLoader.xs:187 
187        RETVAL = dlopen(filename, mode) ; 
(gdb) print filename 
$3 = 0x8155248 "/home/oualline/local/lib/perl5/5.6.1/i586– 
linux/auto/Socket/Socket.so"

Still not your module. Continue as follows:

(gdb) cont 
Continuing. 

Breakpoint 1, 0x805a098 in dlopen () 
(gdb) up 
#1  0x805a746 in XS_DynaLoader_dl_load_file (cv=0x8168d5c) at 
DynaLoader.xs:187 
187        RETVAL = dlopen(filename, mode) ; 
(gdb) print filename 
$4 = 0x82c8f88 "/home/oualline/local/lib/perl5/site_perl/5.6.1/ 
i586–linux/auto/mt_op/mt_op.so"

You’ve finally found the dlopen call that loads the module. You need to set a breakpoint just after the library is loaded. First, use the list command to display the code around the dlopen call:

(gdb) list 
182        mode |= RTLD_GLOBAL; 
183    #else 
184        Perl_warn(aTHX_ "Can't make loaded symbols global on 
this platform while loading %s",filename); 
185    #endif 
186        DLDEBUG(1,PerlIO_printf(Perl_debug_log, 
"dl_load_file(%s,%x):
", filename,flags)); 
187        RETVAL = dlopen(filename, mode) ; 
188        DLDEBUG(2,PerlIO_printf(Perl_debug_log, " libref=%lx
", 
(unsigned long) RETVAL)); 
189        ST(0) = sv_newmortal() ; 
190        if (RETVAL == NULL) 
191        SaveError(aTHX_ "%s",dlerror()) ;

The dlopen call occurs on line 187, so put a breakpoint on the next line, which is line 188:

(gdb) break 188 
Breakpoint 2 at 0x805a74e: file DynaLoader.xs, line 188.

Continue on to the next breakpoint:

(gdb) cont 
Continuing. 

Breakpoint 2, XS_DynaLoader_dl_load_file (cv=0x8168d5c) at DynaLoader.xs:188 
188        DLDEBUG(2,PerlIO_printf(Perl_debug_log, " libref=%lx
", 
(unsigned long) RETVAL));

At this point, the module is loaded. Finally, you are at a point that allows you to set a breakpoint in the module. Put a breakpoint in the main function and continue, as shown here:

(gdb) break XS_mt_op_mt_op 
Breakpoint 3 at 0x4017a9a5: file mt_op.c, line 20. 
(gdb) cont 
Continuing. 

Breakpoint 3, XS_mt_op_mt_op (cv=0x82935bc) at mt_op.c:20 
20        dXSARGS;

You’ve now stopped at the first line of the module. This means that you can use the normal debugging commands to examine the program. This includes listing the source, single-stepping, and examining variables:

(gdb) list 
15 
16 
17    #line 18 "mt_op.c" 
18    XS(XS_mt_op_mt_op) 
19    {
20        dXSARGS; 
21        if (items != 3) 
22        Perl_croak(aTHX_ "Usage: mt_op::mt_op(fd, op, count)"); 
23        {
24        int    fd = (int)SvIV(ST(0)); 
(gdb) n 
21        if (items != 3) 
(gdb) print items 
$6 = 3

Although you took the long way round, you finally found the way to your module. From here, it’s a simple matter of debugging.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset