Penguin
Note: You are viewing an old revision of this page. View the current version.

You might also be interested in the CommonProgrammingBugs page.

Debugging under Linux is done mostly by using gdb(1).

If you want to debug a program:

  1. Compile it with debugging support. This is done by adding the -g option to the gcc(1) command line. If you are using make(1), you can export CFLAGS=-g, you should also set -Wall too, but only because it's a good idea in general. An example: gcc -g -Wall foo.c -o foo
  2. Load your program in gdb: "gdb ./programname"
  3. type "run" at the prompt to run the program.
  4. when the program crashes you should be able to type "bt full" to get a full backtrace of what the program was doing at the time.

useful gdb(1) commands:

bt full
give a complete backtrace of a program. If a program crashes this is what the programmer will want from you.
print
This lets you print out various expressions, eg: "print node" "print *node" "print node->key" "print node->next->key" etc.
break
This lets you set breakpoints at functions or lines in the source code, eg: "break main" or "break sourcefile.cpp:55"
run
run a program up until a break point.
step
step over a function call
next
step into a function call
frame
change which frame you are working on. eg: "frame 1" will change the scope to frame 1.

Other useful debugging tricks and traps:

strace

strace(1) lets you see what a program is doing in a coarse kind of way, if you think strace(1) is too quiet, perhaps ltrace(1)? is for you. for the bsdites amongst us, I believe these are called struss(1)? and sotrace(1)?. The command for this is
strace programname
if the program is already running
strace -p pid

will also work.

signals

If your program hangs, you can press Alt-\ to send it a SIGQUIT and force it to dump core. You can also force them to dump core with the command
kill -QUIT programpid

Core files

To create core files you have to remove the ulimit(1) on them. This can be done with the command
ulimit -c unlimited

Note, this is for the shell (and all it's children) only.

gdb(1) can also do postmortem analysis on core files like so
gdb ./program ./corefile

If you run gdb(1) on your program and it displays the names of the functions but doesn't display their types (eg: what arguments they have or line number information) you probably didn't compile them with -g

modifying a running process

You can use gdb to attach to a currently running process. For example, to change where its stderr is going
$ gdb <executable> <process_id> (gdb) call close(2) $1 = 0 (gdb) call open("/tmp/prog-debug", 0101) $2 = 2 (gdb) cont

Note that the octal 0101 stands for O_CREAT|O_WRONLY, since gdb will complain about no debugging symbols for resolving those words otherwise. Check with your /usr/include files... the c library with debian testing at least has these definitions in /usr/include/bits/fcntl.h. (0100 + 01).

ddd

ddd(1)? appears to be a reasonable GUI interface to gdb(1) for those that are afraid of CommandLines.

assert

use assert(3) everywhere in your source code. It's much nicer at finding your bugs closer to where the bug actually hides.

Electric Fence

Make use of electricfence (libefence) for tracking memory allocation errors. In debian this can be enabled on the fly by setting an LD_PRELOAD variable, like so
LD_PRELOAD=libefence.so.0.0 your-buggy-programme

threads

Note: When using gdb(1) to debug a threaded program, gdb(1) catches two signals (SIGPWR & SIGXCPU) which are used internally by pthreads on Linux. Use

(gdb) handle SIGPWR pass nostop noprint (gdb) handle SIGXCPU pass nostop noprint

to stop gdb halting on receiving these signals.

Other useful commands

  • catchsegv - prints out the backtrace of function calls for a program receiving a SIGSEGV. - don't forget to compile with -g if you want file names and line numbers to be accessible.
  • c++filt(1) - reverses the C++ symbol name-mangling that gcc(1) does, so if the program uses c++ then you can read the function names.

Other neat tools for diagnosing memory errors are: