Difference between revisions of "GDB Debugger Tips"

From Lazarus wiki
Jump to navigationJump to search
Line 3: Line 3:
 
Lazarus comes with GDB as default debugger.  
 
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.
+
Currently (Lazarus 0.9.28) 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.
 
Below are a few of the existing issues (including workarounds where available), that can be encountered while using the debugger.

Revision as of 22:19, 13 January 2011

Introduction

Lazarus comes with GDB as default debugger.

Currently (Lazarus 0.9.28) 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.

Debug Info Type

Stabs

-g or -gs

You should only use if your gdb version does not support dwarf. There are very few other cases where you need it.

You may need it with "var param" (param by ref) procedure foo(var a: integer); However the IDE deals with this in 99% of all cases.

Dwarf

-gw

use with -godwarfsets if you have a recent gdb. Otherwhise sets are not displayed correctly.


General

Strings

If you inspect strings and whis to inspect individual chars by index (mystring[10]), then you must unfortunately specify the index 0-based. That is one less than you would normally: mystring[10-1]

This is because gdb thinks the index is 0-based. This problem will be fixed in some future release.

Properties

Currently the debugger does not support any method execution. Therefore only properties that refer directly to a variable can be inspected.

 TFoo = Class
 private
   FBar: Integer;
   function GetValue: Integer;
 public
   property Bar: Integer read FBar;        // Can be inspected
   property Value: Integer read GetValue;  // Can *not* be inspected
 end;


Nested Procedures / Function

Procedure SomeObject.Outer(NumText: String);
var 
  OuterVarInScope: integer;
  Procedure Nested;
  var i: Integer;
  begin
    writeln(OuterVarInScope);  
  end
var 
  OuterVarOutsideScope: integer;
begin
  Nested;
end

If you step into "Nested", then the IDE allows you to inspect variables from both stack-frames.

This is you can inspect: i, OuterVarInScope, NumText (without having to change the current stack frame, in the stack window)

However there are some caveats:

You can also inspect: OuterVarOutsideScope. That is against pascal scoping rules. This only matters, if you have several nested levels, and they all contain a variable of the same name, but the pascal scoping would hide the variable from the middle frame. Then you get to see the wrong value.

You can not evaluate statements across the 2 frames: "OuterVarnScope-i" does not work.

Variables treated as pointer

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

The IDE tries to correct this in many cases. If not you still have to fix it yourself. (One reasone why this might not be corrected by the IDE can be mixed stabs and dwarf debug info)

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

Dynamic Arrays

To be updated for fpc 2.4.2

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.