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.
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.