From eccab96d54a9455557d3c4d5bff431f6e526d0b7 Mon Sep 17 00:00:00 2001 From: Joel Brobecker Date: Sun, 17 Dec 2017 22:39:33 -0500 Subject: [PATCH] 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 = 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 = 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 | 8 ++ gdb/ada-lang.c | 21 +++- gdb/ada-valprint.c | 6 +- gdb/testsuite/ChangeLog | 5 + gdb/testsuite/gdb.dwarf2/ada-valprint-error.c | 23 ++++ .../gdb.dwarf2/ada-valprint-error.exp | 115 ++++++++++++++++++ 6 files changed, 173 insertions(+), 5 deletions(-) create mode 100644 gdb/testsuite/gdb.dwarf2/ada-valprint-error.c create mode 100644 gdb/testsuite/gdb.dwarf2/ada-valprint-error.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 5e65e5fbf2a..40234723498 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,11 @@ +2017-12-18 Joel Brobecker + + * 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. + 2017-12-18 Joel Brobecker * ada-lang.c (assign_component): Strip any TYPE_CODE_TYPEDEF diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index 14a0bd63a3b..dad2b17794c 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -9101,11 +9101,28 @@ ada_to_fixed_type_1 (struct type *type, const gdb_byte *valaddr, const char *name = ada_type_name (fixed_record_type); char *xvz_name = (char *) alloca (strlen (name) + 7 /* "___XVZ\0" */); + bool xvz_found = false; LONGEST size; xsnprintf (xvz_name, strlen (name) + 7, "%s___XVZ", name); - if (get_int_var_value (xvz_name, size) - && TYPE_LENGTH (fixed_record_type) != size) + TRY + { + xvz_found = get_int_var_value (xvz_name, size); + } + CATCH (except, RETURN_MASK_ERROR) + { + /* We found the variable, but somehow failed to read + its value. Rethrow the same error, but with a little + bit more information, to help the user understand + what went wrong (Eg: the variable might have been + optimized out). */ + throw_error (except.error, + _("unable to read value of %s (%s)"), + xvz_name, except.message); + } + END_CATCH + + if (xvz_found && TYPE_LENGTH (fixed_record_type) != size) { fixed_record_type = copy_type (fixed_record_type); TYPE_LENGTH (fixed_record_type) = size; diff --git a/gdb/ada-valprint.c b/gdb/ada-valprint.c index 91dc301af5f..b4a48ce5152 100644 --- a/gdb/ada-valprint.c +++ b/gdb/ada-valprint.c @@ -1168,16 +1168,16 @@ ada_val_print (struct type *type, struct value *val, const struct value_print_options *options) { - - /* XXX: this catches QUIT/ctrl-c as well. Isn't that busted? */ TRY { ada_val_print_1 (type, embedded_offset, address, stream, recurse, val, options, current_language); } - CATCH (except, RETURN_MASK_ALL) + CATCH (except, RETURN_MASK_ERROR) { + fprintf_filtered (stream, _(""), + except.message); } END_CATCH } diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index c074186c6b4..51c9864185c 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2017-12-18 Joel Brobecker + + * gdb.dwarf2/ada-valprint-error.c: New file. + * gdb.dwarf2/ada-valprint-error.exp: New file. + 2017-12-18 Joel Brobecker * gdb.ada/assign_arr: New testcase. diff --git a/gdb/testsuite/gdb.dwarf2/ada-valprint-error.c b/gdb/testsuite/gdb.dwarf2/ada-valprint-error.c new file mode 100644 index 00000000000..4f04ab73faf --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/ada-valprint-error.c @@ -0,0 +1,23 @@ +/* Copyright 2017 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +int buffer[] = {0, 0}; +void *fd__global = &buffer; + +int +main (void) +{ + return 0; +} diff --git a/gdb/testsuite/gdb.dwarf2/ada-valprint-error.exp b/gdb/testsuite/gdb.dwarf2/ada-valprint-error.exp new file mode 100644 index 00000000000..192b0cbec2c --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/ada-valprint-error.exp @@ -0,0 +1,115 @@ +# Copyright 2017 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +load_lib dwarf.exp + +# This test can only be run on targets which support DWARF-2 and use gas. +if {![dwarf2_support]} { + return 0 +} + +standard_testfile ada-valprint-error.c ada-valprint-error-dw.S + +# We need to know the size of integer and address types in order +# to write some of the debugging info we'd like to generate. +# +# For that, we ask GDB by debugging our ada-valprint-error.c program. +# Any program would do, but since we already have ada-valprint-error.c +# specifically for this testcase, might as well use that. + +if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } { + untested ${testfile}.exp + return -1 +} + +# Make some DWARF for the test. +set asm_file [standard_output_file $srcfile2] +Dwarf::assemble $asm_file { + cu {} { + DW_TAG_compile_unit { + {DW_AT_language @DW_LANG_Ada95} + {DW_AT_name fd.adb} + {DW_AT_comp_dir /tmp} + } { + declare_labels array_elt_label integer_label array_label \ + typedef_label ref_type_label + set ptr_size [get_sizeof "void *" 96] + set int_size [get_sizeof "int" 4] + + # A structure with no size attribute, to mimick structures + # in Ada that have a dynamic size... + array_elt_label: structure_type { + {name fd__Tints_doubledC} + {artificial 1 DW_FORM_flag_present} + } + + # ... and a corresponding XVZ variable, supposed to be there + # to provide the actual size. Except that, in this case, + # the variable has no address, to simulate the fact that + # it has been optimized out (which the compiler can do, + # even if it at the expense of debuggability). + DW_TAG_variable { + {name fd__Tints_doubledC___XVZ} + {DW_AT_type :$integer_label} + {artificial 1 DW_FORM_flag_present} + } + + integer_label: DW_TAG_base_type { + {DW_AT_byte_size $int_size DW_FORM_sdata} + {DW_AT_encoding @DW_ATE_signed} + {DW_AT_name integer} + } + + array_label: DW_TAG_array_type { + {DW_AT_name fd__ints_doubled} + {DW_AT_type :$array_elt_label} + } { + DW_TAG_subrange_type { + {DW_AT_type :$integer_label} + {DW_AT_upper_bound 2 DW_FORM_data1} + } + } + + typedef_label: DW_TAG_typedef { + {DW_AT_name fd__ints_doubled} + {DW_AT_type :$array_label} + } + + ref_type_label: DW_TAG_reference_type { + {DW_AT_byte_size $ptr_size DW_FORM_sdata} + {DW_AT_type :$typedef_label} + } + + DW_TAG_variable { + {name fd__global} + {DW_AT_type :$ref_type_label} + {DW_AT_location { + DW_OP_addr [gdb_target_symbol fd__global] + } SPECIAL_expr} + {external 1 flag} + } + + } + } +} + +if { [prepare_for_testing ${testfile}.exp ${testfile} \ + [list $srcfile $asm_file] {nodebug}] } { + return -1 +} + +gdb_test_no_output "set language ada" + +gdb_test "print fd.global" \ + " = " -- 2.30.2