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.
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
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.
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/.
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 }
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 0
s to 1
s.
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.