Next: , Up: Stack Traceback


8.1.14.1 Non-Symbolic Traceback

Note: this feature is not supported on all platforms. See GNAT.Traceback spec in g-traceb.ads for a complete list of supported platforms.

Tracebacks From an Unhandled Exception

A runtime non-symbolic traceback is a list of addresses of call instructions. To enable this feature you must use the `-E' gnatbind's option. With this option a stack traceback is stored as part of exception information. You can retrieve this information using the addr2line tool.

Here is a simple example:

    procedure STB is
    
       procedure P1 is
       begin
          raise Constraint_Error;
       end P1;
    
       procedure P2 is
       begin
          P1;
       end P2;
    
    begin
       P2;
    end STB;
    $ gnatmake stb -bargs -E
    $ stb
    
    Execution terminated by unhandled exception
    Exception name: CONSTRAINT_ERROR
    Message: stb.adb:5
    Call stack traceback locations:
    0x401373 0x40138b 0x40139c 0x401335 0x4011c4 0x4011f1 0x77e892a4

As we see the traceback lists a sequence of addresses for the unhandled exception CONSTRAINT_ERROR raised in procedure P1. It is easy to guess that this exception come from procedure P1. To translate these addresses into the source lines where the calls appear, the addr2line tool, described below, is invaluable. The use of this tool requires the program to be compiled with debug information.

    $ gnatmake -g stb -bargs -E
    $ stb
    
    Execution terminated by unhandled exception
    Exception name: CONSTRAINT_ERROR
    Message: stb.adb:5
    Call stack traceback locations:
    0x401373 0x40138b 0x40139c 0x401335 0x4011c4 0x4011f1 0x77e892a4
    
    $ addr2line --exe=stb 0x401373 0x40138b 0x40139c 0x401335 0x4011c4
       0x4011f1 0x77e892a4
    
    00401373 at d:/stb/stb.adb:5
    0040138B at d:/stb/stb.adb:10
    0040139C at d:/stb/stb.adb:14
    00401335 at d:/stb/b~stb.adb:104
    004011C4 at /build/.../crt1.c:200
    004011F1 at /build/.../crt1.c:222
    77E892A4 in ?? at ??:0

The addr2line tool has several other useful options:

--functions

to get the function name corresponding to any location


--demangle=gnat

to use the gnat decoding mode for the function names. Note that for binutils version 2.9.x the option is simply --demangle.

    $ addr2line --exe=stb --functions --demangle=gnat 0x401373 0x40138b
       0x40139c 0x401335 0x4011c4 0x4011f1
    
    00401373 in stb.p1 at d:/stb/stb.adb:5
    0040138B in stb.p2 at d:/stb/stb.adb:10
    0040139C in stb at d:/stb/stb.adb:14
    00401335 in main at d:/stb/b~stb.adb:104
    004011C4 in <__mingw_CRTStartup> at /build/.../crt1.c:200
    004011F1 in <mainCRTStartup> at /build/.../crt1.c:222

From this traceback we can see that the exception was raised in stb.adb at line 5, which was reached from a procedure call in stb.adb at line 10, and so on. The b~std.adb is the binder file, which contains the call to the main program. Running gnatbind. The remaining entries are assorted runtime routines, and the output will vary from platform to platform.

It is also possible to use GDB with these traceback addresses to debug the program. For example, we can break at a given code location, as reported in the stack traceback:

    $ gdb -nw stb

Furthermore, this feature is not implemented inside Windows DLL. Only the non-symbolic traceback is reported in this case.

    (gdb) break *0x401373
    Breakpoint 1 at 0x401373: file stb.adb, line 5.

It is important to note that the stack traceback addresses do not change when debug information is included. This is particularly useful because it makes it possible to release software without debug information (to minimize object size), get a field report that includes a stack traceback whenever an internal bug occurs, and then be able to retrieve the sequence of calls with the same program compiled with debug information.

Tracebacks From Exception Occurrences

Non-symbolic tracebacks are obtained by using the `-E' binder argument. The stack traceback is attached to the exception information string, and can be retrieved in an exception handler within the Ada program, by means of the Ada facilities defined in Ada.Exceptions. Here is a simple example:

    with Ada.Text_IO;
    with Ada.Exceptions;
    
    procedure STB is
    
       use Ada;
       use Ada.Exceptions;
    
       procedure P1 is
          K : Positive := 1;
       begin
          K := K - 1;
       exception
          when E : others =>
             Text_IO.Put_Line (Exception_Information (E));
       end P1;
    
       procedure P2 is
       begin
          P1;
       end P2;
    
    begin
       P2;
    end STB;

This program will output:

    $ stb
    
    Exception name: CONSTRAINT_ERROR
    Message: stb.adb:12
    Call stack traceback locations:
    0x4015e4 0x401633 0x401644 0x401461 0x4011c4 0x4011f1 0x77e892a4
Tracebacks From Anywhere in a Program

It is also possible to retrieve a stack traceback from anywhere in a program. For this you need to use the GNAT.Traceback API. This package includes a procedure called Call_Chain that computes a complete stack traceback, as well as useful display procedures described below. It is not necessary to use the `-E gnatbind' option in this case, because the stack traceback mechanism is invoked explicitly.

In the following example we compute a traceback at a specific location in the program, and we display it using GNAT.Debug_Utilities.Image to convert addresses to strings:

    with Ada.Text_IO;
    with GNAT.Traceback;
    with GNAT.Debug_Utilities;
    
    procedure STB is
    
       use Ada;
       use GNAT;
       use GNAT.Traceback;
    
       procedure P1 is
          TB  : Tracebacks_Array (1 .. 10);
          --  We are asking for a maximum of 10 stack frames.
          Len : Natural;
          --  Len will receive the actual number of stack frames returned.
       begin
          Call_Chain (TB, Len);
    
          Text_IO.Put ("In STB.P1 : ");
    
          for K in 1 .. Len loop
             Text_IO.Put (Debug_Utilities.Image (TB (K)));
             Text_IO.Put (' ');
          end loop;
    
          Text_IO.New_Line;
       end P1;
    
       procedure P2 is
       begin
          P1;
       end P2;
    
    begin
       P2;
    end STB;
    $ gnatmake -g stb
    $ stb
    
    In STB.P1 : 16#0040_F1E4# 16#0040_14F2# 16#0040_170B# 16#0040_171C#
    16#0040_1461# 16#0040_11C4# 16#0040_11F1# 16#77E8_92A4#

You can then get further information by invoking the addr2line tool as described earlier (note that the hexadecimal addresses need to be specified in C format, with a leading '0x').