Subsections

- 1 Compiling your program with debugger support
- 2 Using `gdb` to debug your program
- 3 Caveats when debugging with `gdb`
- 4 Support for `gprof`, the GNU profiler
- 5 Detecting heap memory leaks
- 6 Line numbers in run-time error backtraces
- 7 Combining heaptrc and lineinfo

# 10 Debugging your Programs

Free Pascal supports debug information for the GNU debugger `gdb`, or its derivatives Insight on win32 or ddd on LINUX.

This chapter describes shortly how to use this feature. It doesn't attempt to describe completely the GNU debugger, however. For more information on the workings of the GNU debugger, see the `gdb` users' guide.

Free Pascal also suports `gprof`, the GNU profiler, see section for more information on profiling.

# 1 Compiling your program with debugger support

First of all, you must be sure that the compiler is compiled with debugging support. Unfortunately, there is no way to check this at run time, except by trying to compile a program with debugging support.

To compile a program with debugging support, just specify the `-g` option on the command-line, as follows:

    fpc -g hello.pp

This will generate debugging information in the executable from your program. You will notice that the size of the executable increases substantially because of this.

Note that the above will only generate debug information for the code that has been generated when compiling hello.pp. This means that if you used some units (the system unit, for instance) which were not compiled with debugging support, no debugging support will be available for the code in these units.

There are 2 solutions for this problem.

1. Recompile all units manually with the `-g` option.
2. Specify the 'build' option (`-B`) when compiling with debugging support. This will recompile all units, and insert debugging information in each of the units.

The second option may have undesirable side effects. It may be that some units aren't found, or compile incorrectly due to missing conditionals, etc..

If all went well, the executable now contains the necessary information with which you can debug it using GNU `gdb`.

#
2 Using `gdb` to debug your program

To use gdb to debug your program, you can start the debugger, and give it as an option the full name of your program:

    gdb hello

Or, under DOS:

    gdb hello.exe

This starts the debugger, and the debugger immediately loads your program into memory, but it does not run the program yet. Instead, you are presented with the following (more or less) message, followed by the `gdb` prompt `'(gdb)'`:

    GDB is free software and you are welcome to 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.
    GDB 4.15.1 (i486-slackware-linux),
    Copyright 1995 Free Software Foundation, Inc...
    (gdb)

To start the program you can use the `run` command. You can optionally specify command-line parameters, which will then be fed to your program, for example:

    (gdb) run -option -anotheroption needed_argument

If your program runs without problems, `gdb` will inform you of this, and return the exit code of your program. If the exit code was zero, then the message `'Program exited normally'` is displayed.

If something went wrong (a segmentation fault or so), `gdb` will stop the execution of your program, and inform you of this with an appropriate message. You can then use the other `gdb` commands to see what happened. Alternatively, you can instruct `gdb` to stop at a certain point in your program, with the `break` command.

Here is a short list of `gdb` commands, which you are likely to need when debugging your program:

quit
  Exits the debugger.
kill
  Stops a running program.
help
  Gives help on all `gdb` commands.
file
  Loads a new program into the debugger.
directory
  Add a new directory to the search path for source files.

  Remark: My copy of gdb needs '.' to be added explicitly to the search path, otherwise it doesn't find the sources.

list
  Lists the program sources per 10 lines. As an option you can specify a line number or function name.
break
  Sets a breakpoint at a specified line or function
awatch
  Sets a watch-point for an expression. A watch-point stops execution of your program whenever the value of an expression is either read or written.

for more information, see the `gdb` users' guide, or use the `'help'` function in `gdb`.

The appendix contains a sample init file for `gdb`, which produces good results when debugging Free Pascal programs.

It is also possible to use RHIDE, a text-based IDE that uses gdb. There is a version of RHIDE available that can work together with FPC.

# 3 Caveats when debugging with `gdb`

There are some peculiarities of Free Pascal which you should be aware of when using `gdb`. We list the main ones here:

1. Free Pascal generates information for GDB in uppercare letters. This is a consequence of the fact that pascal is a case insensitive language. So, when referring to a variable or function, you need to make its name all uppercase.

   As an example, of you want to watch the value of a loop variable `count`, you should type

       watch COUNT

   Or if you want stop when a certain function (e.g `MyFunction`) is called, type

       break MYFUNCTION

2. `gdb` does not know sets.

3. `gdb` doesn't know strings. Strings are represented in `gdb` as records with a length field and an array of char contaning the string.

   You can also use the following user function to print strings:

       define pst
       set $pos=&$arg0
       set $strlen = {byte}$pos
       print {char}&$arg0.st@($strlen+1)
       end

       document pst
         Print out a Pascal string
       end

   If you insert it in your gdb.ini file, you can look at a string with this function. There is a sample gdb.ini in appendix .

4. Objects are difficult to handle, mainly because `gdb` is oriented towards C and C++. The workaround implemented in Free Pascal is that object methods are represented as functions, with an extra parameter `this` (all lowercase !) The name of this function is a concatenation of the object type and the function name, separated by two underscore characters.

   For example, the method `TPoint.Draw` would be converted to `TPOINT__DRAW`, and could be stopped at with

       break TPOINT__DRAW

5. Global overloaded functions confuse `gdb` because they have the same name. Thus you cannot set a breakpoint at an overloaded function, unless you know its line number, in which case you can set a breakpoint at the starting linenumber of the function.

#
4 Support for `gprof`, the GNU profiler

You can compile your programs with profiling support. for this, you just have to use the compiler switch `-pg`. The compiler wil insert the necessary stuff for profiling.

When you have done this, you can run your program as you normally would run it.

    yourexe

Where yourexe is the name of your executable.

When your program finishes a file called gmon.out is generated. Then you can start the profiler to see the output. You can better redirect the output to a file, becuase it could be quite a lot:

    gprof yourexe > profile.log

Hint: you can use the -flat option to reduce the amount of output of gprof. It will then only output the information about the timings

For more information on the GNU profiler `gprof`, see its manual.

#
5 Detecting heap memory leaks

Free Pascal has a built in mechanism to detect memory leaks. There is a plug-in unit for the memory manager that analyses the memory allocation/deallocation and which prints a memory usage report after the program exits.

The unit that does this is called heaptrc. If you want to use it, you should include it as the first unit in you uses clause. Alternatively, you can supply the `-gh` switch to the compiler, and it will include the unit automatically for you.

After the program exits, you will get a report looking like this:

    Marked memory at 0040FA50 invalid
    Wrong size : 128 allocated 64 freed
      0x00408708
      0x0040CB49
      0x0040C481
    Call trace for block 0x0040FA50 size 128
      0x0040CB3D
      0x0040C481

The output of the heaptrc unit is customizable by setting some variables.

You can find more information about the usage of the heaptrc unit in the Unit reference.

#
6 Line numbers in run-time error backtraces

Normally, when a run-time error occurs, you are presented with a list of addresses that represent the call stack backtrace, i.e. the addresses of all procedures that were invoked when the run-time error occurred.

This list is not very informative, so there exists a unit that generates the file names and line numbers of the called procedures using the addresses of the stack backtrace. This unit is called lineinfo.

You can use this unit by giving the `-gl` option to the compiler. The unit will be automatically included. It is also possible to use the unit explicitly in your `uses` clause, but you must make sure that you compile your program with debug info.

Here is an example program:

    program testline;

    procedure generateerror255;

    begin
      runerror(255);
    end;

    procedure generateanerror;

    begin
      generateerror255;
    end;

    begin
      generateanerror;
    end.

When compiled with `-gl`, the following output is generated:

    Runtime error 255 at 0x0040BDE5
      0x0040BDE5  GENERATEERROR255,  line 6 of testline.pp
      0x0040BDF0  GENERATEANERROR,  line 13 of testline.pp
      0x0040BE0C  main,  line 17 of testline.pp
      0x0040B7B1

Which is more understandable than the normal message. Make sure that all units you use are compiled with debug info, because if they are not, no line number and filename can be found.

# 7 Combining heaptrc and lineinfo

If you combine the lineinfo and the heaptrc information, then the output of the heaptrc unit will contain the names of the files and line numbers of the procedures that occur in the stack backtrace.

In such a case, the output will look something like this:

    Marked memory at 00410DA0 invalid
    Wrong size : 128 allocated 64 freed
      0x004094B8
      0x0040D8F9  main,  line 25 of heapex.pp
      0x0040D231
    Call trace for block 0x00410DA0 size 128
      0x0040D8ED  main,  line 23 of heapex.pp
      0x0040D231

If lines without filename/line-number occur, this means there is a unit which has no debug info included. (in the above case, the getmem call itself)