When developing a new module, server debugging can help pinpoint what is happening in some cases; however, when tracking down such things as segfaults ("signal 11") or tracing the logic through a complex sequence of function calls, more complicated forms of debugging are needed.
The Developer configure
Option
By default, proftpd
compiles into an executable suitable for
running on a live server. However, this means that the executable isn't as
well suited for debugging (debug versions of programs often run slower).
To generate a debug version of proftpd
, use the
--enable-devel
configure option. By itself, this option has
two side effects: first, it enables quite a few -W
compiler
switches, which make the compiler more verbose and more picky about shadowed
variables, prototype mismatches, use of long double
, etc; second,
the generated proftpd
binary will not be stripped of its symbols
when make install
is run. This means the binary will be larger,
but it will also be easier to use debugging tools on the binary. Please
compile your module using --enable-devel
, and fixing any generated
errors and warnings, before contributing it.
The --enable-devel
option can also take parameters that alter
proftpd
's behavior. These parameters are: coredump
,
nodaemon
, and nofork
. The first parameter,
coredump
, enables proftpd
to generate a
core
file under certain conditions (segfault,
SIGABRT
); unless this parameter is used, the code takes stringent
steps explicitly in order to not generate coredumps, by design.
The second parameter, nodaemon
, makes proftpd
not
use any of the functions it would normally use when daemonizing. Finally,
the nofork
parameter means that proftpd
will not
fork()
a process to handle a connecting client--all sessions will
be handled by the same proftpd
process. These parameters
can be combined when using the --enable-devel
option, like so:
./configure --enable-devel=nodaemon:nofork ...or, to use them all:
./configure --enable-devel=coredump:nodaemon:nofork ...
Tracing Programs
Your operating system should provide some utilities to help with system
call tracing (e.g. strace
and ltrace
on
Linux, ktrace
and kdump
on FreeBSD, truss
on Solaris, tusc
on HP-UX); read their respective man pages for
more information.
The GNU Debugger
The GNU debugger, gdb
, is a superb tool for debugging programs.
Like many such excellent tools, it can be intimidating for the uninitiated,
but its use is highly recommended. There are even graphical frontends,
such as ddd
for
those who prefer graphical environments.
gdb
provides the most information when it is used to run a program
that has been linked with the debug version of libc
, and whose
symbols have not been stripped. Thus, configure proftpd
using
the --enable-devel
configure option. Then, run your compiled
proftpd
binary like so:
# gdb ./proftpd Copyright 2001 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. (no debugging symbols found)... (gdb)At the prompt, start running the program, and pass it any of the usual
proftpd
command-line options:
(gdb) run -nd5You can set breakpoints before running the program, step through certain functions, etc. One of the more useful uses of
gdb
is for
determining where, and how, segfaults occur. You run proftpd
under the debugger until you trigger the segfault. gdb
will
display a message about catching the SIGSEGV
signal, and the
name of the function, file, and line number at which it happened. Sometimes
this segfault occurs within the C library, but is almost always due to the
application code. When this happens, at the (gdb)
prompt,
generate a backtrace:
(gdb) backtraceA backtrace is a listing of the function call stack, from the start of the program to the point where the segfault occurs. One can then quickly narrow down where in the application code the bug is lurking.
Memory
C programs are notorious for memory leaks and other memory allocation related
issues. Numerous articles and programs have been written to address this.
I recommend using valgrind
or GNU checker
.
Profiling
Profiling the code can be considered a form of debugging, once all other
functionality-related bugs have been fixed. In order to compile a profile
version of proftpd
, you need the following:
CFLAGS="-DPR_DEVEL_NO_DAEMON -DPR_DEVEL_NO_FORK -g -pg -a" LIBS=-pg ./configure --enable-devel ...The resulting daemon will only handle one session, as is necessary (the daemonizing and
fork()
code interferes with the functioning of the
profiling code added by the compiler). This profile version will generate
two files, bb.out
and gmon.out
, in the
RUN_DIR
directory (typically /var/run/proftpd
).
Then, to see the call graph info, change to the directory where the
bb.out
and gmon.out
profiling files are, and
invoke the following command:
gprof /path/to/proftpdThe
gprof
program has quite a few options for generating call
graphs and timing information; read the man page to find out more information.