improved error message when getting an exception printing a variable
authorJoel Brobecker <brobecker@adacore.com>
Mon, 18 Dec 2017 03:39:33 +0000 (22:39 -0500)
committerJoel Brobecker <brobecker@adacore.com>
Mon, 18 Dec 2017 03:39:33 +0000 (22:39 -0500)
commiteccab96d54a9455557d3c4d5bff431f6e526d0b7
tree97e49f9839a29d3bc754ed2ccdeef7a79c3cb3c1
parent0e2da9f01334a01d1a6e224ecd592d6fbbb22515
improved error message when getting an exception printing a variable

Consider the following Ada code defining a global variable whose
type is an array of static bounds (1 .. 2), but where its elements
are a variant record whose size is not statically known:

    type Ints is array (Natural range <>) of Integer;
    type Bounded_Ints (Max_Size : Natural) is record
       Length : Natural := 0;
       Objs   : Ints (1 .. Max_Size);
    end record;

    type Ints_Doubled is array (1 .. 2) of Bounded_Ints (Idem (0));

    Global : Ints_Doubled;

When compiling this program at -O2 using a GCC-6.4-based compiler
on x86_64-linux, trying to print the value of that global variable
yields:

    (gdb) p global
    $1 =

Let's look at the debugging info, which starts with the global
variable itself...

        .uleb128 0x19   # (DIE (0x25e) DW_TAG_variable)
        .long   .LASF32 # DW_AT_name: "fd__global"
        .long   0x273   # DW_AT_type

... its type is a reference to a typedef ...

        .uleb128 0x14   # (DIE (0x273) DW_TAG_reference_type)
        .byte   0x8     # DW_AT_byte_size
        .long   0x202   # DW_AT_type
        [...]
        .uleb128 0x15   # (DIE (0x202) DW_TAG_typedef)
        .long   .LASF19 # DW_AT_name: "fd__ints_doubled"
        .long   0x20d   # DW_AT_type

... of an array (1..2) ...

        .uleb128 0x2    # (DIE (0x20d) DW_TAG_array_type)
        .long   .LASF19 # DW_AT_name: "fd__ints_doubled"
        .long   0x15b   # DW_AT_type
        .long   0x221   # DW_AT_sibling
        .uleb128 0x16   # (DIE (0x21a) DW_TAG_subrange_type)
        .long   0x40    # DW_AT_type
        .sleb128 2      # DW_AT_upper_bound
        .byte   0       # end of children of DIE 0x20d

... of a struct whose name is fd__Tints_doubledC:

        .uleb128 0x10   # (DIE (0x15b) DW_TAG_structure_type)
        .long   .LASF11 # DW_AT_name: "fd__Tints_doubledC"
        .long   0x1e4   # DW_AT_GNAT_descriptive_type
                        # DW_AT_artificial
        .long   0x1e4   # DW_AT_sibling
        .uleb128 0x7    # (DIE (0x16a) DW_TAG_member)
        .long   .LASF4  # DW_AT_name: "max_size"
        [snip]

The error occurs while Ada evaluator is trying to "fix"
the element type inside the array, so as to determine its actual
size. For that, it searches for a parallel "XVZ" variable,
which, when found, contains the object's actual size.

Unfortunately in our case, the variable exists but has been
optimized out, as seen by the presence of a variable DIE in
the debugging info, but with no address attribute:

        .uleb128 0x18   # (DIE (0x24e) DW_TAG_variable)
        .long   .LASF31 # DW_AT_name: "fd__Tints_doubledC___XVZ"
        .long   0x257   # DW_AT_type
                        # DW_AT_artificial

Discussing this with some members of AdaCore's compiler team,
it is expected that the optimizer can get rid of this variable,
and we don't want to pessimize the code just to improve debuggability,
since -O2 is about performance. So, the idea of this patch is
not to make it work, but provide a bit more information to help
users understand what kind of error is preventing GDB from being
able to print the variable's value.

The first hurdle we had to clear was the fact that ada_val_print
traps all exceptions (including QUIT ones!), and does so completly
silently. So, the fix was to add a trace of the exception being
generated. While doing so, we fix an old XXX/FIXME by only catching
errors, letting QUIT exceptions go through.

Once this is done, we now get an error message, which gives a first
clue as to what was happening:

    (gdb) p fd.global
    $1 = <error reading variable: value has been optimized out>

However, it would be more useful to know which value it was
that was optimized out. For that purpose, we enhanced
ada-lang.c::ada_to_fixed_type_1 so as to re-throw the error
with a message which indicates which variable we failed to read.

With those changes, the new output is now:

    (gdb) p fd.global
    $1 = <error reading variable: unable to read value of fd__Tints_doubledC___XVZ (value has been optimized out)>

gdb/ChangeLog:

        * ada-lang.c (ada_to_fixed_type_1): Rethrow errors with
        a more detailed exception message when getting an exception
        while trying to read the value of an XVZ variable.
        * ada-valprint.c (ada_val_print): Only catch RETURN_MASK_ERROR
        exceptions.  Print an error message when an exception is caught.

gdb/testsuite/ChangeLog:

        * gdb.dwarf2/ada-valprint-error.c: New file.
        * gdb.dwarf2/ada-valprint-error.exp: New file.

Tested on x86_64-linux
gdb/ChangeLog
gdb/ada-lang.c
gdb/ada-valprint.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.dwarf2/ada-valprint-error.c [new file with mode: 0644]
gdb/testsuite/gdb.dwarf2/ada-valprint-error.exp [new file with mode: 0644]