Next Previous Contents

5. Debugging and Profiling

5.1 Preventative maintenance (lint)

There is no widely-used lint for Linux, as most people are satisfied with the warnings that gcc can generate. Probably the most useful is the -Wall switch --- this stands for `Warnings, all' but probably has more mnemonic value if thought of as the thing you bang your head against.

There is a public domain lint available from ftp://larch.lcs.mit.edu/pub/Larch/lclint. I don't know how good it is.

5.2 Debugging

How do I get debugging information into a program ?

You need to compile and link all its bits with the -g switch, and without the -fomit-frame-pointer switch. Actually, you don't need to recompile all of it, just the bits you're interested in debugging.

On a.out configurations the shared libraries are compiled with -fomit-frame-pointer, which gdb won't get on with. Giving the -g option when you link should imply static linking; this is why.

If the linker fails with a message about not finding libg.a, you don't have /usr/lib/libg.a, which is the special debugging-enabled C library. It may be supplied in the libc binary package, or (in newer C library versions) you may need to get the libc source code and build it yourself. You don't actually need it though; you can get enough information for most purposes simply by symlinking it to /usr/lib/libc.a

How do I get it out again?

A lot of GNU software comes set up to compile and link with -g, causing it to make very big (and often static) executables. This is not really such a hot idea.

If the program has an autoconf generated configure script, you can usually turn off debugging information by doing ./configure CFLAGS= or ./configure CFLAGS=-O2. Otherwise, check the Makefile. Of course, if you're using ELF, the program is dynamically linked regardless of the -g setting, so you can just strip it.

Available software

Most people use gdb, which you can get in source form from GNU archive sites, or as a binary from tsx-11 or sunsite. xxgdb is an X debugger based on this (i.e. you need gdb installed first). The source may be found at ftp://ftp.x.org/contrib/xxgdb-1.08.tar.gz

Also, the UPS debugger has been ported by Rick Sladkey. It runs under X as well, but unlike xxgdb, it is not merely an X front end for a text based debugger. It has quite a number of nice features, and if you spend any time debugging stuff, you probably should check it out. The Linux precompiled version and patches for the stock UPS sources can be found in ftp://sunsite.unc.edu/pub/Linux/devel/debuggers/, and the original source at ftp://ftp.x.org/contrib/ups-2.45.2.tar.Z.

Another tool you might find useful for debugging is `strace', which displays the system calls that a process makes. It has a multiplicity of other uses too, including figuring out what pathnames were compiled into binaries that you don't have the source for, exacerbating race conditions in programs that you suspect contain them, and generally learning how things work. The latest version of strace (currently 3.0.8) can be found at ftp://ftp.std.com/pub/jrs/.

Background (daemon) programs

Daemon programs typically execute fork() early, and terminate the parent. This makes for a short debugging session.

The simplest way to get around this is to set a breakpoint for fork, and when the program stops, force it to return 0.

(gdb) list 
1       #include <stdio.h>
2
3       main()
4       {
5         if(fork()==0) printf("child\n");
6         else printf("parent\n");
7       }
(gdb) break fork
Breakpoint 1 at 0x80003b8
(gdb) run
Starting program: /home/dan/src/hello/./fork 
Breakpoint 1 at 0x400177c4

Breakpoint 1, 0x400177c4 in fork ()
(gdb) return 0
Make selected stack frame return now? (y or n) y
#0  0x80004a8 in main ()
    at fork.c:5
5         if(fork()==0) printf("child\n");
(gdb) next
Single stepping until exit from function fork, 
which has no line number information.
child
7       }

Core files

When Linux boots it is usually configured not to produce core files. If you like them, use your shell's builtin command to re-enable them: for C-shell compatibles (e.g. tcsh) this is

% limit core unlimited
while Bourne-like shells (sh, bash, zsh, pdksh) use
$ ulimit -c unlimited

If you want a bit more versatility in your core file naming (for example, if you're trying to conduct a post-mortem using a debugger that's buggy itself) you can make a simple mod to your kernel. Look for the code in fs/binfmt_aout.c and fs/binfmt_elf.c (in newer kernels, you'll have to grep around a little in older ones) that says

        memcpy(corefile,"core.",5);
#if 0
        memcpy(corefile+5,current->comm,sizeof(current->comm));
#else
        corefile[4] = '\0';
#endif

and change the 0s to 1s.

5.3 Profiling

Profiling is a way to examine which bits of a program are called most often or run for longest. It is a good way to optimize code and look at where time is being wasted. You must compile all object files that you require timing information for with -p, and to make sense of the output file you will also need gprof (from the binutils package). See the gprof manual page for details.


Next Previous Contents