GDB Debugger Tips

From Lazarus wiki
Jump to navigationJump to search

Introduction

Lazarus comes with GDB as default debugger.

Currently (Lazarus 0.9.26) not all features are implemented, and some things are not supported by GDB. Development is ongoing.

Below are a few of the existing issues (including workarounds where available), that can be encountered while using the debugger.

General

Properties

Update: With fpc 2.3.1 some of this changed. See the FAQ.

GDB has no concept of pascal-like properties. In addition some properties do have a "read" declaration that points to a function, rather than to a variable. Or they may not have a read declaration at all.

If properties point to a Function, there is currently no work around. Code evaluation is currently not supported. Also remember that it would be dangerous to call the function from the debugger (outside the normal flow of the application). This can modify the state of the application (a function may change other objects)

If a property refers to a variable then you can use the "watch"-window and inspect the variable directly. Usually this is done by prefixing it with a "F" ("property Text : String read FText")

Unfortunately this means you have to use the watch-window, you can not hover the mouse over a property in the source)

Nested Procedures / Function

(Works in Lazarus 0.9.29)


Procedure SomeObject.Outer(NumText: String);
var OuterNum: integer;
  Procedure Nested;
  begin
    self.Num := Outernum;
  end
begin
  OuterNum := StrToInt(NumText);
  Nested;
end

While the "Nested" code is executed, GDB can only see the Stackframe of that Procedure. This Stackframe does *not* contain NumText, OuterNum nor self. (Since "self" is not visible to GDB, Self.Num (or just Num, or anything else on the object) is also not visible, and can not be inspected)

You will also note that the "local variable" window will not show anything belonging to the outer procedure. (Despite GDB being unable to show the info, it is available to your program and execution works)

If you need to inspect those values while in "Nested", you can open the "Stack" window, and use the "current"-button (or context menu) to change the current stackframe to the "Outer" procedure.

You can then see all the values (using the "watches" or the "local variables" window, or hints by hovering the mouse over variables in the source). Executing your app, or stepping to the next instruction, will set the current stack fram back to the "Nested" procedure.

Variables treated as pointer

Sometimes Variables are pointers in GDB, where they are not in Pascal.

if you type SomeObject as a watch it may just say "TSomeClass 0x23ab76". Try typing SomeObject^

Dynamic Arrays

FPC 2.2.4

See the following post for a workaround (it may be too complex for every day use, but it may help for desperate occasions) http://forum.lazarus.freepascal.org/index.php/topic,4763.msg22954.html#msg22954

to look at Array of String try this:

PChar(^LONGINT(^LONGINT(@t)^+0)^)
PChar(^LONGINT(^LONGINT(@t)^+4)^)
PChar(^LONGINT(^LONGINT(@t)^+8)^)

Each string needs an increase of 4 in the offset, so the above are the string at index: 0, 1, 2

and for the length of array (minus 4)

^LONGINT(^LONGINT(@t)^-4)^

FPC 2.3.1

Under fpc 2.3.1 I found the following for some arrays. (using stabs) type

 TStringArray: Array of String;

var

 a: TStringArray

Can be monitored (watch window) using

a^[0]
a^[1]

So you have to add an extra "^"

if you have var

 a : Array of String;

You can view it (but you must have TStringArray declared in your source, and maybe used somewhere, so it was forced into debug info:

TStringArray(@Text)^[0]

If you do not have TStringArray

 Pchar((^Ptrint(@Text)+0)^)
 Pchar((^Ptrint(@Text)+1)^)

Whatever expression you enter in watches: make sure, there are no spaces in it.

Mac OSX

Under OSX you usually install GDB with the Apple developer tools. The version of GDB available at the time of writing this is 6.3.50

This section is a first approach to collect information about known issues and workarounds. The information provided here depends a lot on feedback from OSX users.

Known Problems

Debugging 32 bit app on 64 bit architecture

It is possible and maybe sometime necessary to debug a 32 bit exe on a 64 bit system.

This is only possible with Lazarus 0.9.29 rev 28640 and up. As of Dec 2010 this feature is relatively new, and little tested. You may experience problems.

Debug session freezes

It appears that certain commands are not correctly (or incompletely) processed by gdb 6.3.50. GDB will not signal to the IDE that it finished the command, and the IDE will wait forever for gdb to return. Effectively your debug session becomes non-reactive. (Normally GDB finishes each command with a "<gdb>" prompt for the next command)

This has been observed with:

  • Certain Watch expressions (at least if the watched variable was not available in the current selected function)
  • [Fixed in rev 28640] 32 bit app on 64bit architecture raising an Exception

The only way to deal with this, is to define a time-out, and to assume if the time-out is reached, that the command indeed finished, and simply forgot to signal this fact. However it is impossible:

  • to predict how long a command really takes
  • to guarantee GDB will not later return some results from such a command
  • to guarantee that GDB's internal state is still valid

For those reasons this issue can not be properly fixed at current.

As a work around time-out have been added. To enable them recompile the IDE with the following define: DBG_WITH_TIMEOUT ( -dDBG_WITH_TIMEOUT ) Please note:

  • There is no guarantee how well, or bad this works. You use that at your own risk. However a warning prompt will alert you if a time-out occurred
  • Time-outs have not yet been added to all functions. If you encounter uncaught time-outs (while having the define enabled), then please report them.

An alternative solution seems to be to use a newer version of GDB

Hardware exceptions under Mac OS X

When a hardware exception occurs under Mac OS X, such as an invalid pointer access (SIGSEGV) or an integer division-by-zero on Intel processors, the debugger will catch this exception at the Mach level. Normally, the system translates these Mach exceptions into Unix-style signals where the FPC run time library handles them. The debugger is however unable to propagate Mach exceptions in this way.

The practical upshot is that it is impossible under Mac OS X to continue a program in the debugger once a hardware exception has been triggered. This is not FPC-specific, and cannot be fixed by us.

Using Alternative Debuggers

You can download GDB 7.1 from MacPorts

The following observations have been made:

  • MacPort GDB 7.1 seems to have issues with the stabs debug info from fpc.
Watch out for the linker warnings about "unknown stabs"
To avoid those issues, you must compile your app with -gw (dwarf) (maybe -gw3, not yet tested)
You must also ensure that no code at all, is compiled with stabs. Your LCL may contain stabs, and this will end up in your app, even if you compile the app with -gw. So you may have to recompile your LCL with -gw (or without any debug info). Same for any other unit, package, rtl, .... that may have stabs
  • MacPort GDB 7.1 seems to be unable to handle application-bundles. In order to debug your app, you may have to compile it without the app bundle (or maybe (not tested) you can use "run param" to specify the actual executable inside the bundle)


Those observations may be incomplete or wrong, please update them, if you have more information.

Links

  • Mac OS X comes with a lot of useful tools for debugging and profiling. Just start /Developer/Applications/Instruments.app and try them out.